{"version":3,"sources":["out-editor/vs/editor/fake","out-editor/vs/editor/vs/css.js","out-editor/vs/editor/vs/nls.js","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/dnd.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/fastDomNode.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/iframe.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/list/list.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/list/splice.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/scrollbar/scrollbarState.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/tree/tree.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/arrays.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/assert.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/collections.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/color.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/decorators.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/diff/diffChange.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/errors.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/functional.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/idGenerator.ts","out-editor/vs/editor/vs/base/common/insane/insane.js","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/iterator.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/keyCodes.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/lazy.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/lifecycle.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/linkedList.ts","out-editor/vs/editor/vs/base/common/marked/marked.js","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/navigator.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/history.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/numbers.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/platform.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/process.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/path.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/range.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/list/rangeMap.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/stopwatch.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/event.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/browser.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/canIUse.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/event.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/keyboardEvent.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/mouseEvent.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/cancellation.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/async.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/scrollbar/scrollbarVisibilityController.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/codicons.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/tree/treeIcons.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/comparers.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/scrollable.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/strings.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/buffer.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/extpath.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/hash.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/diff/diff.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/tree/indexTreeModel.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/tree/objectTreeModel.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/search.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/severity.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/types.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/objects.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/uint.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/uri.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/map.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/filters.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/fuzzyScorer.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/glob.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/iconLabels.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/htmlContent.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/marshalling.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/network.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/dom.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/formattedTextRenderer.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/globalMouseMoveMonitor.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/touch.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/iconLabel/iconLabels.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/list/rowCache.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/widget.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/scrollbar/scrollbarArrow.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/scrollbar/horizontalScrollbar.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/scrollbar/verticalScrollbar.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/resources.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/markdownRenderer.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/labels.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/mime.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/uuid.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/worker/simpleWorker.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/parts/quickinput/common/quickInput.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/worker/defaultWorkerFactory.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/aria/aria.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/button/button.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/checkbox/checkbox.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/codicons/codiconStyles.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/contextview/contextview.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/countBadge/countBadge.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/mouseCursor/mouseCursor.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/progressbar/progressbar.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/sash/sash.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/scrollbar/scrollableElement.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/hover/hoverWidget.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/list/listView.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/list/listWidget.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/list/listPaging.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/splitview/splitview.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/parts/quickinput/browser/quickInputUtils.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/config/charWidthReader.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/config/elementSizeObserver.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/editorDom.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/services/abstractCodeEditorService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/minimap/minimapCharSheet.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/minimap/minimapCharRenderer.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/minimap/minimapPreBaked.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/minimap/minimapCharRendererFactory.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/config/editorZoom.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/config/fontInfo.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/core/characterClassifier.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/controller/wordCharacterClassifier.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/core/position.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/core/range.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/controller/textAreaState.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/widget/diffNavigator.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/core/editOperation.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/commands/trimTrailingWhitespaceCommand.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/core/rgba.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/core/selection.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/controller/textAreaInput.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/commands/replaceCommand.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/commands/surroundSelectionCommand.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/core/stringBuilder.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/view/viewLayer.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/core/token.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/diff/diffComputer.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/editorAction.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/editorCommon.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/editorBrowser.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/model.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/model/indentationGuesser.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/model/intervalTree.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/model/pieceTreeTextBuffer/rbTreeBase.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/model/textChange.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/model/textModelEvents.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/model/textModelSearch.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/model/wordHelper.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/modes/abstractMode.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/modes/languageConfiguration.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/modes/languageSelector.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/modes/linkComputer.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/modes/supports.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/modes/supports/characterPair.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/modes/supports/indentRules.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/modes/supports/inplaceReplaceSupport.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/modes/supports/onEnter.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/modes/supports/richEditBrackets.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/modes/supports/electricCharacter.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/modes/languageConfigurationRegistry.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/modes/supports/tokenization.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/modes/tokenizationRegistry.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/services/semanticTokensDto.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/standalone/standaloneEnums.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/standalone/standaloneBase.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/view/overviewZoneManager.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/view/renderingContext.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/lines/rangeUtil.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/view/viewContext.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/view/viewEvents.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/viewLayout/lineDecorations.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/viewLayout/linesLayout.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/viewLayout/viewLineRenderer.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/viewLayout/viewLinesViewportData.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/viewModel/prefixSumComputer.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/model/mirrorTextModel.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/services/editorSimpleWorker.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/viewModel/viewEventHandler.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/view/dynamicViewOverlay.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/view/viewPart.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/decorations/decorations.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/margin/margin.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/marginDecorations/marginDecorations.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/overlayWidgets/overlayWidgets.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/viewZones/viewZones.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/viewModel/viewModel.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/viewModel/monospaceLineBreaksComputer.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/viewModel/viewModelEventDispatcher.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/viewLayout/viewLayout.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/caretOperations/moveCaretCommand.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/codeAction/types.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/colorPicker/colorPickerModel.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/comment/blockCommentCommand.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/comment/lineCommentCommand.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/dnd/dragAndDropCommand.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/find/replaceAllCommand.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/find/replacePattern.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/folding/foldingRanges.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/folding/foldingModel.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/folding/hiddenRangeModel.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/folding/syntaxRangeProvider.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/folding/intializingRangeProvider.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/format/formattingEdit.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/gotoSymbol/link/clickLinkGesture.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/hover/hoverOperation.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/hover/hoverWidgets.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/inPlaceReplace/inPlaceReplaceCommand.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/indentation/indentUtils.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/linesOperations/copyLinesCommand.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/linesOperations/sortLinesCommand.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/smartSelect/bracketSelections.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/smartSelect/wordSelections.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/snippet/snippetParser.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/suggest/completionModel.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/suggest/resizable.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/suggest/suggestCommitCharacters.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/suggest/suggestOvertypingCapturer.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/suggest/wordDistance.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/standalone/common/monarch/monarchCommon.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/standalone/common/monarch/monarchCompile.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/findinput/findInputCheckboxes.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/iconLabel/iconLabel.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/tree/abstractTree.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/tree/dataTree.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/tree/objectTree.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/tree/asyncDataTree.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/actions.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/actionbar/actionViewItems.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/actionbar/actionbar.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/dropdown/dropdown.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/inputbox/inputBox.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/findinput/findInput.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/findinput/replaceInput.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/menu/menu.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/parts/quickinput/browser/quickInputBox.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/errorMessage.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/common/keybindingLabels.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/browser/ui/keybindingLabel/keybindingLabel.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/parts/quickinput/browser/quickInputList.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/base/parts/quickinput/browser/quickInput.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/widget/inlineDiffMargin.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/config/editorOptions.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/viewModel/viewModelDecorations.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/model/editStack.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/standaloneStrings.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/gotoSymbol/referencesModel.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/clipboard/browser/clipboardService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/contextkey/common/contextkeys.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/editor/common/editor.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/extensions/common/extensions.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/files/common/files.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/instantiation/common/descriptors.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/instantiation/common/extensions.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/instantiation/common/graph.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/instantiation/common/instantiation.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/services/bulkEditService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/services/codeEditorService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/services/editorWorkerService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/services/markersDecorationService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/services/modeService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/services/modelService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/modes/languageFeatureRegistry.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/modes.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/core/lineTokens.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/model/tokensStore.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/modes/nullMode.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/model/textModelTokens.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/model/textModel.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/controller/cursorCommon.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/commands/shiftCommand.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/controller/cursorAtomicMoveOperations.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/controller/cursorColumnSelection.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/controller/cursorMoveOperations.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/controller/cursorDeleteOperations.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/controller/cursorTypeOperations.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/controller/cursorWordOperations.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/controller/cursorMoveCommands.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/controller/oneCursor.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/controller/cursorCollection.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/controller/cursor.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/modes/textToHtmlTokenizer.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/services/resolverService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/services/textResourceConfigurationService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/viewModel/minimapTokensColorTracker.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/viewModel/splitLinesCollection.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/viewModel/viewModelImpl.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/documentSymbols/outlineModel.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/folding/indentRangeProvider.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/linesOperations/moveLinesCommand.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/zoneWidget/zoneWidget.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/standalone/common/monarch/monarchLexer.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/standalone/browser/colorizer.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/standalone/common/standaloneThemeService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/clipboard/common/clipboardService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/commands/common/commands.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/services/getSemanticTokens.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/codelens/codelens.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/colorPicker/color.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/documentSymbols/documentSymbols.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/links/getLinks.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/contextkey/common/contextkey.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/editorContextKeys.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/parameterHints/provideSignatureHelp.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/parameterHints/parameterHintsModel.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/suggest/suggestAlternatives.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/suggest/wordContextKey.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/accessibility/common/accessibility.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/contextview/browser/contextView.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/dialogs/common/dialogs.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/instantiation/common/serviceCollection.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/instantiation/common/instantiationService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/keybinding/common/abstractKeybindingService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/keybinding/common/baseResolvedKeybinding.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/keybinding/common/keybinding.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/keybinding/common/keybindingResolver.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/keybinding/common/resolvedKeybindingItem.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/keybinding/common/usLayoutResolvedKeybinding.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/label/common/label.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/layout/browser/layoutService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/contextview/browser/contextViewService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/log/common/log.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/services/editorWorkerServiceImpl.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/services/semanticTokensProviderStyling.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/services/webWorker.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/markers/common/markers.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/gotoError/markerNavigationService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/markers/common/markerService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/notification/common/notification.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/opener/common/opener.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/core/markdownRenderer.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/services/openerService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/hover/modesGlyphHover.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/suggest/suggestWidgetDetails.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/progress/common/progress.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/quickinput/browser/pickerQuickAccess.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/quickinput/common/quickInput.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/registry/common/platform.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/modes/modesRegistry.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/services/getIconClasses.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/jsonschemas/common/jsonContributionRegistry.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/configuration/common/configurationRegistry.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/config/commonEditorConfig.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/config/configuration.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/view/domLineBreaksComputer.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/view/viewOverlays.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/services/languagesRegistry.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/services/modeServiceImpl.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/configuration/common/configuration.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/accessibility/common/accessibilityService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/configuration/common/configurationModels.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/contextkey/browser/contextKeyService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/keybinding/common/keybindingsRegistry.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/browser/contextScopedHistoryWidget.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/quickinput/common/quickAccess.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/quickinput/browser/helpQuickAccess.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/standalone/browser/quickAccess/standaloneHelpQuickAccess.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/quickinput/browser/quickAccess.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/storage/common/storage.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/codelens/codeLensCache.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/suggest/suggestMemory.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/telemetry/common/telemetry.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/quickinput/browser/commandsQuickAccess.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/quickAccess/commandsQuickAccess.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/theme/common/colorRegistry.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/theme/common/styler.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/contextview/browser/contextMenuHandler.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/theme/common/theme.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/lines/viewLine.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/controller/mouseTarget.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/controller/mouseHandler.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/controller/pointerHandler.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/view/viewUserInputEvents.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/lines/viewLines.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/theme/common/themeService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/services/codeEditorServiceImpl.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/minimap/minimap.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/scrollDecoration/scrollDecoration.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/selections/selections.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/view/editorColorRegistry.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/controller/textAreaHandler.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/rulers/rulers.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/services/markerDecorationsServiceImpl.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/codeAction/lightBulbWidget.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/codelens/codelensWidget.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/colorPicker/colorPickerWidget.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/find/findDecorations.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/find/findModel.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/find/findOptionsWidget.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/find/findState.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/gotoSymbol/peek/referencesTree.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/quickAccess/editorNavigationQuickAccess.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/quickAccess/gotoLineQuickAccess.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/quickAccess/gotoSymbolQuickAccess.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/rename/renameInputField.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/symbolIcons/symbolIcons.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/standalone/browser/standaloneCodeServiceImpl.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/standalone/common/themes.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/actions/common/actions.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/editorExtensions.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/controller/coreCommands.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/core/keybindingCancellation.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/core/editorState.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/view/viewController.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/view/viewImpl.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/widget/codeEditorWidget.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/anchorSelect/anchorSelect.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/bracketMatching/bracketMatching.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/caretOperations/caretOperations.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/caretOperations/transpose.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/clipboard/clipboard.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/codeAction/codeAction.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/codeAction/codeActionMenu.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/codeAction/codeActionModel.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/codelens/codelensController.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/colorPicker/colorDetector.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/comment/comment.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/contextmenu/contextmenu.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/cursorUndo/cursorUndo.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/dnd/dnd.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/fontZoom/fontZoom.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/format/format.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/format/formatActions.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/gotoSymbol/goToSymbol.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/gotoSymbol/symbolNavigation.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/hover/getHover.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/hover/markdownHoverParticipant.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/inPlaceReplace/inPlaceReplace.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/indentation/indentation.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/inlineHints/inlineHintsController.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/linesOperations/linesOperations.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/linkedEditing/linkedEditing.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/links/links.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/message/messageController.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/codeAction/codeActionUi.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/codeAction/codeActionCommands.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/codeAction/codeActionContributions.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/rename/rename.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/smartSelect/smartSelect.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/suggest/suggest.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/tokenization/tokenization.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/unusualLineTerminators/unusualLineTerminators.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/wordOperations/wordOperations.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/wordPartOperations/wordPartOperations.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/standalone/browser/quickAccess/standaloneCommandsQuickAccess.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/standalone/browser/quickAccess/standaloneGotoLineQuickAccess.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/standalone/browser/quickAccess/standaloneGotoSymbolQuickAccess.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/actions/browser/menuEntryActionViewItem.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/peekView/peekView.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/suggest/suggestWidgetStatus.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/actions/common/menuService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/contextview/browser/contextMenuService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/list/browser/listService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/quickinput/browser/quickInput.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/standalone/browser/quickInput/standaloneQuickInputServiceImpl.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/severityIcon/common/severityIcon.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/gotoError/gotoErrorWidget.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/theme/common/iconRegistry.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/widget/diffReview.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/browser/widget/diffEditorWidget.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/find/findWidget.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/find/findController.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/folding/foldingDecorations.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/folding/folding.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/gotoError/gotoError.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/hover/markerHoverParticipant.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/hover/modesContentHover.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/multicursor/multicursor.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/parameterHints/parameterHints.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/suggest/suggestWidgetRenderer.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/suggest/suggestWidget.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/undoRedo/common/undoRedo.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/common/services/modelServiceImpl.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/gotoSymbol/peek/referencesController.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/gotoSymbol/goToCommands.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/hover/hover.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/colorPicker/colorContributions.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/viewportSemanticTokens/viewportSemanticTokens.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/standalone/browser/referenceSearch/standaloneReferenceSearch.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/undoRedo/common/undoRedoService.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/workspace/common/workspace.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/standalone/browser/simpleServices.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/standalone/browser/standaloneCodeEditor.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/standalone/browser/standaloneServices.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/standalone/browser/standaloneEditor.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/standalone/browser/standaloneLanguages.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/editor.api.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/platform/workspaces/common/workspaces.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/snippet/snippetVariables.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/snippet/snippetSession.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/snippet/snippetController2.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/suggest/suggestModel.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/contrib/suggest/suggestController.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/editor.all.ts","out-editor/vs/editor/file:/C:/Alex/src/vscode/out-editor-src/vs/editor/editor.main.ts"],"sourcesContent":["}).call(this);","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n/*---------------------------------------------------------------------------------------------\n *---------------------------------------------------------------------------------------------\n *---------------------------------------------------------------------------------------------\n *---------------------------------------------------------------------------------------------\n *---------------------------------------------------------------------------------------------\n * Please make sure to make edits in the .ts file at https://github.com/microsoft/vscode-loader/\n *---------------------------------------------------------------------------------------------\n *---------------------------------------------------------------------------------------------\n *---------------------------------------------------------------------------------------------\n *---------------------------------------------------------------------------------------------\n *--------------------------------------------------------------------------------------------*/\n'use strict';\nvar CSSLoaderPlugin;\n(function (CSSLoaderPlugin) {\n /**\n * Known issue:\n * - In IE there is no way to know if the CSS file loaded successfully or not.\n */\n var BrowserCSSLoader = /** @class */ (function () {\n function BrowserCSSLoader() {\n this._pendingLoads = 0;\n }\n BrowserCSSLoader.prototype.attachListeners = function (name, linkNode, callback, errorback) {\n var unbind = function () {\n linkNode.removeEventListener('load', loadEventListener);\n linkNode.removeEventListener('error', errorEventListener);\n };\n var loadEventListener = function (e) {\n unbind();\n callback();\n };\n var errorEventListener = function (e) {\n unbind();\n errorback(e);\n };\n linkNode.addEventListener('load', loadEventListener);\n linkNode.addEventListener('error', errorEventListener);\n };\n BrowserCSSLoader.prototype._onLoad = function (name, callback) {\n this._pendingLoads--;\n callback();\n };\n BrowserCSSLoader.prototype._onLoadError = function (name, errorback, err) {\n this._pendingLoads--;\n errorback(err);\n };\n BrowserCSSLoader.prototype._insertLinkNode = function (linkNode) {\n this._pendingLoads++;\n var head = document.head || document.getElementsByTagName('head')[0];\n var other = head.getElementsByTagName('link') || head.getElementsByTagName('script');\n if (other.length > 0) {\n head.insertBefore(linkNode, other[other.length - 1]);\n }\n else {\n head.appendChild(linkNode);\n }\n };\n BrowserCSSLoader.prototype.createLinkTag = function (name, cssUrl, externalCallback, externalErrorback) {\n var _this = this;\n var linkNode = document.createElement('link');\n linkNode.setAttribute('rel', 'stylesheet');\n linkNode.setAttribute('type', 'text/css');\n linkNode.setAttribute('data-name', name);\n var callback = function () { return _this._onLoad(name, externalCallback); };\n var errorback = function (err) { return _this._onLoadError(name, externalErrorback, err); };\n this.attachListeners(name, linkNode, callback, errorback);\n linkNode.setAttribute('href', cssUrl);\n return linkNode;\n };\n BrowserCSSLoader.prototype._linkTagExists = function (name, cssUrl) {\n var i, len, nameAttr, hrefAttr, links = document.getElementsByTagName('link');\n for (i = 0, len = links.length; i < len; i++) {\n nameAttr = links[i].getAttribute('data-name');\n hrefAttr = links[i].getAttribute('href');\n if (nameAttr === name || hrefAttr === cssUrl) {\n return true;\n }\n }\n return false;\n };\n BrowserCSSLoader.prototype.load = function (name, cssUrl, externalCallback, externalErrorback) {\n if (this._linkTagExists(name, cssUrl)) {\n externalCallback();\n return;\n }\n var linkNode = this.createLinkTag(name, cssUrl, externalCallback, externalErrorback);\n this._insertLinkNode(linkNode);\n };\n return BrowserCSSLoader;\n }());\n // ------------------------------ Finally, the plugin\n var CSSPlugin = /** @class */ (function () {\n function CSSPlugin() {\n this._cssLoader = new BrowserCSSLoader();\n }\n CSSPlugin.prototype.load = function (name, req, load, config) {\n config = config || {};\n var cssConfig = config['vs/css'] || {};\n if (cssConfig.disabled) {\n // the plugin is asked to not create any style sheets\n load({});\n return;\n }\n var cssUrl = req.toUrl(name + '.css');\n this._cssLoader.load(name, cssUrl, function (contents) {\n load({});\n }, function (err) {\n if (typeof load.error === 'function') {\n load.error('Could not find ' + cssUrl + ' or it was empty');\n }\n });\n };\n return CSSPlugin;\n }());\n CSSLoaderPlugin.CSSPlugin = CSSPlugin;\n define('vs/css', new CSSPlugin());\n})(CSSLoaderPlugin || (CSSLoaderPlugin = {}));\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n/*---------------------------------------------------------------------------------------------\n *---------------------------------------------------------------------------------------------\n *---------------------------------------------------------------------------------------------\n *---------------------------------------------------------------------------------------------\n *---------------------------------------------------------------------------------------------\n * Please make sure to make edits in the .ts file at https://github.com/microsoft/vscode-loader/\n *---------------------------------------------------------------------------------------------\n *---------------------------------------------------------------------------------------------\n *---------------------------------------------------------------------------------------------\n *---------------------------------------------------------------------------------------------\n *--------------------------------------------------------------------------------------------*/\n'use strict';\nvar __spreadArrays = (this && this.__spreadArrays) || function () {\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\n r[k] = a[j];\n return r;\n};\nvar NLSLoaderPlugin;\n(function (NLSLoaderPlugin) {\n var Environment = /** @class */ (function () {\n function Environment() {\n this._detected = false;\n this._isPseudo = false;\n }\n Object.defineProperty(Environment.prototype, \"isPseudo\", {\n get: function () {\n this._detect();\n return this._isPseudo;\n },\n enumerable: true,\n configurable: true\n });\n Environment.prototype._detect = function () {\n if (this._detected) {\n return;\n }\n this._detected = true;\n this._isPseudo = (typeof document !== 'undefined' && document.location && document.location.hash.indexOf('pseudo=true') >= 0);\n };\n return Environment;\n }());\n function _format(message, args, env) {\n var result;\n if (args.length === 0) {\n result = message;\n }\n else {\n result = message.replace(/\\{(\\d+)\\}/g, function (match, rest) {\n var index = rest[0];\n var arg = args[index];\n var result = match;\n if (typeof arg === 'string') {\n result = arg;\n }\n else if (typeof arg === 'number' || typeof arg === 'boolean' || arg === void 0 || arg === null) {\n result = String(arg);\n }\n return result;\n });\n }\n if (env.isPseudo) {\n // FF3B and FF3D is the Unicode zenkaku representation for [ and ]\n result = '\\uFF3B' + result.replace(/[aouei]/g, '$&$&') + '\\uFF3D';\n }\n return result;\n }\n function findLanguageForModule(config, name) {\n var result = config[name];\n if (result)\n return result;\n result = config['*'];\n if (result)\n return result;\n return null;\n }\n function localize(env, data, message) {\n var args = [];\n for (var _i = 3; _i < arguments.length; _i++) {\n args[_i - 3] = arguments[_i];\n }\n return _format(message, args, env);\n }\n function createScopedLocalize(scope, env) {\n return function (idx, defaultValue) {\n var restArgs = Array.prototype.slice.call(arguments, 2);\n return _format(scope[idx], restArgs, env);\n };\n }\n var NLSPlugin = /** @class */ (function () {\n function NLSPlugin(env) {\n var _this = this;\n this._env = env;\n this.localize = function (data, message) {\n var args = [];\n for (var _i = 2; _i < arguments.length; _i++) {\n args[_i - 2] = arguments[_i];\n }\n return localize.apply(void 0, __spreadArrays([_this._env, data, message], args));\n };\n }\n NLSPlugin.prototype.setPseudoTranslation = function (value) {\n this._env._isPseudo = value;\n };\n NLSPlugin.prototype.create = function (key, data) {\n return {\n localize: createScopedLocalize(data[key], this._env)\n };\n };\n NLSPlugin.prototype.load = function (name, req, load, config) {\n var _this = this;\n config = config || {};\n if (!name || name.length === 0) {\n load({\n localize: this.localize\n });\n }\n else {\n var pluginConfig = config['vs/nls'] || {};\n var language = pluginConfig.availableLanguages ? findLanguageForModule(pluginConfig.availableLanguages, name) : null;\n var suffix = '.nls';\n if (language !== null && language !== NLSPlugin.DEFAULT_TAG) {\n suffix = suffix + '.' + language;\n }\n var messagesLoaded_1 = function (messages) {\n if (Array.isArray(messages)) {\n messages.localize = createScopedLocalize(messages, _this._env);\n }\n else {\n messages.localize = createScopedLocalize(messages[name], _this._env);\n }\n load(messages);\n };\n if (typeof pluginConfig.loadBundle === 'function') {\n pluginConfig.loadBundle(name, language, function (err, messages) {\n // We have an error. Load the English default strings to not fail\n if (err) {\n req([name + '.nls'], messagesLoaded_1);\n }\n else {\n messagesLoaded_1(messages);\n }\n });\n }\n else {\n req([name + suffix], messagesLoaded_1);\n }\n }\n };\n NLSPlugin.DEFAULT_TAG = 'i-default';\n return NLSPlugin;\n }());\n NLSLoaderPlugin.NLSPlugin = NLSPlugin;\n define('vs/nls', new NLSPlugin(new Environment()));\n})(NLSLoaderPlugin || (NLSLoaderPlugin = {}));\n","\r\n\r\n// Common data transfers\r\nexport const DataTransfers = {\r\n\r\n\t/**\r\n\t * Application specific resource transfer type\r\n\t */\r\n\tRESOURCES: 'ResourceURLs',\r\n\r\n\t/**\r\n\t * Browser specific transfer type to download\r\n\t */\r\n\tDOWNLOAD_URL: 'DownloadURL',\r\n\r\n\t/**\r\n\t * Browser specific transfer type for files\r\n\t */\r\n\tFILES: 'Files',\r\n\r\n\t/**\r\n\t * Typically transfer type for copy/paste transfers.\r\n\t */\r\n\tTEXT: 'text/plain'\r\n};\r\n\r\nexport interface IDragAndDropData {\r\n\tupdate(dataTransfer: DataTransfer): void;\r\n\tgetData(): any;\r\n}\r\n\r\nexport class DragAndDropData implements IDragAndDropData {\r\n\r\n\tconstructor(private data: T) { }\r\n\r\n\tupdate(): void {\r\n\t\t// noop\r\n\t}\r\n\r\n\tgetData(): T {\r\n\t\treturn this.data;\r\n\t}\r\n}\r\n\r\nexport interface IStaticDND {\r\n\tCurrentDragAndDropData: IDragAndDropData | undefined;\r\n}\r\n\r\nexport const StaticDND: IStaticDND = {\r\n\tCurrentDragAndDropData: undefined\r\n};\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nexport class FastDomNode {\r\n\r\n\tpublic readonly domNode: T;\r\n\tprivate _maxWidth: number;\r\n\tprivate _width: number;\r\n\tprivate _height: number;\r\n\tprivate _top: number;\r\n\tprivate _left: number;\r\n\tprivate _bottom: number;\r\n\tprivate _right: number;\r\n\tprivate _fontFamily: string;\r\n\tprivate _fontWeight: string;\r\n\tprivate _fontSize: number;\r\n\tprivate _fontFeatureSettings: string;\r\n\tprivate _lineHeight: number;\r\n\tprivate _letterSpacing: number;\r\n\tprivate _className: string;\r\n\tprivate _display: string;\r\n\tprivate _position: string;\r\n\tprivate _visibility: string;\r\n\tprivate _backgroundColor: string;\r\n\tprivate _layerHint: boolean;\r\n\tprivate _contain: 'none' | 'strict' | 'content' | 'size' | 'layout' | 'style' | 'paint';\r\n\tprivate _boxShadow: string;\r\n\r\n\tconstructor(domNode: T) {\r\n\t\tthis.domNode = domNode;\r\n\t\tthis._maxWidth = -1;\r\n\t\tthis._width = -1;\r\n\t\tthis._height = -1;\r\n\t\tthis._top = -1;\r\n\t\tthis._left = -1;\r\n\t\tthis._bottom = -1;\r\n\t\tthis._right = -1;\r\n\t\tthis._fontFamily = '';\r\n\t\tthis._fontWeight = '';\r\n\t\tthis._fontSize = -1;\r\n\t\tthis._fontFeatureSettings = '';\r\n\t\tthis._lineHeight = -1;\r\n\t\tthis._letterSpacing = -100;\r\n\t\tthis._className = '';\r\n\t\tthis._display = '';\r\n\t\tthis._position = '';\r\n\t\tthis._visibility = '';\r\n\t\tthis._backgroundColor = '';\r\n\t\tthis._layerHint = false;\r\n\t\tthis._contain = 'none';\r\n\t\tthis._boxShadow = '';\r\n\t}\r\n\r\n\tpublic setMaxWidth(maxWidth: number): void {\r\n\t\tif (this._maxWidth === maxWidth) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._maxWidth = maxWidth;\r\n\t\tthis.domNode.style.maxWidth = this._maxWidth + 'px';\r\n\t}\r\n\r\n\tpublic setWidth(width: number): void {\r\n\t\tif (this._width === width) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._width = width;\r\n\t\tthis.domNode.style.width = this._width + 'px';\r\n\t}\r\n\r\n\tpublic setHeight(height: number): void {\r\n\t\tif (this._height === height) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._height = height;\r\n\t\tthis.domNode.style.height = this._height + 'px';\r\n\t}\r\n\r\n\tpublic setTop(top: number): void {\r\n\t\tif (this._top === top) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._top = top;\r\n\t\tthis.domNode.style.top = this._top + 'px';\r\n\t}\r\n\r\n\tpublic unsetTop(): void {\r\n\t\tif (this._top === -1) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._top = -1;\r\n\t\tthis.domNode.style.top = '';\r\n\t}\r\n\r\n\tpublic setLeft(left: number): void {\r\n\t\tif (this._left === left) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._left = left;\r\n\t\tthis.domNode.style.left = this._left + 'px';\r\n\t}\r\n\r\n\tpublic setBottom(bottom: number): void {\r\n\t\tif (this._bottom === bottom) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._bottom = bottom;\r\n\t\tthis.domNode.style.bottom = this._bottom + 'px';\r\n\t}\r\n\r\n\tpublic setRight(right: number): void {\r\n\t\tif (this._right === right) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._right = right;\r\n\t\tthis.domNode.style.right = this._right + 'px';\r\n\t}\r\n\r\n\tpublic setFontFamily(fontFamily: string): void {\r\n\t\tif (this._fontFamily === fontFamily) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._fontFamily = fontFamily;\r\n\t\tthis.domNode.style.fontFamily = this._fontFamily;\r\n\t}\r\n\r\n\tpublic setFontWeight(fontWeight: string): void {\r\n\t\tif (this._fontWeight === fontWeight) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._fontWeight = fontWeight;\r\n\t\tthis.domNode.style.fontWeight = this._fontWeight;\r\n\t}\r\n\r\n\tpublic setFontSize(fontSize: number): void {\r\n\t\tif (this._fontSize === fontSize) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._fontSize = fontSize;\r\n\t\tthis.domNode.style.fontSize = this._fontSize + 'px';\r\n\t}\r\n\r\n\tpublic setFontFeatureSettings(fontFeatureSettings: string): void {\r\n\t\tif (this._fontFeatureSettings === fontFeatureSettings) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._fontFeatureSettings = fontFeatureSettings;\r\n\t\tthis.domNode.style.fontFeatureSettings = this._fontFeatureSettings;\r\n\t}\r\n\r\n\tpublic setLineHeight(lineHeight: number): void {\r\n\t\tif (this._lineHeight === lineHeight) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._lineHeight = lineHeight;\r\n\t\tthis.domNode.style.lineHeight = this._lineHeight + 'px';\r\n\t}\r\n\r\n\tpublic setLetterSpacing(letterSpacing: number): void {\r\n\t\tif (this._letterSpacing === letterSpacing) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._letterSpacing = letterSpacing;\r\n\t\tthis.domNode.style.letterSpacing = this._letterSpacing + 'px';\r\n\t}\r\n\r\n\tpublic setClassName(className: string): void {\r\n\t\tif (this._className === className) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._className = className;\r\n\t\tthis.domNode.className = this._className;\r\n\t}\r\n\r\n\tpublic toggleClassName(className: string, shouldHaveIt?: boolean): void {\r\n\t\tthis.domNode.classList.toggle(className, shouldHaveIt);\r\n\t\tthis._className = this.domNode.className;\r\n\t}\r\n\r\n\tpublic setDisplay(display: string): void {\r\n\t\tif (this._display === display) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._display = display;\r\n\t\tthis.domNode.style.display = this._display;\r\n\t}\r\n\r\n\tpublic setPosition(position: string): void {\r\n\t\tif (this._position === position) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._position = position;\r\n\t\tthis.domNode.style.position = this._position;\r\n\t}\r\n\r\n\tpublic setVisibility(visibility: string): void {\r\n\t\tif (this._visibility === visibility) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._visibility = visibility;\r\n\t\tthis.domNode.style.visibility = this._visibility;\r\n\t}\r\n\r\n\tpublic setBackgroundColor(backgroundColor: string): void {\r\n\t\tif (this._backgroundColor === backgroundColor) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._backgroundColor = backgroundColor;\r\n\t\tthis.domNode.style.backgroundColor = this._backgroundColor;\r\n\t}\r\n\r\n\tpublic setLayerHinting(layerHint: boolean): void {\r\n\t\tif (this._layerHint === layerHint) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._layerHint = layerHint;\r\n\t\tthis.domNode.style.transform = this._layerHint ? 'translate3d(0px, 0px, 0px)' : '';\r\n\t}\r\n\r\n\tpublic setBoxShadow(boxShadow: string): void {\r\n\t\tif (this._boxShadow === boxShadow) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._boxShadow = boxShadow;\r\n\t\tthis.domNode.style.boxShadow = boxShadow;\r\n\t}\r\n\r\n\tpublic setContain(contain: 'none' | 'strict' | 'content' | 'size' | 'layout' | 'style' | 'paint'): void {\r\n\t\tif (this._contain === contain) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._contain = contain;\r\n\t\t(this.domNode.style).contain = this._contain;\r\n\t}\r\n\r\n\tpublic setAttribute(name: string, value: string): void {\r\n\t\tthis.domNode.setAttribute(name, value);\r\n\t}\r\n\r\n\tpublic removeAttribute(name: string): void {\r\n\t\tthis.domNode.removeAttribute(name);\r\n\t}\r\n\r\n\tpublic appendChild(child: FastDomNode): void {\r\n\t\tthis.domNode.appendChild(child.domNode);\r\n\t}\r\n\r\n\tpublic removeChild(child: FastDomNode): void {\r\n\t\tthis.domNode.removeChild(child.domNode);\r\n\t}\r\n}\r\n\r\nexport function createFastDomNode(domNode: T): FastDomNode {\r\n\treturn new FastDomNode(domNode);\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\n/**\r\n * Represents a window in a possible chain of iframes\r\n */\r\nexport interface IWindowChainElement {\r\n\t/**\r\n\t * The window object for it\r\n\t */\r\n\twindow: Window;\r\n\t/**\r\n\t * The iframe element inside the window.parent corresponding to window\r\n\t */\r\n\tiframeElement: Element | null;\r\n}\r\n\r\nlet hasDifferentOriginAncestorFlag: boolean = false;\r\nlet sameOriginWindowChainCache: IWindowChainElement[] | null = null;\r\n\r\nfunction getParentWindowIfSameOrigin(w: Window): Window | null {\r\n\tif (!w.parent || w.parent === w) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\t// Cannot really tell if we have access to the parent window unless we try to access something in it\r\n\ttry {\r\n\t\tlet location = w.location;\r\n\t\tlet parentLocation = w.parent.location;\r\n\t\tif (location.origin !== 'null' && parentLocation.origin !== 'null') {\r\n\t\t\tif (location.protocol !== parentLocation.protocol || location.hostname !== parentLocation.hostname || location.port !== parentLocation.port) {\r\n\t\t\t\thasDifferentOriginAncestorFlag = true;\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t}\r\n\t} catch (e) {\r\n\t\thasDifferentOriginAncestorFlag = true;\r\n\t\treturn null;\r\n\t}\r\n\r\n\treturn w.parent;\r\n}\r\n\r\nexport class IframeUtils {\r\n\r\n\t/**\r\n\t * Returns a chain of embedded windows with the same origin (which can be accessed programmatically).\r\n\t * Having a chain of length 1 might mean that the current execution environment is running outside of an iframe or inside an iframe embedded in a window with a different origin.\r\n\t * To distinguish if at one point the current execution environment is running inside a window with a different origin, see hasDifferentOriginAncestor()\r\n\t */\r\n\tpublic static getSameOriginWindowChain(): IWindowChainElement[] {\r\n\t\tif (!sameOriginWindowChainCache) {\r\n\t\t\tsameOriginWindowChainCache = [];\r\n\t\t\tlet w: Window | null = window;\r\n\t\t\tlet parent: Window | null;\r\n\t\t\tdo {\r\n\t\t\t\tparent = getParentWindowIfSameOrigin(w);\r\n\t\t\t\tif (parent) {\r\n\t\t\t\t\tsameOriginWindowChainCache.push({\r\n\t\t\t\t\t\twindow: w,\r\n\t\t\t\t\t\tiframeElement: w.frameElement || null\r\n\t\t\t\t\t});\r\n\t\t\t\t} else {\r\n\t\t\t\t\tsameOriginWindowChainCache.push({\r\n\t\t\t\t\t\twindow: w,\r\n\t\t\t\t\t\tiframeElement: null\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t\tw = parent;\r\n\t\t\t} while (w);\r\n\t\t}\r\n\t\treturn sameOriginWindowChainCache.slice(0);\r\n\t}\r\n\r\n\t/**\r\n\t * Returns true if the current execution environment is chained in a list of iframes which at one point ends in a window with a different origin.\r\n\t * Returns false if the current execution environment is not running inside an iframe or if the entire chain of iframes have the same origin.\r\n\t */\r\n\tpublic static hasDifferentOriginAncestor(): boolean {\r\n\t\tif (!sameOriginWindowChainCache) {\r\n\t\t\tthis.getSameOriginWindowChain();\r\n\t\t}\r\n\t\treturn hasDifferentOriginAncestorFlag;\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the position of `childWindow` relative to `ancestorWindow`\r\n\t */\r\n\tpublic static getPositionOfChildWindowRelativeToAncestorWindow(childWindow: Window, ancestorWindow: Window | null) {\r\n\r\n\t\tif (!ancestorWindow || childWindow === ancestorWindow) {\r\n\t\t\treturn {\r\n\t\t\t\ttop: 0,\r\n\t\t\t\tleft: 0\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tlet top = 0, left = 0;\r\n\r\n\t\tlet windowChain = this.getSameOriginWindowChain();\r\n\r\n\t\tfor (const windowChainEl of windowChain) {\r\n\r\n\t\t\ttop += windowChainEl.window.scrollY;\r\n\t\t\tleft += windowChainEl.window.scrollX;\r\n\r\n\t\t\tif (windowChainEl.window === ancestorWindow) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tif (!windowChainEl.iframeElement) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tlet boundingRect = windowChainEl.iframeElement.getBoundingClientRect();\r\n\t\t\ttop += boundingRect.top;\r\n\t\t\tleft += boundingRect.left;\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\ttop: top,\r\n\t\t\tleft: left\r\n\t\t};\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { GestureEvent } from 'vs/base/browser/touch';\r\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { IDragAndDropData } from 'vs/base/browser/dnd';\r\n\r\nexport interface IListVirtualDelegate {\r\n\tgetHeight(element: T): number;\r\n\tgetTemplateId(element: T): string;\r\n\thasDynamicHeight?(element: T): boolean;\r\n\tsetDynamicHeight?(element: T, height: number): void;\r\n}\r\n\r\nexport interface IListRenderer {\r\n\ttemplateId: string;\r\n\trenderTemplate(container: HTMLElement): TTemplateData;\r\n\trenderElement(element: T, index: number, templateData: TTemplateData, height: number | undefined): void;\r\n\tdisposeElement?(element: T, index: number, templateData: TTemplateData, height: number | undefined): void;\r\n\tdisposeTemplate(templateData: TTemplateData): void;\r\n}\r\n\r\nexport interface IListEvent {\r\n\telements: T[];\r\n\tindexes: number[];\r\n\tbrowserEvent?: UIEvent;\r\n}\r\n\r\nexport interface IListMouseEvent {\r\n\tbrowserEvent: MouseEvent;\r\n\telement: T | undefined;\r\n\tindex: number | undefined;\r\n}\r\n\r\nexport interface IListTouchEvent {\r\n\tbrowserEvent: TouchEvent;\r\n\telement: T | undefined;\r\n\tindex: number | undefined;\r\n}\r\n\r\nexport interface IListGestureEvent {\r\n\tbrowserEvent: GestureEvent;\r\n\telement: T | undefined;\r\n\tindex: number | undefined;\r\n}\r\n\r\nexport interface IListDragEvent {\r\n\tbrowserEvent: DragEvent;\r\n\telement: T | undefined;\r\n\tindex: number | undefined;\r\n}\r\n\r\nexport interface IListContextMenuEvent {\r\n\tbrowserEvent: UIEvent;\r\n\tindex: number | undefined;\r\n}\r\n\r\nexport interface IIdentityProvider {\r\n\tgetId(element: T): { toString(): string; };\r\n}\r\n\r\nexport interface IKeyboardNavigationLabelProvider {\r\n\r\n\t/**\r\n\t * Return a keyboard navigation label(s) which will be used by\r\n\t * the list for filtering/navigating. Return `undefined` to make\r\n\t * an element always match.\r\n\t */\r\n\tgetKeyboardNavigationLabel(element: T): { toString(): string | undefined; } | { toString(): string | undefined; }[] | undefined;\r\n}\r\n\r\nexport interface IKeyboardNavigationDelegate {\r\n\tmightProducePrintableCharacter(event: IKeyboardEvent): boolean;\r\n}\r\n\r\nexport const enum ListDragOverEffect {\r\n\tCopy,\r\n\tMove\r\n}\r\n\r\nexport interface IListDragOverReaction {\r\n\taccept: boolean;\r\n\teffect?: ListDragOverEffect;\r\n\tfeedback?: number[]; // use -1 for entire list\r\n}\r\n\r\nexport interface IListDragAndDrop {\r\n\tgetDragURI(element: T): string | null;\r\n\tgetDragLabel?(elements: T[], originalEvent: DragEvent): string | undefined;\r\n\tonDragStart?(data: IDragAndDropData, originalEvent: DragEvent): void;\r\n\tonDragOver(data: IDragAndDropData, targetElement: T | undefined, targetIndex: number | undefined, originalEvent: DragEvent): boolean | IListDragOverReaction;\r\n\tdrop(data: IDragAndDropData, targetElement: T | undefined, targetIndex: number | undefined, originalEvent: DragEvent): void;\r\n\tonDragEnd?(originalEvent: DragEvent): void;\r\n}\r\n\r\nexport class ListError extends Error {\r\n\r\n\tconstructor(user: string, message: string) {\r\n\t\tsuper(`ListError [${user}] ${message}`);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { ISpliceable } from 'vs/base/common/sequence';\r\n\r\nexport class CombinedSpliceable implements ISpliceable {\r\n\r\n\tconstructor(private spliceables: ISpliceable[]) { }\r\n\r\n\tsplice(start: number, deleteCount: number, elements: T[]): void {\r\n\t\tthis.spliceables.forEach(s => s.splice(start, deleteCount, elements));\r\n\t}\r\n}","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\n/**\r\n * The minimal size of the slider (such that it can still be clickable) -- it is artificially enlarged.\r\n */\r\nconst MINIMUM_SLIDER_SIZE = 20;\r\n\r\nexport class ScrollbarState {\r\n\r\n\t/**\r\n\t * For the vertical scrollbar: the width.\r\n\t * For the horizontal scrollbar: the height.\r\n\t */\r\n\tprivate _scrollbarSize: number;\r\n\r\n\t/**\r\n\t * For the vertical scrollbar: the height of the pair horizontal scrollbar.\r\n\t * For the horizontal scrollbar: the width of the pair vertical scrollbar.\r\n\t */\r\n\tprivate readonly _oppositeScrollbarSize: number;\r\n\r\n\t/**\r\n\t * For the vertical scrollbar: the height of the scrollbar's arrows.\r\n\t * For the horizontal scrollbar: the width of the scrollbar's arrows.\r\n\t */\r\n\tprivate readonly _arrowSize: number;\r\n\r\n\t// --- variables\r\n\t/**\r\n\t * For the vertical scrollbar: the viewport height.\r\n\t * For the horizontal scrollbar: the viewport width.\r\n\t */\r\n\tprivate _visibleSize: number;\r\n\r\n\t/**\r\n\t * For the vertical scrollbar: the scroll height.\r\n\t * For the horizontal scrollbar: the scroll width.\r\n\t */\r\n\tprivate _scrollSize: number;\r\n\r\n\t/**\r\n\t * For the vertical scrollbar: the scroll top.\r\n\t * For the horizontal scrollbar: the scroll left.\r\n\t */\r\n\tprivate _scrollPosition: number;\r\n\r\n\t// --- computed variables\r\n\r\n\t/**\r\n\t * `visibleSize` - `oppositeScrollbarSize`\r\n\t */\r\n\tprivate _computedAvailableSize: number;\r\n\t/**\r\n\t * (`scrollSize` > 0 && `scrollSize` > `visibleSize`)\r\n\t */\r\n\tprivate _computedIsNeeded: boolean;\r\n\r\n\tprivate _computedSliderSize: number;\r\n\tprivate _computedSliderRatio: number;\r\n\tprivate _computedSliderPosition: number;\r\n\r\n\tconstructor(arrowSize: number, scrollbarSize: number, oppositeScrollbarSize: number, visibleSize: number, scrollSize: number, scrollPosition: number) {\r\n\t\tthis._scrollbarSize = Math.round(scrollbarSize);\r\n\t\tthis._oppositeScrollbarSize = Math.round(oppositeScrollbarSize);\r\n\t\tthis._arrowSize = Math.round(arrowSize);\r\n\r\n\t\tthis._visibleSize = visibleSize;\r\n\t\tthis._scrollSize = scrollSize;\r\n\t\tthis._scrollPosition = scrollPosition;\r\n\r\n\t\tthis._computedAvailableSize = 0;\r\n\t\tthis._computedIsNeeded = false;\r\n\t\tthis._computedSliderSize = 0;\r\n\t\tthis._computedSliderRatio = 0;\r\n\t\tthis._computedSliderPosition = 0;\r\n\r\n\t\tthis._refreshComputedValues();\r\n\t}\r\n\r\n\tpublic clone(): ScrollbarState {\r\n\t\treturn new ScrollbarState(this._arrowSize, this._scrollbarSize, this._oppositeScrollbarSize, this._visibleSize, this._scrollSize, this._scrollPosition);\r\n\t}\r\n\r\n\tpublic setVisibleSize(visibleSize: number): boolean {\r\n\t\tconst iVisibleSize = Math.round(visibleSize);\r\n\t\tif (this._visibleSize !== iVisibleSize) {\r\n\t\t\tthis._visibleSize = iVisibleSize;\r\n\t\t\tthis._refreshComputedValues();\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic setScrollSize(scrollSize: number): boolean {\r\n\t\tconst iScrollSize = Math.round(scrollSize);\r\n\t\tif (this._scrollSize !== iScrollSize) {\r\n\t\t\tthis._scrollSize = iScrollSize;\r\n\t\t\tthis._refreshComputedValues();\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic setScrollPosition(scrollPosition: number): boolean {\r\n\t\tconst iScrollPosition = Math.round(scrollPosition);\r\n\t\tif (this._scrollPosition !== iScrollPosition) {\r\n\t\t\tthis._scrollPosition = iScrollPosition;\r\n\t\t\tthis._refreshComputedValues();\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic setScrollbarSize(scrollbarSize: number): void {\r\n\t\tthis._scrollbarSize = scrollbarSize;\r\n\t}\r\n\r\n\tprivate static _computeValues(oppositeScrollbarSize: number, arrowSize: number, visibleSize: number, scrollSize: number, scrollPosition: number) {\r\n\t\tconst computedAvailableSize = Math.max(0, visibleSize - oppositeScrollbarSize);\r\n\t\tconst computedRepresentableSize = Math.max(0, computedAvailableSize - 2 * arrowSize);\r\n\t\tconst computedIsNeeded = (scrollSize > 0 && scrollSize > visibleSize);\r\n\r\n\t\tif (!computedIsNeeded) {\r\n\t\t\t// There is no need for a slider\r\n\t\t\treturn {\r\n\t\t\t\tcomputedAvailableSize: Math.round(computedAvailableSize),\r\n\t\t\t\tcomputedIsNeeded: computedIsNeeded,\r\n\t\t\t\tcomputedSliderSize: Math.round(computedRepresentableSize),\r\n\t\t\t\tcomputedSliderRatio: 0,\r\n\t\t\t\tcomputedSliderPosition: 0,\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\t// We must artificially increase the size of the slider if needed, since the slider would be too small to grab with the mouse otherwise\r\n\t\tconst computedSliderSize = Math.round(Math.max(MINIMUM_SLIDER_SIZE, Math.floor(visibleSize * computedRepresentableSize / scrollSize)));\r\n\r\n\t\t// The slider can move from 0 to `computedRepresentableSize` - `computedSliderSize`\r\n\t\t// in the same way `scrollPosition` can move from 0 to `scrollSize` - `visibleSize`.\r\n\t\tconst computedSliderRatio = (computedRepresentableSize - computedSliderSize) / (scrollSize - visibleSize);\r\n\t\tconst computedSliderPosition = (scrollPosition * computedSliderRatio);\r\n\r\n\t\treturn {\r\n\t\t\tcomputedAvailableSize: Math.round(computedAvailableSize),\r\n\t\t\tcomputedIsNeeded: computedIsNeeded,\r\n\t\t\tcomputedSliderSize: Math.round(computedSliderSize),\r\n\t\t\tcomputedSliderRatio: computedSliderRatio,\r\n\t\t\tcomputedSliderPosition: Math.round(computedSliderPosition),\r\n\t\t};\r\n\t}\r\n\r\n\tprivate _refreshComputedValues(): void {\r\n\t\tconst r = ScrollbarState._computeValues(this._oppositeScrollbarSize, this._arrowSize, this._visibleSize, this._scrollSize, this._scrollPosition);\r\n\t\tthis._computedAvailableSize = r.computedAvailableSize;\r\n\t\tthis._computedIsNeeded = r.computedIsNeeded;\r\n\t\tthis._computedSliderSize = r.computedSliderSize;\r\n\t\tthis._computedSliderRatio = r.computedSliderRatio;\r\n\t\tthis._computedSliderPosition = r.computedSliderPosition;\r\n\t}\r\n\r\n\tpublic getArrowSize(): number {\r\n\t\treturn this._arrowSize;\r\n\t}\r\n\r\n\tpublic getScrollPosition(): number {\r\n\t\treturn this._scrollPosition;\r\n\t}\r\n\r\n\tpublic getRectangleLargeSize(): number {\r\n\t\treturn this._computedAvailableSize;\r\n\t}\r\n\r\n\tpublic getRectangleSmallSize(): number {\r\n\t\treturn this._scrollbarSize;\r\n\t}\r\n\r\n\tpublic isNeeded(): boolean {\r\n\t\treturn this._computedIsNeeded;\r\n\t}\r\n\r\n\tpublic getSliderSize(): number {\r\n\t\treturn this._computedSliderSize;\r\n\t}\r\n\r\n\tpublic getSliderPosition(): number {\r\n\t\treturn this._computedSliderPosition;\r\n\t}\r\n\r\n\t/**\r\n\t * Compute a desired `scrollPosition` such that `offset` ends up in the center of the slider.\r\n\t * `offset` is based on the same coordinate system as the `sliderPosition`.\r\n\t */\r\n\tpublic getDesiredScrollPositionFromOffset(offset: number): number {\r\n\t\tif (!this._computedIsNeeded) {\r\n\t\t\t// no need for a slider\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tconst desiredSliderPosition = offset - this._arrowSize - this._computedSliderSize / 2;\r\n\t\treturn Math.round(desiredSliderPosition / this._computedSliderRatio);\r\n\t}\r\n\r\n\t/**\r\n\t * Compute a desired `scrollPosition` from if offset is before or after the slider position.\r\n\t * If offset is before slider, treat as a page up (or left). If after, page down (or right).\r\n\t * `offset` and `_computedSliderPosition` are based on the same coordinate system.\r\n\t * `_visibleSize` corresponds to a \"page\" of lines in the returned coordinate system.\r\n\t */\r\n\tpublic getDesiredScrollPositionFromOffsetPaged(offset: number): number {\r\n\t\tif (!this._computedIsNeeded) {\r\n\t\t\t// no need for a slider\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tconst correctedOffset = offset - this._arrowSize; // compensate if has arrows\r\n\t\tlet desiredScrollPosition = this._scrollPosition;\r\n\t\tif (correctedOffset < this._computedSliderPosition) {\r\n\t\t\tdesiredScrollPosition -= this._visibleSize; // page up/left\r\n\t\t} else {\r\n\t\t\tdesiredScrollPosition += this._visibleSize; // page down/right\r\n\t\t}\r\n\t\treturn desiredScrollPosition;\r\n\t}\r\n\r\n\t/**\r\n\t * Compute a desired `scrollPosition` such that the slider moves by `delta`.\r\n\t */\r\n\tpublic getDesiredScrollPositionFromDelta(delta: number): number {\r\n\t\tif (!this._computedIsNeeded) {\r\n\t\t\t// no need for a slider\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tconst desiredSliderPosition = this._computedSliderPosition + delta;\r\n\t\treturn Math.round(desiredSliderPosition / this._computedSliderRatio);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Event } from 'vs/base/common/event';\r\nimport { IListRenderer, IListDragOverReaction, IListDragAndDrop } from 'vs/base/browser/ui/list/list';\r\nimport { IDragAndDropData } from 'vs/base/browser/dnd';\r\n\r\nexport const enum TreeVisibility {\r\n\r\n\t/**\r\n\t * The tree node should be hidden.\r\n\t */\r\n\tHidden,\r\n\r\n\t/**\r\n\t * The tree node should be visible.\r\n\t */\r\n\tVisible,\r\n\r\n\t/**\r\n\t * The tree node should be visible if any of its descendants is visible.\r\n\t */\r\n\tRecurse\r\n}\r\n\r\n/**\r\n * A composed filter result containing the visibility result as well as\r\n * metadata.\r\n */\r\nexport interface ITreeFilterDataResult {\r\n\r\n\t/**\r\n\t * Whether the node should be visible.\r\n\t */\r\n\tvisibility: boolean | TreeVisibility;\r\n\r\n\t/**\r\n\t * Metadata about the element's visibility which gets forwarded to the\r\n\t * renderer once the element gets rendered.\r\n\t */\r\n\tdata: TFilterData;\r\n}\r\n\r\n/**\r\n * The result of a filter call can be a boolean value indicating whether\r\n * the element should be visible or not, a value of type `TreeVisibility` or\r\n * an object composed of the visibility result as well as additional metadata\r\n * which gets forwarded to the renderer once the element gets rendered.\r\n */\r\nexport type TreeFilterResult = boolean | TreeVisibility | ITreeFilterDataResult;\r\n\r\n/**\r\n * A tree filter is responsible for controlling the visibility of\r\n * elements in a tree.\r\n */\r\nexport interface ITreeFilter {\r\n\r\n\t/**\r\n\t * Returns whether this elements should be visible and, if affirmative,\r\n\t * additional metadata which gets forwarded to the renderer once the element\r\n\t * gets rendered.\r\n\t *\r\n\t * @param element The tree element.\r\n\t */\r\n\tfilter(element: T, parentVisibility: TreeVisibility): TreeFilterResult;\r\n}\r\n\r\nexport interface ITreeSorter {\r\n\tcompare(element: T, otherElement: T): number;\r\n}\r\n\r\nexport interface ITreeElement {\r\n\treadonly element: T;\r\n\treadonly children?: Iterable>;\r\n\treadonly collapsible?: boolean;\r\n\treadonly collapsed?: boolean;\r\n}\r\n\r\nexport interface ITreeNode {\r\n\treadonly element: T;\r\n\treadonly children: ITreeNode[];\r\n\treadonly depth: number;\r\n\treadonly visibleChildrenCount: number;\r\n\treadonly visibleChildIndex: number;\r\n\treadonly collapsible: boolean;\r\n\treadonly collapsed: boolean;\r\n\treadonly visible: boolean;\r\n\treadonly filterData: TFilterData | undefined;\r\n}\r\n\r\nexport interface ICollapseStateChangeEvent {\r\n\tnode: ITreeNode;\r\n\tdeep: boolean;\r\n}\r\n\r\nexport interface ITreeModelSpliceEvent {\r\n\tinsertedNodes: ITreeNode[];\r\n\tdeletedNodes: ITreeNode[];\r\n}\r\n\r\nexport interface ITreeModel {\r\n\r\n\treadonly onDidSplice: Event>;\r\n\treadonly onDidChangeCollapseState: Event>;\r\n\r\n\thas(location: TRef): boolean;\r\n\r\n\tgetListIndex(location: TRef): number;\r\n\tgetListRenderCount(location: TRef): number;\r\n\tgetNode(location?: TRef): ITreeNode;\r\n\tgetNodeLocation(node: ITreeNode): TRef;\r\n\tgetParentNodeLocation(location: TRef): TRef | undefined;\r\n\r\n\tisCollapsible(location: TRef): boolean;\r\n\tsetCollapsible(location: TRef, collapsible?: boolean): boolean;\r\n\tisCollapsed(location: TRef): boolean;\r\n\tsetCollapsed(location: TRef, collapsed?: boolean, recursive?: boolean): boolean;\r\n\texpandTo(location: TRef): void;\r\n\r\n\trerender(location: TRef): void;\r\n\trefilter(): void;\r\n}\r\n\r\nexport interface ITreeRenderer extends IListRenderer, TTemplateData> {\r\n\trenderTwistie?(element: T, twistieElement: HTMLElement): boolean;\r\n\tonDidChangeTwistieState?: Event;\r\n}\r\n\r\nexport interface ITreeEvent {\r\n\telements: T[];\r\n\tbrowserEvent?: UIEvent;\r\n}\r\n\r\nexport enum TreeMouseEventTarget {\r\n\tUnknown,\r\n\tTwistie,\r\n\tElement\r\n}\r\n\r\nexport interface ITreeMouseEvent {\r\n\tbrowserEvent: MouseEvent;\r\n\telement: T | null;\r\n\ttarget: TreeMouseEventTarget;\r\n}\r\n\r\nexport interface IDataSource {\r\n}\r\n\r\nexport interface IAsyncDataSource {\r\n\thasChildren(element: TInput | T): boolean;\r\n\tgetChildren(element: TInput | T): Iterable | Promise>;\r\n}\r\n\r\nexport const enum TreeDragOverBubble {\r\n\tDown,\r\n\tUp\r\n}\r\n\r\nexport interface ITreeDragOverReaction extends IListDragOverReaction {\r\n\tbubble?: TreeDragOverBubble;\r\n\tautoExpand?: boolean;\r\n}\r\n\r\nexport interface ITreeDragAndDrop extends IListDragAndDrop {\r\n\tonDragOver(data: IDragAndDropData, targetElement: T | undefined, targetIndex: number | undefined, originalEvent: DragEvent): boolean | ITreeDragOverReaction;\r\n}\r\n\r\nexport class TreeError extends Error {\r\n\r\n\tconstructor(user: string, message: string) {\r\n\t\tsuper(`TreeError [${user}] ${message}`);\r\n\t}\r\n}\r\n\r\nexport class WeakMapper {\r\n\r\n\tconstructor(private fn: (k: K) => V) { }\r\n\r\n\tprivate _map = new WeakMap();\r\n\r\n\tmap(key: K): V {\r\n\t\tlet result = this._map.get(key);\r\n\r\n\t\tif (!result) {\r\n\t\t\tresult = this.fn(key);\r\n\t\t\tthis._map.set(key, result);\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n}\r\n","\r\n\r\n/**\r\n * Returns the last element of an array.\r\n * @param array The array.\r\n * @param n Which element from the end (default is zero).\r\n */\r\nexport function tail(array: ArrayLike, n: number = 0): T {\r\n\treturn array[array.length - (1 + n)];\r\n}\r\n\r\nexport function tail2(arr: T[]): [T[], T] {\r\n\tif (arr.length === 0) {\r\n\t\tthrow new Error('Invalid tail call');\r\n\t}\r\n\r\n\treturn [arr.slice(0, arr.length - 1), arr[arr.length - 1]];\r\n}\r\n\r\nexport function equals(one: ReadonlyArray | undefined, other: ReadonlyArray | undefined, itemEquals: (a: T, b: T) => boolean = (a, b) => a === b): boolean {\r\n\tif (one === other) {\r\n\t\treturn true;\r\n\t}\r\n\r\n\tif (!one || !other) {\r\n\t\treturn false;\r\n\t}\r\n\r\n\tif (one.length !== other.length) {\r\n\t\treturn false;\r\n\t}\r\n\r\n\tfor (let i = 0, len = one.length; i < len; i++) {\r\n\t\tif (!itemEquals(one[i], other[i])) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n\r\n\treturn true;\r\n}\r\n\r\nexport function binarySearch(array: ReadonlyArray, key: T, comparator: (op1: T, op2: T) => number): number {\r\n\tlet low = 0,\r\n\t\thigh = array.length - 1;\r\n\r\n\twhile (low <= high) {\r\n\t\tconst mid = ((low + high) / 2) | 0;\r\n\t\tconst comp = comparator(array[mid], key);\r\n\t\tif (comp < 0) {\r\n\t\t\tlow = mid + 1;\r\n\t\t} else if (comp > 0) {\r\n\t\t\thigh = mid - 1;\r\n\t\t} else {\r\n\t\t\treturn mid;\r\n\t\t}\r\n\t}\r\n\treturn -(low + 1);\r\n}\r\n\r\n/**\r\n * Takes a sorted array and a function p. The array is sorted in such a way that all elements where p(x) is false\r\n * are located before all elements where p(x) is true.\r\n * @returns the least x for which p(x) is true or array.length if no element fullfills the given function.\r\n */\r\nexport function findFirstInSorted(array: ReadonlyArray, p: (x: T) => boolean): number {\r\n\tlet low = 0, high = array.length;\r\n\tif (high === 0) {\r\n\t\treturn 0; // no children\r\n\t}\r\n\twhile (low < high) {\r\n\t\tconst mid = Math.floor((low + high) / 2);\r\n\t\tif (p(array[mid])) {\r\n\t\t\thigh = mid;\r\n\t\t} else {\r\n\t\t\tlow = mid + 1;\r\n\t\t}\r\n\t}\r\n\treturn low;\r\n}\r\n\r\ntype Compare = (a: T, b: T) => number;\r\n\r\n\r\nexport function quickSelect(nth: number, data: T[], compare: Compare): T {\r\n\r\n\tnth = nth | 0;\r\n\r\n\tif (nth >= data.length) {\r\n\t\tthrow new TypeError('invalid index');\r\n\t}\r\n\r\n\tlet pivotValue = data[Math.floor(data.length * Math.random())];\r\n\tlet lower: T[] = [];\r\n\tlet higher: T[] = [];\r\n\tlet pivots: T[] = [];\r\n\r\n\tfor (let value of data) {\r\n\t\tconst val = compare(value, pivotValue);\r\n\t\tif (val < 0) {\r\n\t\t\tlower.push(value);\r\n\t\t} else if (val > 0) {\r\n\t\t\thigher.push(value);\r\n\t\t} else {\r\n\t\t\tpivots.push(value);\r\n\t\t}\r\n\t}\r\n\r\n\tif (nth < lower.length) {\r\n\t\treturn quickSelect(nth, lower, compare);\r\n\t} else if (nth < lower.length + pivots.length) {\r\n\t\treturn pivots[0];\r\n\t} else {\r\n\t\treturn quickSelect(nth - (lower.length + pivots.length), higher, compare);\r\n\t}\r\n}\r\n\r\n/**\r\n * Like `Array#sort` but always stable. Usually runs a little slower `than Array#sort`\r\n * so only use this when actually needing stable sort.\r\n */\r\nexport function mergeSort(data: T[], compare: Compare): T[] {\r\n\t_sort(data, compare, 0, data.length - 1, []);\r\n\treturn data;\r\n}\r\n\r\nfunction _merge(a: T[], compare: Compare, lo: number, mid: number, hi: number, aux: T[]): void {\r\n\tlet leftIdx = lo, rightIdx = mid + 1;\r\n\tfor (let i = lo; i <= hi; i++) {\r\n\t\taux[i] = a[i];\r\n\t}\r\n\tfor (let i = lo; i <= hi; i++) {\r\n\t\tif (leftIdx > mid) {\r\n\t\t\t// left side consumed\r\n\t\t\ta[i] = aux[rightIdx++];\r\n\t\t} else if (rightIdx > hi) {\r\n\t\t\t// right side consumed\r\n\t\t\ta[i] = aux[leftIdx++];\r\n\t\t} else if (compare(aux[rightIdx], aux[leftIdx]) < 0) {\r\n\t\t\t// right element is less -> comes first\r\n\t\t\ta[i] = aux[rightIdx++];\r\n\t\t} else {\r\n\t\t\t// left element comes first (less or equal)\r\n\t\t\ta[i] = aux[leftIdx++];\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction _sort(a: T[], compare: Compare, lo: number, hi: number, aux: T[]) {\r\n\tif (hi <= lo) {\r\n\t\treturn;\r\n\t}\r\n\tconst mid = lo + ((hi - lo) / 2) | 0;\r\n\t_sort(a, compare, lo, mid, aux);\r\n\t_sort(a, compare, mid + 1, hi, aux);\r\n\tif (compare(a[mid], a[mid + 1]) <= 0) {\r\n\t\t// left and right are sorted and if the last-left element is less\r\n\t\t// or equals than the first-right element there is nothing else\r\n\t\t// to do\r\n\t\treturn;\r\n\t}\r\n\t_merge(a, compare, lo, mid, hi, aux);\r\n}\r\n\r\n\r\nexport function groupBy(data: ReadonlyArray, compare: (a: T, b: T) => number): T[][] {\r\n\tconst result: T[][] = [];\r\n\tlet currentGroup: T[] | undefined = undefined;\r\n\tfor (const element of mergeSort(data.slice(0), compare)) {\r\n\t\tif (!currentGroup || compare(currentGroup[0], element) !== 0) {\r\n\t\t\tcurrentGroup = [element];\r\n\t\t\tresult.push(currentGroup);\r\n\t\t} else {\r\n\t\t\tcurrentGroup.push(element);\r\n\t\t}\r\n\t}\r\n\treturn result;\r\n}\r\n\r\n/**\r\n * @returns New array with all falsy values removed. The original array IS NOT modified.\r\n */\r\nexport function coalesce(array: ReadonlyArray): T[] {\r\n\treturn array.filter(e => !!e);\r\n}\r\n\r\n/**\r\n * @returns false if the provided object is an array and not empty.\r\n */\r\nexport function isFalsyOrEmpty(obj: any): boolean {\r\n\treturn !Array.isArray(obj) || obj.length === 0;\r\n}\r\n\r\n/**\r\n * @returns True if the provided object is an array and has at least one element.\r\n */\r\nexport function isNonEmptyArray(obj: T[] | undefined | null): obj is T[];\r\nexport function isNonEmptyArray(obj: readonly T[] | undefined | null): obj is readonly T[];\r\nexport function isNonEmptyArray(obj: T[] | readonly T[] | undefined | null): obj is T[] | readonly T[] {\r\n\treturn Array.isArray(obj) && obj.length > 0;\r\n}\r\n\r\n/**\r\n * Removes duplicates from the given array. The optional keyFn allows to specify\r\n * how elements are checked for equalness by returning a unique string for each.\r\n */\r\nexport function distinct(array: ReadonlyArray, keyFn?: (t: T) => string): T[] {\r\n\tif (!keyFn) {\r\n\t\treturn array.filter((element, position) => {\r\n\t\t\treturn array.indexOf(element) === position;\r\n\t\t});\r\n\t}\r\n\r\n\tconst seen: { [key: string]: boolean; } = Object.create(null);\r\n\treturn array.filter((elem) => {\r\n\t\tconst key = keyFn(elem);\r\n\t\tif (seen[key]) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tseen[key] = true;\r\n\r\n\t\treturn true;\r\n\t});\r\n}\r\n\r\nexport function distinctES6(array: ReadonlyArray): T[] {\r\n\tconst seen = new Set();\r\n\treturn array.filter(element => {\r\n\t\tif (seen.has(element)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tseen.add(element);\r\n\t\treturn true;\r\n\t});\r\n}\r\n\r\nexport function firstOrDefault(array: ReadonlyArray, notFoundValue: NotFound): T | NotFound;\r\nexport function firstOrDefault(array: ReadonlyArray): T | undefined;\r\nexport function firstOrDefault(array: ReadonlyArray, notFoundValue?: NotFound): T | NotFound | undefined {\r\n\treturn array.length > 0 ? array[0] : notFoundValue;\r\n}\r\n\r\nexport function flatten(arr: T[][]): T[] {\r\n\treturn ([]).concat(...arr);\r\n}\r\n\r\nexport function range(to: number): number[];\r\nexport function range(from: number, to: number): number[];\r\nexport function range(arg: number, to?: number): number[] {\r\n\tlet from = typeof to === 'number' ? arg : 0;\r\n\r\n\tif (typeof to === 'number') {\r\n\t\tfrom = arg;\r\n\t} else {\r\n\t\tfrom = 0;\r\n\t\tto = arg;\r\n\t}\r\n\r\n\tconst result: number[] = [];\r\n\r\n\tif (from <= to) {\r\n\t\tfor (let i = from; i < to; i++) {\r\n\t\t\tresult.push(i);\r\n\t\t}\r\n\t} else {\r\n\t\tfor (let i = from; i > to; i--) {\r\n\t\t\tresult.push(i);\r\n\t\t}\r\n\t}\r\n\r\n\treturn result;\r\n}\r\n\r\n/**\r\n * Insert `insertArr` inside `target` at `insertIndex`.\r\n * Please don't touch unless you understand https://jsperf.com/inserting-an-array-within-an-array\r\n */\r\nexport function arrayInsert(target: T[], insertIndex: number, insertArr: T[]): T[] {\r\n\tconst before = target.slice(0, insertIndex);\r\n\tconst after = target.slice(insertIndex);\r\n\treturn before.concat(insertArr, after);\r\n}\r\n\r\n/**\r\n * Pushes an element to the start of the array, if found.\r\n */\r\nexport function pushToStart(arr: T[], value: T): void {\r\n\tconst index = arr.indexOf(value);\r\n\r\n\tif (index > -1) {\r\n\t\tarr.splice(index, 1);\r\n\t\tarr.unshift(value);\r\n\t}\r\n}\r\n\r\n/**\r\n * Pushes an element to the end of the array, if found.\r\n */\r\nexport function pushToEnd(arr: T[], value: T): void {\r\n\tconst index = arr.indexOf(value);\r\n\r\n\tif (index > -1) {\r\n\t\tarr.splice(index, 1);\r\n\t\tarr.push(value);\r\n\t}\r\n}\r\n\r\nexport function asArray(x: T | T[]): T[];\r\nexport function asArray(x: T | readonly T[]): readonly T[];\r\nexport function asArray(x: T | T[]): T[] {\r\n\treturn Array.isArray(x) ? x : [x];\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\n/**\r\n * Throws an error with the provided message if the provided value does not evaluate to a true Javascript value.\r\n */\r\nexport function ok(value?: unknown, message?: string) {\r\n\tif (!value) {\r\n\t\tthrow new Error(message ? `Assertion failed (${message})` : 'Assertion Failed');\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\n/**\r\n * An interface for a JavaScript object that\r\n * acts a dictionary. The keys are strings.\r\n */\r\nexport type IStringDictionary = Record;\r\n\r\n\r\n/**\r\n * An interface for a JavaScript object that\r\n * acts a dictionary. The keys are numbers.\r\n */\r\nexport type INumberDictionary = Record;\r\n\r\nconst hasOwnProperty = Object.prototype.hasOwnProperty;\r\n\r\n/**\r\n * Iterates over each entry in the provided dictionary. The iterator allows\r\n * to remove elements and will stop when the callback returns {{false}}.\r\n */\r\nexport function forEach(from: IStringDictionary | INumberDictionary, callback: (entry: { key: any; value: T; }, remove: () => void) => any): void {\r\n\tfor (let key in from) {\r\n\t\tif (hasOwnProperty.call(from, key)) {\r\n\t\t\tconst result = callback({ key: key, value: (from as any)[key] }, function () {\r\n\t\t\t\tdelete (from as any)[key];\r\n\t\t\t});\r\n\t\t\tif (result === false) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\nexport class SetMap {\r\n\r\n\tprivate map = new Map>();\r\n\r\n\tadd(key: K, value: V): void {\r\n\t\tlet values = this.map.get(key);\r\n\r\n\t\tif (!values) {\r\n\t\t\tvalues = new Set();\r\n\t\t\tthis.map.set(key, values);\r\n\t\t}\r\n\r\n\t\tvalues.add(value);\r\n\t}\r\n\r\n\tdelete(key: K, value: V): void {\r\n\t\tconst values = this.map.get(key);\r\n\r\n\t\tif (!values) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tvalues.delete(value);\r\n\r\n\t\tif (values.size === 0) {\r\n\t\t\tthis.map.delete(key);\r\n\t\t}\r\n\t}\r\n\r\n\tforEach(key: K, fn: (value: V) => void): void {\r\n\t\tconst values = this.map.get(key);\r\n\r\n\t\tif (!values) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tvalues.forEach(fn);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CharCode } from 'vs/base/common/charCode';\r\n\r\nfunction roundFloat(number: number, decimalPoints: number): number {\r\n\tconst decimal = Math.pow(10, decimalPoints);\r\n\treturn Math.round(number * decimal) / decimal;\r\n}\r\n\r\nexport class RGBA {\r\n\t_rgbaBrand: void;\r\n\r\n\t/**\r\n\t * Red: integer in [0-255]\r\n\t */\r\n\treadonly r: number;\r\n\r\n\t/**\r\n\t * Green: integer in [0-255]\r\n\t */\r\n\treadonly g: number;\r\n\r\n\t/**\r\n\t * Blue: integer in [0-255]\r\n\t */\r\n\treadonly b: number;\r\n\r\n\t/**\r\n\t * Alpha: float in [0-1]\r\n\t */\r\n\treadonly a: number;\r\n\r\n\tconstructor(r: number, g: number, b: number, a: number = 1) {\r\n\t\tthis.r = Math.min(255, Math.max(0, r)) | 0;\r\n\t\tthis.g = Math.min(255, Math.max(0, g)) | 0;\r\n\t\tthis.b = Math.min(255, Math.max(0, b)) | 0;\r\n\t\tthis.a = roundFloat(Math.max(Math.min(1, a), 0), 3);\r\n\t}\r\n\r\n\tstatic equals(a: RGBA, b: RGBA): boolean {\r\n\t\treturn a.r === b.r && a.g === b.g && a.b === b.b && a.a === b.a;\r\n\t}\r\n}\r\n\r\nexport class HSLA {\r\n\r\n\t_hslaBrand: void;\r\n\r\n\t/**\r\n\t * Hue: integer in [0, 360]\r\n\t */\r\n\treadonly h: number;\r\n\r\n\t/**\r\n\t * Saturation: float in [0, 1]\r\n\t */\r\n\treadonly s: number;\r\n\r\n\t/**\r\n\t * Luminosity: float in [0, 1]\r\n\t */\r\n\treadonly l: number;\r\n\r\n\t/**\r\n\t * Alpha: float in [0, 1]\r\n\t */\r\n\treadonly a: number;\r\n\r\n\tconstructor(h: number, s: number, l: number, a: number) {\r\n\t\tthis.h = Math.max(Math.min(360, h), 0) | 0;\r\n\t\tthis.s = roundFloat(Math.max(Math.min(1, s), 0), 3);\r\n\t\tthis.l = roundFloat(Math.max(Math.min(1, l), 0), 3);\r\n\t\tthis.a = roundFloat(Math.max(Math.min(1, a), 0), 3);\r\n\t}\r\n\r\n\tstatic equals(a: HSLA, b: HSLA): boolean {\r\n\t\treturn a.h === b.h && a.s === b.s && a.l === b.l && a.a === b.a;\r\n\t}\r\n\r\n\t/**\r\n\t * Converts an RGB color value to HSL. Conversion formula\r\n\t * adapted from http://en.wikipedia.org/wiki/HSL_color_space.\r\n\t * Assumes r, g, and b are contained in the set [0, 255] and\r\n\t * returns h in the set [0, 360], s, and l in the set [0, 1].\r\n\t */\r\n\tstatic fromRGBA(rgba: RGBA): HSLA {\r\n\t\tconst r = rgba.r / 255;\r\n\t\tconst g = rgba.g / 255;\r\n\t\tconst b = rgba.b / 255;\r\n\t\tconst a = rgba.a;\r\n\r\n\t\tconst max = Math.max(r, g, b);\r\n\t\tconst min = Math.min(r, g, b);\r\n\t\tlet h = 0;\r\n\t\tlet s = 0;\r\n\t\tconst l = (min + max) / 2;\r\n\t\tconst chroma = max - min;\r\n\r\n\t\tif (chroma > 0) {\r\n\t\t\ts = Math.min((l <= 0.5 ? chroma / (2 * l) : chroma / (2 - (2 * l))), 1);\r\n\r\n\t\t\tswitch (max) {\r\n\t\t\t\tcase r: h = (g - b) / chroma + (g < b ? 6 : 0); break;\r\n\t\t\t\tcase g: h = (b - r) / chroma + 2; break;\r\n\t\t\t\tcase b: h = (r - g) / chroma + 4; break;\r\n\t\t\t}\r\n\r\n\t\t\th *= 60;\r\n\t\t\th = Math.round(h);\r\n\t\t}\r\n\t\treturn new HSLA(h, s, l, a);\r\n\t}\r\n\r\n\tprivate static _hue2rgb(p: number, q: number, t: number): number {\r\n\t\tif (t < 0) {\r\n\t\t\tt += 1;\r\n\t\t}\r\n\t\tif (t > 1) {\r\n\t\t\tt -= 1;\r\n\t\t}\r\n\t\tif (t < 1 / 6) {\r\n\t\t\treturn p + (q - p) * 6 * t;\r\n\t\t}\r\n\t\tif (t < 1 / 2) {\r\n\t\t\treturn q;\r\n\t\t}\r\n\t\tif (t < 2 / 3) {\r\n\t\t\treturn p + (q - p) * (2 / 3 - t) * 6;\r\n\t\t}\r\n\t\treturn p;\r\n\t}\r\n\r\n\t/**\r\n\t * Converts an HSL color value to RGB. Conversion formula\r\n\t * adapted from http://en.wikipedia.org/wiki/HSL_color_space.\r\n\t * Assumes h in the set [0, 360] s, and l are contained in the set [0, 1] and\r\n\t * returns r, g, and b in the set [0, 255].\r\n\t */\r\n\tstatic toRGBA(hsla: HSLA): RGBA {\r\n\t\tconst h = hsla.h / 360;\r\n\t\tconst { s, l, a } = hsla;\r\n\t\tlet r: number, g: number, b: number;\r\n\r\n\t\tif (s === 0) {\r\n\t\t\tr = g = b = l; // achromatic\r\n\t\t} else {\r\n\t\t\tconst q = l < 0.5 ? l * (1 + s) : l + s - l * s;\r\n\t\t\tconst p = 2 * l - q;\r\n\t\t\tr = HSLA._hue2rgb(p, q, h + 1 / 3);\r\n\t\t\tg = HSLA._hue2rgb(p, q, h);\r\n\t\t\tb = HSLA._hue2rgb(p, q, h - 1 / 3);\r\n\t\t}\r\n\r\n\t\treturn new RGBA(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255), a);\r\n\t}\r\n}\r\n\r\nexport class HSVA {\r\n\r\n\t_hsvaBrand: void;\r\n\r\n\t/**\r\n\t * Hue: integer in [0, 360]\r\n\t */\r\n\treadonly h: number;\r\n\r\n\t/**\r\n\t * Saturation: float in [0, 1]\r\n\t */\r\n\treadonly s: number;\r\n\r\n\t/**\r\n\t * Value: float in [0, 1]\r\n\t */\r\n\treadonly v: number;\r\n\r\n\t/**\r\n\t * Alpha: float in [0, 1]\r\n\t */\r\n\treadonly a: number;\r\n\r\n\tconstructor(h: number, s: number, v: number, a: number) {\r\n\t\tthis.h = Math.max(Math.min(360, h), 0) | 0;\r\n\t\tthis.s = roundFloat(Math.max(Math.min(1, s), 0), 3);\r\n\t\tthis.v = roundFloat(Math.max(Math.min(1, v), 0), 3);\r\n\t\tthis.a = roundFloat(Math.max(Math.min(1, a), 0), 3);\r\n\t}\r\n\r\n\tstatic equals(a: HSVA, b: HSVA): boolean {\r\n\t\treturn a.h === b.h && a.s === b.s && a.v === b.v && a.a === b.a;\r\n\t}\r\n\r\n\t// from http://www.rapidtables.com/convert/color/rgb-to-hsv.htm\r\n\tstatic fromRGBA(rgba: RGBA): HSVA {\r\n\t\tconst r = rgba.r / 255;\r\n\t\tconst g = rgba.g / 255;\r\n\t\tconst b = rgba.b / 255;\r\n\t\tconst cmax = Math.max(r, g, b);\r\n\t\tconst cmin = Math.min(r, g, b);\r\n\t\tconst delta = cmax - cmin;\r\n\t\tconst s = cmax === 0 ? 0 : (delta / cmax);\r\n\t\tlet m: number;\r\n\r\n\t\tif (delta === 0) {\r\n\t\t\tm = 0;\r\n\t\t} else if (cmax === r) {\r\n\t\t\tm = ((((g - b) / delta) % 6) + 6) % 6;\r\n\t\t} else if (cmax === g) {\r\n\t\t\tm = ((b - r) / delta) + 2;\r\n\t\t} else {\r\n\t\t\tm = ((r - g) / delta) + 4;\r\n\t\t}\r\n\r\n\t\treturn new HSVA(Math.round(m * 60), s, cmax, rgba.a);\r\n\t}\r\n\r\n\t// from http://www.rapidtables.com/convert/color/hsv-to-rgb.htm\r\n\tstatic toRGBA(hsva: HSVA): RGBA {\r\n\t\tconst { h, s, v, a } = hsva;\r\n\t\tconst c = v * s;\r\n\t\tconst x = c * (1 - Math.abs((h / 60) % 2 - 1));\r\n\t\tconst m = v - c;\r\n\t\tlet [r, g, b] = [0, 0, 0];\r\n\r\n\t\tif (h < 60) {\r\n\t\t\tr = c;\r\n\t\t\tg = x;\r\n\t\t} else if (h < 120) {\r\n\t\t\tr = x;\r\n\t\t\tg = c;\r\n\t\t} else if (h < 180) {\r\n\t\t\tg = c;\r\n\t\t\tb = x;\r\n\t\t} else if (h < 240) {\r\n\t\t\tg = x;\r\n\t\t\tb = c;\r\n\t\t} else if (h < 300) {\r\n\t\t\tr = x;\r\n\t\t\tb = c;\r\n\t\t} else if (h <= 360) {\r\n\t\t\tr = c;\r\n\t\t\tb = x;\r\n\t\t}\r\n\r\n\t\tr = Math.round((r + m) * 255);\r\n\t\tg = Math.round((g + m) * 255);\r\n\t\tb = Math.round((b + m) * 255);\r\n\r\n\t\treturn new RGBA(r, g, b, a);\r\n\t}\r\n}\r\n\r\nexport class Color {\r\n\r\n\tstatic fromHex(hex: string): Color {\r\n\t\treturn Color.Format.CSS.parseHex(hex) || Color.red;\r\n\t}\r\n\r\n\treadonly rgba: RGBA;\r\n\tprivate _hsla?: HSLA;\r\n\tget hsla(): HSLA {\r\n\t\tif (this._hsla) {\r\n\t\t\treturn this._hsla;\r\n\t\t} else {\r\n\t\t\treturn HSLA.fromRGBA(this.rgba);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _hsva?: HSVA;\r\n\tget hsva(): HSVA {\r\n\t\tif (this._hsva) {\r\n\t\t\treturn this._hsva;\r\n\t\t}\r\n\t\treturn HSVA.fromRGBA(this.rgba);\r\n\t}\r\n\r\n\tconstructor(arg: RGBA | HSLA | HSVA) {\r\n\t\tif (!arg) {\r\n\t\t\tthrow new Error('Color needs a value');\r\n\t\t} else if (arg instanceof RGBA) {\r\n\t\t\tthis.rgba = arg;\r\n\t\t} else if (arg instanceof HSLA) {\r\n\t\t\tthis._hsla = arg;\r\n\t\t\tthis.rgba = HSLA.toRGBA(arg);\r\n\t\t} else if (arg instanceof HSVA) {\r\n\t\t\tthis._hsva = arg;\r\n\t\t\tthis.rgba = HSVA.toRGBA(arg);\r\n\t\t} else {\r\n\t\t\tthrow new Error('Invalid color ctor argument');\r\n\t\t}\r\n\t}\r\n\r\n\tequals(other: Color | null): boolean {\r\n\t\treturn !!other && RGBA.equals(this.rgba, other.rgba) && HSLA.equals(this.hsla, other.hsla) && HSVA.equals(this.hsva, other.hsva);\r\n\t}\r\n\r\n\t/**\r\n\t * http://www.w3.org/TR/WCAG20/#relativeluminancedef\r\n\t * Returns the number in the set [0, 1]. O => Darkest Black. 1 => Lightest white.\r\n\t */\r\n\tgetRelativeLuminance(): number {\r\n\t\tconst R = Color._relativeLuminanceForComponent(this.rgba.r);\r\n\t\tconst G = Color._relativeLuminanceForComponent(this.rgba.g);\r\n\t\tconst B = Color._relativeLuminanceForComponent(this.rgba.b);\r\n\t\tconst luminance = 0.2126 * R + 0.7152 * G + 0.0722 * B;\r\n\r\n\t\treturn roundFloat(luminance, 4);\r\n\t}\r\n\r\n\tprivate static _relativeLuminanceForComponent(color: number): number {\r\n\t\tconst c = color / 255;\r\n\t\treturn (c <= 0.03928) ? c / 12.92 : Math.pow(((c + 0.055) / 1.055), 2.4);\r\n\t}\r\n\r\n\t/**\r\n\t *\thttp://24ways.org/2010/calculating-color-contrast\r\n\t * Return 'true' if lighter color otherwise 'false'\r\n\t */\r\n\tisLighter(): boolean {\r\n\t\tconst yiq = (this.rgba.r * 299 + this.rgba.g * 587 + this.rgba.b * 114) / 1000;\r\n\t\treturn yiq >= 128;\r\n\t}\r\n\r\n\tisLighterThan(another: Color): boolean {\r\n\t\tconst lum1 = this.getRelativeLuminance();\r\n\t\tconst lum2 = another.getRelativeLuminance();\r\n\t\treturn lum1 > lum2;\r\n\t}\r\n\r\n\tisDarkerThan(another: Color): boolean {\r\n\t\tconst lum1 = this.getRelativeLuminance();\r\n\t\tconst lum2 = another.getRelativeLuminance();\r\n\t\treturn lum1 < lum2;\r\n\t}\r\n\r\n\tlighten(factor: number): Color {\r\n\t\treturn new Color(new HSLA(this.hsla.h, this.hsla.s, this.hsla.l + this.hsla.l * factor, this.hsla.a));\r\n\t}\r\n\r\n\tdarken(factor: number): Color {\r\n\t\treturn new Color(new HSLA(this.hsla.h, this.hsla.s, this.hsla.l - this.hsla.l * factor, this.hsla.a));\r\n\t}\r\n\r\n\ttransparent(factor: number): Color {\r\n\t\tconst { r, g, b, a } = this.rgba;\r\n\t\treturn new Color(new RGBA(r, g, b, a * factor));\r\n\t}\r\n\r\n\tisTransparent(): boolean {\r\n\t\treturn this.rgba.a === 0;\r\n\t}\r\n\r\n\tisOpaque(): boolean {\r\n\t\treturn this.rgba.a === 1;\r\n\t}\r\n\r\n\topposite(): Color {\r\n\t\treturn new Color(new RGBA(255 - this.rgba.r, 255 - this.rgba.g, 255 - this.rgba.b, this.rgba.a));\r\n\t}\r\n\r\n\ttoString(): string {\r\n\t\treturn '' + Color.Format.CSS.format(this);\r\n\t}\r\n\r\n\tstatic getLighterColor(of: Color, relative: Color, factor?: number): Color {\r\n\t\tif (of.isLighterThan(relative)) {\r\n\t\t\treturn of;\r\n\t\t}\r\n\t\tfactor = factor ? factor : 0.5;\r\n\t\tconst lum1 = of.getRelativeLuminance();\r\n\t\tconst lum2 = relative.getRelativeLuminance();\r\n\t\tfactor = factor * (lum2 - lum1) / lum2;\r\n\t\treturn of.lighten(factor);\r\n\t}\r\n\r\n\tstatic getDarkerColor(of: Color, relative: Color, factor?: number): Color {\r\n\t\tif (of.isDarkerThan(relative)) {\r\n\t\t\treturn of;\r\n\t\t}\r\n\t\tfactor = factor ? factor : 0.5;\r\n\t\tconst lum1 = of.getRelativeLuminance();\r\n\t\tconst lum2 = relative.getRelativeLuminance();\r\n\t\tfactor = factor * (lum1 - lum2) / lum1;\r\n\t\treturn of.darken(factor);\r\n\t}\r\n\r\n\tstatic readonly white = new Color(new RGBA(255, 255, 255, 1));\r\n\tstatic readonly black = new Color(new RGBA(0, 0, 0, 1));\r\n\tstatic readonly red = new Color(new RGBA(255, 0, 0, 1));\r\n\tstatic readonly blue = new Color(new RGBA(0, 0, 255, 1));\r\n\tstatic readonly cyan = new Color(new RGBA(0, 255, 255, 1));\r\n\tstatic readonly lightgrey = new Color(new RGBA(211, 211, 211, 1));\r\n\tstatic readonly transparent = new Color(new RGBA(0, 0, 0, 0));\r\n}\r\n\r\nexport namespace Color {\r\n\texport namespace Format {\r\n\t\texport namespace CSS {\r\n\r\n\t\t\texport function formatRGB(color: Color): string {\r\n\t\t\t\tif (color.rgba.a === 1) {\r\n\t\t\t\t\treturn `rgb(${color.rgba.r}, ${color.rgba.g}, ${color.rgba.b})`;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn Color.Format.CSS.formatRGBA(color);\r\n\t\t\t}\r\n\r\n\t\t\texport function formatRGBA(color: Color): string {\r\n\t\t\t\treturn `rgba(${color.rgba.r}, ${color.rgba.g}, ${color.rgba.b}, ${+(color.rgba.a).toFixed(2)})`;\r\n\t\t\t}\r\n\r\n\t\t\texport function formatHSL(color: Color): string {\r\n\t\t\t\tif (color.hsla.a === 1) {\r\n\t\t\t\t\treturn `hsl(${color.hsla.h}, ${(color.hsla.s * 100).toFixed(2)}%, ${(color.hsla.l * 100).toFixed(2)}%)`;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn Color.Format.CSS.formatHSLA(color);\r\n\t\t\t}\r\n\r\n\t\t\texport function formatHSLA(color: Color): string {\r\n\t\t\t\treturn `hsla(${color.hsla.h}, ${(color.hsla.s * 100).toFixed(2)}%, ${(color.hsla.l * 100).toFixed(2)}%, ${color.hsla.a.toFixed(2)})`;\r\n\t\t\t}\r\n\r\n\t\t\tfunction _toTwoDigitHex(n: number): string {\r\n\t\t\t\tconst r = n.toString(16);\r\n\t\t\t\treturn r.length !== 2 ? '0' + r : r;\r\n\t\t\t}\r\n\r\n\t\t\t/**\r\n\t\t\t * Formats the color as #RRGGBB\r\n\t\t\t */\r\n\t\t\texport function formatHex(color: Color): string {\r\n\t\t\t\treturn `#${_toTwoDigitHex(color.rgba.r)}${_toTwoDigitHex(color.rgba.g)}${_toTwoDigitHex(color.rgba.b)}`;\r\n\t\t\t}\r\n\r\n\t\t\t/**\r\n\t\t\t * Formats the color as #RRGGBBAA\r\n\t\t\t * If 'compact' is set, colors without transparancy will be printed as #RRGGBB\r\n\t\t\t */\r\n\t\t\texport function formatHexA(color: Color, compact = false): string {\r\n\t\t\t\tif (compact && color.rgba.a === 1) {\r\n\t\t\t\t\treturn Color.Format.CSS.formatHex(color);\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn `#${_toTwoDigitHex(color.rgba.r)}${_toTwoDigitHex(color.rgba.g)}${_toTwoDigitHex(color.rgba.b)}${_toTwoDigitHex(Math.round(color.rgba.a * 255))}`;\r\n\t\t\t}\r\n\r\n\t\t\t/**\r\n\t\t\t * The default format will use HEX if opaque and RGBA otherwise.\r\n\t\t\t */\r\n\t\t\texport function format(color: Color): string | null {\r\n\t\t\t\tif (color.isOpaque()) {\r\n\t\t\t\t\treturn Color.Format.CSS.formatHex(color);\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn Color.Format.CSS.formatRGBA(color);\r\n\t\t\t}\r\n\r\n\t\t\t/**\r\n\t\t\t * Converts an Hex color value to a Color.\r\n\t\t\t * returns r, g, and b are contained in the set [0, 255]\r\n\t\t\t * @param hex string (#RGB, #RGBA, #RRGGBB or #RRGGBBAA).\r\n\t\t\t */\r\n\t\t\texport function parseHex(hex: string): Color | null {\r\n\t\t\t\tconst length = hex.length;\r\n\r\n\t\t\t\tif (length === 0) {\r\n\t\t\t\t\t// Invalid color\r\n\t\t\t\t\treturn null;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (hex.charCodeAt(0) !== CharCode.Hash) {\r\n\t\t\t\t\t// Does not begin with a #\r\n\t\t\t\t\treturn null;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (length === 7) {\r\n\t\t\t\t\t// #RRGGBB format\r\n\t\t\t\t\tconst r = 16 * _parseHexDigit(hex.charCodeAt(1)) + _parseHexDigit(hex.charCodeAt(2));\r\n\t\t\t\t\tconst g = 16 * _parseHexDigit(hex.charCodeAt(3)) + _parseHexDigit(hex.charCodeAt(4));\r\n\t\t\t\t\tconst b = 16 * _parseHexDigit(hex.charCodeAt(5)) + _parseHexDigit(hex.charCodeAt(6));\r\n\t\t\t\t\treturn new Color(new RGBA(r, g, b, 1));\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (length === 9) {\r\n\t\t\t\t\t// #RRGGBBAA format\r\n\t\t\t\t\tconst r = 16 * _parseHexDigit(hex.charCodeAt(1)) + _parseHexDigit(hex.charCodeAt(2));\r\n\t\t\t\t\tconst g = 16 * _parseHexDigit(hex.charCodeAt(3)) + _parseHexDigit(hex.charCodeAt(4));\r\n\t\t\t\t\tconst b = 16 * _parseHexDigit(hex.charCodeAt(5)) + _parseHexDigit(hex.charCodeAt(6));\r\n\t\t\t\t\tconst a = 16 * _parseHexDigit(hex.charCodeAt(7)) + _parseHexDigit(hex.charCodeAt(8));\r\n\t\t\t\t\treturn new Color(new RGBA(r, g, b, a / 255));\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (length === 4) {\r\n\t\t\t\t\t// #RGB format\r\n\t\t\t\t\tconst r = _parseHexDigit(hex.charCodeAt(1));\r\n\t\t\t\t\tconst g = _parseHexDigit(hex.charCodeAt(2));\r\n\t\t\t\t\tconst b = _parseHexDigit(hex.charCodeAt(3));\r\n\t\t\t\t\treturn new Color(new RGBA(16 * r + r, 16 * g + g, 16 * b + b));\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (length === 5) {\r\n\t\t\t\t\t// #RGBA format\r\n\t\t\t\t\tconst r = _parseHexDigit(hex.charCodeAt(1));\r\n\t\t\t\t\tconst g = _parseHexDigit(hex.charCodeAt(2));\r\n\t\t\t\t\tconst b = _parseHexDigit(hex.charCodeAt(3));\r\n\t\t\t\t\tconst a = _parseHexDigit(hex.charCodeAt(4));\r\n\t\t\t\t\treturn new Color(new RGBA(16 * r + r, 16 * g + g, 16 * b + b, (16 * a + a) / 255));\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Invalid color\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\r\n\t\t\tfunction _parseHexDigit(charCode: CharCode): number {\r\n\t\t\t\tswitch (charCode) {\r\n\t\t\t\t\tcase CharCode.Digit0: return 0;\r\n\t\t\t\t\tcase CharCode.Digit1: return 1;\r\n\t\t\t\t\tcase CharCode.Digit2: return 2;\r\n\t\t\t\t\tcase CharCode.Digit3: return 3;\r\n\t\t\t\t\tcase CharCode.Digit4: return 4;\r\n\t\t\t\t\tcase CharCode.Digit5: return 5;\r\n\t\t\t\t\tcase CharCode.Digit6: return 6;\r\n\t\t\t\t\tcase CharCode.Digit7: return 7;\r\n\t\t\t\t\tcase CharCode.Digit8: return 8;\r\n\t\t\t\t\tcase CharCode.Digit9: return 9;\r\n\t\t\t\t\tcase CharCode.a: return 10;\r\n\t\t\t\t\tcase CharCode.A: return 10;\r\n\t\t\t\t\tcase CharCode.b: return 11;\r\n\t\t\t\t\tcase CharCode.B: return 11;\r\n\t\t\t\t\tcase CharCode.c: return 12;\r\n\t\t\t\t\tcase CharCode.C: return 12;\r\n\t\t\t\t\tcase CharCode.d: return 13;\r\n\t\t\t\t\tcase CharCode.D: return 13;\r\n\t\t\t\t\tcase CharCode.e: return 14;\r\n\t\t\t\t\tcase CharCode.E: return 14;\r\n\t\t\t\t\tcase CharCode.f: return 15;\r\n\t\t\t\t\tcase CharCode.F: return 15;\r\n\t\t\t\t}\r\n\t\t\t\treturn 0;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n","\r\n\r\nlet memoizeId = 0;\r\nexport function createMemoizer() {\r\n\tconst memoizeKeyPrefix = `$memoize${memoizeId++}`;\r\n\tlet self: any = undefined;\r\n\r\n\tconst result = function memoize(target: any, key: string, descriptor: any) {\r\n\t\tlet fnKey: string | null = null;\r\n\t\tlet fn: Function | null = null;\r\n\r\n\t\tif (typeof descriptor.value === 'function') {\r\n\t\t\tfnKey = 'value';\r\n\t\t\tfn = descriptor.value;\r\n\r\n\t\t\tif (fn!.length !== 0) {\r\n\t\t\t\tconsole.warn('Memoize should only be used in functions with zero parameters');\r\n\t\t\t}\r\n\t\t} else if (typeof descriptor.get === 'function') {\r\n\t\t\tfnKey = 'get';\r\n\t\t\tfn = descriptor.get;\r\n\t\t}\r\n\r\n\t\tif (!fn) {\r\n\t\t\tthrow new Error('not supported');\r\n\t\t}\r\n\r\n\t\tconst memoizeKey = `${memoizeKeyPrefix}:${key}`;\r\n\t\tdescriptor[fnKey!] = function (...args: any[]) {\r\n\t\t\tself = this;\r\n\r\n\t\t\tif (!this.hasOwnProperty(memoizeKey)) {\r\n\t\t\t\tObject.defineProperty(this, memoizeKey, {\r\n\t\t\t\t\tconfigurable: true,\r\n\t\t\t\t\tenumerable: false,\r\n\t\t\t\t\twritable: true,\r\n\t\t\t\t\tvalue: fn!.apply(this, args)\r\n\t\t\t\t});\r\n\t\t\t}\r\n\r\n\t\t\treturn this[memoizeKey];\r\n\t\t};\r\n\t};\r\n\r\n\tresult.clear = () => {\r\n\t\tif (typeof self === 'undefined') {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tObject.getOwnPropertyNames(self).forEach(property => {\r\n\t\t\tif (property.indexOf(memoizeKeyPrefix) === 0) {\r\n\t\t\t\tdelete self[property];\r\n\t\t\t}\r\n\t\t});\r\n\t};\r\n\r\n\treturn result;\r\n}\r\n\r\nexport function memoize(target: any, key: string, descriptor: any) {\r\n\treturn createMemoizer()(target, key, descriptor);\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\n/**\r\n * Represents information about a specific difference between two sequences.\r\n */\r\nexport class DiffChange {\r\n\r\n\t/**\r\n\t * The position of the first element in the original sequence which\r\n\t * this change affects.\r\n\t */\r\n\tpublic originalStart: number;\r\n\r\n\t/**\r\n\t * The number of elements from the original sequence which were\r\n\t * affected.\r\n\t */\r\n\tpublic originalLength: number;\r\n\r\n\t/**\r\n\t * The position of the first element in the modified sequence which\r\n\t * this change affects.\r\n\t */\r\n\tpublic modifiedStart: number;\r\n\r\n\t/**\r\n\t * The number of elements from the modified sequence which were\r\n\t * affected (added).\r\n\t */\r\n\tpublic modifiedLength: number;\r\n\r\n\t/**\r\n\t * Constructs a new DiffChange with the given sequence information\r\n\t * and content.\r\n\t */\r\n\tconstructor(originalStart: number, originalLength: number, modifiedStart: number, modifiedLength: number) {\r\n\t\t//Debug.Assert(originalLength > 0 || modifiedLength > 0, \"originalLength and modifiedLength cannot both be <= 0\");\r\n\t\tthis.originalStart = originalStart;\r\n\t\tthis.originalLength = originalLength;\r\n\t\tthis.modifiedStart = modifiedStart;\r\n\t\tthis.modifiedLength = modifiedLength;\r\n\t}\r\n\r\n\t/**\r\n\t * The end point (exclusive) of the change in the original sequence.\r\n\t */\r\n\tpublic getOriginalEnd() {\r\n\t\treturn this.originalStart + this.originalLength;\r\n\t}\r\n\r\n\t/**\r\n\t * The end point (exclusive) of the change in the modified sequence.\r\n\t */\r\n\tpublic getModifiedEnd() {\r\n\t\treturn this.modifiedStart + this.modifiedLength;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nexport interface ErrorListenerCallback {\r\n\t(error: any): void;\r\n}\r\n\r\n// Avoid circular dependency on EventEmitter by implementing a subset of the interface.\r\nexport class ErrorHandler {\r\n\tprivate unexpectedErrorHandler: (e: any) => void;\r\n\tprivate listeners: ErrorListenerCallback[];\r\n\r\n\tconstructor() {\r\n\r\n\t\tthis.listeners = [];\r\n\r\n\t\tthis.unexpectedErrorHandler = function (e: any) {\r\n\t\t\tsetTimeout(() => {\r\n\t\t\t\tif (e.stack) {\r\n\t\t\t\t\tthrow new Error(e.message + '\\n\\n' + e.stack);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthrow e;\r\n\t\t\t}, 0);\r\n\t\t};\r\n\t}\r\n\r\n\tprivate emit(e: any): void {\r\n\t\tthis.listeners.forEach((listener) => {\r\n\t\t\tlistener(e);\r\n\t\t});\r\n\t}\r\n\r\n\tonUnexpectedError(e: any): void {\r\n\t\tthis.unexpectedErrorHandler(e);\r\n\t\tthis.emit(e);\r\n\t}\r\n\r\n\t// For external errors, we don't want the listeners to be called\r\n\tonUnexpectedExternalError(e: any): void {\r\n\t\tthis.unexpectedErrorHandler(e);\r\n\t}\r\n}\r\n\r\nexport const errorHandler = new ErrorHandler();\r\n\r\nexport function onUnexpectedError(e: any): undefined {\r\n\t// ignore errors from cancelled promises\r\n\tif (!isPromiseCanceledError(e)) {\r\n\t\terrorHandler.onUnexpectedError(e);\r\n\t}\r\n\treturn undefined;\r\n}\r\n\r\nexport function onUnexpectedExternalError(e: any): undefined {\r\n\t// ignore errors from cancelled promises\r\n\tif (!isPromiseCanceledError(e)) {\r\n\t\terrorHandler.onUnexpectedExternalError(e);\r\n\t}\r\n\treturn undefined;\r\n}\r\n\r\nexport interface SerializedError {\r\n}\r\n\r\nexport function transformErrorForSerialization(error: Error): SerializedError;\r\nexport function transformErrorForSerialization(error: any): any;\r\nexport function transformErrorForSerialization(error: any): any {\r\n\tif (error instanceof Error) {\r\n\t\tlet { name, message } = error;\r\n\t\tconst stack: string = (error).stacktrace || (error).stack;\r\n\t\treturn {\r\n\t\t\t$isError: true,\r\n\t\t\tname,\r\n\t\t\tmessage,\r\n\t\t\tstack\r\n\t\t};\r\n\t}\r\n\r\n\t// return as is\r\n\treturn error;\r\n}\r\n\r\nconst canceledName = 'Canceled';\r\n\r\n/**\r\n * Checks if the given error is a promise in canceled state\r\n */\r\nexport function isPromiseCanceledError(error: any): boolean {\r\n\treturn error instanceof Error && error.name === canceledName && error.message === canceledName;\r\n}\r\n\r\n/**\r\n * Returns an error that signals cancellation.\r\n */\r\nexport function canceled(): Error {\r\n\tconst error = new Error(canceledName);\r\n\terror.name = error.message;\r\n\treturn error;\r\n}\r\n\r\nexport function illegalArgument(name?: string): Error {\r\n\tif (name) {\r\n\t\treturn new Error(`Illegal argument: ${name}`);\r\n\t} else {\r\n\t\treturn new Error('Illegal argument');\r\n\t}\r\n}\r\n\r\nexport function illegalState(name?: string): Error {\r\n\tif (name) {\r\n\t\treturn new Error(`Illegal state: ${name}`);\r\n\t} else {\r\n\t\treturn new Error('Illegal state');\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nexport function once(this: unknown, fn: T): T {\r\n\tconst _this = this;\r\n\tlet didCall = false;\r\n\tlet result: unknown;\r\n\r\n\treturn function () {\r\n\t\tif (didCall) {\r\n\t\t\treturn result;\r\n\t\t}\r\n\r\n\t\tdidCall = true;\r\n\t\tresult = fn.apply(_this, arguments);\r\n\r\n\t\treturn result;\r\n\t} as unknown as T;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nexport class IdGenerator {\r\n\r\n\tprivate _prefix: string;\r\n\tprivate _lastId: number;\r\n\r\n\tconstructor(prefix: string) {\r\n\t\tthis._prefix = prefix;\r\n\t\tthis._lastId = 0;\r\n\t}\r\n\r\n\tpublic nextId(): string {\r\n\t\treturn this._prefix + (++this._lastId);\r\n\t}\r\n}\r\n\r\nexport const defaultGenerator = new IdGenerator('id#');","/*\nThe MIT License (MIT)\n\nCopyright © 2015 Nicolas Bevacqua\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n\nlet __insane_func;\n\n(function () { function r(e, n, t) { function o(i, f) { if (!n[i]) { if (!e[i]) { var c = \"function\" == typeof require && require; if (!f && c) return c(i, !0); if (u) return u(i, !0); var a = new Error(\"Cannot find module '\" + i + \"'\"); throw a.code = \"MODULE_NOT_FOUND\", a } var p = n[i] = { exports: {} }; e[i][0].call(p.exports, function (r) { var n = e[i][1][r]; return o(n || r) }, p, p.exports, r, e, n, t) } return n[i].exports } for (var u = \"function\" == typeof require && require, i = 0; i < t.length; i++)o(t[i]); return o } return r })()({\n\t1: [function (require, module, exports) {\n\t\t'use strict';\n\n\t\tvar toMap = require('./toMap');\n\t\tvar uris = ['background', 'base', 'cite', 'href', 'longdesc', 'src', 'usemap'];\n\n\t\tmodule.exports = {\n\t\t\turis: toMap(uris) // attributes that have an href and hence need to be sanitized\n\t\t};\n\n\t}, { \"./toMap\": 10 }], 2: [function (require, module, exports) {\n\t\t'use strict';\n\n\t\tvar defaults = {\n\t\t\tallowedAttributes: {\n\t\t\t\t'*': ['title', 'accesskey'],\n\t\t\t\ta: ['href', 'name', 'target', 'aria-label'],\n\t\t\t\tiframe: ['allowfullscreen', 'frameborder', 'src'],\n\t\t\t\timg: ['src', 'alt', 'title', 'aria-label']\n\t\t\t},\n\t\t\tallowedClasses: {},\n\t\t\tallowedSchemes: ['http', 'https', 'mailto'],\n\t\t\tallowedTags: [\n\t\t\t\t'a', 'abbr', 'article', 'b', 'blockquote', 'br', 'caption', 'code', 'del', 'details', 'div', 'em',\n\t\t\t\t'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'img', 'ins', 'kbd', 'li', 'main', 'mark',\n\t\t\t\t'ol', 'p', 'pre', 'section', 'span', 'strike', 'strong', 'sub', 'summary', 'sup', 'table',\n\t\t\t\t'tbody', 'td', 'th', 'thead', 'tr', 'u', 'ul'\n\t\t\t],\n\t\t\tfilter: null\n\t\t};\n\n\t\tmodule.exports = defaults;\n\n\t}, {}], 3: [function (require, module, exports) {\n\t\t'use strict';\n\n\t\tvar toMap = require('./toMap');\n\t\tvar voids = ['area', 'br', 'col', 'hr', 'img', 'wbr', 'input', 'base', 'basefont', 'link', 'meta'];\n\n\t\tmodule.exports = {\n\t\t\tvoids: toMap(voids)\n\t\t};\n\n\t}, { \"./toMap\": 10 }], 4: [function (require, module, exports) {\n\t\t'use strict';\n\n\t\tvar he = require('he');\n\t\tvar assign = require('assignment');\n\t\tvar parser = require('./parser');\n\t\tvar sanitizer = require('./sanitizer');\n\t\tvar defaults = require('./defaults');\n\n\t\tfunction insane(html, options, strict) {\n\t\t\tvar buffer = [];\n\t\t\tvar configuration = strict === true ? options : assign({}, defaults, options);\n\t\t\tvar handler = sanitizer(buffer, configuration);\n\n\t\t\tparser(html, handler);\n\n\t\t\treturn buffer.join('');\n\t\t}\n\n\t\tinsane.defaults = defaults;\n\t\tmodule.exports = insane;\n\t\t__insane_func = insane;\n\n\t}, { \"./defaults\": 2, \"./parser\": 7, \"./sanitizer\": 8, \"assignment\": 6, \"he\": 9 }], 5: [function (require, module, exports) {\n\t\t'use strict';\n\n\t\tmodule.exports = function lowercase(string) {\n\t\t\treturn typeof string === 'string' ? string.toLowerCase() : string;\n\t\t};\n\n\t}, {}], 6: [function (require, module, exports) {\n\t\t'use strict';\n\n\t\tfunction assignment(result) {\n\t\t\tvar stack = Array.prototype.slice.call(arguments, 1);\n\t\t\tvar item;\n\t\t\tvar key;\n\t\t\twhile (stack.length) {\n\t\t\t\titem = stack.shift();\n\t\t\t\tfor (key in item) {\n\t\t\t\t\tif (item.hasOwnProperty(key)) {\n\t\t\t\t\t\tif (Object.prototype.toString.call(result[key]) === '[object Object]') {\n\t\t\t\t\t\t\tresult[key] = assignment(result[key], item[key]);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresult[key] = item[key];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\tmodule.exports = assignment;\n\n\t}, {}], 7: [function (require, module, exports) {\n\t\t'use strict';\n\n\t\tvar he = require('he');\n\t\tvar lowercase = require('./lowercase');\n\t\tvar attributes = require('./attributes');\n\t\tvar elements = require('./elements');\n\t\tvar rstart = /^<\\s*([\\w:-]+)((?:\\s+[\\w:-]+(?:\\s*=\\s*(?:(?:\"[^\"]*\")|(?:'[^']*')|[^>\\s]+))?)*)\\s*(\\/?)\\s*>/;\n\t\tvar rend = /^<\\s*\\/\\s*([\\w:-]+)[^>]*>/;\n\t\tvar rattrs = /([\\w:-]+)(?:\\s*=\\s*(?:(?:\"((?:[^\"])*)\")|(?:'((?:[^'])*)')|([^>\\s]+)))?/g;\n\t\tvar rtag = /^');\n\t\t\t\tif (index >= 0) {\n\t\t\t\t\tif (handler.comment) {\n\t\t\t\t\t\thandler.comment(html.substring(4, index));\n\t\t\t\t\t}\n\t\t\t\t\thtml = html.substring(index + 3);\n\t\t\t\t\tchars = false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction parseTagDecode() {\n\t\t\t\tif (!chars) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tvar text;\n\t\t\t\tvar index = html.indexOf('<');\n\t\t\t\tif (index >= 0) {\n\t\t\t\t\ttext = html.substring(0, index);\n\t\t\t\t\thtml = html.substring(index);\n\t\t\t\t} else {\n\t\t\t\t\ttext = html;\n\t\t\t\t\thtml = '';\n\t\t\t\t}\n\t\t\t\tif (handler.chars) {\n\t\t\t\t\thandler.chars(text);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction parseStartTag(tag, tagName, rest, unary) {\n\t\t\t\tvar attrs = {};\n\t\t\t\tvar low = lowercase(tagName);\n\t\t\t\tvar u = elements.voids[low] || !!unary;\n\n\t\t\t\trest.replace(rattrs, attrReplacer);\n\n\t\t\t\tif (!u) {\n\t\t\t\t\tstack.push(low);\n\t\t\t\t}\n\t\t\t\tif (handler.start) {\n\t\t\t\t\thandler.start(low, attrs, u);\n\t\t\t\t}\n\n\t\t\t\tfunction attrReplacer(match, name, doubleQuotedValue, singleQuotedValue, unquotedValue) {\n\t\t\t\t\tif (doubleQuotedValue === void 0 && singleQuotedValue === void 0 && unquotedValue === void 0) {\n\t\t\t\t\t\tattrs[name] = void 0; // attribute is like \n\t\t\t\t\t} else {\n\t\t\t\t\t\tattrs[name] = he.decode(doubleQuotedValue || singleQuotedValue || unquotedValue || '');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction parseEndTag(tag, tagName) {\n\t\t\t\tvar i;\n\t\t\t\tvar pos = 0;\n\t\t\t\tvar low = lowercase(tagName);\n\t\t\t\tif (low) {\n\t\t\t\t\tfor (pos = stack.length - 1; pos >= 0; pos--) {\n\t\t\t\t\t\tif (stack[pos] === low) {\n\t\t\t\t\t\t\tbreak; // find the closest opened tag of the same type\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (pos >= 0) {\n\t\t\t\t\tfor (i = stack.length - 1; i >= pos; i--) {\n\t\t\t\t\t\tif (handler.end) { // close all the open elements, up the stack\n\t\t\t\t\t\t\thandler.end(stack[i]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tstack.length = pos;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tmodule.exports = parser;\n\n\t}, { \"./attributes\": 1, \"./elements\": 3, \"./lowercase\": 5, \"he\": 9 }], 8: [function (require, module, exports) {\n\t\t'use strict';\n\n\t\tvar he = require('he');\n\t\tvar lowercase = require('./lowercase');\n\t\tvar attributes = require('./attributes');\n\t\tvar elements = require('./elements');\n\n\t\tfunction sanitizer(buffer, options) {\n\t\t\tvar last;\n\t\t\tvar context;\n\t\t\tvar o = options || {};\n\n\t\t\treset();\n\n\t\t\treturn {\n\t\t\t\tstart: start,\n\t\t\t\tend: end,\n\t\t\t\tchars: chars\n\t\t\t};\n\n\t\t\tfunction out(value) {\n\t\t\t\tbuffer.push(value);\n\t\t\t}\n\n\t\t\tfunction start(tag, attrs, unary) {\n\t\t\t\tvar low = lowercase(tag);\n\n\t\t\t\tif (context.ignoring) {\n\t\t\t\t\tignore(low); return;\n\t\t\t\t}\n\t\t\t\tif ((o.allowedTags || []).indexOf(low) === -1) {\n\t\t\t\t\tignore(low); return;\n\t\t\t\t}\n\t\t\t\tif (o.filter && !o.filter({ tag: low, attrs: attrs })) {\n\t\t\t\t\tignore(low); return;\n\t\t\t\t}\n\n\t\t\t\tout('<');\n\t\t\t\tout(low);\n\t\t\t\tObject.keys(attrs).forEach(parse);\n\t\t\t\tout(unary ? '/>' : '>');\n\n\t\t\t\tfunction parse(key) {\n\t\t\t\t\tvar value = attrs[key];\n\t\t\t\t\tvar classesOk = (o.allowedClasses || {})[low] || [];\n\t\t\t\t\tvar attrsOk = (o.allowedAttributes || {})[low] || [];\n\t\t\t\t\tattrsOk = attrsOk.concat((o.allowedAttributes || {})['*'] || []);\n\t\t\t\t\tvar valid;\n\t\t\t\t\tvar lkey = lowercase(key);\n\t\t\t\t\tif (lkey === 'class' && attrsOk.indexOf(lkey) === -1) {\n\t\t\t\t\t\tvalue = value.split(' ').filter(isValidClass).join(' ').trim();\n\t\t\t\t\t\tvalid = value.length;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvalid = attrsOk.indexOf(lkey) !== -1 && (attributes.uris[lkey] !== true || testUrl(value));\n\t\t\t\t\t}\n\t\t\t\t\tif (valid) {\n\t\t\t\t\t\tout(' ');\n\t\t\t\t\t\tout(key);\n\t\t\t\t\t\tif (typeof value === 'string') {\n\t\t\t\t\t\t\tout('=\"');\n\t\t\t\t\t\t\tout(he.encode(value));\n\t\t\t\t\t\t\tout('\"');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfunction isValidClass(className) {\n\t\t\t\t\t\treturn classesOk && classesOk.indexOf(className) !== -1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction end(tag) {\n\t\t\t\tvar low = lowercase(tag);\n\t\t\t\tvar allowed = (o.allowedTags || []).indexOf(low) !== -1;\n\t\t\t\tif (allowed) {\n\t\t\t\t\tif (context.ignoring === false) {\n\t\t\t\t\t\tout('');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tunignore(low);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tunignore(low);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction testUrl(text) {\n\t\t\t\tvar start = text[0];\n\t\t\t\tif (start === '#' || start === '/') {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tvar colon = text.indexOf(':');\n\t\t\t\tif (colon === -1) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tvar questionmark = text.indexOf('?');\n\t\t\t\tif (questionmark !== -1 && colon > questionmark) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tvar hash = text.indexOf('#');\n\t\t\t\tif (hash !== -1 && colon > hash) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\treturn o.allowedSchemes.some(matches);\n\n\t\t\t\tfunction matches(scheme) {\n\t\t\t\t\treturn text.indexOf(scheme + ':') === 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction chars(text) {\n\t\t\t\tif (context.ignoring === false) {\n\t\t\t\t\tout(o.transformText ? o.transformText(text) : text);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction ignore(tag) {\n\t\t\t\tif (elements.voids[tag]) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (context.ignoring === false) {\n\t\t\t\t\tcontext = { ignoring: tag, depth: 1 };\n\t\t\t\t} else if (context.ignoring === tag) {\n\t\t\t\t\tcontext.depth++;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction unignore(tag) {\n\t\t\t\tif (context.ignoring === tag) {\n\t\t\t\t\tif (--context.depth <= 0) {\n\t\t\t\t\t\treset();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction reset() {\n\t\t\t\tcontext = { ignoring: false, depth: 0 };\n\t\t\t}\n\t\t}\n\n\t\tmodule.exports = sanitizer;\n\n\t}, { \"./attributes\": 1, \"./elements\": 3, \"./lowercase\": 5, \"he\": 9 }], 9: [function (require, module, exports) {\n\t\t'use strict';\n\n\t\tvar escapes = {\n\t\t\t'&': '&',\n\t\t\t'<': '<',\n\t\t\t'>': '>',\n\t\t\t'\"': '"',\n\t\t\t\"'\": '''\n\t\t};\n\t\tvar unescapes = {\n\t\t\t'&': '&',\n\t\t\t'<': '<',\n\t\t\t'>': '>',\n\t\t\t'"': '\"',\n\t\t\t''': \"'\"\n\t\t};\n\t\tvar rescaped = /(&|<|>|"|')/g;\n\t\tvar runescaped = /[&<>\"']/g;\n\n\t\tfunction escapeHtmlChar(match) {\n\t\t\treturn escapes[match];\n\t\t}\n\t\tfunction unescapeHtmlChar(match) {\n\t\t\treturn unescapes[match];\n\t\t}\n\n\t\tfunction escapeHtml(text) {\n\t\t\treturn text == null ? '' : String(text).replace(runescaped, escapeHtmlChar);\n\t\t}\n\n\t\tfunction unescapeHtml(html) {\n\t\t\treturn html == null ? '' : String(html).replace(rescaped, unescapeHtmlChar);\n\t\t}\n\n\t\tescapeHtml.options = unescapeHtml.options = {};\n\n\t\tmodule.exports = {\n\t\t\tencode: escapeHtml,\n\t\t\tescape: escapeHtml,\n\t\t\tdecode: unescapeHtml,\n\t\t\tunescape: unescapeHtml,\n\t\t\tversion: '1.0.0-browser'\n\t\t};\n\n\t}, {}], 10: [function (require, module, exports) {\n\t\t'use strict';\n\n\t\tfunction toMap(list) {\n\t\t\treturn list.reduce(asKey, {});\n\t\t}\n\n\t\tfunction asKey(accumulator, item) {\n\t\t\taccumulator[item] = true;\n\t\t\treturn accumulator;\n\t\t}\n\n\t\tmodule.exports = toMap;\n\n\t}, {}]\n}, {}, [4]);\n\n// ESM-comment-begin\ndefine(\"vs/base/common/insane/insane\", function() { return { insane: __insane_func }; });\n// ESM-comment-end\n\n// ESM-uncomment-begin\n// export var insane = __insane_func;\n// ESM-uncomment-end\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nexport namespace Iterable {\r\n\r\n\texport function is(thing: any): thing is IterableIterator {\r\n\t\treturn thing && typeof thing === 'object' && typeof thing[Symbol.iterator] === 'function';\r\n\t}\r\n\r\n\tconst _empty: Iterable = Object.freeze([]);\r\n\texport function empty(): Iterable {\r\n\t\treturn _empty;\r\n\t}\r\n\r\n\texport function* single(element: T): Iterable {\r\n\t\tyield element;\r\n\t}\r\n\r\n\texport function from(iterable: Iterable | undefined | null): Iterable {\r\n\t\treturn iterable || _empty;\r\n\t}\r\n\r\n\texport function isEmpty(iterable: Iterable | undefined | null): boolean {\r\n\t\treturn !iterable || iterable[Symbol.iterator]().next().done === true;\r\n\t}\r\n\r\n\texport function first(iterable: Iterable): T | undefined {\r\n\t\treturn iterable[Symbol.iterator]().next().value;\r\n\t}\r\n\r\n\texport function some(iterable: Iterable, predicate: (t: T) => boolean): boolean {\r\n\t\tfor (const element of iterable) {\r\n\t\t\tif (predicate(element)) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\texport function filter(iterable: Iterable, predicate: (t: T) => t is R): Iterable;\r\n\texport function filter(iterable: Iterable, predicate: (t: T) => boolean): Iterable;\r\n\texport function* filter(iterable: Iterable, predicate: (t: T) => boolean): Iterable {\r\n\t\tfor (const element of iterable) {\r\n\t\t\tif (predicate(element)) {\r\n\t\t\t\tyield element;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\texport function* map(iterable: Iterable, fn: (t: T) => R): Iterable {\r\n\t\tfor (const element of iterable) {\r\n\t\t\tyield fn(element);\r\n\t\t}\r\n\t}\r\n\r\n\texport function* concat(...iterables: Iterable[]): Iterable {\r\n\t\tfor (const iterable of iterables) {\r\n\t\t\tfor (const element of iterable) {\r\n\t\t\t\tyield element;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\texport function* concatNested(iterables: Iterable>): Iterable {\r\n\t\tfor (const iterable of iterables) {\r\n\t\t\tfor (const element of iterable) {\r\n\t\t\t\tyield element;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Returns an iterable slice of the array, with the same semantics as `array.slice()`.\r\n\t */\r\n\texport function* slice(iterable: ReadonlyArray, from: number, to = iterable.length): Iterable {\r\n\t\tif (from < 0) {\r\n\t\t\tfrom += iterable.length;\r\n\t\t}\r\n\r\n\t\tif (to < 0) {\r\n\t\t\tto += iterable.length;\r\n\t\t} else if (to > iterable.length) {\r\n\t\t\tto = iterable.length;\r\n\t\t}\r\n\r\n\t\tfor (; from < to; from++) {\r\n\t\t\tyield iterable[from];\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Consumes `atMost` elements from iterable and returns the consumed elements,\r\n\t * and an iterable for the rest of the elements.\r\n\t */\r\n\texport function consume(iterable: Iterable, atMost: number = Number.POSITIVE_INFINITY): [T[], Iterable] {\r\n\t\tconst consumed: T[] = [];\r\n\r\n\t\tif (atMost === 0) {\r\n\t\t\treturn [consumed, iterable];\r\n\t\t}\r\n\r\n\t\tconst iterator = iterable[Symbol.iterator]();\r\n\r\n\t\tfor (let i = 0; i < atMost; i++) {\r\n\t\t\tconst next = iterator.next();\r\n\r\n\t\t\tif (next.done) {\r\n\t\t\t\treturn [consumed, Iterable.empty()];\r\n\t\t\t}\r\n\r\n\t\t\tconsumed.push(next.value);\r\n\t\t}\r\n\r\n\t\treturn [consumed, { [Symbol.iterator]() { return iterator; } }];\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { OperatingSystem } from 'vs/base/common/platform';\r\nimport { illegalArgument } from 'vs/base/common/errors';\r\n\r\n/**\r\n * Virtual Key Codes, the value does not hold any inherent meaning.\r\n * Inspired somewhat from https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx\r\n * But these are \"more general\", as they should work across browsers & OS`s.\r\n */\r\nexport const enum KeyCode {\r\n\t/**\r\n\t * Placed first to cover the 0 value of the enum.\r\n\t */\r\n\tUnknown = 0,\r\n\r\n\tBackspace = 1,\r\n\tTab = 2,\r\n\tEnter = 3,\r\n\tShift = 4,\r\n\tCtrl = 5,\r\n\tAlt = 6,\r\n\tPauseBreak = 7,\r\n\tCapsLock = 8,\r\n\tEscape = 9,\r\n\tSpace = 10,\r\n\tPageUp = 11,\r\n\tPageDown = 12,\r\n\tEnd = 13,\r\n\tHome = 14,\r\n\tLeftArrow = 15,\r\n\tUpArrow = 16,\r\n\tRightArrow = 17,\r\n\tDownArrow = 18,\r\n\tInsert = 19,\r\n\tDelete = 20,\r\n\r\n\tKEY_0 = 21,\r\n\tKEY_1 = 22,\r\n\tKEY_2 = 23,\r\n\tKEY_3 = 24,\r\n\tKEY_4 = 25,\r\n\tKEY_5 = 26,\r\n\tKEY_6 = 27,\r\n\tKEY_7 = 28,\r\n\tKEY_8 = 29,\r\n\tKEY_9 = 30,\r\n\r\n\tKEY_A = 31,\r\n\tKEY_B = 32,\r\n\tKEY_C = 33,\r\n\tKEY_D = 34,\r\n\tKEY_E = 35,\r\n\tKEY_F = 36,\r\n\tKEY_G = 37,\r\n\tKEY_H = 38,\r\n\tKEY_I = 39,\r\n\tKEY_J = 40,\r\n\tKEY_K = 41,\r\n\tKEY_L = 42,\r\n\tKEY_M = 43,\r\n\tKEY_N = 44,\r\n\tKEY_O = 45,\r\n\tKEY_P = 46,\r\n\tKEY_Q = 47,\r\n\tKEY_R = 48,\r\n\tKEY_S = 49,\r\n\tKEY_T = 50,\r\n\tKEY_U = 51,\r\n\tKEY_V = 52,\r\n\tKEY_W = 53,\r\n\tKEY_X = 54,\r\n\tKEY_Y = 55,\r\n\tKEY_Z = 56,\r\n\r\n\tMeta = 57,\r\n\tContextMenu = 58,\r\n\r\n\tF1 = 59,\r\n\tF2 = 60,\r\n\tF3 = 61,\r\n\tF4 = 62,\r\n\tF5 = 63,\r\n\tF6 = 64,\r\n\tF7 = 65,\r\n\tF8 = 66,\r\n\tF9 = 67,\r\n\tF10 = 68,\r\n\tF11 = 69,\r\n\tF12 = 70,\r\n\tF13 = 71,\r\n\tF14 = 72,\r\n\tF15 = 73,\r\n\tF16 = 74,\r\n\tF17 = 75,\r\n\tF18 = 76,\r\n\tF19 = 77,\r\n\r\n\tNumLock = 78,\r\n\tScrollLock = 79,\r\n\r\n\t/**\r\n\t * Used for miscellaneous characters; it can vary by keyboard.\r\n\t * For the US standard keyboard, the ';:' key\r\n\t */\r\n\tUS_SEMICOLON = 80,\r\n\t/**\r\n\t * For any country/region, the '+' key\r\n\t * For the US standard keyboard, the '=+' key\r\n\t */\r\n\tUS_EQUAL = 81,\r\n\t/**\r\n\t * For any country/region, the ',' key\r\n\t * For the US standard keyboard, the ',<' key\r\n\t */\r\n\tUS_COMMA = 82,\r\n\t/**\r\n\t * For any country/region, the '-' key\r\n\t * For the US standard keyboard, the '-_' key\r\n\t */\r\n\tUS_MINUS = 83,\r\n\t/**\r\n\t * For any country/region, the '.' key\r\n\t * For the US standard keyboard, the '.>' key\r\n\t */\r\n\tUS_DOT = 84,\r\n\t/**\r\n\t * Used for miscellaneous characters; it can vary by keyboard.\r\n\t * For the US standard keyboard, the '/?' key\r\n\t */\r\n\tUS_SLASH = 85,\r\n\t/**\r\n\t * Used for miscellaneous characters; it can vary by keyboard.\r\n\t * For the US standard keyboard, the '`~' key\r\n\t */\r\n\tUS_BACKTICK = 86,\r\n\t/**\r\n\t * Used for miscellaneous characters; it can vary by keyboard.\r\n\t * For the US standard keyboard, the '[{' key\r\n\t */\r\n\tUS_OPEN_SQUARE_BRACKET = 87,\r\n\t/**\r\n\t * Used for miscellaneous characters; it can vary by keyboard.\r\n\t * For the US standard keyboard, the '\\|' key\r\n\t */\r\n\tUS_BACKSLASH = 88,\r\n\t/**\r\n\t * Used for miscellaneous characters; it can vary by keyboard.\r\n\t * For the US standard keyboard, the ']}' key\r\n\t */\r\n\tUS_CLOSE_SQUARE_BRACKET = 89,\r\n\t/**\r\n\t * Used for miscellaneous characters; it can vary by keyboard.\r\n\t * For the US standard keyboard, the ''\"' key\r\n\t */\r\n\tUS_QUOTE = 90,\r\n\t/**\r\n\t * Used for miscellaneous characters; it can vary by keyboard.\r\n\t */\r\n\tOEM_8 = 91,\r\n\t/**\r\n\t * Either the angle bracket key or the backslash key on the RT 102-key keyboard.\r\n\t */\r\n\tOEM_102 = 92,\r\n\r\n\tNUMPAD_0 = 93, // VK_NUMPAD0, 0x60, Numeric keypad 0 key\r\n\tNUMPAD_1 = 94, // VK_NUMPAD1, 0x61, Numeric keypad 1 key\r\n\tNUMPAD_2 = 95, // VK_NUMPAD2, 0x62, Numeric keypad 2 key\r\n\tNUMPAD_3 = 96, // VK_NUMPAD3, 0x63, Numeric keypad 3 key\r\n\tNUMPAD_4 = 97, // VK_NUMPAD4, 0x64, Numeric keypad 4 key\r\n\tNUMPAD_5 = 98, // VK_NUMPAD5, 0x65, Numeric keypad 5 key\r\n\tNUMPAD_6 = 99, // VK_NUMPAD6, 0x66, Numeric keypad 6 key\r\n\tNUMPAD_7 = 100, // VK_NUMPAD7, 0x67, Numeric keypad 7 key\r\n\tNUMPAD_8 = 101, // VK_NUMPAD8, 0x68, Numeric keypad 8 key\r\n\tNUMPAD_9 = 102, // VK_NUMPAD9, 0x69, Numeric keypad 9 key\r\n\r\n\tNUMPAD_MULTIPLY = 103,\t// VK_MULTIPLY, 0x6A, Multiply key\r\n\tNUMPAD_ADD = 104,\t\t// VK_ADD, 0x6B, Add key\r\n\tNUMPAD_SEPARATOR = 105,\t// VK_SEPARATOR, 0x6C, Separator key\r\n\tNUMPAD_SUBTRACT = 106,\t// VK_SUBTRACT, 0x6D, Subtract key\r\n\tNUMPAD_DECIMAL = 107,\t// VK_DECIMAL, 0x6E, Decimal key\r\n\tNUMPAD_DIVIDE = 108,\t// VK_DIVIDE, 0x6F,\r\n\r\n\t/**\r\n\t * Cover all key codes when IME is processing input.\r\n\t */\r\n\tKEY_IN_COMPOSITION = 109,\r\n\r\n\tABNT_C1 = 110, // Brazilian (ABNT) Keyboard\r\n\tABNT_C2 = 111, // Brazilian (ABNT) Keyboard\r\n\r\n\t/**\r\n\t * Placed last to cover the length of the enum.\r\n\t * Please do not depend on this value!\r\n\t */\r\n\tMAX_VALUE\r\n}\r\n\r\nclass KeyCodeStrMap {\r\n\r\n\tprivate _keyCodeToStr: string[];\r\n\tprivate _strToKeyCode: { [str: string]: KeyCode; };\r\n\r\n\tconstructor() {\r\n\t\tthis._keyCodeToStr = [];\r\n\t\tthis._strToKeyCode = Object.create(null);\r\n\t}\r\n\r\n\tdefine(keyCode: KeyCode, str: string): void {\r\n\t\tthis._keyCodeToStr[keyCode] = str;\r\n\t\tthis._strToKeyCode[str.toLowerCase()] = keyCode;\r\n\t}\r\n\r\n\tkeyCodeToStr(keyCode: KeyCode): string {\r\n\t\treturn this._keyCodeToStr[keyCode];\r\n\t}\r\n\r\n\tstrToKeyCode(str: string): KeyCode {\r\n\t\treturn this._strToKeyCode[str.toLowerCase()] || KeyCode.Unknown;\r\n\t}\r\n}\r\n\r\nconst uiMap = new KeyCodeStrMap();\r\nconst userSettingsUSMap = new KeyCodeStrMap();\r\nconst userSettingsGeneralMap = new KeyCodeStrMap();\r\n\r\n(function () {\r\n\r\n\tfunction define(keyCode: KeyCode, uiLabel: string, usUserSettingsLabel: string = uiLabel, generalUserSettingsLabel: string = usUserSettingsLabel): void {\r\n\t\tuiMap.define(keyCode, uiLabel);\r\n\t\tuserSettingsUSMap.define(keyCode, usUserSettingsLabel);\r\n\t\tuserSettingsGeneralMap.define(keyCode, generalUserSettingsLabel);\r\n\t}\r\n\r\n\tdefine(KeyCode.Unknown, 'unknown');\r\n\r\n\tdefine(KeyCode.Backspace, 'Backspace');\r\n\tdefine(KeyCode.Tab, 'Tab');\r\n\tdefine(KeyCode.Enter, 'Enter');\r\n\tdefine(KeyCode.Shift, 'Shift');\r\n\tdefine(KeyCode.Ctrl, 'Ctrl');\r\n\tdefine(KeyCode.Alt, 'Alt');\r\n\tdefine(KeyCode.PauseBreak, 'PauseBreak');\r\n\tdefine(KeyCode.CapsLock, 'CapsLock');\r\n\tdefine(KeyCode.Escape, 'Escape');\r\n\tdefine(KeyCode.Space, 'Space');\r\n\tdefine(KeyCode.PageUp, 'PageUp');\r\n\tdefine(KeyCode.PageDown, 'PageDown');\r\n\tdefine(KeyCode.End, 'End');\r\n\tdefine(KeyCode.Home, 'Home');\r\n\r\n\tdefine(KeyCode.LeftArrow, 'LeftArrow', 'Left');\r\n\tdefine(KeyCode.UpArrow, 'UpArrow', 'Up');\r\n\tdefine(KeyCode.RightArrow, 'RightArrow', 'Right');\r\n\tdefine(KeyCode.DownArrow, 'DownArrow', 'Down');\r\n\tdefine(KeyCode.Insert, 'Insert');\r\n\tdefine(KeyCode.Delete, 'Delete');\r\n\r\n\tdefine(KeyCode.KEY_0, '0');\r\n\tdefine(KeyCode.KEY_1, '1');\r\n\tdefine(KeyCode.KEY_2, '2');\r\n\tdefine(KeyCode.KEY_3, '3');\r\n\tdefine(KeyCode.KEY_4, '4');\r\n\tdefine(KeyCode.KEY_5, '5');\r\n\tdefine(KeyCode.KEY_6, '6');\r\n\tdefine(KeyCode.KEY_7, '7');\r\n\tdefine(KeyCode.KEY_8, '8');\r\n\tdefine(KeyCode.KEY_9, '9');\r\n\r\n\tdefine(KeyCode.KEY_A, 'A');\r\n\tdefine(KeyCode.KEY_B, 'B');\r\n\tdefine(KeyCode.KEY_C, 'C');\r\n\tdefine(KeyCode.KEY_D, 'D');\r\n\tdefine(KeyCode.KEY_E, 'E');\r\n\tdefine(KeyCode.KEY_F, 'F');\r\n\tdefine(KeyCode.KEY_G, 'G');\r\n\tdefine(KeyCode.KEY_H, 'H');\r\n\tdefine(KeyCode.KEY_I, 'I');\r\n\tdefine(KeyCode.KEY_J, 'J');\r\n\tdefine(KeyCode.KEY_K, 'K');\r\n\tdefine(KeyCode.KEY_L, 'L');\r\n\tdefine(KeyCode.KEY_M, 'M');\r\n\tdefine(KeyCode.KEY_N, 'N');\r\n\tdefine(KeyCode.KEY_O, 'O');\r\n\tdefine(KeyCode.KEY_P, 'P');\r\n\tdefine(KeyCode.KEY_Q, 'Q');\r\n\tdefine(KeyCode.KEY_R, 'R');\r\n\tdefine(KeyCode.KEY_S, 'S');\r\n\tdefine(KeyCode.KEY_T, 'T');\r\n\tdefine(KeyCode.KEY_U, 'U');\r\n\tdefine(KeyCode.KEY_V, 'V');\r\n\tdefine(KeyCode.KEY_W, 'W');\r\n\tdefine(KeyCode.KEY_X, 'X');\r\n\tdefine(KeyCode.KEY_Y, 'Y');\r\n\tdefine(KeyCode.KEY_Z, 'Z');\r\n\r\n\tdefine(KeyCode.Meta, 'Meta');\r\n\tdefine(KeyCode.ContextMenu, 'ContextMenu');\r\n\r\n\tdefine(KeyCode.F1, 'F1');\r\n\tdefine(KeyCode.F2, 'F2');\r\n\tdefine(KeyCode.F3, 'F3');\r\n\tdefine(KeyCode.F4, 'F4');\r\n\tdefine(KeyCode.F5, 'F5');\r\n\tdefine(KeyCode.F6, 'F6');\r\n\tdefine(KeyCode.F7, 'F7');\r\n\tdefine(KeyCode.F8, 'F8');\r\n\tdefine(KeyCode.F9, 'F9');\r\n\tdefine(KeyCode.F10, 'F10');\r\n\tdefine(KeyCode.F11, 'F11');\r\n\tdefine(KeyCode.F12, 'F12');\r\n\tdefine(KeyCode.F13, 'F13');\r\n\tdefine(KeyCode.F14, 'F14');\r\n\tdefine(KeyCode.F15, 'F15');\r\n\tdefine(KeyCode.F16, 'F16');\r\n\tdefine(KeyCode.F17, 'F17');\r\n\tdefine(KeyCode.F18, 'F18');\r\n\tdefine(KeyCode.F19, 'F19');\r\n\r\n\tdefine(KeyCode.NumLock, 'NumLock');\r\n\tdefine(KeyCode.ScrollLock, 'ScrollLock');\r\n\r\n\tdefine(KeyCode.US_SEMICOLON, ';', ';', 'OEM_1');\r\n\tdefine(KeyCode.US_EQUAL, '=', '=', 'OEM_PLUS');\r\n\tdefine(KeyCode.US_COMMA, ',', ',', 'OEM_COMMA');\r\n\tdefine(KeyCode.US_MINUS, '-', '-', 'OEM_MINUS');\r\n\tdefine(KeyCode.US_DOT, '.', '.', 'OEM_PERIOD');\r\n\tdefine(KeyCode.US_SLASH, '/', '/', 'OEM_2');\r\n\tdefine(KeyCode.US_BACKTICK, '`', '`', 'OEM_3');\r\n\tdefine(KeyCode.ABNT_C1, 'ABNT_C1');\r\n\tdefine(KeyCode.ABNT_C2, 'ABNT_C2');\r\n\tdefine(KeyCode.US_OPEN_SQUARE_BRACKET, '[', '[', 'OEM_4');\r\n\tdefine(KeyCode.US_BACKSLASH, '\\\\', '\\\\', 'OEM_5');\r\n\tdefine(KeyCode.US_CLOSE_SQUARE_BRACKET, ']', ']', 'OEM_6');\r\n\tdefine(KeyCode.US_QUOTE, '\\'', '\\'', 'OEM_7');\r\n\tdefine(KeyCode.OEM_8, 'OEM_8');\r\n\tdefine(KeyCode.OEM_102, 'OEM_102');\r\n\r\n\tdefine(KeyCode.NUMPAD_0, 'NumPad0');\r\n\tdefine(KeyCode.NUMPAD_1, 'NumPad1');\r\n\tdefine(KeyCode.NUMPAD_2, 'NumPad2');\r\n\tdefine(KeyCode.NUMPAD_3, 'NumPad3');\r\n\tdefine(KeyCode.NUMPAD_4, 'NumPad4');\r\n\tdefine(KeyCode.NUMPAD_5, 'NumPad5');\r\n\tdefine(KeyCode.NUMPAD_6, 'NumPad6');\r\n\tdefine(KeyCode.NUMPAD_7, 'NumPad7');\r\n\tdefine(KeyCode.NUMPAD_8, 'NumPad8');\r\n\tdefine(KeyCode.NUMPAD_9, 'NumPad9');\r\n\r\n\tdefine(KeyCode.NUMPAD_MULTIPLY, 'NumPad_Multiply');\r\n\tdefine(KeyCode.NUMPAD_ADD, 'NumPad_Add');\r\n\tdefine(KeyCode.NUMPAD_SEPARATOR, 'NumPad_Separator');\r\n\tdefine(KeyCode.NUMPAD_SUBTRACT, 'NumPad_Subtract');\r\n\tdefine(KeyCode.NUMPAD_DECIMAL, 'NumPad_Decimal');\r\n\tdefine(KeyCode.NUMPAD_DIVIDE, 'NumPad_Divide');\r\n\r\n})();\r\n\r\nexport namespace KeyCodeUtils {\r\n\texport function toString(keyCode: KeyCode): string {\r\n\t\treturn uiMap.keyCodeToStr(keyCode);\r\n\t}\r\n\texport function fromString(key: string): KeyCode {\r\n\t\treturn uiMap.strToKeyCode(key);\r\n\t}\r\n\r\n\texport function toUserSettingsUS(keyCode: KeyCode): string {\r\n\t\treturn userSettingsUSMap.keyCodeToStr(keyCode);\r\n\t}\r\n\texport function toUserSettingsGeneral(keyCode: KeyCode): string {\r\n\t\treturn userSettingsGeneralMap.keyCodeToStr(keyCode);\r\n\t}\r\n\texport function fromUserSettings(key: string): KeyCode {\r\n\t\treturn userSettingsUSMap.strToKeyCode(key) || userSettingsGeneralMap.strToKeyCode(key);\r\n\t}\r\n}\r\n\r\n/**\r\n * Binary encoding strategy:\r\n * ```\r\n * 1111 11\r\n * 5432 1098 7654 3210\r\n * ---- CSAW KKKK KKKK\r\n * C = bit 11 = ctrlCmd flag\r\n * S = bit 10 = shift flag\r\n * A = bit 9 = alt flag\r\n * W = bit 8 = winCtrl flag\r\n * K = bits 0-7 = key code\r\n * ```\r\n */\r\nconst enum BinaryKeybindingsMask {\r\n\tCtrlCmd = (1 << 11) >>> 0,\r\n\tShift = (1 << 10) >>> 0,\r\n\tAlt = (1 << 9) >>> 0,\r\n\tWinCtrl = (1 << 8) >>> 0,\r\n\tKeyCode = 0x000000FF\r\n}\r\n\r\nexport const enum KeyMod {\r\n\tCtrlCmd = (1 << 11) >>> 0,\r\n\tShift = (1 << 10) >>> 0,\r\n\tAlt = (1 << 9) >>> 0,\r\n\tWinCtrl = (1 << 8) >>> 0,\r\n}\r\n\r\nexport function KeyChord(firstPart: number, secondPart: number): number {\r\n\tconst chordPart = ((secondPart & 0x0000FFFF) << 16) >>> 0;\r\n\treturn (firstPart | chordPart) >>> 0;\r\n}\r\n\r\nexport function createKeybinding(keybinding: number, OS: OperatingSystem): Keybinding | null {\r\n\tif (keybinding === 0) {\r\n\t\treturn null;\r\n\t}\r\n\tconst firstPart = (keybinding & 0x0000FFFF) >>> 0;\r\n\tconst chordPart = (keybinding & 0xFFFF0000) >>> 16;\r\n\tif (chordPart !== 0) {\r\n\t\treturn new ChordKeybinding([\r\n\t\t\tcreateSimpleKeybinding(firstPart, OS),\r\n\t\t\tcreateSimpleKeybinding(chordPart, OS)\r\n\t\t]);\r\n\t}\r\n\treturn new ChordKeybinding([createSimpleKeybinding(firstPart, OS)]);\r\n}\r\n\r\nexport function createSimpleKeybinding(keybinding: number, OS: OperatingSystem): SimpleKeybinding {\r\n\r\n\tconst ctrlCmd = (keybinding & BinaryKeybindingsMask.CtrlCmd ? true : false);\r\n\tconst winCtrl = (keybinding & BinaryKeybindingsMask.WinCtrl ? true : false);\r\n\r\n\tconst ctrlKey = (OS === OperatingSystem.Macintosh ? winCtrl : ctrlCmd);\r\n\tconst shiftKey = (keybinding & BinaryKeybindingsMask.Shift ? true : false);\r\n\tconst altKey = (keybinding & BinaryKeybindingsMask.Alt ? true : false);\r\n\tconst metaKey = (OS === OperatingSystem.Macintosh ? ctrlCmd : winCtrl);\r\n\tconst keyCode = (keybinding & BinaryKeybindingsMask.KeyCode);\r\n\r\n\treturn new SimpleKeybinding(ctrlKey, shiftKey, altKey, metaKey, keyCode);\r\n}\r\n\r\nexport class SimpleKeybinding {\r\n\tpublic readonly ctrlKey: boolean;\r\n\tpublic readonly shiftKey: boolean;\r\n\tpublic readonly altKey: boolean;\r\n\tpublic readonly metaKey: boolean;\r\n\tpublic readonly keyCode: KeyCode;\r\n\r\n\tconstructor(ctrlKey: boolean, shiftKey: boolean, altKey: boolean, metaKey: boolean, keyCode: KeyCode) {\r\n\t\tthis.ctrlKey = ctrlKey;\r\n\t\tthis.shiftKey = shiftKey;\r\n\t\tthis.altKey = altKey;\r\n\t\tthis.metaKey = metaKey;\r\n\t\tthis.keyCode = keyCode;\r\n\t}\r\n\r\n\tpublic equals(other: SimpleKeybinding): boolean {\r\n\t\treturn (\r\n\t\t\tthis.ctrlKey === other.ctrlKey\r\n\t\t\t&& this.shiftKey === other.shiftKey\r\n\t\t\t&& this.altKey === other.altKey\r\n\t\t\t&& this.metaKey === other.metaKey\r\n\t\t\t&& this.keyCode === other.keyCode\r\n\t\t);\r\n\t}\r\n\r\n\tpublic isModifierKey(): boolean {\r\n\t\treturn (\r\n\t\t\tthis.keyCode === KeyCode.Unknown\r\n\t\t\t|| this.keyCode === KeyCode.Ctrl\r\n\t\t\t|| this.keyCode === KeyCode.Meta\r\n\t\t\t|| this.keyCode === KeyCode.Alt\r\n\t\t\t|| this.keyCode === KeyCode.Shift\r\n\t\t);\r\n\t}\r\n\r\n\tpublic toChord(): ChordKeybinding {\r\n\t\treturn new ChordKeybinding([this]);\r\n\t}\r\n\r\n\t/**\r\n\t * Does this keybinding refer to the key code of a modifier and it also has the modifier flag?\r\n\t */\r\n\tpublic isDuplicateModifierCase(): boolean {\r\n\t\treturn (\r\n\t\t\t(this.ctrlKey && this.keyCode === KeyCode.Ctrl)\r\n\t\t\t|| (this.shiftKey && this.keyCode === KeyCode.Shift)\r\n\t\t\t|| (this.altKey && this.keyCode === KeyCode.Alt)\r\n\t\t\t|| (this.metaKey && this.keyCode === KeyCode.Meta)\r\n\t\t);\r\n\t}\r\n}\r\n\r\nexport class ChordKeybinding {\r\n\tpublic readonly parts: SimpleKeybinding[];\r\n\r\n\tconstructor(parts: SimpleKeybinding[]) {\r\n\t\tif (parts.length === 0) {\r\n\t\t\tthrow illegalArgument(`parts`);\r\n\t\t}\r\n\t\tthis.parts = parts;\r\n\t}\r\n}\r\n\r\nexport type Keybinding = ChordKeybinding;\r\n\r\nexport class ResolvedKeybindingPart {\r\n\treadonly ctrlKey: boolean;\r\n\treadonly shiftKey: boolean;\r\n\treadonly altKey: boolean;\r\n\treadonly metaKey: boolean;\r\n\r\n\treadonly keyLabel: string | null;\r\n\treadonly keyAriaLabel: string | null;\r\n\r\n\tconstructor(ctrlKey: boolean, shiftKey: boolean, altKey: boolean, metaKey: boolean, kbLabel: string | null, kbAriaLabel: string | null) {\r\n\t\tthis.ctrlKey = ctrlKey;\r\n\t\tthis.shiftKey = shiftKey;\r\n\t\tthis.altKey = altKey;\r\n\t\tthis.metaKey = metaKey;\r\n\t\tthis.keyLabel = kbLabel;\r\n\t\tthis.keyAriaLabel = kbAriaLabel;\r\n\t}\r\n}\r\n\r\n/**\r\n * A resolved keybinding. Can be a simple keybinding or a chord keybinding.\r\n */\r\nexport abstract class ResolvedKeybinding {\r\n\t/**\r\n\t * This prints the binding in a format suitable for displaying in the UI.\r\n\t */\r\n\tpublic abstract getLabel(): string | null;\r\n\t/**\r\n\t * This prints the binding in a format suitable for ARIA.\r\n\t */\r\n\tpublic abstract getAriaLabel(): string | null;\r\n\r\n\t/**\r\n\t * Is the binding a chord?\r\n\t */\r\n\tpublic abstract isChord(): boolean;\r\n\r\n\t/**\r\n\t * Returns the parts that comprise of the keybinding.\r\n\t * Simple keybindings return one element.\r\n\t */\r\n\tpublic abstract getParts(): ResolvedKeybindingPart[];\r\n\r\n\t/**\r\n\t * Returns the parts that should be used for dispatching.\r\n\t */\r\n\tpublic abstract getDispatchParts(): (string | null)[];\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\n/**\r\n * A value that is resolved synchronously when it is first needed.\r\n */\r\nexport interface Lazy {\r\n\r\n\r\n\tgetValue(): T;\r\n}\r\n\r\nexport class Lazy {\r\n\r\n\tprivate _didRun: boolean = false;\r\n\tprivate _value?: T;\r\n\tprivate _error: Error | undefined;\r\n\r\n\tconstructor(\r\n\t\tprivate readonly executor: () => T,\r\n\t) { }\r\n\r\n\t/**\r\n\t * Get the wrapped value.\r\n\t *\r\n\t * This will force evaluation of the lazy value if it has not been resolved yet. Lazy values are only\r\n\t * resolved once. `getValue` will re-throw exceptions that are hit while resolving the value\r\n\t */\r\n\tgetValue(): T {\r\n\t\tif (!this._didRun) {\r\n\t\t\ttry {\r\n\t\t\t\tthis._value = this.executor();\r\n\t\t\t} catch (err) {\r\n\t\t\t\tthis._error = err;\r\n\t\t\t} finally {\r\n\t\t\t\tthis._didRun = true;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (this._error) {\r\n\t\t\tthrow this._error;\r\n\t\t}\r\n\t\treturn this._value!;\r\n\t}\r\n\r\n\t/**\r\n\t * Get the wrapped value without forcing evaluation.\r\n\t */\r\n\tget rawValue(): T | undefined { return this._value; }\r\n}\r\n","\r\nimport { Iterable } from 'vs/base/common/iterator';\r\n\r\n/**\r\n * Enables logging of potentially leaked disposables.\r\n *\r\n * A disposable is considered leaked if it is not disposed or not registered as the child of\r\n * another disposable. This tracking is very simple an only works for classes that either\r\n * extend Disposable or use a DisposableStore. This means there are a lot of false positives.\r\n */\r\nconst TRACK_DISPOSABLES = false;\r\nlet disposableTracker: IDisposableTracker | null = null;\r\n\r\nexport interface IDisposableTracker {\r\n\ttrackDisposable(x: IDisposable): void;\r\n\tmarkTracked(x: IDisposable): void;\r\n}\r\n\r\nif (TRACK_DISPOSABLES) {\r\n\tconst __is_disposable_tracked__ = '__is_disposable_tracked__';\r\n\tdisposableTracker = new class implements IDisposableTracker {\r\n\t\ttrackDisposable(x: IDisposable): void {\r\n\t\t\tconst stack = new Error('Potentially leaked disposable').stack!;\r\n\t\t\tsetTimeout(() => {\r\n\t\t\t\tif (!(x as any)[__is_disposable_tracked__]) {\r\n\t\t\t\t\tconsole.log(stack);\r\n\t\t\t\t}\r\n\t\t\t}, 3000);\r\n\t\t}\r\n\r\n\t\tmarkTracked(x: IDisposable): void {\r\n\t\t\tif (x && x !== Disposable.None) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\t(x as any)[__is_disposable_tracked__] = true;\r\n\t\t\t\t} catch {\r\n\t\t\t\t\t// noop\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t};\r\n}\r\n\r\nfunction markTracked(x: T): void {\r\n\tif (!disposableTracker) {\r\n\t\treturn;\r\n\t}\r\n\tdisposableTracker.markTracked(x);\r\n}\r\n\r\nexport function trackDisposable(x: T): T {\r\n\tif (!disposableTracker) {\r\n\t\treturn x;\r\n\t}\r\n\tdisposableTracker.trackDisposable(x);\r\n\treturn x;\r\n}\r\n\r\nexport class MultiDisposeError extends Error {\r\n\tconstructor(\r\n\t\tpublic readonly errors: any[]\r\n\t) {\r\n\t\tsuper(`Encounter errors while disposing of store. Errors: [${errors.join(', ')}]`);\r\n\t}\r\n}\r\n\r\nexport interface IDisposable {\r\n\tdispose(): void;\r\n}\r\n\r\nexport function isDisposable(thing: E): thing is E & IDisposable {\r\n\treturn typeof (thing).dispose === 'function' && (thing).dispose.length === 0;\r\n}\r\n\r\nexport function dispose(disposable: T): T;\r\nexport function dispose(disposable: T | undefined): T | undefined;\r\nexport function dispose = IterableIterator>(disposables: IterableIterator): A;\r\nexport function dispose(disposables: Array): Array;\r\nexport function dispose(disposables: ReadonlyArray): ReadonlyArray;\r\nexport function dispose(arg: T | IterableIterator | undefined): any {\r\n\tif (Iterable.is(arg)) {\r\n\t\tlet errors: any[] = [];\r\n\r\n\t\tfor (const d of arg) {\r\n\t\t\tif (d) {\r\n\t\t\t\tmarkTracked(d);\r\n\t\t\t\ttry {\r\n\t\t\t\t\td.dispose();\r\n\t\t\t\t} catch (e) {\r\n\t\t\t\t\terrors.push(e);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (errors.length === 1) {\r\n\t\t\tthrow errors[0];\r\n\t\t} else if (errors.length > 1) {\r\n\t\t\tthrow new MultiDisposeError(errors);\r\n\t\t}\r\n\r\n\t\treturn Array.isArray(arg) ? [] : arg;\r\n\t} else if (arg) {\r\n\t\tmarkTracked(arg);\r\n\t\targ.dispose();\r\n\t\treturn arg;\r\n\t}\r\n}\r\n\r\n\r\nexport function combinedDisposable(...disposables: IDisposable[]): IDisposable {\r\n\tdisposables.forEach(markTracked);\r\n\treturn toDisposable(() => dispose(disposables));\r\n}\r\n\r\nexport function toDisposable(fn: () => void): IDisposable {\r\n\tconst self = trackDisposable({\r\n\t\tdispose: () => {\r\n\t\t\tmarkTracked(self);\r\n\t\t\tfn();\r\n\t\t}\r\n\t});\r\n\treturn self;\r\n}\r\n\r\nexport class DisposableStore implements IDisposable {\r\n\r\n\tstatic DISABLE_DISPOSED_WARNING = false;\r\n\r\n\tprivate _toDispose = new Set();\r\n\tprivate _isDisposed = false;\r\n\r\n\t/**\r\n\t * Dispose of all registered disposables and mark this object as disposed.\r\n\t *\r\n\t * Any future disposables added to this object will be disposed of on `add`.\r\n\t */\r\n\tpublic dispose(): void {\r\n\t\tif (this._isDisposed) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tmarkTracked(this);\r\n\t\tthis._isDisposed = true;\r\n\t\tthis.clear();\r\n\t}\r\n\r\n\t/**\r\n\t * Dispose of all registered disposables but do not mark this object as disposed.\r\n\t */\r\n\tpublic clear(): void {\r\n\t\ttry {\r\n\t\t\tdispose(this._toDispose.values());\r\n\t\t} finally {\r\n\t\t\tthis._toDispose.clear();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic add(t: T): T {\r\n\t\tif (!t) {\r\n\t\t\treturn t;\r\n\t\t}\r\n\t\tif ((t as unknown as DisposableStore) === this) {\r\n\t\t\tthrow new Error('Cannot register a disposable on itself!');\r\n\t\t}\r\n\r\n\t\tmarkTracked(t);\r\n\t\tif (this._isDisposed) {\r\n\t\t\tif (!DisposableStore.DISABLE_DISPOSED_WARNING) {\r\n\t\t\t\tconsole.warn(new Error('Trying to add a disposable to a DisposableStore that has already been disposed of. The added object will be leaked!').stack);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tthis._toDispose.add(t);\r\n\t\t}\r\n\r\n\t\treturn t;\r\n\t}\r\n}\r\n\r\nexport abstract class Disposable implements IDisposable {\r\n\r\n\tstatic readonly None = Object.freeze({ dispose() { } });\r\n\r\n\tprivate readonly _store = new DisposableStore();\r\n\r\n\tconstructor() {\r\n\t\ttrackDisposable(this);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tmarkTracked(this);\r\n\r\n\t\tthis._store.dispose();\r\n\t}\r\n\r\n\tprotected _register(t: T): T {\r\n\t\tif ((t as unknown as Disposable) === this) {\r\n\t\t\tthrow new Error('Cannot register a disposable on itself!');\r\n\t\t}\r\n\t\treturn this._store.add(t);\r\n\t}\r\n}\r\n\r\n/**\r\n * Manages the lifecycle of a disposable value that may be changed.\r\n *\r\n * This ensures that when the disposable value is changed, the previously held disposable is disposed of. You can\r\n * also register a `MutableDisposable` on a `Disposable` to ensure it is automatically cleaned up.\r\n */\r\nexport class MutableDisposable implements IDisposable {\r\n\tprivate _value?: T;\r\n\tprivate _isDisposed = false;\r\n\r\n\tconstructor() {\r\n\t\ttrackDisposable(this);\r\n\t}\r\n\r\n\tget value(): T | undefined {\r\n\t\treturn this._isDisposed ? undefined : this._value;\r\n\t}\r\n\r\n\tset value(value: T | undefined) {\r\n\t\tif (this._isDisposed || value === this._value) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this._value) {\r\n\t\t\tthis._value.dispose();\r\n\t\t}\r\n\t\tif (value) {\r\n\t\t\tmarkTracked(value);\r\n\t\t}\r\n\t\tthis._value = value;\r\n\t}\r\n\r\n\tclear() {\r\n\t\tthis.value = undefined;\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._isDisposed = true;\r\n\t\tmarkTracked(this);\r\n\t\tif (this._value) {\r\n\t\t\tthis._value.dispose();\r\n\t\t}\r\n\t\tthis._value = undefined;\r\n\t}\r\n}\r\n\r\nexport interface IReference extends IDisposable {\r\n\treadonly object: T;\r\n}\r\n\r\nexport class ImmortalReference implements IReference {\r\n\tconstructor(public object: T) { }\r\n\tdispose(): void { /* noop */ }\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nclass Node {\r\n\r\n\tstatic readonly Undefined = new Node(undefined);\r\n\r\n\telement: E;\r\n\tnext: Node;\r\n\tprev: Node;\r\n\r\n\tconstructor(element: E) {\r\n\t\tthis.element = element;\r\n\t\tthis.next = Node.Undefined;\r\n\t\tthis.prev = Node.Undefined;\r\n\t}\r\n}\r\n\r\nexport class LinkedList {\r\n\r\n\tprivate _first: Node = Node.Undefined;\r\n\tprivate _last: Node = Node.Undefined;\r\n\tprivate _size: number = 0;\r\n\r\n\tget size(): number {\r\n\t\treturn this._size;\r\n\t}\r\n\r\n\tisEmpty(): boolean {\r\n\t\treturn this._first === Node.Undefined;\r\n\t}\r\n\r\n\tclear(): void {\r\n\t\tthis._first = Node.Undefined;\r\n\t\tthis._last = Node.Undefined;\r\n\t\tthis._size = 0;\r\n\t}\r\n\r\n\tunshift(element: E): () => void {\r\n\t\treturn this._insert(element, false);\r\n\t}\r\n\r\n\tpush(element: E): () => void {\r\n\t\treturn this._insert(element, true);\r\n\t}\r\n\r\n\tprivate _insert(element: E, atTheEnd: boolean): () => void {\r\n\t\tconst newNode = new Node(element);\r\n\t\tif (this._first === Node.Undefined) {\r\n\t\t\tthis._first = newNode;\r\n\t\t\tthis._last = newNode;\r\n\r\n\t\t} else if (atTheEnd) {\r\n\t\t\t// push\r\n\t\t\tconst oldLast = this._last!;\r\n\t\t\tthis._last = newNode;\r\n\t\t\tnewNode.prev = oldLast;\r\n\t\t\toldLast.next = newNode;\r\n\r\n\t\t} else {\r\n\t\t\t// unshift\r\n\t\t\tconst oldFirst = this._first;\r\n\t\t\tthis._first = newNode;\r\n\t\t\tnewNode.next = oldFirst;\r\n\t\t\toldFirst.prev = newNode;\r\n\t\t}\r\n\t\tthis._size += 1;\r\n\r\n\t\tlet didRemove = false;\r\n\t\treturn () => {\r\n\t\t\tif (!didRemove) {\r\n\t\t\t\tdidRemove = true;\r\n\t\t\t\tthis._remove(newNode);\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\tshift(): E | undefined {\r\n\t\tif (this._first === Node.Undefined) {\r\n\t\t\treturn undefined;\r\n\t\t} else {\r\n\t\t\tconst res = this._first.element;\r\n\t\t\tthis._remove(this._first);\r\n\t\t\treturn res;\r\n\t\t}\r\n\t}\r\n\r\n\tpop(): E | undefined {\r\n\t\tif (this._last === Node.Undefined) {\r\n\t\t\treturn undefined;\r\n\t\t} else {\r\n\t\t\tconst res = this._last.element;\r\n\t\t\tthis._remove(this._last);\r\n\t\t\treturn res;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _remove(node: Node): void {\r\n\t\tif (node.prev !== Node.Undefined && node.next !== Node.Undefined) {\r\n\t\t\t// middle\r\n\t\t\tconst anchor = node.prev;\r\n\t\t\tanchor.next = node.next;\r\n\t\t\tnode.next.prev = anchor;\r\n\r\n\t\t} else if (node.prev === Node.Undefined && node.next === Node.Undefined) {\r\n\t\t\t// only node\r\n\t\t\tthis._first = Node.Undefined;\r\n\t\t\tthis._last = Node.Undefined;\r\n\r\n\t\t} else if (node.next === Node.Undefined) {\r\n\t\t\t// last\r\n\t\t\tthis._last = this._last!.prev!;\r\n\t\t\tthis._last.next = Node.Undefined;\r\n\r\n\t\t} else if (node.prev === Node.Undefined) {\r\n\t\t\t// first\r\n\t\t\tthis._first = this._first!.next!;\r\n\t\t\tthis._first.prev = Node.Undefined;\r\n\t\t}\r\n\r\n\t\t// done\r\n\t\tthis._size -= 1;\r\n\t}\r\n\r\n\t*[Symbol.iterator](): Iterator {\r\n\t\tlet node = this._first;\r\n\t\twhile (node !== Node.Undefined) {\r\n\t\t\tyield node.element;\r\n\t\t\tnode = node.next;\r\n\t\t}\r\n\t}\r\n}\r\n","/**\n * marked - a markdown parser\n * Copyright (c) 2011-2020, Christopher Jeffrey. (MIT Licensed)\n * https://github.com/markedjs/marked\n */\n\n/**\n * DO NOT EDIT THIS FILE\n * The code in this file is generated from files in ./src/\n */\n\n(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n typeof define === 'function' && define.amd ? define(\"vs/base/common/marked/marked\", factory) :\n (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.marked = factory());\n}(this, (function () { 'use strict';\n\n function _defineProperties(target, props) {\n for (var i = 0; i < props.length; i++) {\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n if (\"value\" in descriptor) descriptor.writable = true;\n Object.defineProperty(target, descriptor.key, descriptor);\n }\n }\n\n function _createClass(Constructor, protoProps, staticProps) {\n if (protoProps) _defineProperties(Constructor.prototype, protoProps);\n if (staticProps) _defineProperties(Constructor, staticProps);\n return Constructor;\n }\n\n function _unsupportedIterableToArray(o, minLen) {\n if (!o) return;\n if (typeof o === \"string\") return _arrayLikeToArray(o, minLen);\n var n = Object.prototype.toString.call(o).slice(8, -1);\n if (n === \"Object\" && o.constructor) n = o.constructor.name;\n if (n === \"Map\" || n === \"Set\") return Array.from(o);\n if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);\n }\n\n function _arrayLikeToArray(arr, len) {\n if (len == null || len > arr.length) len = arr.length;\n\n for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];\n\n return arr2;\n }\n\n function _createForOfIteratorHelperLoose(o, allowArrayLike) {\n var it;\n\n if (typeof Symbol === \"undefined\" || o[Symbol.iterator] == null) {\n if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === \"number\") {\n if (it) o = it;\n var i = 0;\n return function () {\n if (i >= o.length) return {\n done: true\n };\n return {\n done: false,\n value: o[i++]\n };\n };\n }\n\n throw new TypeError(\"Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n }\n\n it = o[Symbol.iterator]();\n return it.next.bind(it);\n }\n\n function createCommonjsModule(fn, module) {\n \treturn module = { exports: {} }, fn(module, module.exports), module.exports;\n }\n\n var defaults = createCommonjsModule(function (module) {\n function getDefaults() {\n return {\n baseUrl: null,\n breaks: false,\n gfm: true,\n headerIds: true,\n headerPrefix: '',\n highlight: null,\n langPrefix: 'language-',\n mangle: true,\n pedantic: false,\n renderer: null,\n sanitize: false,\n sanitizer: null,\n silent: false,\n smartLists: false,\n smartypants: false,\n tokenizer: null,\n walkTokens: null,\n xhtml: false\n };\n }\n\n function changeDefaults(newDefaults) {\n module.exports.defaults = newDefaults;\n }\n\n module.exports = {\n defaults: getDefaults(),\n getDefaults: getDefaults,\n changeDefaults: changeDefaults\n };\n });\n var defaults_1 = defaults.defaults;\n var defaults_2 = defaults.getDefaults;\n var defaults_3 = defaults.changeDefaults;\n\n /**\n * Helpers\n */\n var escapeTest = /[&<>\"']/;\n var escapeReplace = /[&<>\"']/g;\n var escapeTestNoEncode = /[<>\"']|&(?!#?\\w+;)/;\n var escapeReplaceNoEncode = /[<>\"']|&(?!#?\\w+;)/g;\n var escapeReplacements = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": '''\n };\n\n var getEscapeReplacement = function getEscapeReplacement(ch) {\n return escapeReplacements[ch];\n };\n\n function escape(html, encode) {\n if (encode) {\n if (escapeTest.test(html)) {\n return html.replace(escapeReplace, getEscapeReplacement);\n }\n } else {\n if (escapeTestNoEncode.test(html)) {\n return html.replace(escapeReplaceNoEncode, getEscapeReplacement);\n }\n }\n\n return html;\n }\n\n var unescapeTest = /&(#(?:\\d+)|(?:#x[0-9A-Fa-f]+)|(?:\\w+));?/ig;\n\n function unescape(html) {\n // explicitly match decimal, hex, and named HTML entities\n return html.replace(unescapeTest, function (_, n) {\n n = n.toLowerCase();\n if (n === 'colon') return ':';\n\n if (n.charAt(0) === '#') {\n return n.charAt(1) === 'x' ? String.fromCharCode(parseInt(n.substring(2), 16)) : String.fromCharCode(+n.substring(1));\n }\n\n return '';\n });\n }\n\n var caret = /(^|[^\\[])\\^/g;\n\n function edit(regex, opt) {\n regex = regex.source || regex;\n opt = opt || '';\n var obj = {\n replace: function replace(name, val) {\n val = val.source || val;\n val = val.replace(caret, '$1');\n regex = regex.replace(name, val);\n return obj;\n },\n getRegex: function getRegex() {\n return new RegExp(regex, opt);\n }\n };\n return obj;\n }\n\n var nonWordAndColonTest = /[^\\w:]/g;\n var originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;\n\n function cleanUrl(sanitize, base, href) {\n if (sanitize) {\n var prot;\n\n try {\n prot = decodeURIComponent(unescape(href)).replace(nonWordAndColonTest, '').toLowerCase();\n } catch (e) {\n return null;\n }\n\n if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0 || prot.indexOf('data:') === 0) {\n return null;\n }\n }\n\n if (base && !originIndependentUrl.test(href)) {\n href = resolveUrl(base, href);\n }\n\n try {\n href = encodeURI(href).replace(/%25/g, '%');\n } catch (e) {\n return null;\n }\n\n return href;\n }\n\n var baseUrls = {};\n var justDomain = /^[^:]+:\\/*[^/]*$/;\n var protocol = /^([^:]+:)[\\s\\S]*$/;\n var domain = /^([^:]+:\\/*[^/]*)[\\s\\S]*$/;\n\n function resolveUrl(base, href) {\n if (!baseUrls[' ' + base]) {\n // we can ignore everything in base after the last slash of its path component,\n // but we might need to add _that_\n // https://tools.ietf.org/html/rfc3986#section-3\n if (justDomain.test(base)) {\n baseUrls[' ' + base] = base + '/';\n } else {\n baseUrls[' ' + base] = rtrim(base, '/', true);\n }\n }\n\n base = baseUrls[' ' + base];\n var relativeBase = base.indexOf(':') === -1;\n\n if (href.substring(0, 2) === '//') {\n if (relativeBase) {\n return href;\n }\n\n return base.replace(protocol, '$1') + href;\n } else if (href.charAt(0) === '/') {\n if (relativeBase) {\n return href;\n }\n\n return base.replace(domain, '$1') + href;\n } else {\n return base + href;\n }\n }\n\n var noopTest = {\n exec: function noopTest() {}\n };\n\n function merge(obj) {\n var i = 1,\n target,\n key;\n\n for (; i < arguments.length; i++) {\n target = arguments[i];\n\n for (key in target) {\n if (Object.prototype.hasOwnProperty.call(target, key)) {\n obj[key] = target[key];\n }\n }\n }\n\n return obj;\n }\n\n function splitCells(tableRow, count) {\n // ensure that every cell-delimiting pipe has a space\n // before it to distinguish it from an escaped pipe\n var row = tableRow.replace(/\\|/g, function (match, offset, str) {\n var escaped = false,\n curr = offset;\n\n while (--curr >= 0 && str[curr] === '\\\\') {\n escaped = !escaped;\n }\n\n if (escaped) {\n // odd number of slashes means | is escaped\n // so we leave it alone\n return '|';\n } else {\n // add space before unescaped |\n return ' |';\n }\n }),\n cells = row.split(/ \\|/);\n var i = 0;\n\n if (cells.length > count) {\n cells.splice(count);\n } else {\n while (cells.length < count) {\n cells.push('');\n }\n }\n\n for (; i < cells.length; i++) {\n // leading or trailing whitespace is ignored per the gfm spec\n cells[i] = cells[i].trim().replace(/\\\\\\|/g, '|');\n }\n\n return cells;\n } // Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').\n // /c*$/ is vulnerable to REDOS.\n // invert: Remove suffix of non-c chars instead. Default falsey.\n\n\n function rtrim(str, c, invert) {\n var l = str.length;\n\n if (l === 0) {\n return '';\n } // Length of suffix matching the invert condition.\n\n\n var suffLen = 0; // Step left until we fail to match the invert condition.\n\n while (suffLen < l) {\n var currChar = str.charAt(l - suffLen - 1);\n\n if (currChar === c && !invert) {\n suffLen++;\n } else if (currChar !== c && invert) {\n suffLen++;\n } else {\n break;\n }\n }\n\n return str.substr(0, l - suffLen);\n }\n\n function findClosingBracket(str, b) {\n if (str.indexOf(b[1]) === -1) {\n return -1;\n }\n\n var l = str.length;\n var level = 0,\n i = 0;\n\n for (; i < l; i++) {\n if (str[i] === '\\\\') {\n i++;\n } else if (str[i] === b[0]) {\n level++;\n } else if (str[i] === b[1]) {\n level--;\n\n if (level < 0) {\n return i;\n }\n }\n }\n\n return -1;\n }\n\n function checkSanitizeDeprecation(opt) {\n if (opt && opt.sanitize && !opt.silent) {\n console.warn('marked(): sanitize and sanitizer parameters are deprecated since version 0.7.0, should not be used and will be removed in the future. Read more here: https://marked.js.org/#/USING_ADVANCED.md#options');\n }\n } // copied from https://stackoverflow.com/a/5450113/806777\n\n\n function repeatString(pattern, count) {\n if (count < 1) {\n return '';\n }\n\n var result = '';\n\n while (count > 1) {\n if (count & 1) {\n result += pattern;\n }\n\n count >>= 1;\n pattern += pattern;\n }\n\n return result + pattern;\n }\n\n var helpers = {\n escape: escape,\n unescape: unescape,\n edit: edit,\n cleanUrl: cleanUrl,\n resolveUrl: resolveUrl,\n noopTest: noopTest,\n merge: merge,\n splitCells: splitCells,\n rtrim: rtrim,\n findClosingBracket: findClosingBracket,\n checkSanitizeDeprecation: checkSanitizeDeprecation,\n repeatString: repeatString\n };\n\n var defaults$1 = defaults.defaults;\n var rtrim$1 = helpers.rtrim,\n splitCells$1 = helpers.splitCells,\n _escape = helpers.escape,\n findClosingBracket$1 = helpers.findClosingBracket;\n\n function outputLink(cap, link, raw) {\n var href = link.href;\n var title = link.title ? _escape(link.title) : null;\n var text = cap[1].replace(/\\\\([\\[\\]])/g, '$1');\n\n if (cap[0].charAt(0) !== '!') {\n return {\n type: 'link',\n raw: raw,\n href: href,\n title: title,\n text: text\n };\n } else {\n return {\n type: 'image',\n raw: raw,\n href: href,\n title: title,\n text: _escape(text)\n };\n }\n }\n\n function indentCodeCompensation(raw, text) {\n var matchIndentToCode = raw.match(/^(\\s+)(?:```)/);\n\n if (matchIndentToCode === null) {\n return text;\n }\n\n var indentToCode = matchIndentToCode[1];\n return text.split('\\n').map(function (node) {\n var matchIndentInNode = node.match(/^\\s+/);\n\n if (matchIndentInNode === null) {\n return node;\n }\n\n var indentInNode = matchIndentInNode[0];\n\n if (indentInNode.length >= indentToCode.length) {\n return node.slice(indentToCode.length);\n }\n\n return node;\n }).join('\\n');\n }\n /**\n * Tokenizer\n */\n\n\n var Tokenizer_1 = /*#__PURE__*/function () {\n function Tokenizer(options) {\n this.options = options || defaults$1;\n }\n\n var _proto = Tokenizer.prototype;\n\n _proto.space = function space(src) {\n var cap = this.rules.block.newline.exec(src);\n\n if (cap) {\n if (cap[0].length > 1) {\n return {\n type: 'space',\n raw: cap[0]\n };\n }\n\n return {\n raw: '\\n'\n };\n }\n };\n\n _proto.code = function code(src, tokens) {\n var cap = this.rules.block.code.exec(src);\n\n if (cap) {\n var lastToken = tokens[tokens.length - 1]; // An indented code block cannot interrupt a paragraph.\n\n if (lastToken && lastToken.type === 'paragraph') {\n return {\n raw: cap[0],\n text: cap[0].trimRight()\n };\n }\n\n var text = cap[0].replace(/^ {4}/gm, '');\n return {\n type: 'code',\n raw: cap[0],\n codeBlockStyle: 'indented',\n text: !this.options.pedantic ? rtrim$1(text, '\\n') : text\n };\n }\n };\n\n _proto.fences = function fences(src) {\n var cap = this.rules.block.fences.exec(src);\n\n if (cap) {\n var raw = cap[0];\n var text = indentCodeCompensation(raw, cap[3] || '');\n return {\n type: 'code',\n raw: raw,\n lang: cap[2] ? cap[2].trim() : cap[2],\n text: text\n };\n }\n };\n\n _proto.heading = function heading(src) {\n var cap = this.rules.block.heading.exec(src);\n\n if (cap) {\n return {\n type: 'heading',\n raw: cap[0],\n depth: cap[1].length,\n text: cap[2]\n };\n }\n };\n\n _proto.nptable = function nptable(src) {\n var cap = this.rules.block.nptable.exec(src);\n\n if (cap) {\n var item = {\n type: 'table',\n header: splitCells$1(cap[1].replace(/^ *| *\\| *$/g, '')),\n align: cap[2].replace(/^ *|\\| *$/g, '').split(/ *\\| */),\n cells: cap[3] ? cap[3].replace(/\\n$/, '').split('\\n') : [],\n raw: cap[0]\n };\n\n if (item.header.length === item.align.length) {\n var l = item.align.length;\n var i;\n\n for (i = 0; i < l; i++) {\n if (/^ *-+: *$/.test(item.align[i])) {\n item.align[i] = 'right';\n } else if (/^ *:-+: *$/.test(item.align[i])) {\n item.align[i] = 'center';\n } else if (/^ *:-+ *$/.test(item.align[i])) {\n item.align[i] = 'left';\n } else {\n item.align[i] = null;\n }\n }\n\n l = item.cells.length;\n\n for (i = 0; i < l; i++) {\n item.cells[i] = splitCells$1(item.cells[i], item.header.length);\n }\n\n return item;\n }\n }\n };\n\n _proto.hr = function hr(src) {\n var cap = this.rules.block.hr.exec(src);\n\n if (cap) {\n return {\n type: 'hr',\n raw: cap[0]\n };\n }\n };\n\n _proto.blockquote = function blockquote(src) {\n var cap = this.rules.block.blockquote.exec(src);\n\n if (cap) {\n var text = cap[0].replace(/^ *> ?/gm, '');\n return {\n type: 'blockquote',\n raw: cap[0],\n text: text\n };\n }\n };\n\n _proto.list = function list(src) {\n var cap = this.rules.block.list.exec(src);\n\n if (cap) {\n var raw = cap[0];\n var bull = cap[2];\n var isordered = bull.length > 1;\n var isparen = bull[bull.length - 1] === ')';\n var list = {\n type: 'list',\n raw: raw,\n ordered: isordered,\n start: isordered ? +bull.slice(0, -1) : '',\n loose: false,\n items: []\n }; // Get each top-level item.\n\n var itemMatch = cap[0].match(this.rules.block.item);\n var next = false,\n item,\n space,\n b,\n addBack,\n loose,\n istask,\n ischecked;\n var l = itemMatch.length;\n\n for (var i = 0; i < l; i++) {\n item = itemMatch[i];\n raw = item; // Remove the list item's bullet\n // so it is seen as the next token.\n\n space = item.length;\n item = item.replace(/^ *([*+-]|\\d+[.)]) ?/, ''); // Outdent whatever the\n // list item contains. Hacky.\n\n if (~item.indexOf('\\n ')) {\n space -= item.length;\n item = !this.options.pedantic ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') : item.replace(/^ {1,4}/gm, '');\n } // Determine whether the next list item belongs here.\n // Backpedal if it does not belong in this list.\n\n\n if (i !== l - 1) {\n b = this.rules.block.bullet.exec(itemMatch[i + 1])[0];\n\n if (isordered ? b.length === 1 || !isparen && b[b.length - 1] === ')' : b.length > 1 || this.options.smartLists && b !== bull) {\n addBack = itemMatch.slice(i + 1).join('\\n');\n list.raw = list.raw.substring(0, list.raw.length - addBack.length);\n i = l - 1;\n }\n } // Determine whether item is loose or not.\n // Use: /(^|\\n)(?! )[^\\n]+\\n\\n(?!\\s*$)/\n // for discount behavior.\n\n\n loose = next || /\\n\\n(?!\\s*$)/.test(item);\n\n if (i !== l - 1) {\n next = item.charAt(item.length - 1) === '\\n';\n if (!loose) loose = next;\n }\n\n if (loose) {\n list.loose = true;\n } // Check for task list items\n\n\n istask = /^\\[[ xX]\\] /.test(item);\n ischecked = undefined;\n\n if (istask) {\n ischecked = item[1] !== ' ';\n item = item.replace(/^\\[[ xX]\\] +/, '');\n }\n\n list.items.push({\n type: 'list_item',\n raw: raw,\n task: istask,\n checked: ischecked,\n loose: loose,\n text: item\n });\n }\n\n return list;\n }\n };\n\n _proto.html = function html(src) {\n var cap = this.rules.block.html.exec(src);\n\n if (cap) {\n return {\n type: this.options.sanitize ? 'paragraph' : 'html',\n raw: cap[0],\n pre: !this.options.sanitizer && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),\n text: this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0]\n };\n }\n };\n\n _proto.def = function def(src) {\n var cap = this.rules.block.def.exec(src);\n\n if (cap) {\n if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1);\n var tag = cap[1].toLowerCase().replace(/\\s+/g, ' ');\n return {\n tag: tag,\n raw: cap[0],\n href: cap[2],\n title: cap[3]\n };\n }\n };\n\n _proto.table = function table(src) {\n var cap = this.rules.block.table.exec(src);\n\n if (cap) {\n var item = {\n type: 'table',\n header: splitCells$1(cap[1].replace(/^ *| *\\| *$/g, '')),\n align: cap[2].replace(/^ *|\\| *$/g, '').split(/ *\\| */),\n cells: cap[3] ? cap[3].replace(/\\n$/, '').split('\\n') : []\n };\n\n if (item.header.length === item.align.length) {\n item.raw = cap[0];\n var l = item.align.length;\n var i;\n\n for (i = 0; i < l; i++) {\n if (/^ *-+: *$/.test(item.align[i])) {\n item.align[i] = 'right';\n } else if (/^ *:-+: *$/.test(item.align[i])) {\n item.align[i] = 'center';\n } else if (/^ *:-+ *$/.test(item.align[i])) {\n item.align[i] = 'left';\n } else {\n item.align[i] = null;\n }\n }\n\n l = item.cells.length;\n\n for (i = 0; i < l; i++) {\n item.cells[i] = splitCells$1(item.cells[i].replace(/^ *\\| *| *\\| *$/g, ''), item.header.length);\n }\n\n return item;\n }\n }\n };\n\n _proto.lheading = function lheading(src) {\n var cap = this.rules.block.lheading.exec(src);\n\n if (cap) {\n return {\n type: 'heading',\n raw: cap[0],\n depth: cap[2].charAt(0) === '=' ? 1 : 2,\n text: cap[1]\n };\n }\n };\n\n _proto.paragraph = function paragraph(src) {\n var cap = this.rules.block.paragraph.exec(src);\n\n if (cap) {\n return {\n type: 'paragraph',\n raw: cap[0],\n text: cap[1].charAt(cap[1].length - 1) === '\\n' ? cap[1].slice(0, -1) : cap[1]\n };\n }\n };\n\n _proto.text = function text(src, tokens) {\n var cap = this.rules.block.text.exec(src);\n\n if (cap) {\n var lastToken = tokens[tokens.length - 1];\n\n if (lastToken && lastToken.type === 'text') {\n return {\n raw: cap[0],\n text: cap[0]\n };\n }\n\n return {\n type: 'text',\n raw: cap[0],\n text: cap[0]\n };\n }\n };\n\n _proto.escape = function escape(src) {\n var cap = this.rules.inline.escape.exec(src);\n\n if (cap) {\n return {\n type: 'escape',\n raw: cap[0],\n text: _escape(cap[1])\n };\n }\n };\n\n _proto.tag = function tag(src, inLink, inRawBlock) {\n var cap = this.rules.inline.tag.exec(src);\n\n if (cap) {\n if (!inLink && /^/i.test(cap[0])) {\n inLink = false;\n }\n\n if (!inRawBlock && /^<(pre|code|kbd|script)(\\s|>)/i.test(cap[0])) {\n inRawBlock = true;\n } else if (inRawBlock && /^<\\/(pre|code|kbd|script)(\\s|>)/i.test(cap[0])) {\n inRawBlock = false;\n }\n\n return {\n type: this.options.sanitize ? 'text' : 'html',\n raw: cap[0],\n inLink: inLink,\n inRawBlock: inRawBlock,\n text: this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0]\n };\n }\n };\n\n _proto.link = function link(src) {\n var cap = this.rules.inline.link.exec(src);\n\n if (cap) {\n var lastParenIndex = findClosingBracket$1(cap[2], '()');\n\n if (lastParenIndex > -1) {\n var start = cap[0].indexOf('!') === 0 ? 5 : 4;\n var linkLen = start + cap[1].length + lastParenIndex;\n cap[2] = cap[2].substring(0, lastParenIndex);\n cap[0] = cap[0].substring(0, linkLen).trim();\n cap[3] = '';\n }\n\n var href = cap[2];\n var title = '';\n\n if (this.options.pedantic) {\n var link = /^([^'\"]*[^\\s])\\s+(['\"])(.*)\\2/.exec(href);\n\n if (link) {\n href = link[1];\n title = link[3];\n } else {\n title = '';\n }\n } else {\n title = cap[3] ? cap[3].slice(1, -1) : '';\n }\n\n href = href.trim().replace(/^<([\\s\\S]*)>$/, '$1');\n var token = outputLink(cap, {\n href: href ? href.replace(this.rules.inline._escapes, '$1') : href,\n title: title ? title.replace(this.rules.inline._escapes, '$1') : title\n }, cap[0]);\n return token;\n }\n };\n\n _proto.reflink = function reflink(src, links) {\n var cap;\n\n if ((cap = this.rules.inline.reflink.exec(src)) || (cap = this.rules.inline.nolink.exec(src))) {\n var link = (cap[2] || cap[1]).replace(/\\s+/g, ' ');\n link = links[link.toLowerCase()];\n\n if (!link || !link.href) {\n var text = cap[0].charAt(0);\n return {\n type: 'text',\n raw: text,\n text: text\n };\n }\n\n var token = outputLink(cap, link, cap[0]);\n return token;\n }\n };\n\n _proto.strong = function strong(src, maskedSrc, prevChar) {\n if (prevChar === void 0) {\n prevChar = '';\n }\n\n var match = this.rules.inline.strong.start.exec(src);\n\n if (match && (!match[1] || match[1] && (prevChar === '' || this.rules.inline.punctuation.exec(prevChar)))) {\n maskedSrc = maskedSrc.slice(-1 * src.length);\n var endReg = match[0] === '**' ? this.rules.inline.strong.endAst : this.rules.inline.strong.endUnd;\n endReg.lastIndex = 0;\n var cap;\n\n while ((match = endReg.exec(maskedSrc)) != null) {\n cap = this.rules.inline.strong.middle.exec(maskedSrc.slice(0, match.index + 3));\n\n if (cap) {\n return {\n type: 'strong',\n raw: src.slice(0, cap[0].length),\n text: src.slice(2, cap[0].length - 2)\n };\n }\n }\n }\n };\n\n _proto.em = function em(src, maskedSrc, prevChar) {\n if (prevChar === void 0) {\n prevChar = '';\n }\n\n var match = this.rules.inline.em.start.exec(src);\n\n if (match && (!match[1] || match[1] && (prevChar === '' || this.rules.inline.punctuation.exec(prevChar)))) {\n maskedSrc = maskedSrc.slice(-1 * src.length);\n var endReg = match[0] === '*' ? this.rules.inline.em.endAst : this.rules.inline.em.endUnd;\n endReg.lastIndex = 0;\n var cap;\n\n while ((match = endReg.exec(maskedSrc)) != null) {\n cap = this.rules.inline.em.middle.exec(maskedSrc.slice(0, match.index + 2));\n\n if (cap) {\n return {\n type: 'em',\n raw: src.slice(0, cap[0].length),\n text: src.slice(1, cap[0].length - 1)\n };\n }\n }\n }\n };\n\n _proto.codespan = function codespan(src) {\n var cap = this.rules.inline.code.exec(src);\n\n if (cap) {\n var text = cap[2].replace(/\\n/g, ' ');\n var hasNonSpaceChars = /[^ ]/.test(text);\n var hasSpaceCharsOnBothEnds = text.startsWith(' ') && text.endsWith(' ');\n\n if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {\n text = text.substring(1, text.length - 1);\n }\n\n text = _escape(text, true);\n return {\n type: 'codespan',\n raw: cap[0],\n text: text\n };\n }\n };\n\n _proto.br = function br(src) {\n var cap = this.rules.inline.br.exec(src);\n\n if (cap) {\n return {\n type: 'br',\n raw: cap[0]\n };\n }\n };\n\n _proto.del = function del(src) {\n var cap = this.rules.inline.del.exec(src);\n\n if (cap) {\n return {\n type: 'del',\n raw: cap[0],\n text: cap[1]\n };\n }\n };\n\n _proto.autolink = function autolink(src, mangle) {\n var cap = this.rules.inline.autolink.exec(src);\n\n if (cap) {\n var text, href;\n\n if (cap[2] === '@') {\n text = _escape(this.options.mangle ? mangle(cap[1]) : cap[1]);\n href = 'mailto:' + text;\n } else {\n text = _escape(cap[1]);\n href = text;\n }\n\n return {\n type: 'link',\n raw: cap[0],\n text: text,\n href: href,\n tokens: [{\n type: 'text',\n raw: text,\n text: text\n }]\n };\n }\n };\n\n _proto.url = function url(src, mangle) {\n var cap;\n\n if (cap = this.rules.inline.url.exec(src)) {\n var text, href;\n\n if (cap[2] === '@') {\n text = _escape(this.options.mangle ? mangle(cap[0]) : cap[0]);\n href = 'mailto:' + text;\n } else {\n // do extended autolink path validation\n var prevCapZero;\n\n do {\n prevCapZero = cap[0];\n cap[0] = this.rules.inline._backpedal.exec(cap[0])[0];\n } while (prevCapZero !== cap[0]);\n\n text = _escape(cap[0]);\n\n if (cap[1] === 'www.') {\n href = 'http://' + text;\n } else {\n href = text;\n }\n }\n\n return {\n type: 'link',\n raw: cap[0],\n text: text,\n href: href,\n tokens: [{\n type: 'text',\n raw: text,\n text: text\n }]\n };\n }\n };\n\n _proto.inlineText = function inlineText(src, inRawBlock, smartypants) {\n var cap = this.rules.inline.text.exec(src);\n\n if (cap) {\n var text;\n\n if (inRawBlock) {\n text = this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0];\n } else {\n text = _escape(this.options.smartypants ? smartypants(cap[0]) : cap[0]);\n }\n\n return {\n type: 'text',\n raw: cap[0],\n text: text\n };\n }\n };\n\n return Tokenizer;\n }();\n\n var noopTest$1 = helpers.noopTest,\n edit$1 = helpers.edit,\n merge$1 = helpers.merge;\n /**\n * Block-Level Grammar\n */\n\n var block = {\n newline: /^\\n+/,\n code: /^( {4}[^\\n]+\\n*)+/,\n fences: /^ {0,3}(`{3,}(?=[^`\\n]*\\n)|~{3,})([^\\n]*)\\n(?:|([\\s\\S]*?)\\n)(?: {0,3}\\1[~`]* *(?:\\n+|$)|$)/,\n hr: /^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)/,\n heading: /^ {0,3}(#{1,6}) +([^\\n]*?)(?: +#+)? *(?:\\n+|$)/,\n blockquote: /^( {0,3}> ?(paragraph|[^\\n]*)(?:\\n|$))+/,\n list: /^( {0,3})(bull) [\\s\\S]+?(?:hr|def|\\n{2,}(?! )(?!\\1bull )\\n*|\\s*$)/,\n html: '^ {0,3}(?:' // optional indentation\n + '<(script|pre|style)[\\\\s>][\\\\s\\\\S]*?(?:[^\\\\n]*\\\\n+|$)' // (1)\n + '|comment[^\\\\n]*(\\\\n+|$)' // (2)\n + '|<\\\\?[\\\\s\\\\S]*?(?:\\\\?>\\\\n*|$)' // (3)\n + '|\\\\n*|$)' // (4)\n + '|\\\\n*|$)' // (5)\n + '|)[\\\\s\\\\S]*?(?:\\\\n{2,}|$)' // (6)\n + '|<(?!script|pre|style)([a-z][\\\\w-]*)(?:attribute)*? */?>(?=[ \\\\t]*(?:\\\\n|$))[\\\\s\\\\S]*?(?:\\\\n{2,}|$)' // (7) open tag\n + '|(?=[ \\\\t]*(?:\\\\n|$))[\\\\s\\\\S]*?(?:\\\\n{2,}|$)' // (7) closing tag\n + ')',\n def: /^ {0,3}\\[(label)\\]: *\\n? *]+)>?(?:(?: +\\n? *| *\\n *)(title))? *(?:\\n+|$)/,\n nptable: noopTest$1,\n table: noopTest$1,\n lheading: /^([^\\n]+)\\n {0,3}(=+|-+) *(?:\\n+|$)/,\n // regex template, placeholders will be replaced according to different paragraph\n // interruption rules of commonmark and the original markdown spec:\n _paragraph: /^([^\\n]+(?:\\n(?!hr|heading|lheading|blockquote|fences|list|html)[^\\n]+)*)/,\n text: /^[^\\n]+/\n };\n block._label = /(?!\\s*\\])(?:\\\\[\\[\\]]|[^\\[\\]])+/;\n block._title = /(?:\"(?:\\\\\"?|[^\"\\\\])*\"|'[^'\\n]*(?:\\n[^'\\n]+)*\\n?'|\\([^()]*\\))/;\n block.def = edit$1(block.def).replace('label', block._label).replace('title', block._title).getRegex();\n block.bullet = /(?:[*+-]|\\d{1,9}[.)])/;\n block.item = /^( *)(bull) ?[^\\n]*(?:\\n(?!\\1bull ?)[^\\n]*)*/;\n block.item = edit$1(block.item, 'gm').replace(/bull/g, block.bullet).getRegex();\n block.list = edit$1(block.list).replace(/bull/g, block.bullet).replace('hr', '\\\\n+(?=\\\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\\\* *){3,})(?:\\\\n+|$))').replace('def', '\\\\n+(?=' + block.def.source + ')').getRegex();\n block._tag = 'address|article|aside|base|basefont|blockquote|body|caption' + '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption' + '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe' + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option' + '|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr' + '|track|ul';\n block._comment = /|$)/;\n block.html = edit$1(block.html, 'i').replace('comment', block._comment).replace('tag', block._tag).replace('attribute', / +[a-zA-Z:_][\\w.:-]*(?: *= *\"[^\"\\n]*\"| *= *'[^'\\n]*'| *= *[^\\s\"'=<>`]+)?/).getRegex();\n block.paragraph = edit$1(block._paragraph).replace('hr', block.hr).replace('heading', ' {0,3}#{1,6} ').replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs\n .replace('blockquote', ' {0,3}>').replace('fences', ' {0,3}(?:`{3,}(?=[^`\\\\n]*\\\\n)|~{3,})[^\\\\n]*\\\\n').replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt\n .replace('html', ')|<(?:script|pre|style|!--)').replace('tag', block._tag) // pars can be interrupted by type (6) html blocks\n .getRegex();\n block.blockquote = edit$1(block.blockquote).replace('paragraph', block.paragraph).getRegex();\n /**\n * Normal Block Grammar\n */\n\n block.normal = merge$1({}, block);\n /**\n * GFM Block Grammar\n */\n\n block.gfm = merge$1({}, block.normal, {\n nptable: '^ *([^|\\\\n ].*\\\\|.*)\\\\n' // Header\n + ' {0,3}([-:]+ *\\\\|[-| :]*)' // Align\n + '(?:\\\\n((?:(?!\\\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\\\n|$))*)\\\\n*|$)',\n // Cells\n table: '^ *\\\\|(.+)\\\\n' // Header\n + ' {0,3}\\\\|?( *[-:]+[-| :]*)' // Align\n + '(?:\\\\n *((?:(?!\\\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\\\n|$))*)\\\\n*|$)' // Cells\n\n });\n block.gfm.nptable = edit$1(block.gfm.nptable).replace('hr', block.hr).replace('heading', ' {0,3}#{1,6} ').replace('blockquote', ' {0,3}>').replace('code', ' {4}[^\\\\n]').replace('fences', ' {0,3}(?:`{3,}(?=[^`\\\\n]*\\\\n)|~{3,})[^\\\\n]*\\\\n').replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt\n .replace('html', ')|<(?:script|pre|style|!--)').replace('tag', block._tag) // tables can be interrupted by type (6) html blocks\n .getRegex();\n block.gfm.table = edit$1(block.gfm.table).replace('hr', block.hr).replace('heading', ' {0,3}#{1,6} ').replace('blockquote', ' {0,3}>').replace('code', ' {4}[^\\\\n]').replace('fences', ' {0,3}(?:`{3,}(?=[^`\\\\n]*\\\\n)|~{3,})[^\\\\n]*\\\\n').replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt\n .replace('html', ')|<(?:script|pre|style|!--)').replace('tag', block._tag) // tables can be interrupted by type (6) html blocks\n .getRegex();\n /**\n * Pedantic grammar (original John Gruber's loose markdown specification)\n */\n\n block.pedantic = merge$1({}, block.normal, {\n html: edit$1('^ *(?:comment *(?:\\\\n|\\\\s*$)' + '|<(tag)[\\\\s\\\\S]+? *(?:\\\\n{2,}|\\\\s*$)' // closed tag\n + '|\\\\s]*)*?/?> *(?:\\\\n{2,}|\\\\s*$))').replace('comment', block._comment).replace(/tag/g, '(?!(?:' + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub' + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)' + '\\\\b)\\\\w+(?!:|[^\\\\w\\\\s@]*@)\\\\b').getRegex(),\n def: /^ *\\[([^\\]]+)\\]: *]+)>?(?: +([\"(][^\\n]+[\")]))? *(?:\\n+|$)/,\n heading: /^ *(#{1,6}) *([^\\n]+?) *(?:#+ *)?(?:\\n+|$)/,\n fences: noopTest$1,\n // fences not supported\n paragraph: edit$1(block.normal._paragraph).replace('hr', block.hr).replace('heading', ' *#{1,6} *[^\\n]').replace('lheading', block.lheading).replace('blockquote', ' {0,3}>').replace('|fences', '').replace('|list', '').replace('|html', '').getRegex()\n });\n /**\n * Inline-Level Grammar\n */\n\n var inline = {\n escape: /^\\\\([!\"#$%&'()*+,\\-./:;<=>?@\\[\\]\\\\^_`{|}~])/,\n autolink: /^<(scheme:[^\\s\\x00-\\x1f<>]*|email)>/,\n url: noopTest$1,\n tag: '^comment' + '|^' // self-closing tag\n + '|^<[a-zA-Z][\\\\w-]*(?:attribute)*?\\\\s*/?>' // open tag\n + '|^<\\\\?[\\\\s\\\\S]*?\\\\?>' // processing instruction, e.g. \n + '|^' // declaration, e.g. \n + '|^',\n // CDATA section\n link: /^!?\\[(label)\\]\\(\\s*(href)(?:\\s+(title))?\\s*\\)/,\n reflink: /^!?\\[(label)\\]\\[(?!\\s*\\])((?:\\\\[\\[\\]]?|[^\\[\\]\\\\])+)\\]/,\n nolink: /^!?\\[(?!\\s*\\])((?:\\[[^\\[\\]]*\\]|\\\\[\\[\\]]|[^\\[\\]])*)\\](?:\\[\\])?/,\n reflinkSearch: 'reflink|nolink(?!\\\\()',\n strong: {\n start: /^(?:(\\*\\*(?=[*punctuation]))|\\*\\*)(?![\\s])|__/,\n // (1) returns if starts w/ punctuation\n middle: /^\\*\\*(?:(?:(?!overlapSkip)(?:[^*]|\\\\\\*)|overlapSkip)|\\*(?:(?!overlapSkip)(?:[^*]|\\\\\\*)|overlapSkip)*?\\*)+?\\*\\*$|^__(?![\\s])((?:(?:(?!overlapSkip)(?:[^_]|\\\\_)|overlapSkip)|_(?:(?!overlapSkip)(?:[^_]|\\\\_)|overlapSkip)*?_)+?)__$/,\n endAst: /[^punctuation\\s]\\*\\*(?!\\*)|[punctuation]\\*\\*(?!\\*)(?:(?=[punctuation_\\s]|$))/,\n // last char can't be punct, or final * must also be followed by punct (or endline)\n endUnd: /[^\\s]__(?!_)(?:(?=[punctuation*\\s])|$)/ // last char can't be a space, and final _ must preceed punct or \\s (or endline)\n\n },\n em: {\n start: /^(?:(\\*(?=[punctuation]))|\\*)(?![*\\s])|_/,\n // (1) returns if starts w/ punctuation\n middle: /^\\*(?:(?:(?!overlapSkip)(?:[^*]|\\\\\\*)|overlapSkip)|\\*(?:(?!overlapSkip)(?:[^*]|\\\\\\*)|overlapSkip)*?\\*)+?\\*$|^_(?![_\\s])(?:(?:(?!overlapSkip)(?:[^_]|\\\\_)|overlapSkip)|_(?:(?!overlapSkip)(?:[^_]|\\\\_)|overlapSkip)*?_)+?_$/,\n endAst: /[^punctuation\\s]\\*(?!\\*)|[punctuation]\\*(?!\\*)(?:(?=[punctuation_\\s]|$))/,\n // last char can't be punct, or final * must also be followed by punct (or endline)\n endUnd: /[^\\s]_(?!_)(?:(?=[punctuation*\\s])|$)/ // last char can't be a space, and final _ must preceed punct or \\s (or endline)\n\n },\n code: /^(`+)([^`]|[^`][\\s\\S]*?[^`])\\1(?!`)/,\n br: /^( {2,}|\\\\)\\n(?!\\s*$)/,\n del: noopTest$1,\n text: /^(`+|[^`])(?:(?= {2,}\\n)|[\\s\\S]*?(?:(?=[\\\\?@\\\\[\\\\]`^{|}~';\n inline.punctuation = edit$1(inline.punctuation).replace(/punctuation/g, inline._punctuation).getRegex(); // sequences em should skip over [title](link), `code`, \n\n inline._blockSkip = '\\\\[[^\\\\]]*?\\\\]\\\\([^\\\\)]*?\\\\)|`[^`]*?`|<[^>]*?>';\n inline._overlapSkip = '__[^_]*?__|\\\\*\\\\*\\\\[^\\\\*\\\\]*?\\\\*\\\\*';\n inline._comment = edit$1(block._comment).replace('(?:-->|$)', '-->').getRegex();\n inline.em.start = edit$1(inline.em.start).replace(/punctuation/g, inline._punctuation).getRegex();\n inline.em.middle = edit$1(inline.em.middle).replace(/punctuation/g, inline._punctuation).replace(/overlapSkip/g, inline._overlapSkip).getRegex();\n inline.em.endAst = edit$1(inline.em.endAst, 'g').replace(/punctuation/g, inline._punctuation).getRegex();\n inline.em.endUnd = edit$1(inline.em.endUnd, 'g').replace(/punctuation/g, inline._punctuation).getRegex();\n inline.strong.start = edit$1(inline.strong.start).replace(/punctuation/g, inline._punctuation).getRegex();\n inline.strong.middle = edit$1(inline.strong.middle).replace(/punctuation/g, inline._punctuation).replace(/overlapSkip/g, inline._overlapSkip).getRegex();\n inline.strong.endAst = edit$1(inline.strong.endAst, 'g').replace(/punctuation/g, inline._punctuation).getRegex();\n inline.strong.endUnd = edit$1(inline.strong.endUnd, 'g').replace(/punctuation/g, inline._punctuation).getRegex();\n inline.blockSkip = edit$1(inline._blockSkip, 'g').getRegex();\n inline.overlapSkip = edit$1(inline._overlapSkip, 'g').getRegex();\n inline._escapes = /\\\\([!\"#$%&'()*+,\\-./:;<=>?@\\[\\]\\\\^_`{|}~])/g;\n inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;\n inline._email = /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/;\n inline.autolink = edit$1(inline.autolink).replace('scheme', inline._scheme).replace('email', inline._email).getRegex();\n inline._attribute = /\\s+[a-zA-Z:_][\\w.:-]*(?:\\s*=\\s*\"[^\"]*\"|\\s*=\\s*'[^']*'|\\s*=\\s*[^\\s\"'=<>`]+)?/;\n inline.tag = edit$1(inline.tag).replace('comment', inline._comment).replace('attribute', inline._attribute).getRegex();\n inline._label = /(?:\\[(?:\\\\.|[^\\[\\]\\\\])*\\]|\\\\.|`[^`]*`|[^\\[\\]\\\\`])*?/;\n inline._href = /<(?:\\\\[<>]?|[^\\s<>\\\\])*>|[^\\s\\x00-\\x1f]*/;\n inline._title = /\"(?:\\\\\"?|[^\"\\\\])*\"|'(?:\\\\'?|[^'\\\\])*'|\\((?:\\\\\\)?|[^)\\\\])*\\)/;\n inline.link = edit$1(inline.link).replace('label', inline._label).replace('href', inline._href).replace('title', inline._title).getRegex();\n inline.reflink = edit$1(inline.reflink).replace('label', inline._label).getRegex();\n inline.reflinkSearch = edit$1(inline.reflinkSearch, 'g').replace('reflink', inline.reflink).replace('nolink', inline.nolink).getRegex();\n /**\n * Normal Inline Grammar\n */\n\n inline.normal = merge$1({}, inline);\n /**\n * Pedantic Inline Grammar\n */\n\n inline.pedantic = merge$1({}, inline.normal, {\n strong: {\n start: /^__|\\*\\*/,\n middle: /^__(?=\\S)([\\s\\S]*?\\S)__(?!_)|^\\*\\*(?=\\S)([\\s\\S]*?\\S)\\*\\*(?!\\*)/,\n endAst: /\\*\\*(?!\\*)/g,\n endUnd: /__(?!_)/g\n },\n em: {\n start: /^_|\\*/,\n middle: /^()\\*(?=\\S)([\\s\\S]*?\\S)\\*(?!\\*)|^_(?=\\S)([\\s\\S]*?\\S)_(?!_)/,\n endAst: /\\*(?!\\*)/g,\n endUnd: /_(?!_)/g\n },\n link: edit$1(/^!?\\[(label)\\]\\((.*?)\\)/).replace('label', inline._label).getRegex(),\n reflink: edit$1(/^!?\\[(label)\\]\\s*\\[([^\\]]*)\\]/).replace('label', inline._label).getRegex()\n });\n /**\n * GFM Inline Grammar\n */\n\n inline.gfm = merge$1({}, inline.normal, {\n escape: edit$1(inline.escape).replace('])', '~|])').getRegex(),\n _extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,\n url: /^((?:ftp|https?):\\/\\/|www\\.)(?:[a-zA-Z0-9\\-]+\\.?)+[^\\s<]*|^email/,\n _backpedal: /(?:[^?!.,:;*_~()&]+|\\([^)]*\\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,\n del: /^~+(?=\\S)([\\s\\S]*?\\S)~+/,\n text: /^(`+|[^`])(?:(?= {2,}\\n)|[\\s\\S]*?(?:(?=[\\\\ 0.5) {\n ch = 'x' + ch.toString(16);\n }\n\n out += '&#' + ch + ';';\n }\n\n return out;\n }\n /**\n * Block Lexer\n */\n\n\n var Lexer_1 = /*#__PURE__*/function () {\n function Lexer(options) {\n this.tokens = [];\n this.tokens.links = Object.create(null);\n this.options = options || defaults$2;\n this.options.tokenizer = this.options.tokenizer || new Tokenizer_1();\n this.tokenizer = this.options.tokenizer;\n this.tokenizer.options = this.options;\n var rules = {\n block: block$1.normal,\n inline: inline$1.normal\n };\n\n if (this.options.pedantic) {\n rules.block = block$1.pedantic;\n rules.inline = inline$1.pedantic;\n } else if (this.options.gfm) {\n rules.block = block$1.gfm;\n\n if (this.options.breaks) {\n rules.inline = inline$1.breaks;\n } else {\n rules.inline = inline$1.gfm;\n }\n }\n\n this.tokenizer.rules = rules;\n }\n /**\n * Expose Rules\n */\n\n\n /**\n * Static Lex Method\n */\n Lexer.lex = function lex(src, options) {\n var lexer = new Lexer(options);\n return lexer.lex(src);\n }\n /**\n * Static Lex Inline Method\n */\n ;\n\n Lexer.lexInline = function lexInline(src, options) {\n var lexer = new Lexer(options);\n return lexer.inlineTokens(src);\n }\n /**\n * Preprocessing\n */\n ;\n\n var _proto = Lexer.prototype;\n\n _proto.lex = function lex(src) {\n src = src.replace(/\\r\\n|\\r/g, '\\n').replace(/\\t/g, ' ');\n this.blockTokens(src, this.tokens, true);\n this.inline(this.tokens);\n return this.tokens;\n }\n /**\n * Lexing\n */\n ;\n\n _proto.blockTokens = function blockTokens(src, tokens, top) {\n if (tokens === void 0) {\n tokens = [];\n }\n\n if (top === void 0) {\n top = true;\n }\n\n src = src.replace(/^ +$/gm, '');\n var token, i, l, lastToken;\n\n while (src) {\n // newline\n if (token = this.tokenizer.space(src)) {\n src = src.substring(token.raw.length);\n\n if (token.type) {\n tokens.push(token);\n }\n\n continue;\n } // code\n\n\n if (token = this.tokenizer.code(src, tokens)) {\n src = src.substring(token.raw.length);\n\n if (token.type) {\n tokens.push(token);\n } else {\n lastToken = tokens[tokens.length - 1];\n lastToken.raw += '\\n' + token.raw;\n lastToken.text += '\\n' + token.text;\n }\n\n continue;\n } // fences\n\n\n if (token = this.tokenizer.fences(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n } // heading\n\n\n if (token = this.tokenizer.heading(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n } // table no leading pipe (gfm)\n\n\n if (token = this.tokenizer.nptable(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n } // hr\n\n\n if (token = this.tokenizer.hr(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n } // blockquote\n\n\n if (token = this.tokenizer.blockquote(src)) {\n src = src.substring(token.raw.length);\n token.tokens = this.blockTokens(token.text, [], top);\n tokens.push(token);\n continue;\n } // list\n\n\n if (token = this.tokenizer.list(src)) {\n src = src.substring(token.raw.length);\n l = token.items.length;\n\n for (i = 0; i < l; i++) {\n token.items[i].tokens = this.blockTokens(token.items[i].text, [], false);\n }\n\n tokens.push(token);\n continue;\n } // html\n\n\n if (token = this.tokenizer.html(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n } // def\n\n\n if (top && (token = this.tokenizer.def(src))) {\n src = src.substring(token.raw.length);\n\n if (!this.tokens.links[token.tag]) {\n this.tokens.links[token.tag] = {\n href: token.href,\n title: token.title\n };\n }\n\n continue;\n } // table (gfm)\n\n\n if (token = this.tokenizer.table(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n } // lheading\n\n\n if (token = this.tokenizer.lheading(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n } // top-level paragraph\n\n\n if (top && (token = this.tokenizer.paragraph(src))) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n } // text\n\n\n if (token = this.tokenizer.text(src, tokens)) {\n src = src.substring(token.raw.length);\n\n if (token.type) {\n tokens.push(token);\n } else {\n lastToken = tokens[tokens.length - 1];\n lastToken.raw += '\\n' + token.raw;\n lastToken.text += '\\n' + token.text;\n }\n\n continue;\n }\n\n if (src) {\n var errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);\n\n if (this.options.silent) {\n console.error(errMsg);\n break;\n } else {\n throw new Error(errMsg);\n }\n }\n }\n\n return tokens;\n };\n\n _proto.inline = function inline(tokens) {\n var i, j, k, l2, row, token;\n var l = tokens.length;\n\n for (i = 0; i < l; i++) {\n token = tokens[i];\n\n switch (token.type) {\n case 'paragraph':\n case 'text':\n case 'heading':\n {\n token.tokens = [];\n this.inlineTokens(token.text, token.tokens);\n break;\n }\n\n case 'table':\n {\n token.tokens = {\n header: [],\n cells: []\n }; // header\n\n l2 = token.header.length;\n\n for (j = 0; j < l2; j++) {\n token.tokens.header[j] = [];\n this.inlineTokens(token.header[j], token.tokens.header[j]);\n } // cells\n\n\n l2 = token.cells.length;\n\n for (j = 0; j < l2; j++) {\n row = token.cells[j];\n token.tokens.cells[j] = [];\n\n for (k = 0; k < row.length; k++) {\n token.tokens.cells[j][k] = [];\n this.inlineTokens(row[k], token.tokens.cells[j][k]);\n }\n }\n\n break;\n }\n\n case 'blockquote':\n {\n this.inline(token.tokens);\n break;\n }\n\n case 'list':\n {\n l2 = token.items.length;\n\n for (j = 0; j < l2; j++) {\n this.inline(token.items[j].tokens);\n }\n\n break;\n }\n }\n }\n\n return tokens;\n }\n /**\n * Lexing/Compiling\n */\n ;\n\n _proto.inlineTokens = function inlineTokens(src, tokens, inLink, inRawBlock, prevChar) {\n if (tokens === void 0) {\n tokens = [];\n }\n\n if (inLink === void 0) {\n inLink = false;\n }\n\n if (inRawBlock === void 0) {\n inRawBlock = false;\n }\n\n if (prevChar === void 0) {\n prevChar = '';\n }\n\n var token; // String with links masked to avoid interference with em and strong\n\n var maskedSrc = src;\n var match; // Mask out reflinks\n\n if (this.tokens.links) {\n var links = Object.keys(this.tokens.links);\n\n if (links.length > 0) {\n while ((match = this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc)) != null) {\n if (links.includes(match[0].slice(match[0].lastIndexOf('[') + 1, -1))) {\n maskedSrc = maskedSrc.slice(0, match.index) + '[' + repeatString$1('a', match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex);\n }\n }\n }\n } // Mask out other blocks\n\n\n while ((match = this.tokenizer.rules.inline.blockSkip.exec(maskedSrc)) != null) {\n maskedSrc = maskedSrc.slice(0, match.index) + '[' + repeatString$1('a', match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);\n }\n\n while (src) {\n // escape\n if (token = this.tokenizer.escape(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n } // tag\n\n\n if (token = this.tokenizer.tag(src, inLink, inRawBlock)) {\n src = src.substring(token.raw.length);\n inLink = token.inLink;\n inRawBlock = token.inRawBlock;\n tokens.push(token);\n continue;\n } // link\n\n\n if (token = this.tokenizer.link(src)) {\n src = src.substring(token.raw.length);\n\n if (token.type === 'link') {\n token.tokens = this.inlineTokens(token.text, [], true, inRawBlock);\n }\n\n tokens.push(token);\n continue;\n } // reflink, nolink\n\n\n if (token = this.tokenizer.reflink(src, this.tokens.links)) {\n src = src.substring(token.raw.length);\n\n if (token.type === 'link') {\n token.tokens = this.inlineTokens(token.text, [], true, inRawBlock);\n }\n\n tokens.push(token);\n continue;\n } // strong\n\n\n if (token = this.tokenizer.strong(src, maskedSrc, prevChar)) {\n src = src.substring(token.raw.length);\n token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);\n tokens.push(token);\n continue;\n } // em\n\n\n if (token = this.tokenizer.em(src, maskedSrc, prevChar)) {\n src = src.substring(token.raw.length);\n token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);\n tokens.push(token);\n continue;\n } // code\n\n\n if (token = this.tokenizer.codespan(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n } // br\n\n\n if (token = this.tokenizer.br(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n } // del (gfm)\n\n\n if (token = this.tokenizer.del(src)) {\n src = src.substring(token.raw.length);\n token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);\n tokens.push(token);\n continue;\n } // autolink\n\n\n if (token = this.tokenizer.autolink(src, mangle)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n } // url (gfm)\n\n\n if (!inLink && (token = this.tokenizer.url(src, mangle))) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n } // text\n\n\n if (token = this.tokenizer.inlineText(src, inRawBlock, smartypants)) {\n src = src.substring(token.raw.length);\n prevChar = token.raw.slice(-1);\n tokens.push(token);\n continue;\n }\n\n if (src) {\n var errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);\n\n if (this.options.silent) {\n console.error(errMsg);\n break;\n } else {\n throw new Error(errMsg);\n }\n }\n }\n\n return tokens;\n };\n\n _createClass(Lexer, null, [{\n key: \"rules\",\n get: function get() {\n return {\n block: block$1,\n inline: inline$1\n };\n }\n }]);\n\n return Lexer;\n }();\n\n var defaults$3 = defaults.defaults;\n var cleanUrl$1 = helpers.cleanUrl,\n escape$1 = helpers.escape;\n /**\n * Renderer\n */\n\n var Renderer_1 = /*#__PURE__*/function () {\n function Renderer(options) {\n this.options = options || defaults$3;\n }\n\n var _proto = Renderer.prototype;\n\n _proto.code = function code(_code, infostring, escaped) {\n var lang = (infostring || '').match(/\\S*/)[0];\n\n if (this.options.highlight) {\n var out = this.options.highlight(_code, lang);\n\n if (out != null && out !== _code) {\n escaped = true;\n _code = out;\n }\n }\n\n if (!lang) {\n return '
' + (escaped ? _code : escape$1(_code, true)) + '
\\n';\n }\n\n return '
' + (escaped ? _code : escape$1(_code, true)) + '
\\n';\n };\n\n _proto.blockquote = function blockquote(quote) {\n return '
\\n' + quote + '
\\n';\n };\n\n _proto.html = function html(_html) {\n return _html;\n };\n\n _proto.heading = function heading(text, level, raw, slugger) {\n if (this.options.headerIds) {\n return '' + text + '\\n';\n } // ignore IDs\n\n\n return '' + text + '\\n';\n };\n\n _proto.hr = function hr() {\n return this.options.xhtml ? '
\\n' : '
\\n';\n };\n\n _proto.list = function list(body, ordered, start) {\n var type = ordered ? 'ol' : 'ul',\n startatt = ordered && start !== 1 ? ' start=\"' + start + '\"' : '';\n return '<' + type + startatt + '>\\n' + body + '\\n';\n };\n\n _proto.listitem = function listitem(text) {\n return '
  • ' + text + '
  • \\n';\n };\n\n _proto.checkbox = function checkbox(checked) {\n return ' ';\n };\n\n _proto.paragraph = function paragraph(text) {\n return '

    ' + text + '

    \\n';\n };\n\n _proto.table = function table(header, body) {\n if (body) body = '' + body + '';\n return '\\n' + '\\n' + header + '\\n' + body + '
    \\n';\n };\n\n _proto.tablerow = function tablerow(content) {\n return '\\n' + content + '\\n';\n };\n\n _proto.tablecell = function tablecell(content, flags) {\n var type = flags.header ? 'th' : 'td';\n var tag = flags.align ? '<' + type + ' align=\"' + flags.align + '\">' : '<' + type + '>';\n return tag + content + '\\n';\n } // span level renderer\n ;\n\n _proto.strong = function strong(text) {\n return '' + text + '';\n };\n\n _proto.em = function em(text) {\n return '' + text + '';\n };\n\n _proto.codespan = function codespan(text) {\n return '' + text + '';\n };\n\n _proto.br = function br() {\n return this.options.xhtml ? '
    ' : '
    ';\n };\n\n _proto.del = function del(text) {\n return '' + text + '';\n };\n\n _proto.link = function link(href, title, text) {\n href = cleanUrl$1(this.options.sanitize, this.options.baseUrl, href);\n\n if (href === null) {\n return text;\n }\n\n var out = '
    ';\n return out;\n };\n\n _proto.image = function image(href, title, text) {\n href = cleanUrl$1(this.options.sanitize, this.options.baseUrl, href);\n\n if (href === null) {\n return text;\n }\n\n var out = '\"'' : '>';\n return out;\n };\n\n _proto.text = function text(_text) {\n return _text;\n };\n\n return Renderer;\n }();\n\n /**\n * TextRenderer\n * returns only the textual part of the token\n */\n var TextRenderer_1 = /*#__PURE__*/function () {\n function TextRenderer() {}\n\n var _proto = TextRenderer.prototype;\n\n // no need for block level renderers\n _proto.strong = function strong(text) {\n return text;\n };\n\n _proto.em = function em(text) {\n return text;\n };\n\n _proto.codespan = function codespan(text) {\n return text;\n };\n\n _proto.del = function del(text) {\n return text;\n };\n\n _proto.html = function html(text) {\n return text;\n };\n\n _proto.text = function text(_text) {\n return _text;\n };\n\n _proto.link = function link(href, title, text) {\n return '' + text;\n };\n\n _proto.image = function image(href, title, text) {\n return '' + text;\n };\n\n _proto.br = function br() {\n return '';\n };\n\n return TextRenderer;\n }();\n\n /**\n * Slugger generates header id\n */\n var Slugger_1 = /*#__PURE__*/function () {\n function Slugger() {\n this.seen = {};\n }\n\n var _proto = Slugger.prototype;\n\n _proto.serialize = function serialize(value) {\n return value.toLowerCase().trim() // remove html tags\n .replace(/<[!\\/a-z].*?>/ig, '') // remove unwanted chars\n .replace(/[\\u2000-\\u206F\\u2E00-\\u2E7F\\\\'!\"#$%&()*+,./:;<=>?@[\\]^`{|}~]/g, '').replace(/\\s/g, '-');\n }\n /**\n * Finds the next safe (unique) slug to use\n */\n ;\n\n _proto.getNextSafeSlug = function getNextSafeSlug(originalSlug, isDryRun) {\n var slug = originalSlug;\n var occurenceAccumulator = 0;\n\n if (this.seen.hasOwnProperty(slug)) {\n occurenceAccumulator = this.seen[originalSlug];\n\n do {\n occurenceAccumulator++;\n slug = originalSlug + '-' + occurenceAccumulator;\n } while (this.seen.hasOwnProperty(slug));\n }\n\n if (!isDryRun) {\n this.seen[originalSlug] = occurenceAccumulator;\n this.seen[slug] = 0;\n }\n\n return slug;\n }\n /**\n * Convert string to unique id\n * @param {object} options\n * @param {boolean} options.dryrun Generates the next unique slug without updating the internal accumulator.\n */\n ;\n\n _proto.slug = function slug(value, options) {\n if (options === void 0) {\n options = {};\n }\n\n var slug = this.serialize(value);\n return this.getNextSafeSlug(slug, options.dryrun);\n };\n\n return Slugger;\n }();\n\n var defaults$4 = defaults.defaults;\n var unescape$1 = helpers.unescape;\n /**\n * Parsing & Compiling\n */\n\n var Parser_1 = /*#__PURE__*/function () {\n function Parser(options) {\n this.options = options || defaults$4;\n this.options.renderer = this.options.renderer || new Renderer_1();\n this.renderer = this.options.renderer;\n this.renderer.options = this.options;\n this.textRenderer = new TextRenderer_1();\n this.slugger = new Slugger_1();\n }\n /**\n * Static Parse Method\n */\n\n\n Parser.parse = function parse(tokens, options) {\n var parser = new Parser(options);\n return parser.parse(tokens);\n }\n /**\n * Static Parse Inline Method\n */\n ;\n\n Parser.parseInline = function parseInline(tokens, options) {\n var parser = new Parser(options);\n return parser.parseInline(tokens);\n }\n /**\n * Parse Loop\n */\n ;\n\n var _proto = Parser.prototype;\n\n _proto.parse = function parse(tokens, top) {\n if (top === void 0) {\n top = true;\n }\n\n var out = '',\n i,\n j,\n k,\n l2,\n l3,\n row,\n cell,\n header,\n body,\n token,\n ordered,\n start,\n loose,\n itemBody,\n item,\n checked,\n task,\n checkbox;\n var l = tokens.length;\n\n for (i = 0; i < l; i++) {\n token = tokens[i];\n\n switch (token.type) {\n case 'space':\n {\n continue;\n }\n\n case 'hr':\n {\n out += this.renderer.hr();\n continue;\n }\n\n case 'heading':\n {\n out += this.renderer.heading(this.parseInline(token.tokens), token.depth, unescape$1(this.parseInline(token.tokens, this.textRenderer)), this.slugger);\n continue;\n }\n\n case 'code':\n {\n out += this.renderer.code(token.text, token.lang, token.escaped);\n continue;\n }\n\n case 'table':\n {\n header = ''; // header\n\n cell = '';\n l2 = token.header.length;\n\n for (j = 0; j < l2; j++) {\n cell += this.renderer.tablecell(this.parseInline(token.tokens.header[j]), {\n header: true,\n align: token.align[j]\n });\n }\n\n header += this.renderer.tablerow(cell);\n body = '';\n l2 = token.cells.length;\n\n for (j = 0; j < l2; j++) {\n row = token.tokens.cells[j];\n cell = '';\n l3 = row.length;\n\n for (k = 0; k < l3; k++) {\n cell += this.renderer.tablecell(this.parseInline(row[k]), {\n header: false,\n align: token.align[k]\n });\n }\n\n body += this.renderer.tablerow(cell);\n }\n\n out += this.renderer.table(header, body);\n continue;\n }\n\n case 'blockquote':\n {\n body = this.parse(token.tokens);\n out += this.renderer.blockquote(body);\n continue;\n }\n\n case 'list':\n {\n ordered = token.ordered;\n start = token.start;\n loose = token.loose;\n l2 = token.items.length;\n body = '';\n\n for (j = 0; j < l2; j++) {\n item = token.items[j];\n checked = item.checked;\n task = item.task;\n itemBody = '';\n\n if (item.task) {\n checkbox = this.renderer.checkbox(checked);\n\n if (loose) {\n if (item.tokens.length > 0 && item.tokens[0].type === 'text') {\n item.tokens[0].text = checkbox + ' ' + item.tokens[0].text;\n\n if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') {\n item.tokens[0].tokens[0].text = checkbox + ' ' + item.tokens[0].tokens[0].text;\n }\n } else {\n item.tokens.unshift({\n type: 'text',\n text: checkbox\n });\n }\n } else {\n itemBody += checkbox;\n }\n }\n\n itemBody += this.parse(item.tokens, loose);\n body += this.renderer.listitem(itemBody, task, checked);\n }\n\n out += this.renderer.list(body, ordered, start);\n continue;\n }\n\n case 'html':\n {\n // TODO parse inline content if parameter markdown=1\n out += this.renderer.html(token.text);\n continue;\n }\n\n case 'paragraph':\n {\n out += this.renderer.paragraph(this.parseInline(token.tokens));\n continue;\n }\n\n case 'text':\n {\n body = token.tokens ? this.parseInline(token.tokens) : token.text;\n\n while (i + 1 < l && tokens[i + 1].type === 'text') {\n token = tokens[++i];\n body += '\\n' + (token.tokens ? this.parseInline(token.tokens) : token.text);\n }\n\n out += top ? this.renderer.paragraph(body) : body;\n continue;\n }\n\n default:\n {\n var errMsg = 'Token with \"' + token.type + '\" type was not found.';\n\n if (this.options.silent) {\n console.error(errMsg);\n return;\n } else {\n throw new Error(errMsg);\n }\n }\n }\n }\n\n return out;\n }\n /**\n * Parse Inline Tokens\n */\n ;\n\n _proto.parseInline = function parseInline(tokens, renderer) {\n renderer = renderer || this.renderer;\n var out = '',\n i,\n token;\n var l = tokens.length;\n\n for (i = 0; i < l; i++) {\n token = tokens[i];\n\n switch (token.type) {\n case 'escape':\n {\n out += renderer.text(token.text);\n break;\n }\n\n case 'html':\n {\n out += renderer.html(token.text);\n break;\n }\n\n case 'link':\n {\n out += renderer.link(token.href, token.title, this.parseInline(token.tokens, renderer));\n break;\n }\n\n case 'image':\n {\n out += renderer.image(token.href, token.title, token.text);\n break;\n }\n\n case 'strong':\n {\n out += renderer.strong(this.parseInline(token.tokens, renderer));\n break;\n }\n\n case 'em':\n {\n out += renderer.em(this.parseInline(token.tokens, renderer));\n break;\n }\n\n case 'codespan':\n {\n out += renderer.codespan(token.text);\n break;\n }\n\n case 'br':\n {\n out += renderer.br();\n break;\n }\n\n case 'del':\n {\n out += renderer.del(this.parseInline(token.tokens, renderer));\n break;\n }\n\n case 'text':\n {\n out += renderer.text(token.text);\n break;\n }\n\n default:\n {\n var errMsg = 'Token with \"' + token.type + '\" type was not found.';\n\n if (this.options.silent) {\n console.error(errMsg);\n return;\n } else {\n throw new Error(errMsg);\n }\n }\n }\n }\n\n return out;\n };\n\n return Parser;\n }();\n\n var merge$2 = helpers.merge,\n checkSanitizeDeprecation$1 = helpers.checkSanitizeDeprecation,\n escape$2 = helpers.escape;\n var getDefaults = defaults.getDefaults,\n changeDefaults = defaults.changeDefaults,\n defaults$5 = defaults.defaults;\n /**\n * Marked\n */\n\n function marked(src, opt, callback) {\n // throw error in case of non string input\n if (typeof src === 'undefined' || src === null) {\n throw new Error('marked(): input parameter is undefined or null');\n }\n\n if (typeof src !== 'string') {\n throw new Error('marked(): input parameter is of type ' + Object.prototype.toString.call(src) + ', string expected');\n }\n\n if (typeof opt === 'function') {\n callback = opt;\n opt = null;\n }\n\n opt = merge$2({}, marked.defaults, opt || {});\n checkSanitizeDeprecation$1(opt);\n\n if (callback) {\n var highlight = opt.highlight;\n var tokens;\n\n try {\n tokens = Lexer_1.lex(src, opt);\n } catch (e) {\n return callback(e);\n }\n\n var done = function done(err) {\n var out;\n\n if (!err) {\n try {\n out = Parser_1.parse(tokens, opt);\n } catch (e) {\n err = e;\n }\n }\n\n opt.highlight = highlight;\n return err ? callback(err) : callback(null, out);\n };\n\n if (!highlight || highlight.length < 3) {\n return done();\n }\n\n delete opt.highlight;\n if (!tokens.length) return done();\n var pending = 0;\n marked.walkTokens(tokens, function (token) {\n if (token.type === 'code') {\n pending++;\n setTimeout(function () {\n highlight(token.text, token.lang, function (err, code) {\n if (err) {\n return done(err);\n }\n\n if (code != null && code !== token.text) {\n token.text = code;\n token.escaped = true;\n }\n\n pending--;\n\n if (pending === 0) {\n done();\n }\n });\n }, 0);\n }\n });\n\n if (pending === 0) {\n done();\n }\n\n return;\n }\n\n try {\n var _tokens = Lexer_1.lex(src, opt);\n\n if (opt.walkTokens) {\n marked.walkTokens(_tokens, opt.walkTokens);\n }\n\n return Parser_1.parse(_tokens, opt);\n } catch (e) {\n e.message += '\\nPlease report this to https://github.com/markedjs/marked.';\n\n if (opt.silent) {\n return '

    An error occurred:

    ' + escape$2(e.message + '', true) + '
    ';\n }\n\n throw e;\n }\n }\n /**\n * Options\n */\n\n\n marked.options = marked.setOptions = function (opt) {\n merge$2(marked.defaults, opt);\n changeDefaults(marked.defaults);\n return marked;\n };\n\n marked.getDefaults = getDefaults;\n marked.defaults = defaults$5;\n /**\n * Use Extension\n */\n\n marked.use = function (extension) {\n var opts = merge$2({}, extension);\n\n if (extension.renderer) {\n (function () {\n var renderer = marked.defaults.renderer || new Renderer_1();\n\n var _loop = function _loop(prop) {\n var prevRenderer = renderer[prop];\n\n renderer[prop] = function () {\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n var ret = extension.renderer[prop].apply(renderer, args);\n\n if (ret === false) {\n ret = prevRenderer.apply(renderer, args);\n }\n\n return ret;\n };\n };\n\n for (var prop in extension.renderer) {\n _loop(prop);\n }\n\n opts.renderer = renderer;\n })();\n }\n\n if (extension.tokenizer) {\n (function () {\n var tokenizer = marked.defaults.tokenizer || new Tokenizer_1();\n\n var _loop2 = function _loop2(prop) {\n var prevTokenizer = tokenizer[prop];\n\n tokenizer[prop] = function () {\n for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n args[_key2] = arguments[_key2];\n }\n\n var ret = extension.tokenizer[prop].apply(tokenizer, args);\n\n if (ret === false) {\n ret = prevTokenizer.apply(tokenizer, args);\n }\n\n return ret;\n };\n };\n\n for (var prop in extension.tokenizer) {\n _loop2(prop);\n }\n\n opts.tokenizer = tokenizer;\n })();\n }\n\n if (extension.walkTokens) {\n var walkTokens = marked.defaults.walkTokens;\n\n opts.walkTokens = function (token) {\n extension.walkTokens(token);\n\n if (walkTokens) {\n walkTokens(token);\n }\n };\n }\n\n marked.setOptions(opts);\n };\n /**\n * Run callback for every token\n */\n\n\n marked.walkTokens = function (tokens, callback) {\n for (var _iterator = _createForOfIteratorHelperLoose(tokens), _step; !(_step = _iterator()).done;) {\n var token = _step.value;\n callback(token);\n\n switch (token.type) {\n case 'table':\n {\n for (var _iterator2 = _createForOfIteratorHelperLoose(token.tokens.header), _step2; !(_step2 = _iterator2()).done;) {\n var cell = _step2.value;\n marked.walkTokens(cell, callback);\n }\n\n for (var _iterator3 = _createForOfIteratorHelperLoose(token.tokens.cells), _step3; !(_step3 = _iterator3()).done;) {\n var row = _step3.value;\n\n for (var _iterator4 = _createForOfIteratorHelperLoose(row), _step4; !(_step4 = _iterator4()).done;) {\n var _cell = _step4.value;\n marked.walkTokens(_cell, callback);\n }\n }\n\n break;\n }\n\n case 'list':\n {\n marked.walkTokens(token.items, callback);\n break;\n }\n\n default:\n {\n if (token.tokens) {\n marked.walkTokens(token.tokens, callback);\n }\n }\n }\n }\n };\n /**\n * Parse Inline\n */\n\n\n marked.parseInline = function (src, opt) {\n // throw error in case of non string input\n if (typeof src === 'undefined' || src === null) {\n throw new Error('marked.parseInline(): input parameter is undefined or null');\n }\n\n if (typeof src !== 'string') {\n throw new Error('marked.parseInline(): input parameter is of type ' + Object.prototype.toString.call(src) + ', string expected');\n }\n\n opt = merge$2({}, marked.defaults, opt || {});\n checkSanitizeDeprecation$1(opt);\n\n try {\n var tokens = Lexer_1.lexInline(src, opt);\n\n if (opt.walkTokens) {\n marked.walkTokens(tokens, opt.walkTokens);\n }\n\n return Parser_1.parseInline(tokens, opt);\n } catch (e) {\n e.message += '\\nPlease report this to https://github.com/markedjs/marked.';\n\n if (opt.silent) {\n return '

    An error occurred:

    ' + escape$2(e.message + '', true) + '
    ';\n }\n\n throw e;\n }\n };\n /**\n * Expose\n */\n\n\n marked.Parser = Parser_1;\n marked.parser = Parser_1.parse;\n marked.Renderer = Renderer_1;\n marked.TextRenderer = TextRenderer_1;\n marked.Lexer = Lexer_1;\n marked.lexer = Lexer_1.lex;\n marked.Tokenizer = Tokenizer_1;\n marked.Slugger = Slugger_1;\n marked.parse = marked;\n var marked_1 = marked;\n\n return marked_1;\n\n})));\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nexport interface INavigator {\r\n}\r\n\r\nexport class ArrayNavigator implements INavigator {\r\n\r\n\tconstructor(\r\n\t\tprivate readonly items: readonly T[],\r\n\t\tprotected start: number = 0,\r\n\t\tprotected end: number = items.length,\r\n\t\tprotected index = start - 1\r\n\t) { }\r\n\r\n\tcurrent(): T | null {\r\n\t\tif (this.index === this.start - 1 || this.index === this.end) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\treturn this.items[this.index];\r\n\t}\r\n\r\n\tnext(): T | null {\r\n\t\tthis.index = Math.min(this.index + 1, this.end);\r\n\t\treturn this.current();\r\n\t}\r\n\r\n\tprevious(): T | null {\r\n\t\tthis.index = Math.max(this.index - 1, this.start - 1);\r\n\t\treturn this.current();\r\n\t}\r\n\r\n\tfirst(): T | null {\r\n\t\tthis.index = this.start;\r\n\t\treturn this.current();\r\n\t}\r\n\r\n\tlast(): T | null {\r\n\t\tthis.index = this.end - 1;\r\n\t\treturn this.current();\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { INavigator, ArrayNavigator } from 'vs/base/common/navigator';\r\n\r\nexport class HistoryNavigator implements INavigator {\r\n\r\n\tprivate _history!: Set;\r\n\tprivate _limit: number;\r\n\tprivate _navigator!: ArrayNavigator;\r\n\r\n\tconstructor(history: readonly T[] = [], limit: number = 10) {\r\n\t\tthis._initialize(history);\r\n\t\tthis._limit = limit;\r\n\t\tthis._onChange();\r\n\t}\r\n\r\n\tpublic add(t: T) {\r\n\t\tthis._history.delete(t);\r\n\t\tthis._history.add(t);\r\n\t\tthis._onChange();\r\n\t}\r\n\r\n\tpublic next(): T | null {\r\n\t\tif (this._currentPosition() !== this._elements.length - 1) {\r\n\t\t\treturn this._navigator.next();\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic previous(): T | null {\r\n\t\tif (this._currentPosition() !== 0) {\r\n\t\t\treturn this._navigator.previous();\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic current(): T | null {\r\n\t\treturn this._navigator.current();\r\n\t}\r\n\r\n\tpublic first(): T | null {\r\n\t\treturn this._navigator.first();\r\n\t}\r\n\r\n\tpublic last(): T | null {\r\n\t\treturn this._navigator.last();\r\n\t}\r\n\r\n\tpublic has(t: T): boolean {\r\n\t\treturn this._history.has(t);\r\n\t}\r\n\r\n\tprivate _onChange() {\r\n\t\tthis._reduceToLimit();\r\n\t\tconst elements = this._elements;\r\n\t\tthis._navigator = new ArrayNavigator(elements, 0, elements.length, elements.length);\r\n\t}\r\n\r\n\tprivate _reduceToLimit() {\r\n\t\tconst data = this._elements;\r\n\t\tif (data.length > this._limit) {\r\n\t\t\tthis._initialize(data.slice(data.length - this._limit));\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _currentPosition(): number {\r\n\t\tconst currentElement = this._navigator.current();\r\n\t\tif (!currentElement) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\r\n\t\treturn this._elements.indexOf(currentElement);\r\n\t}\r\n\r\n\tprivate _initialize(history: readonly T[]): void {\r\n\t\tthis._history = new Set();\r\n\t\tfor (const entry of history) {\r\n\t\t\tthis._history.add(entry);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate get _elements(): T[] {\r\n\t\tconst elements: T[] = [];\r\n\t\tthis._history.forEach(e => elements.push(e));\r\n\t\treturn elements;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nexport function clamp(value: number, min: number, max: number): number {\r\n\treturn Math.min(Math.max(value, min), max);\r\n}\r\n\r\nexport class MovingAverage {\r\n\r\n\tprivate _n = 1;\r\n\tprivate _val = 0;\r\n\r\n\tupdate(value: number): this {\r\n\t\tthis._val = this._val + (value - this._val) / this._n;\r\n\t\tthis._n += 1;\r\n\t\treturn this;\r\n\t}\r\n\r\n\tget value(): number {\r\n\t\treturn this._val;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nconst LANGUAGE_DEFAULT = 'en';\r\n\r\nlet _isWindows = false;\r\nlet _isMacintosh = false;\r\nlet _isLinux = false;\r\nlet _isLinuxSnap = false;\r\nlet _isNative = false;\r\nlet _isWeb = false;\r\nlet _isIOS = false;\r\nlet _locale: string | undefined = undefined;\r\nlet _language: string = LANGUAGE_DEFAULT;\r\nlet _translationsConfigFile: string | undefined = undefined;\r\nlet _userAgent: string | undefined = undefined;\r\n\r\ninterface NLSConfig {\r\n\tlocale: string;\r\n\tavailableLanguages: { [key: string]: string; };\r\n\t_translationsConfigFile: string;\r\n}\r\n\r\nexport interface IProcessEnvironment {\r\n\t[key: string]: string;\r\n}\r\n\r\nexport interface INodeProcess {\r\n\tplatform: 'win32' | 'linux' | 'darwin';\r\n\tenv: IProcessEnvironment;\r\n\tnextTick: Function;\r\n\tversions?: {\r\n\t\telectron?: string;\r\n\t};\r\n\tsandboxed?: boolean; // Electron\r\n\ttype?: string;\r\n\tcwd(): string;\r\n}\r\ndeclare const process: INodeProcess;\r\ndeclare const global: any;\r\n\r\ninterface INavigator {\r\n\tuserAgent: string;\r\n\tlanguage: string;\r\n\tmaxTouchPoints?: number;\r\n}\r\ndeclare const navigator: INavigator;\r\ndeclare const self: any;\r\n\r\nconst _globals = (typeof self === 'object' ? self : typeof global === 'object' ? global : {} as any);\r\n\r\nlet nodeProcess: INodeProcess | undefined = undefined;\r\nif (typeof process !== 'undefined') {\r\n\t// Native environment (non-sandboxed)\r\n\tnodeProcess = process;\r\n} else if (typeof _globals.vscode !== 'undefined') {\r\n\t// Native environment (sandboxed)\r\n\tnodeProcess = _globals.vscode.process;\r\n}\r\n\r\nconst isElectronRenderer = typeof nodeProcess?.versions?.electron === 'string' && nodeProcess.type === 'renderer';\r\nexport const isElectronSandboxed = isElectronRenderer && nodeProcess?.sandboxed;\r\nexport const browserCodeLoadingCacheStrategy: 'none' | 'code' | 'bypassHeatCheck' | 'bypassHeatCheckAndEagerCompile' | undefined = (() => {\r\n\r\n\t// Always enabled when sandbox is enabled\r\n\tif (isElectronSandboxed) {\r\n\t\treturn 'bypassHeatCheck';\r\n\t}\r\n\r\n\t// Otherwise, only enabled conditionally\r\n\tconst env = nodeProcess?.env['ENABLE_VSCODE_BROWSER_CODE_LOADING'];\r\n\tif (typeof env === 'string') {\r\n\t\tif (env === 'none' || env === 'code' || env === 'bypassHeatCheck' || env === 'bypassHeatCheckAndEagerCompile') {\r\n\t\t\treturn env;\r\n\t\t}\r\n\r\n\t\treturn 'bypassHeatCheck';\r\n\t}\r\n\r\n\treturn undefined;\r\n})();\r\nexport const isPreferringBrowserCodeLoad = typeof browserCodeLoadingCacheStrategy === 'string';\r\n\r\n// Web environment\r\nif (typeof navigator === 'object' && !isElectronRenderer) {\r\n\t_userAgent = navigator.userAgent;\r\n\t_isWindows = _userAgent.indexOf('Windows') >= 0;\r\n\t_isMacintosh = _userAgent.indexOf('Macintosh') >= 0;\r\n\t_isIOS = (_userAgent.indexOf('Macintosh') >= 0 || _userAgent.indexOf('iPad') >= 0 || _userAgent.indexOf('iPhone') >= 0) && !!navigator.maxTouchPoints && navigator.maxTouchPoints > 0;\r\n\t_isLinux = _userAgent.indexOf('Linux') >= 0;\r\n\t_isWeb = true;\r\n\t_locale = navigator.language;\r\n\t_language = _locale;\r\n}\r\n\r\n// Native environment\r\nelse if (typeof nodeProcess === 'object') {\r\n\t_isWindows = (nodeProcess.platform === 'win32');\r\n\t_isMacintosh = (nodeProcess.platform === 'darwin');\r\n\t_isLinux = (nodeProcess.platform === 'linux');\r\n\t_isLinuxSnap = _isLinux && !!nodeProcess.env['SNAP'] && !!nodeProcess.env['SNAP_REVISION'];\r\n\t_locale = LANGUAGE_DEFAULT;\r\n\t_language = LANGUAGE_DEFAULT;\r\n\tconst rawNlsConfig = nodeProcess.env['VSCODE_NLS_CONFIG'];\r\n\tif (rawNlsConfig) {\r\n\t\ttry {\r\n\t\t\tconst nlsConfig: NLSConfig = JSON.parse(rawNlsConfig);\r\n\t\t\tconst resolved = nlsConfig.availableLanguages['*'];\r\n\t\t\t_locale = nlsConfig.locale;\r\n\t\t\t// VSCode's default language is 'en'\r\n\t\t\t_language = resolved ? resolved : LANGUAGE_DEFAULT;\r\n\t\t\t_translationsConfigFile = nlsConfig._translationsConfigFile;\r\n\t\t} catch (e) {\r\n\t\t}\r\n\t}\r\n\t_isNative = true;\r\n}\r\n\r\n// Unknown environment\r\nelse {\r\n\tconsole.error('Unable to resolve platform.');\r\n}\r\n\r\nexport const enum Platform {\r\n\tWeb,\r\n\tMac,\r\n\tLinux,\r\n\tWindows\r\n}\r\n\r\nlet _platform: Platform = Platform.Web;\r\nif (_isMacintosh) {\r\n\t_platform = Platform.Mac;\r\n} else if (_isWindows) {\r\n\t_platform = Platform.Windows;\r\n} else if (_isLinux) {\r\n\t_platform = Platform.Linux;\r\n}\r\n\r\nexport const isWindows = _isWindows;\r\nexport const isMacintosh = _isMacintosh;\r\nexport const isLinux = _isLinux;\r\nexport const isNative = _isNative;\r\nexport const isWeb = _isWeb;\r\nexport const isIOS = _isIOS;\r\nexport const userAgent = _userAgent;\r\n\r\nexport const globals: any = _globals;\r\n\r\ninterface ISetImmediate {\r\n\t(callback: (...args: any[]) => void): void;\r\n}\r\n\r\nexport const setImmediate: ISetImmediate = (function defineSetImmediate() {\r\n\tif (globals.setImmediate) {\r\n\t\treturn globals.setImmediate.bind(globals);\r\n\t}\r\n\tif (typeof globals.postMessage === 'function' && !globals.importScripts) {\r\n\t\tinterface IQueueElement {\r\n\t\t\tid: number;\r\n\t\t\tcallback: () => void;\r\n\t\t}\r\n\t\tlet pending: IQueueElement[] = [];\r\n\t\tglobals.addEventListener('message', (e: MessageEvent) => {\r\n\t\t\tif (e.data && e.data.vscodeSetImmediateId) {\r\n\t\t\t\tfor (let i = 0, len = pending.length; i < len; i++) {\r\n\t\t\t\t\tconst candidate = pending[i];\r\n\t\t\t\t\tif (candidate.id === e.data.vscodeSetImmediateId) {\r\n\t\t\t\t\t\tpending.splice(i, 1);\r\n\t\t\t\t\t\tcandidate.callback();\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\t\tlet lastId = 0;\r\n\t\treturn (callback: () => void) => {\r\n\t\t\tconst myId = ++lastId;\r\n\t\t\tpending.push({\r\n\t\t\t\tid: myId,\r\n\t\t\t\tcallback: callback\r\n\t\t\t});\r\n\t\t\tglobals.postMessage({ vscodeSetImmediateId: myId }, '*');\r\n\t\t};\r\n\t}\r\n\tif (nodeProcess && typeof nodeProcess.nextTick === 'function') {\r\n\t\treturn nodeProcess.nextTick.bind(nodeProcess);\r\n\t}\r\n\tconst _promise = Promise.resolve();\r\n\treturn (callback: (...args: any[]) => void) => _promise.then(callback);\r\n})();\r\n\r\nexport const enum OperatingSystem {\r\n\tWindows = 1,\r\n\tMacintosh = 2,\r\n\tLinux = 3\r\n}\r\nexport const OS = (_isMacintosh || _isIOS ? OperatingSystem.Macintosh : (_isWindows ? OperatingSystem.Windows : OperatingSystem.Linux));\r\n\r\nlet _isLittleEndian = true;\r\nlet _isLittleEndianComputed = false;\r\nexport function isLittleEndian(): boolean {\r\n\tif (!_isLittleEndianComputed) {\r\n\t\t_isLittleEndianComputed = true;\r\n\t\tconst test = new Uint8Array(2);\r\n\t\ttest[0] = 1;\r\n\t\ttest[1] = 2;\r\n\t\tconst view = new Uint16Array(test.buffer);\r\n\t\t_isLittleEndian = (view[0] === (2 << 8) + 1);\r\n\t}\r\n\treturn _isLittleEndian;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { isWindows, isMacintosh, setImmediate, globals, INodeProcess } from 'vs/base/common/platform';\r\n\r\ndeclare const process: INodeProcess;\r\n\r\nlet safeProcess: INodeProcess;\r\n\r\n// Native node.js environment\r\nif (typeof process !== 'undefined') {\r\n\tsafeProcess = process;\r\n}\r\n\r\n// Native sandbox environment\r\nelse if (typeof globals.vscode !== 'undefined') {\r\n\tsafeProcess = {\r\n\r\n\t\t// Supported\r\n\t\tget platform(): 'win32' | 'linux' | 'darwin' { return globals.vscode.process.platform; },\r\n\t\tget env() { return globals.vscode.process.env; },\r\n\t\tnextTick(callback: (...args: any[]) => void): void { return setImmediate(callback); },\r\n\r\n\t\t// Unsupported\r\n\t\tcwd(): string { return globals.vscode.process.env['VSCODE_CWD'] || globals.vscode.process.execPath.substr(0, globals.vscode.process.execPath.lastIndexOf(globals.vscode.process.platform === 'win32' ? '\\\\' : '/')); }\r\n\t};\r\n}\r\n\r\n// Web environment\r\nelse {\r\n\tsafeProcess = {\r\n\r\n\t\t// Supported\r\n\t\tget platform(): 'win32' | 'linux' | 'darwin' { return isWindows ? 'win32' : isMacintosh ? 'darwin' : 'linux'; },\r\n\t\tnextTick(callback: (...args: any[]) => void): void { return setImmediate(callback); },\r\n\r\n\t\t// Unsupported\r\n\t\tget env() { return Object.create(null); },\r\n\t\tcwd(): string { return '/'; }\r\n\t};\r\n}\r\n\r\nexport const cwd = safeProcess.cwd;\r\nexport const env = safeProcess.env;\r\nexport const platform = safeProcess.platform;\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\n// NOTE: VSCode's copy of nodejs path library to be usable in common (non-node) namespace\r\n// Copied from: https://github.com/nodejs/node/blob/v12.8.1/lib/path.js\r\n\r\n/**\r\n * Copyright Joyent, Inc. and other Node contributors.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a\r\n * copy of this software and associated documentation files (the\r\n * \"Software\"), to deal in the Software without restriction, including\r\n * without limitation the rights to use, copy, modify, merge, publish,\r\n * distribute, sublicense, and/or sell copies of the Software, and to permit\r\n * persons to whom the Software is furnished to do so, subject to the\r\n * following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included\r\n * in all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\r\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\r\n * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\r\n * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\r\n * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\r\n * USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n */\r\n\r\nimport * as process from 'vs/base/common/process';\r\n\r\nconst CHAR_UPPERCASE_A = 65;/* A */\r\nconst CHAR_LOWERCASE_A = 97; /* a */\r\nconst CHAR_UPPERCASE_Z = 90; /* Z */\r\nconst CHAR_LOWERCASE_Z = 122; /* z */\r\nconst CHAR_DOT = 46; /* . */\r\nconst CHAR_FORWARD_SLASH = 47; /* / */\r\nconst CHAR_BACKWARD_SLASH = 92; /* \\ */\r\nconst CHAR_COLON = 58; /* : */\r\nconst CHAR_QUESTION_MARK = 63; /* ? */\r\n\r\nclass ErrorInvalidArgType extends Error {\r\n\tcode: 'ERR_INVALID_ARG_TYPE';\r\n\tconstructor(name: string, expected: string, actual: unknown) {\r\n\t\t// determiner: 'must be' or 'must not be'\r\n\t\tlet determiner;\r\n\t\tif (typeof expected === 'string' && expected.indexOf('not ') === 0) {\r\n\t\t\tdeterminer = 'must not be';\r\n\t\t\texpected = expected.replace(/^not /, '');\r\n\t\t} else {\r\n\t\t\tdeterminer = 'must be';\r\n\t\t}\r\n\r\n\t\tconst type = name.indexOf('.') !== -1 ? 'property' : 'argument';\r\n\t\tlet msg = `The \"${name}\" ${type} ${determiner} of type ${expected}`;\r\n\r\n\t\tmsg += `. Received type ${typeof actual}`;\r\n\t\tsuper(msg);\r\n\r\n\t\tthis.code = 'ERR_INVALID_ARG_TYPE';\r\n\t}\r\n}\r\n\r\nfunction validateString(value: string, name: string) {\r\n\tif (typeof value !== 'string') {\r\n\t\tthrow new ErrorInvalidArgType(name, 'string', value);\r\n\t}\r\n}\r\n\r\nfunction isPathSeparator(code: number | undefined) {\r\n\treturn code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;\r\n}\r\n\r\nfunction isPosixPathSeparator(code: number | undefined) {\r\n\treturn code === CHAR_FORWARD_SLASH;\r\n}\r\n\r\nfunction isWindowsDeviceRoot(code: number) {\r\n\treturn code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z ||\r\n\t\tcode >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z;\r\n}\r\n\r\n// Resolves . and .. elements in a path with directory names\r\nfunction normalizeString(path: string, allowAboveRoot: boolean, separator: string, isPathSeparator: (code?: number) => boolean) {\r\n\tlet res = '';\r\n\tlet lastSegmentLength = 0;\r\n\tlet lastSlash = -1;\r\n\tlet dots = 0;\r\n\tlet code = 0;\r\n\tfor (let i = 0; i <= path.length; ++i) {\r\n\t\tif (i < path.length) {\r\n\t\t\tcode = path.charCodeAt(i);\r\n\t\t}\r\n\t\telse if (isPathSeparator(code)) {\r\n\t\t\tbreak;\r\n\t\t}\r\n\t\telse {\r\n\t\t\tcode = CHAR_FORWARD_SLASH;\r\n\t\t}\r\n\r\n\t\tif (isPathSeparator(code)) {\r\n\t\t\tif (lastSlash === i - 1 || dots === 1) {\r\n\t\t\t\t// NOOP\r\n\t\t\t} else if (dots === 2) {\r\n\t\t\t\tif (res.length < 2 || lastSegmentLength !== 2 ||\r\n\t\t\t\t\tres.charCodeAt(res.length - 1) !== CHAR_DOT ||\r\n\t\t\t\t\tres.charCodeAt(res.length - 2) !== CHAR_DOT) {\r\n\t\t\t\t\tif (res.length > 2) {\r\n\t\t\t\t\t\tconst lastSlashIndex = res.lastIndexOf(separator);\r\n\t\t\t\t\t\tif (lastSlashIndex === -1) {\r\n\t\t\t\t\t\t\tres = '';\r\n\t\t\t\t\t\t\tlastSegmentLength = 0;\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tres = res.slice(0, lastSlashIndex);\r\n\t\t\t\t\t\t\tlastSegmentLength = res.length - 1 - res.lastIndexOf(separator);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tlastSlash = i;\r\n\t\t\t\t\t\tdots = 0;\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t} else if (res.length !== 0) {\r\n\t\t\t\t\t\tres = '';\r\n\t\t\t\t\t\tlastSegmentLength = 0;\r\n\t\t\t\t\t\tlastSlash = i;\r\n\t\t\t\t\t\tdots = 0;\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tif (allowAboveRoot) {\r\n\t\t\t\t\tres += res.length > 0 ? `${separator}..` : '..';\r\n\t\t\t\t\tlastSegmentLength = 2;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tif (res.length > 0) {\r\n\t\t\t\t\tres += `${separator}${path.slice(lastSlash + 1, i)}`;\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\tres = path.slice(lastSlash + 1, i);\r\n\t\t\t\t}\r\n\t\t\t\tlastSegmentLength = i - lastSlash - 1;\r\n\t\t\t}\r\n\t\t\tlastSlash = i;\r\n\t\t\tdots = 0;\r\n\t\t} else if (code === CHAR_DOT && dots !== -1) {\r\n\t\t\t++dots;\r\n\t\t} else {\r\n\t\t\tdots = -1;\r\n\t\t}\r\n\t}\r\n\treturn res;\r\n}\r\n\r\nfunction _format(sep: string, pathObject: ParsedPath) {\r\n\tif (pathObject === null || typeof pathObject !== 'object') {\r\n\t\tthrow new ErrorInvalidArgType('pathObject', 'Object', pathObject);\r\n\t}\r\n\tconst dir = pathObject.dir || pathObject.root;\r\n\tconst base = pathObject.base ||\r\n\t\t`${pathObject.name || ''}${pathObject.ext || ''}`;\r\n\tif (!dir) {\r\n\t\treturn base;\r\n\t}\r\n\treturn dir === pathObject.root ? `${dir}${base}` : `${dir}${sep}${base}`;\r\n}\r\n\r\nexport interface ParsedPath {\r\n\troot: string;\r\n\tdir: string;\r\n\tbase: string;\r\n\text: string;\r\n\tname: string;\r\n}\r\n\r\nexport interface IPath {\r\n\tnormalize(path: string): string;\r\n\tisAbsolute(path: string): boolean;\r\n\tjoin(...paths: string[]): string;\r\n\tresolve(...pathSegments: string[]): string;\r\n\trelative(from: string, to: string): string;\r\n\tdirname(path: string): string;\r\n\tbasename(path: string, ext?: string): string;\r\n\textname(path: string): string;\r\n\tformat(pathObject: ParsedPath): string;\r\n\tparse(path: string): ParsedPath;\r\n\ttoNamespacedPath(path: string): string;\r\n\tsep: '\\\\' | '/';\r\n\tdelimiter: string;\r\n\twin32: IPath | null;\r\n\tposix: IPath | null;\r\n}\r\n\r\nexport const win32: IPath = {\r\n\t// path.resolve([from ...], to)\r\n\tresolve(...pathSegments: string[]): string {\r\n\t\tlet resolvedDevice = '';\r\n\t\tlet resolvedTail = '';\r\n\t\tlet resolvedAbsolute = false;\r\n\r\n\t\tfor (let i = pathSegments.length - 1; i >= -1; i--) {\r\n\t\t\tlet path;\r\n\t\t\tif (i >= 0) {\r\n\t\t\t\tpath = pathSegments[i];\r\n\t\t\t\tvalidateString(path, 'path');\r\n\r\n\t\t\t\t// Skip empty entries\r\n\t\t\t\tif (path.length === 0) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t} else if (resolvedDevice.length === 0) {\r\n\t\t\t\tpath = process.cwd();\r\n\t\t\t} else {\r\n\t\t\t\t// Windows has the concept of drive-specific current working\r\n\t\t\t\t// directories. If we've resolved a drive letter but not yet an\r\n\t\t\t\t// absolute path, get cwd for that drive, or the process cwd if\r\n\t\t\t\t// the drive cwd is not available. We're sure the device is not\r\n\t\t\t\t// a UNC path at this points, because UNC paths are always absolute.\r\n\t\t\t\tpath = process.env[`=${resolvedDevice}`] || process.cwd();\r\n\r\n\t\t\t\t// Verify that a cwd was found and that it actually points\r\n\t\t\t\t// to our drive. If not, default to the drive's root.\r\n\t\t\t\tif (path === undefined ||\r\n\t\t\t\t\tpath.slice(0, 2).toLowerCase() !== resolvedDevice.toLowerCase() &&\r\n\t\t\t\t\tpath.charCodeAt(2) === CHAR_BACKWARD_SLASH) {\r\n\t\t\t\t\tpath = `${resolvedDevice}\\\\`;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tconst len = path.length;\r\n\t\t\tlet rootEnd = 0;\r\n\t\t\tlet device = '';\r\n\t\t\tlet isAbsolute = false;\r\n\t\t\tconst code = path.charCodeAt(0);\r\n\r\n\t\t\t// Try to match a root\r\n\t\t\tif (len === 1) {\r\n\t\t\t\tif (isPathSeparator(code)) {\r\n\t\t\t\t\t// `path` contains just a path separator\r\n\t\t\t\t\trootEnd = 1;\r\n\t\t\t\t\tisAbsolute = true;\r\n\t\t\t\t}\r\n\t\t\t} else if (isPathSeparator(code)) {\r\n\t\t\t\t// Possible UNC root\r\n\r\n\t\t\t\t// If we started with a separator, we know we at least have an\r\n\t\t\t\t// absolute path of some kind (UNC or otherwise)\r\n\t\t\t\tisAbsolute = true;\r\n\r\n\t\t\t\tif (isPathSeparator(path.charCodeAt(1))) {\r\n\t\t\t\t\t// Matched double path separator at beginning\r\n\t\t\t\t\tlet j = 2;\r\n\t\t\t\t\tlet last = j;\r\n\t\t\t\t\t// Match 1 or more non-path separators\r\n\t\t\t\t\twhile (j < len && !isPathSeparator(path.charCodeAt(j))) {\r\n\t\t\t\t\t\tj++;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (j < len && j !== last) {\r\n\t\t\t\t\t\tconst firstPart = path.slice(last, j);\r\n\t\t\t\t\t\t// Matched!\r\n\t\t\t\t\t\tlast = j;\r\n\t\t\t\t\t\t// Match 1 or more path separators\r\n\t\t\t\t\t\twhile (j < len && isPathSeparator(path.charCodeAt(j))) {\r\n\t\t\t\t\t\t\tj++;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (j < len && j !== last) {\r\n\t\t\t\t\t\t\t// Matched!\r\n\t\t\t\t\t\t\tlast = j;\r\n\t\t\t\t\t\t\t// Match 1 or more non-path separators\r\n\t\t\t\t\t\t\twhile (j < len && !isPathSeparator(path.charCodeAt(j))) {\r\n\t\t\t\t\t\t\t\tj++;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tif (j === len || j !== last) {\r\n\t\t\t\t\t\t\t\t// We matched a UNC root\r\n\t\t\t\t\t\t\t\tdevice = `\\\\\\\\${firstPart}\\\\${path.slice(last, j)}`;\r\n\t\t\t\t\t\t\t\trootEnd = j;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\trootEnd = 1;\r\n\t\t\t\t}\r\n\t\t\t} else if (isWindowsDeviceRoot(code) &&\r\n\t\t\t\tpath.charCodeAt(1) === CHAR_COLON) {\r\n\t\t\t\t// Possible device root\r\n\t\t\t\tdevice = path.slice(0, 2);\r\n\t\t\t\trootEnd = 2;\r\n\t\t\t\tif (len > 2 && isPathSeparator(path.charCodeAt(2))) {\r\n\t\t\t\t\t// Treat separator following drive name as an absolute path\r\n\t\t\t\t\t// indicator\r\n\t\t\t\t\tisAbsolute = true;\r\n\t\t\t\t\trootEnd = 3;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (device.length > 0) {\r\n\t\t\t\tif (resolvedDevice.length > 0) {\r\n\t\t\t\t\tif (device.toLowerCase() !== resolvedDevice.toLowerCase()) {\r\n\t\t\t\t\t\t// This path points to another device so it is not applicable\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tresolvedDevice = device;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (resolvedAbsolute) {\r\n\t\t\t\tif (resolvedDevice.length > 0) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tresolvedTail = `${path.slice(rootEnd)}\\\\${resolvedTail}`;\r\n\t\t\t\tresolvedAbsolute = isAbsolute;\r\n\t\t\t\tif (isAbsolute && resolvedDevice.length > 0) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// At this point the path should be resolved to a full absolute path,\r\n\t\t// but handle relative paths to be safe (might happen when process.cwd()\r\n\t\t// fails)\r\n\r\n\t\t// Normalize the tail path\r\n\t\tresolvedTail = normalizeString(resolvedTail, !resolvedAbsolute, '\\\\',\r\n\t\t\tisPathSeparator);\r\n\r\n\t\treturn resolvedAbsolute ?\r\n\t\t\t`${resolvedDevice}\\\\${resolvedTail}` :\r\n\t\t\t`${resolvedDevice}${resolvedTail}` || '.';\r\n\t},\r\n\r\n\tnormalize(path: string): string {\r\n\t\tvalidateString(path, 'path');\r\n\t\tconst len = path.length;\r\n\t\tif (len === 0) {\r\n\t\t\treturn '.';\r\n\t\t}\r\n\t\tlet rootEnd = 0;\r\n\t\tlet device;\r\n\t\tlet isAbsolute = false;\r\n\t\tconst code = path.charCodeAt(0);\r\n\r\n\t\t// Try to match a root\r\n\t\tif (len === 1) {\r\n\t\t\t// `path` contains just a single char, exit early to avoid\r\n\t\t\t// unnecessary work\r\n\t\t\treturn isPosixPathSeparator(code) ? '\\\\' : path;\r\n\t\t}\r\n\t\tif (isPathSeparator(code)) {\r\n\t\t\t// Possible UNC root\r\n\r\n\t\t\t// If we started with a separator, we know we at least have an absolute\r\n\t\t\t// path of some kind (UNC or otherwise)\r\n\t\t\tisAbsolute = true;\r\n\r\n\t\t\tif (isPathSeparator(path.charCodeAt(1))) {\r\n\t\t\t\t// Matched double path separator at beginning\r\n\t\t\t\tlet j = 2;\r\n\t\t\t\tlet last = j;\r\n\t\t\t\t// Match 1 or more non-path separators\r\n\t\t\t\twhile (j < len && !isPathSeparator(path.charCodeAt(j))) {\r\n\t\t\t\t\tj++;\r\n\t\t\t\t}\r\n\t\t\t\tif (j < len && j !== last) {\r\n\t\t\t\t\tconst firstPart = path.slice(last, j);\r\n\t\t\t\t\t// Matched!\r\n\t\t\t\t\tlast = j;\r\n\t\t\t\t\t// Match 1 or more path separators\r\n\t\t\t\t\twhile (j < len && isPathSeparator(path.charCodeAt(j))) {\r\n\t\t\t\t\t\tj++;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (j < len && j !== last) {\r\n\t\t\t\t\t\t// Matched!\r\n\t\t\t\t\t\tlast = j;\r\n\t\t\t\t\t\t// Match 1 or more non-path separators\r\n\t\t\t\t\t\twhile (j < len && !isPathSeparator(path.charCodeAt(j))) {\r\n\t\t\t\t\t\t\tj++;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (j === len) {\r\n\t\t\t\t\t\t\t// We matched a UNC root only\r\n\t\t\t\t\t\t\t// Return the normalized version of the UNC root since there\r\n\t\t\t\t\t\t\t// is nothing left to process\r\n\t\t\t\t\t\t\treturn `\\\\\\\\${firstPart}\\\\${path.slice(last)}\\\\`;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (j !== last) {\r\n\t\t\t\t\t\t\t// We matched a UNC root with leftovers\r\n\t\t\t\t\t\t\tdevice = `\\\\\\\\${firstPart}\\\\${path.slice(last, j)}`;\r\n\t\t\t\t\t\t\trootEnd = j;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\trootEnd = 1;\r\n\t\t\t}\r\n\t\t} else if (isWindowsDeviceRoot(code) && path.charCodeAt(1) === CHAR_COLON) {\r\n\t\t\t// Possible device root\r\n\t\t\tdevice = path.slice(0, 2);\r\n\t\t\trootEnd = 2;\r\n\t\t\tif (len > 2 && isPathSeparator(path.charCodeAt(2))) {\r\n\t\t\t\t// Treat separator following drive name as an absolute path\r\n\t\t\t\t// indicator\r\n\t\t\t\tisAbsolute = true;\r\n\t\t\t\trootEnd = 3;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet tail = rootEnd < len ?\r\n\t\t\tnormalizeString(path.slice(rootEnd), !isAbsolute, '\\\\', isPathSeparator) :\r\n\t\t\t'';\r\n\t\tif (tail.length === 0 && !isAbsolute) {\r\n\t\t\ttail = '.';\r\n\t\t}\r\n\t\tif (tail.length > 0 && isPathSeparator(path.charCodeAt(len - 1))) {\r\n\t\t\ttail += '\\\\';\r\n\t\t}\r\n\t\tif (device === undefined) {\r\n\t\t\treturn isAbsolute ? `\\\\${tail}` : tail;\r\n\t\t}\r\n\t\treturn isAbsolute ? `${device}\\\\${tail}` : `${device}${tail}`;\r\n\t},\r\n\r\n\tisAbsolute(path: string): boolean {\r\n\t\tvalidateString(path, 'path');\r\n\t\tconst len = path.length;\r\n\t\tif (len === 0) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tconst code = path.charCodeAt(0);\r\n\t\treturn isPathSeparator(code) ||\r\n\t\t\t// Possible device root\r\n\t\t\tlen > 2 &&\r\n\t\t\tisWindowsDeviceRoot(code) &&\r\n\t\t\tpath.charCodeAt(1) === CHAR_COLON &&\r\n\t\t\tisPathSeparator(path.charCodeAt(2));\r\n\t},\r\n\r\n\tjoin(...paths: string[]): string {\r\n\t\tif (paths.length === 0) {\r\n\t\t\treturn '.';\r\n\t\t}\r\n\r\n\t\tlet joined;\r\n\t\tlet firstPart: string | undefined;\r\n\t\tfor (let i = 0; i < paths.length; ++i) {\r\n\t\t\tconst arg = paths[i];\r\n\t\t\tvalidateString(arg, 'path');\r\n\t\t\tif (arg.length > 0) {\r\n\t\t\t\tif (joined === undefined) {\r\n\t\t\t\t\tjoined = firstPart = arg;\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\tjoined += `\\\\${arg}`;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (joined === undefined) {\r\n\t\t\treturn '.';\r\n\t\t}\r\n\r\n\t\t// Make sure that the joined path doesn't start with two slashes, because\r\n\t\t// normalize() will mistake it for an UNC path then.\r\n\t\t//\r\n\t\t// This step is skipped when it is very clear that the user actually\r\n\t\t// intended to point at an UNC path. This is assumed when the first\r\n\t\t// non-empty string arguments starts with exactly two slashes followed by\r\n\t\t// at least one more non-slash character.\r\n\t\t//\r\n\t\t// Note that for normalize() to treat a path as an UNC path it needs to\r\n\t\t// have at least 2 components, so we don't filter for that here.\r\n\t\t// This means that the user can use join to construct UNC paths from\r\n\t\t// a server name and a share name; for example:\r\n\t\t// path.join('//server', 'share') -> '\\\\\\\\server\\\\share\\\\')\r\n\t\tlet needsReplace = true;\r\n\t\tlet slashCount = 0;\r\n\t\tif (typeof firstPart === 'string' && isPathSeparator(firstPart.charCodeAt(0))) {\r\n\t\t\t++slashCount;\r\n\t\t\tconst firstLen = firstPart.length;\r\n\t\t\tif (firstLen > 1 && isPathSeparator(firstPart.charCodeAt(1))) {\r\n\t\t\t\t++slashCount;\r\n\t\t\t\tif (firstLen > 2) {\r\n\t\t\t\t\tif (isPathSeparator(firstPart.charCodeAt(2))) {\r\n\t\t\t\t\t\t++slashCount;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t// We matched a UNC path in the first part\r\n\t\t\t\t\t\tneedsReplace = false;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (needsReplace) {\r\n\t\t\t// Find any more consecutive slashes we need to replace\r\n\t\t\twhile (slashCount < joined.length &&\r\n\t\t\t\tisPathSeparator(joined.charCodeAt(slashCount))) {\r\n\t\t\t\tslashCount++;\r\n\t\t\t}\r\n\r\n\t\t\t// Replace the slashes if needed\r\n\t\t\tif (slashCount >= 2) {\r\n\t\t\t\tjoined = `\\\\${joined.slice(slashCount)}`;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn win32.normalize(joined);\r\n\t},\r\n\r\n\r\n\t// It will solve the relative path from `from` to `to`, for instance:\r\n\t// from = 'C:\\\\orandea\\\\test\\\\aaa'\r\n\t// to = 'C:\\\\orandea\\\\impl\\\\bbb'\r\n\t// The output of the function should be: '..\\\\..\\\\impl\\\\bbb'\r\n\trelative(from: string, to: string): string {\r\n\t\tvalidateString(from, 'from');\r\n\t\tvalidateString(to, 'to');\r\n\r\n\t\tif (from === to) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\r\n\t\tconst fromOrig = win32.resolve(from);\r\n\t\tconst toOrig = win32.resolve(to);\r\n\r\n\t\tif (fromOrig === toOrig) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\r\n\t\tfrom = fromOrig.toLowerCase();\r\n\t\tto = toOrig.toLowerCase();\r\n\r\n\t\tif (from === to) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\r\n\t\t// Trim any leading backslashes\r\n\t\tlet fromStart = 0;\r\n\t\twhile (fromStart < from.length &&\r\n\t\t\tfrom.charCodeAt(fromStart) === CHAR_BACKWARD_SLASH) {\r\n\t\t\tfromStart++;\r\n\t\t}\r\n\t\t// Trim trailing backslashes (applicable to UNC paths only)\r\n\t\tlet fromEnd = from.length;\r\n\t\twhile (fromEnd - 1 > fromStart &&\r\n\t\t\tfrom.charCodeAt(fromEnd - 1) === CHAR_BACKWARD_SLASH) {\r\n\t\t\tfromEnd--;\r\n\t\t}\r\n\t\tconst fromLen = fromEnd - fromStart;\r\n\r\n\t\t// Trim any leading backslashes\r\n\t\tlet toStart = 0;\r\n\t\twhile (toStart < to.length &&\r\n\t\t\tto.charCodeAt(toStart) === CHAR_BACKWARD_SLASH) {\r\n\t\t\ttoStart++;\r\n\t\t}\r\n\t\t// Trim trailing backslashes (applicable to UNC paths only)\r\n\t\tlet toEnd = to.length;\r\n\t\twhile (toEnd - 1 > toStart &&\r\n\t\t\tto.charCodeAt(toEnd - 1) === CHAR_BACKWARD_SLASH) {\r\n\t\t\ttoEnd--;\r\n\t\t}\r\n\t\tconst toLen = toEnd - toStart;\r\n\r\n\t\t// Compare paths to find the longest common path from root\r\n\t\tconst length = fromLen < toLen ? fromLen : toLen;\r\n\t\tlet lastCommonSep = -1;\r\n\t\tlet i = 0;\r\n\t\tfor (; i < length; i++) {\r\n\t\t\tconst fromCode = from.charCodeAt(fromStart + i);\r\n\t\t\tif (fromCode !== to.charCodeAt(toStart + i)) {\r\n\t\t\t\tbreak;\r\n\t\t\t} else if (fromCode === CHAR_BACKWARD_SLASH) {\r\n\t\t\t\tlastCommonSep = i;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// We found a mismatch before the first common path separator was seen, so\r\n\t\t// return the original `to`.\r\n\t\tif (i !== length) {\r\n\t\t\tif (lastCommonSep === -1) {\r\n\t\t\t\treturn toOrig;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tif (toLen > length) {\r\n\t\t\t\tif (to.charCodeAt(toStart + i) === CHAR_BACKWARD_SLASH) {\r\n\t\t\t\t\t// We get here if `from` is the exact base path for `to`.\r\n\t\t\t\t\t// For example: from='C:\\\\foo\\\\bar'; to='C:\\\\foo\\\\bar\\\\baz'\r\n\t\t\t\t\treturn toOrig.slice(toStart + i + 1);\r\n\t\t\t\t}\r\n\t\t\t\tif (i === 2) {\r\n\t\t\t\t\t// We get here if `from` is the device root.\r\n\t\t\t\t\t// For example: from='C:\\\\'; to='C:\\\\foo'\r\n\t\t\t\t\treturn toOrig.slice(toStart + i);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (fromLen > length) {\r\n\t\t\t\tif (from.charCodeAt(fromStart + i) === CHAR_BACKWARD_SLASH) {\r\n\t\t\t\t\t// We get here if `to` is the exact base path for `from`.\r\n\t\t\t\t\t// For example: from='C:\\\\foo\\\\bar'; to='C:\\\\foo'\r\n\t\t\t\t\tlastCommonSep = i;\r\n\t\t\t\t} else if (i === 2) {\r\n\t\t\t\t\t// We get here if `to` is the device root.\r\n\t\t\t\t\t// For example: from='C:\\\\foo\\\\bar'; to='C:\\\\'\r\n\t\t\t\t\tlastCommonSep = 3;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (lastCommonSep === -1) {\r\n\t\t\t\tlastCommonSep = 0;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet out = '';\r\n\t\t// Generate the relative path based on the path difference between `to` and\r\n\t\t// `from`\r\n\t\tfor (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {\r\n\t\t\tif (i === fromEnd || from.charCodeAt(i) === CHAR_BACKWARD_SLASH) {\r\n\t\t\t\tout += out.length === 0 ? '..' : '\\\\..';\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\ttoStart += lastCommonSep;\r\n\r\n\t\t// Lastly, append the rest of the destination (`to`) path that comes after\r\n\t\t// the common path parts\r\n\t\tif (out.length > 0) {\r\n\t\t\treturn `${out}${toOrig.slice(toStart, toEnd)}`;\r\n\t\t}\r\n\r\n\t\tif (toOrig.charCodeAt(toStart) === CHAR_BACKWARD_SLASH) {\r\n\t\t\t++toStart;\r\n\t\t}\r\n\r\n\t\treturn toOrig.slice(toStart, toEnd);\r\n\t},\r\n\r\n\ttoNamespacedPath(path: string): string {\r\n\t\t// Note: this will *probably* throw somewhere.\r\n\t\tif (typeof path !== 'string') {\r\n\t\t\treturn path;\r\n\t\t}\r\n\r\n\t\tif (path.length === 0) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\r\n\t\tconst resolvedPath = win32.resolve(path);\r\n\r\n\t\tif (resolvedPath.length <= 2) {\r\n\t\t\treturn path;\r\n\t\t}\r\n\r\n\t\tif (resolvedPath.charCodeAt(0) === CHAR_BACKWARD_SLASH) {\r\n\t\t\t// Possible UNC root\r\n\t\t\tif (resolvedPath.charCodeAt(1) === CHAR_BACKWARD_SLASH) {\r\n\t\t\t\tconst code = resolvedPath.charCodeAt(2);\r\n\t\t\t\tif (code !== CHAR_QUESTION_MARK && code !== CHAR_DOT) {\r\n\t\t\t\t\t// Matched non-long UNC root, convert the path to a long UNC path\r\n\t\t\t\t\treturn `\\\\\\\\?\\\\UNC\\\\${resolvedPath.slice(2)}`;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else if (isWindowsDeviceRoot(resolvedPath.charCodeAt(0)) &&\r\n\t\t\tresolvedPath.charCodeAt(1) === CHAR_COLON &&\r\n\t\t\tresolvedPath.charCodeAt(2) === CHAR_BACKWARD_SLASH) {\r\n\t\t\t// Matched device root, convert the path to a long UNC path\r\n\t\t\treturn `\\\\\\\\?\\\\${resolvedPath}`;\r\n\t\t}\r\n\r\n\t\treturn path;\r\n\t},\r\n\r\n\tdirname(path: string): string {\r\n\t\tvalidateString(path, 'path');\r\n\t\tconst len = path.length;\r\n\t\tif (len === 0) {\r\n\t\t\treturn '.';\r\n\t\t}\r\n\t\tlet rootEnd = -1;\r\n\t\tlet offset = 0;\r\n\t\tconst code = path.charCodeAt(0);\r\n\r\n\t\tif (len === 1) {\r\n\t\t\t// `path` contains just a path separator, exit early to avoid\r\n\t\t\t// unnecessary work or a dot.\r\n\t\t\treturn isPathSeparator(code) ? path : '.';\r\n\t\t}\r\n\r\n\t\t// Try to match a root\r\n\t\tif (isPathSeparator(code)) {\r\n\t\t\t// Possible UNC root\r\n\r\n\t\t\trootEnd = offset = 1;\r\n\r\n\t\t\tif (isPathSeparator(path.charCodeAt(1))) {\r\n\t\t\t\t// Matched double path separator at beginning\r\n\t\t\t\tlet j = 2;\r\n\t\t\t\tlet last = j;\r\n\t\t\t\t// Match 1 or more non-path separators\r\n\t\t\t\twhile (j < len && !isPathSeparator(path.charCodeAt(j))) {\r\n\t\t\t\t\tj++;\r\n\t\t\t\t}\r\n\t\t\t\tif (j < len && j !== last) {\r\n\t\t\t\t\t// Matched!\r\n\t\t\t\t\tlast = j;\r\n\t\t\t\t\t// Match 1 or more path separators\r\n\t\t\t\t\twhile (j < len && isPathSeparator(path.charCodeAt(j))) {\r\n\t\t\t\t\t\tj++;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (j < len && j !== last) {\r\n\t\t\t\t\t\t// Matched!\r\n\t\t\t\t\t\tlast = j;\r\n\t\t\t\t\t\t// Match 1 or more non-path separators\r\n\t\t\t\t\t\twhile (j < len && !isPathSeparator(path.charCodeAt(j))) {\r\n\t\t\t\t\t\t\tj++;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (j === len) {\r\n\t\t\t\t\t\t\t// We matched a UNC root only\r\n\t\t\t\t\t\t\treturn path;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (j !== last) {\r\n\t\t\t\t\t\t\t// We matched a UNC root with leftovers\r\n\r\n\t\t\t\t\t\t\t// Offset by 1 to include the separator after the UNC root to\r\n\t\t\t\t\t\t\t// treat it as a \"normal root\" on top of a (UNC) root\r\n\t\t\t\t\t\t\trootEnd = offset = j + 1;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t// Possible device root\r\n\t\t} else if (isWindowsDeviceRoot(code) && path.charCodeAt(1) === CHAR_COLON) {\r\n\t\t\trootEnd = len > 2 && isPathSeparator(path.charCodeAt(2)) ? 3 : 2;\r\n\t\t\toffset = rootEnd;\r\n\t\t}\r\n\r\n\t\tlet end = -1;\r\n\t\tlet matchedSlash = true;\r\n\t\tfor (let i = len - 1; i >= offset; --i) {\r\n\t\t\tif (isPathSeparator(path.charCodeAt(i))) {\r\n\t\t\t\tif (!matchedSlash) {\r\n\t\t\t\t\tend = i;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\t// We saw the first non-path separator\r\n\t\t\t\tmatchedSlash = false;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (end === -1) {\r\n\t\t\tif (rootEnd === -1) {\r\n\t\t\t\treturn '.';\r\n\t\t\t}\r\n\r\n\t\t\tend = rootEnd;\r\n\t\t}\r\n\t\treturn path.slice(0, end);\r\n\t},\r\n\r\n\tbasename(path: string, ext?: string): string {\r\n\t\tif (ext !== undefined) {\r\n\t\t\tvalidateString(ext, 'ext');\r\n\t\t}\r\n\t\tvalidateString(path, 'path');\r\n\t\tlet start = 0;\r\n\t\tlet end = -1;\r\n\t\tlet matchedSlash = true;\r\n\t\tlet i;\r\n\r\n\t\t// Check for a drive letter prefix so as not to mistake the following\r\n\t\t// path separator as an extra separator at the end of the path that can be\r\n\t\t// disregarded\r\n\t\tif (path.length >= 2 &&\r\n\t\t\tisWindowsDeviceRoot(path.charCodeAt(0)) &&\r\n\t\t\tpath.charCodeAt(1) === CHAR_COLON) {\r\n\t\t\tstart = 2;\r\n\t\t}\r\n\r\n\t\tif (ext !== undefined && ext.length > 0 && ext.length <= path.length) {\r\n\t\t\tif (ext === path) {\r\n\t\t\t\treturn '';\r\n\t\t\t}\r\n\t\t\tlet extIdx = ext.length - 1;\r\n\t\t\tlet firstNonSlashEnd = -1;\r\n\t\t\tfor (i = path.length - 1; i >= start; --i) {\r\n\t\t\t\tconst code = path.charCodeAt(i);\r\n\t\t\t\tif (isPathSeparator(code)) {\r\n\t\t\t\t\t// If we reached a path separator that was not part of a set of path\r\n\t\t\t\t\t// separators at the end of the string, stop now\r\n\t\t\t\t\tif (!matchedSlash) {\r\n\t\t\t\t\t\tstart = i + 1;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tif (firstNonSlashEnd === -1) {\r\n\t\t\t\t\t\t// We saw the first non-path separator, remember this index in case\r\n\t\t\t\t\t\t// we need it if the extension ends up not matching\r\n\t\t\t\t\t\tmatchedSlash = false;\r\n\t\t\t\t\t\tfirstNonSlashEnd = i + 1;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (extIdx >= 0) {\r\n\t\t\t\t\t\t// Try to match the explicit extension\r\n\t\t\t\t\t\tif (code === ext.charCodeAt(extIdx)) {\r\n\t\t\t\t\t\t\tif (--extIdx === -1) {\r\n\t\t\t\t\t\t\t\t// We matched the extension, so mark this as the end of our path\r\n\t\t\t\t\t\t\t\t// component\r\n\t\t\t\t\t\t\t\tend = i;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t// Extension does not match, so our result is the entire path\r\n\t\t\t\t\t\t\t// component\r\n\t\t\t\t\t\t\textIdx = -1;\r\n\t\t\t\t\t\t\tend = firstNonSlashEnd;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (start === end) {\r\n\t\t\t\tend = firstNonSlashEnd;\r\n\t\t\t} else if (end === -1) {\r\n\t\t\t\tend = path.length;\r\n\t\t\t}\r\n\t\t\treturn path.slice(start, end);\r\n\t\t}\r\n\t\tfor (i = path.length - 1; i >= start; --i) {\r\n\t\t\tif (isPathSeparator(path.charCodeAt(i))) {\r\n\t\t\t\t// If we reached a path separator that was not part of a set of path\r\n\t\t\t\t// separators at the end of the string, stop now\r\n\t\t\t\tif (!matchedSlash) {\r\n\t\t\t\t\tstart = i + 1;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t} else if (end === -1) {\r\n\t\t\t\t// We saw the first non-path separator, mark this as the end of our\r\n\t\t\t\t// path component\r\n\t\t\t\tmatchedSlash = false;\r\n\t\t\t\tend = i + 1;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (end === -1) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\treturn path.slice(start, end);\r\n\t},\r\n\r\n\textname(path: string): string {\r\n\t\tvalidateString(path, 'path');\r\n\t\tlet start = 0;\r\n\t\tlet startDot = -1;\r\n\t\tlet startPart = 0;\r\n\t\tlet end = -1;\r\n\t\tlet matchedSlash = true;\r\n\t\t// Track the state of characters (if any) we see before our first dot and\r\n\t\t// after any path separator we find\r\n\t\tlet preDotState = 0;\r\n\r\n\t\t// Check for a drive letter prefix so as not to mistake the following\r\n\t\t// path separator as an extra separator at the end of the path that can be\r\n\t\t// disregarded\r\n\r\n\t\tif (path.length >= 2 &&\r\n\t\t\tpath.charCodeAt(1) === CHAR_COLON &&\r\n\t\t\tisWindowsDeviceRoot(path.charCodeAt(0))) {\r\n\t\t\tstart = startPart = 2;\r\n\t\t}\r\n\r\n\t\tfor (let i = path.length - 1; i >= start; --i) {\r\n\t\t\tconst code = path.charCodeAt(i);\r\n\t\t\tif (isPathSeparator(code)) {\r\n\t\t\t\t// If we reached a path separator that was not part of a set of path\r\n\t\t\t\t// separators at the end of the string, stop now\r\n\t\t\t\tif (!matchedSlash) {\r\n\t\t\t\t\tstartPart = i + 1;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (end === -1) {\r\n\t\t\t\t// We saw the first non-path separator, mark this as the end of our\r\n\t\t\t\t// extension\r\n\t\t\t\tmatchedSlash = false;\r\n\t\t\t\tend = i + 1;\r\n\t\t\t}\r\n\t\t\tif (code === CHAR_DOT) {\r\n\t\t\t\t// If this is our first dot, mark it as the start of our extension\r\n\t\t\t\tif (startDot === -1) {\r\n\t\t\t\t\tstartDot = i;\r\n\t\t\t\t}\r\n\t\t\t\telse if (preDotState !== 1) {\r\n\t\t\t\t\tpreDotState = 1;\r\n\t\t\t\t}\r\n\t\t\t} else if (startDot !== -1) {\r\n\t\t\t\t// We saw a non-dot and non-path separator before our dot, so we should\r\n\t\t\t\t// have a good chance at having a non-empty extension\r\n\t\t\t\tpreDotState = -1;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (startDot === -1 ||\r\n\t\t\tend === -1 ||\r\n\t\t\t// We saw a non-dot character immediately before the dot\r\n\t\t\tpreDotState === 0 ||\r\n\t\t\t// The (right-most) trimmed path component is exactly '..'\r\n\t\t\t(preDotState === 1 &&\r\n\t\t\t\tstartDot === end - 1 &&\r\n\t\t\t\tstartDot === startPart + 1)) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\treturn path.slice(startDot, end);\r\n\t},\r\n\r\n\tformat: _format.bind(null, '\\\\'),\r\n\r\n\tparse(path) {\r\n\t\tvalidateString(path, 'path');\r\n\r\n\t\tconst ret = { root: '', dir: '', base: '', ext: '', name: '' };\r\n\t\tif (path.length === 0) {\r\n\t\t\treturn ret;\r\n\t\t}\r\n\r\n\t\tconst len = path.length;\r\n\t\tlet rootEnd = 0;\r\n\t\tlet code = path.charCodeAt(0);\r\n\r\n\t\tif (len === 1) {\r\n\t\t\tif (isPathSeparator(code)) {\r\n\t\t\t\t// `path` contains just a path separator, exit early to avoid\r\n\t\t\t\t// unnecessary work\r\n\t\t\t\tret.root = ret.dir = path;\r\n\t\t\t\treturn ret;\r\n\t\t\t}\r\n\t\t\tret.base = ret.name = path;\r\n\t\t\treturn ret;\r\n\t\t}\r\n\t\t// Try to match a root\r\n\t\tif (isPathSeparator(code)) {\r\n\t\t\t// Possible UNC root\r\n\r\n\t\t\trootEnd = 1;\r\n\t\t\tif (isPathSeparator(path.charCodeAt(1))) {\r\n\t\t\t\t// Matched double path separator at beginning\r\n\t\t\t\tlet j = 2;\r\n\t\t\t\tlet last = j;\r\n\t\t\t\t// Match 1 or more non-path separators\r\n\t\t\t\twhile (j < len && !isPathSeparator(path.charCodeAt(j))) {\r\n\t\t\t\t\tj++;\r\n\t\t\t\t}\r\n\t\t\t\tif (j < len && j !== last) {\r\n\t\t\t\t\t// Matched!\r\n\t\t\t\t\tlast = j;\r\n\t\t\t\t\t// Match 1 or more path separators\r\n\t\t\t\t\twhile (j < len && isPathSeparator(path.charCodeAt(j))) {\r\n\t\t\t\t\t\tj++;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (j < len && j !== last) {\r\n\t\t\t\t\t\t// Matched!\r\n\t\t\t\t\t\tlast = j;\r\n\t\t\t\t\t\t// Match 1 or more non-path separators\r\n\t\t\t\t\t\twhile (j < len && !isPathSeparator(path.charCodeAt(j))) {\r\n\t\t\t\t\t\t\tj++;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (j === len) {\r\n\t\t\t\t\t\t\t// We matched a UNC root only\r\n\t\t\t\t\t\t\trootEnd = j;\r\n\t\t\t\t\t\t} else if (j !== last) {\r\n\t\t\t\t\t\t\t// We matched a UNC root with leftovers\r\n\t\t\t\t\t\t\trootEnd = j + 1;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else if (isWindowsDeviceRoot(code) && path.charCodeAt(1) === CHAR_COLON) {\r\n\t\t\t// Possible device root\r\n\t\t\tif (len <= 2) {\r\n\t\t\t\t// `path` contains just a drive root, exit early to avoid\r\n\t\t\t\t// unnecessary work\r\n\t\t\t\tret.root = ret.dir = path;\r\n\t\t\t\treturn ret;\r\n\t\t\t}\r\n\t\t\trootEnd = 2;\r\n\t\t\tif (isPathSeparator(path.charCodeAt(2))) {\r\n\t\t\t\tif (len === 3) {\r\n\t\t\t\t\t// `path` contains just a drive root, exit early to avoid\r\n\t\t\t\t\t// unnecessary work\r\n\t\t\t\t\tret.root = ret.dir = path;\r\n\t\t\t\t\treturn ret;\r\n\t\t\t\t}\r\n\t\t\t\trootEnd = 3;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (rootEnd > 0) {\r\n\t\t\tret.root = path.slice(0, rootEnd);\r\n\t\t}\r\n\r\n\t\tlet startDot = -1;\r\n\t\tlet startPart = rootEnd;\r\n\t\tlet end = -1;\r\n\t\tlet matchedSlash = true;\r\n\t\tlet i = path.length - 1;\r\n\r\n\t\t// Track the state of characters (if any) we see before our first dot and\r\n\t\t// after any path separator we find\r\n\t\tlet preDotState = 0;\r\n\r\n\t\t// Get non-dir info\r\n\t\tfor (; i >= rootEnd; --i) {\r\n\t\t\tcode = path.charCodeAt(i);\r\n\t\t\tif (isPathSeparator(code)) {\r\n\t\t\t\t// If we reached a path separator that was not part of a set of path\r\n\t\t\t\t// separators at the end of the string, stop now\r\n\t\t\t\tif (!matchedSlash) {\r\n\t\t\t\t\tstartPart = i + 1;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (end === -1) {\r\n\t\t\t\t// We saw the first non-path separator, mark this as the end of our\r\n\t\t\t\t// extension\r\n\t\t\t\tmatchedSlash = false;\r\n\t\t\t\tend = i + 1;\r\n\t\t\t}\r\n\t\t\tif (code === CHAR_DOT) {\r\n\t\t\t\t// If this is our first dot, mark it as the start of our extension\r\n\t\t\t\tif (startDot === -1) {\r\n\t\t\t\t\tstartDot = i;\r\n\t\t\t\t} else if (preDotState !== 1) {\r\n\t\t\t\t\tpreDotState = 1;\r\n\t\t\t\t}\r\n\t\t\t} else if (startDot !== -1) {\r\n\t\t\t\t// We saw a non-dot and non-path separator before our dot, so we should\r\n\t\t\t\t// have a good chance at having a non-empty extension\r\n\t\t\t\tpreDotState = -1;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (end !== -1) {\r\n\t\t\tif (startDot === -1 ||\r\n\t\t\t\t// We saw a non-dot character immediately before the dot\r\n\t\t\t\tpreDotState === 0 ||\r\n\t\t\t\t// The (right-most) trimmed path component is exactly '..'\r\n\t\t\t\t(preDotState === 1 &&\r\n\t\t\t\t\tstartDot === end - 1 &&\r\n\t\t\t\t\tstartDot === startPart + 1)) {\r\n\t\t\t\tret.base = ret.name = path.slice(startPart, end);\r\n\t\t\t} else {\r\n\t\t\t\tret.name = path.slice(startPart, startDot);\r\n\t\t\t\tret.base = path.slice(startPart, end);\r\n\t\t\t\tret.ext = path.slice(startDot, end);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// If the directory is the root, use the entire root as the `dir` including\r\n\t\t// the trailing slash if any (`C:\\abc` -> `C:\\`). Otherwise, strip out the\r\n\t\t// trailing slash (`C:\\abc\\def` -> `C:\\abc`).\r\n\t\tif (startPart > 0 && startPart !== rootEnd) {\r\n\t\t\tret.dir = path.slice(0, startPart - 1);\r\n\t\t} else {\r\n\t\t\tret.dir = ret.root;\r\n\t\t}\r\n\r\n\t\treturn ret;\r\n\t},\r\n\r\n\tsep: '\\\\',\r\n\tdelimiter: ';',\r\n\twin32: null,\r\n\tposix: null\r\n};\r\n\r\nexport const posix: IPath = {\r\n\t// path.resolve([from ...], to)\r\n\tresolve(...pathSegments: string[]): string {\r\n\t\tlet resolvedPath = '';\r\n\t\tlet resolvedAbsolute = false;\r\n\r\n\t\tfor (let i = pathSegments.length - 1; i >= -1 && !resolvedAbsolute; i--) {\r\n\t\t\tconst path = i >= 0 ? pathSegments[i] : process.cwd();\r\n\r\n\t\t\tvalidateString(path, 'path');\r\n\r\n\t\t\t// Skip empty entries\r\n\t\t\tif (path.length === 0) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tresolvedPath = `${path}/${resolvedPath}`;\r\n\t\t\tresolvedAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH;\r\n\t\t}\r\n\r\n\t\t// At this point the path should be resolved to a full absolute path, but\r\n\t\t// handle relative paths to be safe (might happen when process.cwd() fails)\r\n\r\n\t\t// Normalize the path\r\n\t\tresolvedPath = normalizeString(resolvedPath, !resolvedAbsolute, '/',\r\n\t\t\tisPosixPathSeparator);\r\n\r\n\t\tif (resolvedAbsolute) {\r\n\t\t\treturn `/${resolvedPath}`;\r\n\t\t}\r\n\t\treturn resolvedPath.length > 0 ? resolvedPath : '.';\r\n\t},\r\n\r\n\tnormalize(path: string): string {\r\n\t\tvalidateString(path, 'path');\r\n\r\n\t\tif (path.length === 0) {\r\n\t\t\treturn '.';\r\n\t\t}\r\n\r\n\t\tconst isAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH;\r\n\t\tconst trailingSeparator =\r\n\t\t\tpath.charCodeAt(path.length - 1) === CHAR_FORWARD_SLASH;\r\n\r\n\t\t// Normalize the path\r\n\t\tpath = normalizeString(path, !isAbsolute, '/', isPosixPathSeparator);\r\n\r\n\t\tif (path.length === 0) {\r\n\t\t\tif (isAbsolute) {\r\n\t\t\t\treturn '/';\r\n\t\t\t}\r\n\t\t\treturn trailingSeparator ? './' : '.';\r\n\t\t}\r\n\t\tif (trailingSeparator) {\r\n\t\t\tpath += '/';\r\n\t\t}\r\n\r\n\t\treturn isAbsolute ? `/${path}` : path;\r\n\t},\r\n\r\n\tisAbsolute(path: string): boolean {\r\n\t\tvalidateString(path, 'path');\r\n\t\treturn path.length > 0 && path.charCodeAt(0) === CHAR_FORWARD_SLASH;\r\n\t},\r\n\r\n\tjoin(...paths: string[]): string {\r\n\t\tif (paths.length === 0) {\r\n\t\t\treturn '.';\r\n\t\t}\r\n\t\tlet joined;\r\n\t\tfor (let i = 0; i < paths.length; ++i) {\r\n\t\t\tconst arg = paths[i];\r\n\t\t\tvalidateString(arg, 'path');\r\n\t\t\tif (arg.length > 0) {\r\n\t\t\t\tif (joined === undefined) {\r\n\t\t\t\t\tjoined = arg;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tjoined += `/${arg}`;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (joined === undefined) {\r\n\t\t\treturn '.';\r\n\t\t}\r\n\t\treturn posix.normalize(joined);\r\n\t},\r\n\r\n\trelative(from: string, to: string): string {\r\n\t\tvalidateString(from, 'from');\r\n\t\tvalidateString(to, 'to');\r\n\r\n\t\tif (from === to) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\r\n\t\t// Trim leading forward slashes.\r\n\t\tfrom = posix.resolve(from);\r\n\t\tto = posix.resolve(to);\r\n\r\n\t\tif (from === to) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\r\n\t\tconst fromStart = 1;\r\n\t\tconst fromEnd = from.length;\r\n\t\tconst fromLen = fromEnd - fromStart;\r\n\t\tconst toStart = 1;\r\n\t\tconst toLen = to.length - toStart;\r\n\r\n\t\t// Compare paths to find the longest common path from root\r\n\t\tconst length = (fromLen < toLen ? fromLen : toLen);\r\n\t\tlet lastCommonSep = -1;\r\n\t\tlet i = 0;\r\n\t\tfor (; i < length; i++) {\r\n\t\t\tconst fromCode = from.charCodeAt(fromStart + i);\r\n\t\t\tif (fromCode !== to.charCodeAt(toStart + i)) {\r\n\t\t\t\tbreak;\r\n\t\t\t} else if (fromCode === CHAR_FORWARD_SLASH) {\r\n\t\t\t\tlastCommonSep = i;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (i === length) {\r\n\t\t\tif (toLen > length) {\r\n\t\t\t\tif (to.charCodeAt(toStart + i) === CHAR_FORWARD_SLASH) {\r\n\t\t\t\t\t// We get here if `from` is the exact base path for `to`.\r\n\t\t\t\t\t// For example: from='/foo/bar'; to='/foo/bar/baz'\r\n\t\t\t\t\treturn to.slice(toStart + i + 1);\r\n\t\t\t\t}\r\n\t\t\t\tif (i === 0) {\r\n\t\t\t\t\t// We get here if `from` is the root\r\n\t\t\t\t\t// For example: from='/'; to='/foo'\r\n\t\t\t\t\treturn to.slice(toStart + i);\r\n\t\t\t\t}\r\n\t\t\t} else if (fromLen > length) {\r\n\t\t\t\tif (from.charCodeAt(fromStart + i) === CHAR_FORWARD_SLASH) {\r\n\t\t\t\t\t// We get here if `to` is the exact base path for `from`.\r\n\t\t\t\t\t// For example: from='/foo/bar/baz'; to='/foo/bar'\r\n\t\t\t\t\tlastCommonSep = i;\r\n\t\t\t\t} else if (i === 0) {\r\n\t\t\t\t\t// We get here if `to` is the root.\r\n\t\t\t\t\t// For example: from='/foo/bar'; to='/'\r\n\t\t\t\t\tlastCommonSep = 0;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet out = '';\r\n\t\t// Generate the relative path based on the path difference between `to`\r\n\t\t// and `from`.\r\n\t\tfor (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {\r\n\t\t\tif (i === fromEnd || from.charCodeAt(i) === CHAR_FORWARD_SLASH) {\r\n\t\t\t\tout += out.length === 0 ? '..' : '/..';\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Lastly, append the rest of the destination (`to`) path that comes after\r\n\t\t// the common path parts.\r\n\t\treturn `${out}${to.slice(toStart + lastCommonSep)}`;\r\n\t},\r\n\r\n\ttoNamespacedPath(path: string): string {\r\n\t\t// Non-op on posix systems\r\n\t\treturn path;\r\n\t},\r\n\r\n\tdirname(path: string): string {\r\n\t\tvalidateString(path, 'path');\r\n\t\tif (path.length === 0) {\r\n\t\t\treturn '.';\r\n\t\t}\r\n\t\tconst hasRoot = path.charCodeAt(0) === CHAR_FORWARD_SLASH;\r\n\t\tlet end = -1;\r\n\t\tlet matchedSlash = true;\r\n\t\tfor (let i = path.length - 1; i >= 1; --i) {\r\n\t\t\tif (path.charCodeAt(i) === CHAR_FORWARD_SLASH) {\r\n\t\t\t\tif (!matchedSlash) {\r\n\t\t\t\t\tend = i;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\t// We saw the first non-path separator\r\n\t\t\t\tmatchedSlash = false;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (end === -1) {\r\n\t\t\treturn hasRoot ? '/' : '.';\r\n\t\t}\r\n\t\tif (hasRoot && end === 1) {\r\n\t\t\treturn '//';\r\n\t\t}\r\n\t\treturn path.slice(0, end);\r\n\t},\r\n\r\n\tbasename(path: string, ext?: string): string {\r\n\t\tif (ext !== undefined) {\r\n\t\t\tvalidateString(ext, 'ext');\r\n\t\t}\r\n\t\tvalidateString(path, 'path');\r\n\r\n\t\tlet start = 0;\r\n\t\tlet end = -1;\r\n\t\tlet matchedSlash = true;\r\n\t\tlet i;\r\n\r\n\t\tif (ext !== undefined && ext.length > 0 && ext.length <= path.length) {\r\n\t\t\tif (ext === path) {\r\n\t\t\t\treturn '';\r\n\t\t\t}\r\n\t\t\tlet extIdx = ext.length - 1;\r\n\t\t\tlet firstNonSlashEnd = -1;\r\n\t\t\tfor (i = path.length - 1; i >= 0; --i) {\r\n\t\t\t\tconst code = path.charCodeAt(i);\r\n\t\t\t\tif (code === CHAR_FORWARD_SLASH) {\r\n\t\t\t\t\t// If we reached a path separator that was not part of a set of path\r\n\t\t\t\t\t// separators at the end of the string, stop now\r\n\t\t\t\t\tif (!matchedSlash) {\r\n\t\t\t\t\t\tstart = i + 1;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tif (firstNonSlashEnd === -1) {\r\n\t\t\t\t\t\t// We saw the first non-path separator, remember this index in case\r\n\t\t\t\t\t\t// we need it if the extension ends up not matching\r\n\t\t\t\t\t\tmatchedSlash = false;\r\n\t\t\t\t\t\tfirstNonSlashEnd = i + 1;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (extIdx >= 0) {\r\n\t\t\t\t\t\t// Try to match the explicit extension\r\n\t\t\t\t\t\tif (code === ext.charCodeAt(extIdx)) {\r\n\t\t\t\t\t\t\tif (--extIdx === -1) {\r\n\t\t\t\t\t\t\t\t// We matched the extension, so mark this as the end of our path\r\n\t\t\t\t\t\t\t\t// component\r\n\t\t\t\t\t\t\t\tend = i;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t// Extension does not match, so our result is the entire path\r\n\t\t\t\t\t\t\t// component\r\n\t\t\t\t\t\t\textIdx = -1;\r\n\t\t\t\t\t\t\tend = firstNonSlashEnd;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (start === end) {\r\n\t\t\t\tend = firstNonSlashEnd;\r\n\t\t\t} else if (end === -1) {\r\n\t\t\t\tend = path.length;\r\n\t\t\t}\r\n\t\t\treturn path.slice(start, end);\r\n\t\t}\r\n\t\tfor (i = path.length - 1; i >= 0; --i) {\r\n\t\t\tif (path.charCodeAt(i) === CHAR_FORWARD_SLASH) {\r\n\t\t\t\t// If we reached a path separator that was not part of a set of path\r\n\t\t\t\t// separators at the end of the string, stop now\r\n\t\t\t\tif (!matchedSlash) {\r\n\t\t\t\t\tstart = i + 1;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t} else if (end === -1) {\r\n\t\t\t\t// We saw the first non-path separator, mark this as the end of our\r\n\t\t\t\t// path component\r\n\t\t\t\tmatchedSlash = false;\r\n\t\t\t\tend = i + 1;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (end === -1) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\treturn path.slice(start, end);\r\n\t},\r\n\r\n\textname(path: string): string {\r\n\t\tvalidateString(path, 'path');\r\n\t\tlet startDot = -1;\r\n\t\tlet startPart = 0;\r\n\t\tlet end = -1;\r\n\t\tlet matchedSlash = true;\r\n\t\t// Track the state of characters (if any) we see before our first dot and\r\n\t\t// after any path separator we find\r\n\t\tlet preDotState = 0;\r\n\t\tfor (let i = path.length - 1; i >= 0; --i) {\r\n\t\t\tconst code = path.charCodeAt(i);\r\n\t\t\tif (code === CHAR_FORWARD_SLASH) {\r\n\t\t\t\t// If we reached a path separator that was not part of a set of path\r\n\t\t\t\t// separators at the end of the string, stop now\r\n\t\t\t\tif (!matchedSlash) {\r\n\t\t\t\t\tstartPart = i + 1;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (end === -1) {\r\n\t\t\t\t// We saw the first non-path separator, mark this as the end of our\r\n\t\t\t\t// extension\r\n\t\t\t\tmatchedSlash = false;\r\n\t\t\t\tend = i + 1;\r\n\t\t\t}\r\n\t\t\tif (code === CHAR_DOT) {\r\n\t\t\t\t// If this is our first dot, mark it as the start of our extension\r\n\t\t\t\tif (startDot === -1) {\r\n\t\t\t\t\tstartDot = i;\r\n\t\t\t\t}\r\n\t\t\t\telse if (preDotState !== 1) {\r\n\t\t\t\t\tpreDotState = 1;\r\n\t\t\t\t}\r\n\t\t\t} else if (startDot !== -1) {\r\n\t\t\t\t// We saw a non-dot and non-path separator before our dot, so we should\r\n\t\t\t\t// have a good chance at having a non-empty extension\r\n\t\t\t\tpreDotState = -1;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (startDot === -1 ||\r\n\t\t\tend === -1 ||\r\n\t\t\t// We saw a non-dot character immediately before the dot\r\n\t\t\tpreDotState === 0 ||\r\n\t\t\t// The (right-most) trimmed path component is exactly '..'\r\n\t\t\t(preDotState === 1 &&\r\n\t\t\t\tstartDot === end - 1 &&\r\n\t\t\t\tstartDot === startPart + 1)) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\treturn path.slice(startDot, end);\r\n\t},\r\n\r\n\tformat: _format.bind(null, '/'),\r\n\r\n\tparse(path: string): ParsedPath {\r\n\t\tvalidateString(path, 'path');\r\n\r\n\t\tconst ret = { root: '', dir: '', base: '', ext: '', name: '' };\r\n\t\tif (path.length === 0) {\r\n\t\t\treturn ret;\r\n\t\t}\r\n\t\tconst isAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH;\r\n\t\tlet start;\r\n\t\tif (isAbsolute) {\r\n\t\t\tret.root = '/';\r\n\t\t\tstart = 1;\r\n\t\t} else {\r\n\t\t\tstart = 0;\r\n\t\t}\r\n\t\tlet startDot = -1;\r\n\t\tlet startPart = 0;\r\n\t\tlet end = -1;\r\n\t\tlet matchedSlash = true;\r\n\t\tlet i = path.length - 1;\r\n\r\n\t\t// Track the state of characters (if any) we see before our first dot and\r\n\t\t// after any path separator we find\r\n\t\tlet preDotState = 0;\r\n\r\n\t\t// Get non-dir info\r\n\t\tfor (; i >= start; --i) {\r\n\t\t\tconst code = path.charCodeAt(i);\r\n\t\t\tif (code === CHAR_FORWARD_SLASH) {\r\n\t\t\t\t// If we reached a path separator that was not part of a set of path\r\n\t\t\t\t// separators at the end of the string, stop now\r\n\t\t\t\tif (!matchedSlash) {\r\n\t\t\t\t\tstartPart = i + 1;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (end === -1) {\r\n\t\t\t\t// We saw the first non-path separator, mark this as the end of our\r\n\t\t\t\t// extension\r\n\t\t\t\tmatchedSlash = false;\r\n\t\t\t\tend = i + 1;\r\n\t\t\t}\r\n\t\t\tif (code === CHAR_DOT) {\r\n\t\t\t\t// If this is our first dot, mark it as the start of our extension\r\n\t\t\t\tif (startDot === -1) {\r\n\t\t\t\t\tstartDot = i;\r\n\t\t\t\t} else if (preDotState !== 1) {\r\n\t\t\t\t\tpreDotState = 1;\r\n\t\t\t\t}\r\n\t\t\t} else if (startDot !== -1) {\r\n\t\t\t\t// We saw a non-dot and non-path separator before our dot, so we should\r\n\t\t\t\t// have a good chance at having a non-empty extension\r\n\t\t\t\tpreDotState = -1;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (end !== -1) {\r\n\t\t\tconst start = startPart === 0 && isAbsolute ? 1 : startPart;\r\n\t\t\tif (startDot === -1 ||\r\n\t\t\t\t// We saw a non-dot character immediately before the dot\r\n\t\t\t\tpreDotState === 0 ||\r\n\t\t\t\t// The (right-most) trimmed path component is exactly '..'\r\n\t\t\t\t(preDotState === 1 &&\r\n\t\t\t\t\tstartDot === end - 1 &&\r\n\t\t\t\t\tstartDot === startPart + 1)) {\r\n\t\t\t\tret.base = ret.name = path.slice(start, end);\r\n\t\t\t} else {\r\n\t\t\t\tret.name = path.slice(start, startDot);\r\n\t\t\t\tret.base = path.slice(start, end);\r\n\t\t\t\tret.ext = path.slice(startDot, end);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (startPart > 0) {\r\n\t\t\tret.dir = path.slice(0, startPart - 1);\r\n\t\t} else if (isAbsolute) {\r\n\t\t\tret.dir = '/';\r\n\t\t}\r\n\r\n\t\treturn ret;\r\n\t},\r\n\r\n\tsep: '/',\r\n\tdelimiter: ':',\r\n\twin32: null,\r\n\tposix: null\r\n};\r\n\r\nposix.win32 = win32.win32 = win32;\r\nposix.posix = win32.posix = posix;\r\n\r\nexport const normalize = (process.platform === 'win32' ? win32.normalize : posix.normalize);\r\nexport const resolve = (process.platform === 'win32' ? win32.resolve : posix.resolve);\r\nexport const relative = (process.platform === 'win32' ? win32.relative : posix.relative);\r\nexport const dirname = (process.platform === 'win32' ? win32.dirname : posix.dirname);\r\nexport const basename = (process.platform === 'win32' ? win32.basename : posix.basename);\r\nexport const extname = (process.platform === 'win32' ? win32.extname : posix.extname);\r\nexport const sep = (process.platform === 'win32' ? win32.sep : posix.sep);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nexport interface IRange {\r\n\tstart: number;\r\n\tend: number;\r\n}\r\n\r\nexport namespace Range {\r\n\r\n\t/**\r\n\t * Returns the intersection between two ranges as a range itself.\r\n\t * Returns `{ start: 0, end: 0 }` if the intersection is empty.\r\n\t */\r\n\texport function intersect(one: IRange, other: IRange): IRange {\r\n\t\tif (one.start >= other.end || other.start >= one.end) {\r\n\t\t\treturn { start: 0, end: 0 };\r\n\t\t}\r\n\r\n\t\tconst start = Math.max(one.start, other.start);\r\n\t\tconst end = Math.min(one.end, other.end);\r\n\r\n\t\tif (end - start <= 0) {\r\n\t\t\treturn { start: 0, end: 0 };\r\n\t\t}\r\n\r\n\t\treturn { start, end };\r\n\t}\r\n\r\n\texport function isEmpty(range: IRange): boolean {\r\n\t\treturn range.end - range.start <= 0;\r\n\t}\r\n\r\n\texport function intersects(one: IRange, other: IRange): boolean {\r\n\t\treturn !isEmpty(intersect(one, other));\r\n\t}\r\n\r\n\texport function relativeComplement(one: IRange, other: IRange): IRange[] {\r\n\t\tconst result: IRange[] = [];\r\n\t\tconst first = { start: one.start, end: Math.min(other.start, one.end) };\r\n\t\tconst second = { start: Math.max(other.end, one.start), end: one.end };\r\n\r\n\t\tif (!isEmpty(first)) {\r\n\t\t\tresult.push(first);\r\n\t\t}\r\n\r\n\t\tif (!isEmpty(second)) {\r\n\t\t\tresult.push(second);\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IRange, Range } from 'vs/base/common/range';\r\n\r\nexport interface IItem {\r\n\tsize: number;\r\n}\r\n\r\nexport interface IRangedGroup {\r\n\trange: IRange;\r\n\tsize: number;\r\n}\r\n\r\n/**\r\n * Returns the intersection between a ranged group and a range.\r\n * Returns `[]` if the intersection is empty.\r\n */\r\nexport function groupIntersect(range: IRange, groups: IRangedGroup[]): IRangedGroup[] {\r\n\tconst result: IRangedGroup[] = [];\r\n\r\n\tfor (let r of groups) {\r\n\t\tif (range.start >= r.range.end) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tif (range.end < r.range.start) {\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tconst intersection = Range.intersect(range, r.range);\r\n\r\n\t\tif (Range.isEmpty(intersection)) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tresult.push({\r\n\t\t\trange: intersection,\r\n\t\t\tsize: r.size\r\n\t\t});\r\n\t}\r\n\r\n\treturn result;\r\n}\r\n\r\n/**\r\n * Shifts a range by that `much`.\r\n */\r\nexport function shift({ start, end }: IRange, much: number): IRange {\r\n\treturn { start: start + much, end: end + much };\r\n}\r\n\r\n/**\r\n * Consolidates a collection of ranged groups.\r\n *\r\n * Consolidation is the process of merging consecutive ranged groups\r\n * that share the same `size`.\r\n */\r\nexport function consolidate(groups: IRangedGroup[]): IRangedGroup[] {\r\n\tconst result: IRangedGroup[] = [];\r\n\tlet previousGroup: IRangedGroup | null = null;\r\n\r\n\tfor (let group of groups) {\r\n\t\tconst start = group.range.start;\r\n\t\tconst end = group.range.end;\r\n\t\tconst size = group.size;\r\n\r\n\t\tif (previousGroup && size === previousGroup.size) {\r\n\t\t\tpreviousGroup.range.end = end;\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tpreviousGroup = { range: { start, end }, size };\r\n\t\tresult.push(previousGroup);\r\n\t}\r\n\r\n\treturn result;\r\n}\r\n\r\n/**\r\n * Concatenates several collections of ranged groups into a single\r\n * collection.\r\n */\r\nfunction concat(...groups: IRangedGroup[][]): IRangedGroup[] {\r\n\treturn consolidate(groups.reduce((r, g) => r.concat(g), []));\r\n}\r\n\r\nexport class RangeMap {\r\n\r\n\tprivate groups: IRangedGroup[] = [];\r\n\tprivate _size = 0;\r\n\r\n\tsplice(index: number, deleteCount: number, items: IItem[] = []): void {\r\n\t\tconst diff = items.length - deleteCount;\r\n\t\tconst before = groupIntersect({ start: 0, end: index }, this.groups);\r\n\t\tconst after = groupIntersect({ start: index + deleteCount, end: Number.POSITIVE_INFINITY }, this.groups)\r\n\t\t\t.map(g => ({ range: shift(g.range, diff), size: g.size }));\r\n\r\n\t\tconst middle = items.map((item, i) => ({\r\n\t\t\trange: { start: index + i, end: index + i + 1 },\r\n\t\t\tsize: item.size\r\n\t\t}));\r\n\r\n\t\tthis.groups = concat(before, middle, after);\r\n\t\tthis._size = this.groups.reduce((t, g) => t + (g.size * (g.range.end - g.range.start)), 0);\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the number of items in the range map.\r\n\t */\r\n\tget count(): number {\r\n\t\tconst len = this.groups.length;\r\n\r\n\t\tif (!len) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\treturn this.groups[len - 1].range.end;\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the sum of the sizes of all items in the range map.\r\n\t */\r\n\tget size(): number {\r\n\t\treturn this._size;\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the index of the item at the given position.\r\n\t */\r\n\tindexAt(position: number): number {\r\n\t\tif (position < 0) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\r\n\t\tlet index = 0;\r\n\t\tlet size = 0;\r\n\r\n\t\tfor (let group of this.groups) {\r\n\t\t\tconst count = group.range.end - group.range.start;\r\n\t\t\tconst newSize = size + (count * group.size);\r\n\r\n\t\t\tif (position < newSize) {\r\n\t\t\t\treturn index + Math.floor((position - size) / group.size);\r\n\t\t\t}\r\n\r\n\t\t\tindex += count;\r\n\t\t\tsize = newSize;\r\n\t\t}\r\n\r\n\t\treturn index;\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the index of the item right after the item at the\r\n\t * index of the given position.\r\n\t */\r\n\tindexAfter(position: number): number {\r\n\t\treturn Math.min(this.indexAt(position) + 1, this.count);\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the start position of the item at the given index.\r\n\t */\r\n\tpositionAt(index: number): number {\r\n\t\tif (index < 0) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\r\n\t\tlet position = 0;\r\n\t\tlet count = 0;\r\n\r\n\t\tfor (let group of this.groups) {\r\n\t\t\tconst groupCount = group.range.end - group.range.start;\r\n\t\t\tconst newCount = count + groupCount;\r\n\r\n\t\t\tif (index < newCount) {\r\n\t\t\t\treturn position + ((index - count) * group.size);\r\n\t\t\t}\r\n\r\n\t\t\tposition += groupCount * group.size;\r\n\t\t\tcount = newCount;\r\n\t\t}\r\n\r\n\t\treturn -1;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { globals } from 'vs/base/common/platform';\r\n\r\nconst hasPerformanceNow = (globals.performance && typeof globals.performance.now === 'function');\r\n\r\nexport class StopWatch {\r\n\r\n\tprivate _highResolution: boolean;\r\n\tprivate _startTime: number;\r\n\tprivate _stopTime: number;\r\n\r\n\tpublic static create(highResolution: boolean = true): StopWatch {\r\n\t\treturn new StopWatch(highResolution);\r\n\t}\r\n\r\n\tconstructor(highResolution: boolean) {\r\n\t\tthis._highResolution = hasPerformanceNow && highResolution;\r\n\t\tthis._startTime = this._now();\r\n\t\tthis._stopTime = -1;\r\n\t}\r\n\r\n\tpublic stop(): void {\r\n\t\tthis._stopTime = this._now();\r\n\t}\r\n\r\n\tpublic elapsed(): number {\r\n\t\tif (this._stopTime !== -1) {\r\n\t\t\treturn this._stopTime - this._startTime;\r\n\t\t}\r\n\t\treturn this._now() - this._startTime;\r\n\t}\r\n\r\n\tprivate _now(): number {\r\n\t\treturn this._highResolution ? globals.performance.now() : Date.now();\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport { Disposable, IDisposable, combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { LinkedList } from 'vs/base/common/linkedList';\r\nimport { StopWatch } from 'vs/base/common/stopwatch';\r\n\r\n/**\r\n * To an event a function with one or zero parameters\r\n * can be subscribed. The event is the subscriber function itself.\r\n */\r\nexport interface Event {\r\n\t(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore): IDisposable;\r\n}\r\n\r\nexport namespace Event {\r\n\texport const None: Event = () => Disposable.None;\r\n\r\n\t/**\r\n\t * Given an event, returns another event which only fires once.\r\n\t */\r\n\texport function once(event: Event): Event {\r\n\t\treturn (listener, thisArgs = null, disposables?) => {\r\n\t\t\t// we need this, in case the event fires during the listener call\r\n\t\t\tlet didFire = false;\r\n\t\t\tlet result: IDisposable;\r\n\t\t\tresult = event(e => {\r\n\t\t\t\tif (didFire) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t} else if (result) {\r\n\t\t\t\t\tresult.dispose();\r\n\t\t\t\t} else {\r\n\t\t\t\t\tdidFire = true;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn listener.call(thisArgs, e);\r\n\t\t\t}, null, disposables);\r\n\r\n\t\t\tif (didFire) {\r\n\t\t\t\tresult.dispose();\r\n\t\t\t}\r\n\r\n\t\t\treturn result;\r\n\t\t};\r\n\t}\r\n\r\n\t/**\r\n\t * Given an event and a `map` function, returns another event which maps each element\r\n\t * through the mapping function.\r\n\t */\r\n\texport function map(event: Event, map: (i: I) => O): Event {\r\n\t\treturn snapshot((listener, thisArgs = null, disposables?) => event(i => listener.call(thisArgs, map(i)), null, disposables));\r\n\t}\r\n\r\n\t/**\r\n\t * Given an event and an `each` function, returns another identical event and calls\r\n\t * the `each` function per each element.\r\n\t */\r\n\texport function forEach(event: Event, each: (i: I) => void): Event {\r\n\t\treturn snapshot((listener, thisArgs = null, disposables?) => event(i => { each(i); listener.call(thisArgs, i); }, null, disposables));\r\n\t}\r\n\r\n\t/**\r\n\t * Given an event and a `filter` function, returns another event which emits those\r\n\t * elements for which the `filter` function returns `true`.\r\n\t */\r\n\texport function filter(event: Event, filter: (e: T) => boolean): Event;\r\n\texport function filter(event: Event, filter: (e: T | R) => e is R): Event;\r\n\texport function filter(event: Event, filter: (e: T) => boolean): Event {\r\n\t\treturn snapshot((listener, thisArgs = null, disposables?) => event(e => filter(e) && listener.call(thisArgs, e), null, disposables));\r\n\t}\r\n\r\n\t/**\r\n\t * Given an event, returns the same event but typed as `Event`.\r\n\t */\r\n\texport function signal(event: Event): Event {\r\n\t\treturn event as Event as Event;\r\n\t}\r\n\r\n\t/**\r\n\t * Given a collection of events, returns a single event which emits\r\n\t * whenever any of the provided events emit.\r\n\t */\r\n\texport function any(...events: Event[]): Event;\r\n\texport function any(...events: Event[]): Event;\r\n\texport function any(...events: Event[]): Event {\r\n\t\treturn (listener, thisArgs = null, disposables?) => combinedDisposable(...events.map(event => event(e => listener.call(thisArgs, e), null, disposables)));\r\n\t}\r\n\r\n\t/**\r\n\t * Given an event and a `merge` function, returns another event which maps each element\r\n\t * and the cumulative result through the `merge` function. Similar to `map`, but with memory.\r\n\t */\r\n\texport function reduce(event: Event, merge: (last: O | undefined, event: I) => O, initial?: O): Event {\r\n\t\tlet output: O | undefined = initial;\r\n\r\n\t\treturn map(event, e => {\r\n\t\t\toutput = merge(output, e);\r\n\t\t\treturn output;\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * Given a chain of event processing functions (filter, map, etc), each\r\n\t * function will be invoked per event & per listener. Snapshotting an event\r\n\t * chain allows each function to be invoked just once per event.\r\n\t */\r\n\texport function snapshot(event: Event): Event {\r\n\t\tlet listener: IDisposable;\r\n\t\tconst emitter = new Emitter({\r\n\t\t\tonFirstListenerAdd() {\r\n\t\t\t\tlistener = event(emitter.fire, emitter);\r\n\t\t\t},\r\n\t\t\tonLastListenerRemove() {\r\n\t\t\t\tlistener.dispose();\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\treturn emitter.event;\r\n\t}\r\n\r\n\t/**\r\n\t * Debounces the provided event, given a `merge` function.\r\n\t *\r\n\t * @param event The input event.\r\n\t * @param merge The reducing function.\r\n\t * @param delay The debouncing delay in millis.\r\n\t * @param leading Whether the event should fire in the leading phase of the timeout.\r\n\t * @param leakWarningThreshold The leak warning threshold override.\r\n\t */\r\n\texport function debounce(event: Event, merge: (last: T | undefined, event: T) => T, delay?: number, leading?: boolean, leakWarningThreshold?: number): Event;\r\n\texport function debounce(event: Event, merge: (last: O | undefined, event: I) => O, delay?: number, leading?: boolean, leakWarningThreshold?: number): Event;\r\n\texport function debounce(event: Event, merge: (last: O | undefined, event: I) => O, delay: number = 100, leading = false, leakWarningThreshold?: number): Event {\r\n\r\n\t\tlet subscription: IDisposable;\r\n\t\tlet output: O | undefined = undefined;\r\n\t\tlet handle: any = undefined;\r\n\t\tlet numDebouncedCalls = 0;\r\n\r\n\t\tconst emitter = new Emitter({\r\n\t\t\tleakWarningThreshold,\r\n\t\t\tonFirstListenerAdd() {\r\n\t\t\t\tsubscription = event(cur => {\r\n\t\t\t\t\tnumDebouncedCalls++;\r\n\t\t\t\t\toutput = merge(output, cur);\r\n\r\n\t\t\t\t\tif (leading && !handle) {\r\n\t\t\t\t\t\temitter.fire(output);\r\n\t\t\t\t\t\toutput = undefined;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tclearTimeout(handle);\r\n\t\t\t\t\thandle = setTimeout(() => {\r\n\t\t\t\t\t\tconst _output = output;\r\n\t\t\t\t\t\toutput = undefined;\r\n\t\t\t\t\t\thandle = undefined;\r\n\t\t\t\t\t\tif (!leading || numDebouncedCalls > 1) {\r\n\t\t\t\t\t\t\temitter.fire(_output!);\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tnumDebouncedCalls = 0;\r\n\t\t\t\t\t}, delay);\r\n\t\t\t\t});\r\n\t\t\t},\r\n\t\t\tonLastListenerRemove() {\r\n\t\t\t\tsubscription.dispose();\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\treturn emitter.event;\r\n\t}\r\n\r\n\t/**\r\n\t * Given an event, it returns another event which fires only once and as soon as\r\n\t * the input event emits. The event data is the number of millis it took for the\r\n\t * event to fire.\r\n\t */\r\n\texport function stopwatch(event: Event): Event {\r\n\t\tconst start = new Date().getTime();\r\n\t\treturn map(once(event), _ => new Date().getTime() - start);\r\n\t}\r\n\r\n\t/**\r\n\t * Given an event, it returns another event which fires only when the event\r\n\t * element changes.\r\n\t */\r\n\texport function latch(event: Event): Event {\r\n\t\tlet firstCall = true;\r\n\t\tlet cache: T;\r\n\r\n\t\treturn filter(event, value => {\r\n\t\t\tconst shouldEmit = firstCall || value !== cache;\r\n\t\t\tfirstCall = false;\r\n\t\t\tcache = value;\r\n\t\t\treturn shouldEmit;\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * Buffers the provided event until a first listener comes\r\n\t * along, at which point fire all the events at once and\r\n\t * pipe the event from then on.\r\n\t *\r\n\t * ```typescript\r\n\t * const emitter = new Emitter();\r\n\t * const event = emitter.event;\r\n\t * const bufferedEvent = buffer(event);\r\n\t *\r\n\t * emitter.fire(1);\r\n\t * emitter.fire(2);\r\n\t * emitter.fire(3);\r\n\t * // nothing...\r\n\t *\r\n\t * const listener = bufferedEvent(num => console.log(num));\r\n\t * // 1, 2, 3\r\n\t *\r\n\t * emitter.fire(4);\r\n\t * // 4\r\n\t * ```\r\n\t */\r\n\texport function buffer(event: Event, nextTick = false, _buffer: T[] = []): Event {\r\n\t\tlet buffer: T[] | null = _buffer.slice();\r\n\r\n\t\tlet listener: IDisposable | null = event(e => {\r\n\t\t\tif (buffer) {\r\n\t\t\t\tbuffer.push(e);\r\n\t\t\t} else {\r\n\t\t\t\temitter.fire(e);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tconst flush = () => {\r\n\t\t\tif (buffer) {\r\n\t\t\t\tbuffer.forEach(e => emitter.fire(e));\r\n\t\t\t}\r\n\t\t\tbuffer = null;\r\n\t\t};\r\n\r\n\t\tconst emitter = new Emitter({\r\n\t\t\tonFirstListenerAdd() {\r\n\t\t\t\tif (!listener) {\r\n\t\t\t\t\tlistener = event(e => emitter.fire(e));\r\n\t\t\t\t}\r\n\t\t\t},\r\n\r\n\t\t\tonFirstListenerDidAdd() {\r\n\t\t\t\tif (buffer) {\r\n\t\t\t\t\tif (nextTick) {\r\n\t\t\t\t\t\tsetTimeout(flush);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tflush();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t},\r\n\r\n\t\t\tonLastListenerRemove() {\r\n\t\t\t\tif (listener) {\r\n\t\t\t\t\tlistener.dispose();\r\n\t\t\t\t}\r\n\t\t\t\tlistener = null;\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\treturn emitter.event;\r\n\t}\r\n\r\n\texport interface IChainableEvent {\r\n\t\tevent: Event;\r\n\t\tmap(fn: (i: T) => O): IChainableEvent;\r\n\t\tforEach(fn: (i: T) => void): IChainableEvent;\r\n\t\tfilter(fn: (e: T) => boolean): IChainableEvent;\r\n\t\tfilter(fn: (e: T | R) => e is R): IChainableEvent;\r\n\t\treduce(merge: (last: R | undefined, event: T) => R, initial?: R): IChainableEvent;\r\n\t\tlatch(): IChainableEvent;\r\n\t\tdebounce(merge: (last: T | undefined, event: T) => T, delay?: number, leading?: boolean, leakWarningThreshold?: number): IChainableEvent;\r\n\t\tdebounce(merge: (last: R | undefined, event: T) => R, delay?: number, leading?: boolean, leakWarningThreshold?: number): IChainableEvent;\r\n\t\ton(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore): IDisposable;\r\n\t\tonce(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]): IDisposable;\r\n\t}\r\n\r\n\tclass ChainableEvent implements IChainableEvent {\r\n\r\n\t\tconstructor(readonly event: Event) { }\r\n\r\n\t\tmap(fn: (i: T) => O): IChainableEvent {\r\n\t\t\treturn new ChainableEvent(map(this.event, fn));\r\n\t\t}\r\n\r\n\t\tforEach(fn: (i: T) => void): IChainableEvent {\r\n\t\t\treturn new ChainableEvent(forEach(this.event, fn));\r\n\t\t}\r\n\r\n\t\tfilter(fn: (e: T) => boolean): IChainableEvent;\r\n\t\tfilter(fn: (e: T | R) => e is R): IChainableEvent;\r\n\t\tfilter(fn: (e: T) => boolean): IChainableEvent {\r\n\t\t\treturn new ChainableEvent(filter(this.event, fn));\r\n\t\t}\r\n\r\n\t\treduce(merge: (last: R | undefined, event: T) => R, initial?: R): IChainableEvent {\r\n\t\t\treturn new ChainableEvent(reduce(this.event, merge, initial));\r\n\t\t}\r\n\r\n\t\tlatch(): IChainableEvent {\r\n\t\t\treturn new ChainableEvent(latch(this.event));\r\n\t\t}\r\n\r\n\t\tdebounce(merge: (last: T | undefined, event: T) => T, delay?: number, leading?: boolean, leakWarningThreshold?: number): IChainableEvent;\r\n\t\tdebounce(merge: (last: R | undefined, event: T) => R, delay?: number, leading?: boolean, leakWarningThreshold?: number): IChainableEvent;\r\n\t\tdebounce(merge: (last: R | undefined, event: T) => R, delay: number = 100, leading = false, leakWarningThreshold?: number): IChainableEvent {\r\n\t\t\treturn new ChainableEvent(debounce(this.event, merge, delay, leading, leakWarningThreshold));\r\n\t\t}\r\n\r\n\t\ton(listener: (e: T) => any, thisArgs: any, disposables: IDisposable[] | DisposableStore) {\r\n\t\t\treturn this.event(listener, thisArgs, disposables);\r\n\t\t}\r\n\r\n\t\tonce(listener: (e: T) => any, thisArgs: any, disposables: IDisposable[]) {\r\n\t\t\treturn once(this.event)(listener, thisArgs, disposables);\r\n\t\t}\r\n\t}\r\n\r\n\texport function chain(event: Event): IChainableEvent {\r\n\t\treturn new ChainableEvent(event);\r\n\t}\r\n\r\n\texport interface NodeEventEmitter {\r\n\t\ton(event: string | symbol, listener: Function): unknown;\r\n\t\tremoveListener(event: string | symbol, listener: Function): unknown;\r\n\t}\r\n\r\n\texport function fromNodeEventEmitter(emitter: NodeEventEmitter, eventName: string, map: (...args: any[]) => T = id => id): Event {\r\n\t\tconst fn = (...args: any[]) => result.fire(map(...args));\r\n\t\tconst onFirstListenerAdd = () => emitter.on(eventName, fn);\r\n\t\tconst onLastListenerRemove = () => emitter.removeListener(eventName, fn);\r\n\t\tconst result = new Emitter({ onFirstListenerAdd, onLastListenerRemove });\r\n\r\n\t\treturn result.event;\r\n\t}\r\n\r\n\texport interface DOMEventEmitter {\r\n\t\taddEventListener(event: string | symbol, listener: Function): void;\r\n\t\tremoveEventListener(event: string | symbol, listener: Function): void;\r\n\t}\r\n\r\n\texport function fromDOMEventEmitter(emitter: DOMEventEmitter, eventName: string, map: (...args: any[]) => T = id => id): Event {\r\n\t\tconst fn = (...args: any[]) => result.fire(map(...args));\r\n\t\tconst onFirstListenerAdd = () => emitter.addEventListener(eventName, fn);\r\n\t\tconst onLastListenerRemove = () => emitter.removeEventListener(eventName, fn);\r\n\t\tconst result = new Emitter({ onFirstListenerAdd, onLastListenerRemove });\r\n\r\n\t\treturn result.event;\r\n\t}\r\n\r\n\texport function fromPromise(promise: Promise): Event {\r\n\t\tconst emitter = new Emitter();\r\n\t\tlet shouldEmit = false;\r\n\r\n\t\tpromise\r\n\t\t\t.then(undefined, () => null)\r\n\t\t\t.then(() => {\r\n\t\t\t\tif (!shouldEmit) {\r\n\t\t\t\t\tsetTimeout(() => emitter.fire(undefined), 0);\r\n\t\t\t\t} else {\r\n\t\t\t\t\temitter.fire(undefined);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\tshouldEmit = true;\r\n\t\treturn emitter.event;\r\n\t}\r\n\r\n\texport function toPromise(event: Event): Promise {\r\n\t\treturn new Promise(resolve => once(event)(resolve));\r\n\t}\r\n}\r\n\r\ntype Listener = [(e: T) => void, any] | ((e: T) => void);\r\n\r\nexport interface EmitterOptions {\r\n\tonFirstListenerAdd?: Function;\r\n\tonFirstListenerDidAdd?: Function;\r\n\tonListenerDidAdd?: Function;\r\n\tonLastListenerRemove?: Function;\r\n\tleakWarningThreshold?: number;\r\n\r\n\t/** ONLY enable this during development */\r\n\t_profName?: string\r\n}\r\n\r\n\r\nclass EventProfiling {\r\n\r\n\tprivate static _idPool = 0;\r\n\r\n\tprivate _name: string;\r\n\tprivate _stopWatch?: StopWatch;\r\n\tprivate _listenerCount: number = 0;\r\n\tprivate _invocationCount = 0;\r\n\tprivate _elapsedOverall = 0;\r\n\r\n\tconstructor(name: string) {\r\n\t\tthis._name = `${name}_${EventProfiling._idPool++}`;\r\n\t}\r\n\r\n\tstart(listenerCount: number): void {\r\n\t\tthis._stopWatch = new StopWatch(true);\r\n\t\tthis._listenerCount = listenerCount;\r\n\t}\r\n\r\n\tstop(): void {\r\n\t\tif (this._stopWatch) {\r\n\t\t\tconst elapsed = this._stopWatch.elapsed();\r\n\t\t\tthis._elapsedOverall += elapsed;\r\n\t\t\tthis._invocationCount += 1;\r\n\r\n\t\t\tconsole.info(`did FIRE ${this._name}: elapsed_ms: ${elapsed.toFixed(5)}, listener: ${this._listenerCount} (elapsed_overall: ${this._elapsedOverall.toFixed(2)}, invocations: ${this._invocationCount})`);\r\n\t\t\tthis._stopWatch = undefined;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nlet _globalLeakWarningThreshold = -1;\r\n\r\nclass LeakageMonitor {\r\n\r\n\tprivate _stacks: Map | undefined;\r\n\tprivate _warnCountdown: number = 0;\r\n\r\n\tconstructor(\r\n\t\treadonly customThreshold?: number,\r\n\t\treadonly name: string = Math.random().toString(18).slice(2, 5),\r\n\t) { }\r\n\r\n\tdispose(): void {\r\n\t\tif (this._stacks) {\r\n\t\t\tthis._stacks.clear();\r\n\t\t}\r\n\t}\r\n\r\n\tcheck(listenerCount: number): undefined | (() => void) {\r\n\r\n\t\tlet threshold = _globalLeakWarningThreshold;\r\n\t\tif (typeof this.customThreshold === 'number') {\r\n\t\t\tthreshold = this.customThreshold;\r\n\t\t}\r\n\r\n\t\tif (threshold <= 0 || listenerCount < threshold) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\r\n\t\tif (!this._stacks) {\r\n\t\t\tthis._stacks = new Map();\r\n\t\t}\r\n\t\tconst stack = new Error().stack!.split('\\n').slice(3).join('\\n');\r\n\t\tconst count = (this._stacks.get(stack) || 0);\r\n\t\tthis._stacks.set(stack, count + 1);\r\n\t\tthis._warnCountdown -= 1;\r\n\r\n\t\tif (this._warnCountdown <= 0) {\r\n\t\t\t// only warn on first exceed and then every time the limit\r\n\t\t\t// is exceeded by 50% again\r\n\t\t\tthis._warnCountdown = threshold * 0.5;\r\n\r\n\t\t\t// find most frequent listener and print warning\r\n\t\t\tlet topStack: string | undefined;\r\n\t\t\tlet topCount: number = 0;\r\n\t\t\tfor (const [stack, count] of this._stacks) {\r\n\t\t\t\tif (!topStack || topCount < count) {\r\n\t\t\t\t\ttopStack = stack;\r\n\t\t\t\t\ttopCount = count;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tconsole.warn(`[${this.name}] potential listener LEAK detected, having ${listenerCount} listeners already. MOST frequent listener (${topCount}):`);\r\n\t\t\tconsole.warn(topStack!);\r\n\t\t}\r\n\r\n\t\treturn () => {\r\n\t\t\tconst count = (this._stacks!.get(stack) || 0);\r\n\t\t\tthis._stacks!.set(stack, count - 1);\r\n\t\t};\r\n\t}\r\n}\r\n\r\n/**\r\n * The Emitter can be used to expose an Event to the public\r\n * to fire it from the insides.\r\n * Sample:\r\n\tclass Document {\r\n\r\n\t\tprivate readonly _onDidChange = new Emitter<(value:string)=>any>();\r\n\r\n\t\tpublic onDidChange = this._onDidChange.event;\r\n\r\n\t\t// getter-style\r\n\t\t// get onDidChange(): Event<(value:string)=>any> {\r\n\t\t// \treturn this._onDidChange.event;\r\n\t\t// }\r\n\r\n\t\tprivate _doIt() {\r\n\t\t\t//...\r\n\t\t\tthis._onDidChange.fire(value);\r\n\t\t}\r\n\t}\r\n */\r\nexport class Emitter {\r\n\r\n\tprivate static readonly _noop = function () { };\r\n\r\n\tprivate readonly _options?: EmitterOptions;\r\n\tprivate readonly _leakageMon?: LeakageMonitor;\r\n\tprivate readonly _perfMon?: EventProfiling;\r\n\tprivate _disposed: boolean = false;\r\n\tprivate _event?: Event;\r\n\tprivate _deliveryQueue?: LinkedList<[Listener, T]>;\r\n\tprotected _listeners?: LinkedList>;\r\n\r\n\tconstructor(options?: EmitterOptions) {\r\n\t\tthis._options = options;\r\n\t\tthis._leakageMon = _globalLeakWarningThreshold > 0 ? new LeakageMonitor(this._options && this._options.leakWarningThreshold) : undefined;\r\n\t\tthis._perfMon = this._options?._profName ? new EventProfiling(this._options._profName) : undefined;\r\n\t}\r\n\r\n\t/**\r\n\t * For the public to allow to subscribe\r\n\t * to events from this Emitter\r\n\t */\r\n\tget event(): Event {\r\n\t\tif (!this._event) {\r\n\t\t\tthis._event = (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore) => {\r\n\t\t\t\tif (!this._listeners) {\r\n\t\t\t\t\tthis._listeners = new LinkedList();\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst firstListener = this._listeners.isEmpty();\r\n\r\n\t\t\t\tif (firstListener && this._options && this._options.onFirstListenerAdd) {\r\n\t\t\t\t\tthis._options.onFirstListenerAdd(this);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst remove = this._listeners.push(!thisArgs ? listener : [listener, thisArgs]);\r\n\r\n\t\t\t\tif (firstListener && this._options && this._options.onFirstListenerDidAdd) {\r\n\t\t\t\t\tthis._options.onFirstListenerDidAdd(this);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (this._options && this._options.onListenerDidAdd) {\r\n\t\t\t\t\tthis._options.onListenerDidAdd(this, listener, thisArgs);\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// check and record this emitter for potential leakage\r\n\t\t\t\tconst removeMonitor = this._leakageMon?.check(this._listeners.size);\r\n\r\n\t\t\t\tlet result: IDisposable;\r\n\t\t\t\tresult = {\r\n\t\t\t\t\tdispose: () => {\r\n\t\t\t\t\t\tif (removeMonitor) {\r\n\t\t\t\t\t\t\tremoveMonitor();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tresult.dispose = Emitter._noop;\r\n\t\t\t\t\t\tif (!this._disposed) {\r\n\t\t\t\t\t\t\tremove();\r\n\t\t\t\t\t\t\tif (this._options && this._options.onLastListenerRemove) {\r\n\t\t\t\t\t\t\t\tconst hasListeners = (this._listeners && !this._listeners.isEmpty());\r\n\t\t\t\t\t\t\t\tif (!hasListeners) {\r\n\t\t\t\t\t\t\t\t\tthis._options.onLastListenerRemove(this);\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t};\r\n\t\t\t\tif (disposables instanceof DisposableStore) {\r\n\t\t\t\t\tdisposables.add(result);\r\n\t\t\t\t} else if (Array.isArray(disposables)) {\r\n\t\t\t\t\tdisposables.push(result);\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn result;\r\n\t\t\t};\r\n\t\t}\r\n\t\treturn this._event;\r\n\t}\r\n\r\n\t/**\r\n\t * To be kept private to fire an event to\r\n\t * subscribers\r\n\t */\r\n\tfire(event: T): void {\r\n\t\tif (this._listeners) {\r\n\t\t\t// put all [listener,event]-pairs into delivery queue\r\n\t\t\t// then emit all event. an inner/nested event might be\r\n\t\t\t// the driver of this\r\n\r\n\t\t\tif (!this._deliveryQueue) {\r\n\t\t\t\tthis._deliveryQueue = new LinkedList();\r\n\t\t\t}\r\n\r\n\t\t\tfor (let listener of this._listeners) {\r\n\t\t\t\tthis._deliveryQueue.push([listener, event]);\r\n\t\t\t}\r\n\r\n\t\t\t// start/stop performance insight collection\r\n\t\t\tthis._perfMon?.start(this._deliveryQueue.size);\r\n\r\n\t\t\twhile (this._deliveryQueue.size > 0) {\r\n\t\t\t\tconst [listener, event] = this._deliveryQueue.shift()!;\r\n\t\t\t\ttry {\r\n\t\t\t\t\tif (typeof listener === 'function') {\r\n\t\t\t\t\t\tlistener.call(undefined, event);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tlistener[0].call(listener[1], event);\r\n\t\t\t\t\t}\r\n\t\t\t\t} catch (e) {\r\n\t\t\t\t\tonUnexpectedError(e);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tthis._perfMon?.stop();\r\n\t\t}\r\n\t}\r\n\r\n\tdispose() {\r\n\t\tthis._listeners?.clear();\r\n\t\tthis._deliveryQueue?.clear();\r\n\t\tthis._leakageMon?.dispose();\r\n\t\tthis._disposed = true;\r\n\t}\r\n}\r\n\r\nexport class PauseableEmitter extends Emitter {\r\n\r\n\tprivate _isPaused = 0;\r\n\tprivate _eventQueue = new LinkedList();\r\n\tprivate _mergeFn?: (input: T[]) => T;\r\n\r\n\tconstructor(options?: EmitterOptions & { merge?: (input: T[]) => T }) {\r\n\t\tsuper(options);\r\n\t\tthis._mergeFn = options?.merge;\r\n\t}\r\n\r\n\tpause(): void {\r\n\t\tthis._isPaused++;\r\n\t}\r\n\r\n\tresume(): void {\r\n\t\tif (this._isPaused !== 0 && --this._isPaused === 0) {\r\n\t\t\tif (this._mergeFn) {\r\n\t\t\t\t// use the merge function to create a single composite\r\n\t\t\t\t// event. make a copy in case firing pauses this emitter\r\n\t\t\t\tconst events = Array.from(this._eventQueue);\r\n\t\t\t\tthis._eventQueue.clear();\r\n\t\t\t\tsuper.fire(this._mergeFn(events));\r\n\r\n\t\t\t} else {\r\n\t\t\t\t// no merging, fire each event individually and test\r\n\t\t\t\t// that this emitter isn't paused halfway through\r\n\t\t\t\twhile (!this._isPaused && this._eventQueue.size !== 0) {\r\n\t\t\t\t\tsuper.fire(this._eventQueue.shift()!);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tfire(event: T): void {\r\n\t\tif (this._listeners) {\r\n\t\t\tif (this._isPaused !== 0) {\r\n\t\t\t\tthis._eventQueue.push(event);\r\n\t\t\t} else {\r\n\t\t\t\tsuper.fire(event);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\n/**\r\n * The EventBufferer is useful in situations in which you want\r\n * to delay firing your events during some code.\r\n * You can wrap that code and be sure that the event will not\r\n * be fired during that wrap.\r\n *\r\n * ```\r\n * const emitter: Emitter;\r\n * const delayer = new EventDelayer();\r\n * const delayedEvent = delayer.wrapEvent(emitter.event);\r\n *\r\n * delayedEvent(console.log);\r\n *\r\n * delayer.bufferEvents(() => {\r\n * emitter.fire(); // event will not be fired yet\r\n * });\r\n *\r\n * // event will only be fired at this point\r\n * ```\r\n */\r\nexport class EventBufferer {\r\n\r\n\tprivate buffers: Function[][] = [];\r\n\r\n\twrapEvent(event: Event): Event {\r\n\t\treturn (listener, thisArgs?, disposables?) => {\r\n\t\t\treturn event(i => {\r\n\t\t\t\tconst buffer = this.buffers[this.buffers.length - 1];\r\n\r\n\t\t\t\tif (buffer) {\r\n\t\t\t\t\tbuffer.push(() => listener.call(thisArgs, i));\r\n\t\t\t\t} else {\r\n\t\t\t\t\tlistener.call(thisArgs, i);\r\n\t\t\t\t}\r\n\t\t\t}, undefined, disposables);\r\n\t\t};\r\n\t}\r\n\r\n\tbufferEvents(fn: () => R): R {\r\n\t\tconst buffer: Array<() => R> = [];\r\n\t\tthis.buffers.push(buffer);\r\n\t\tconst r = fn();\r\n\t\tthis.buffers.pop();\r\n\t\tbuffer.forEach(flush => flush());\r\n\t\treturn r;\r\n\t}\r\n}\r\n\r\n/**\r\n * A Relay is an event forwarder which functions as a replugabble event pipe.\r\n * Once created, you can connect an input event to it and it will simply forward\r\n * events from that input event through its own `event` property. The `input`\r\n * can be changed at any point in time.\r\n */\r\nexport class Relay implements IDisposable {\r\n\r\n\tprivate listening = false;\r\n\tprivate inputEvent: Event = Event.None;\r\n\tprivate inputEventListener: IDisposable = Disposable.None;\r\n\r\n\tprivate readonly emitter = new Emitter({\r\n\t\tonFirstListenerDidAdd: () => {\r\n\t\t\tthis.listening = true;\r\n\t\t\tthis.inputEventListener = this.inputEvent(this.emitter.fire, this.emitter);\r\n\t\t},\r\n\t\tonLastListenerRemove: () => {\r\n\t\t\tthis.listening = false;\r\n\t\t\tthis.inputEventListener.dispose();\r\n\t\t}\r\n\t});\r\n\r\n\treadonly event: Event = this.emitter.event;\r\n\r\n\tset input(event: Event) {\r\n\t\tthis.inputEvent = event;\r\n\r\n\t\tif (this.listening) {\r\n\t\t\tthis.inputEventListener.dispose();\r\n\t\t\tthis.inputEventListener = event(this.emitter.fire, this.emitter);\r\n\t\t}\r\n\t}\r\n\r\n\tdispose() {\r\n\t\tthis.inputEventListener.dispose();\r\n\t\tthis.emitter.dispose();\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\n\r\nclass WindowManager {\r\n\r\n\tpublic static readonly INSTANCE = new WindowManager();\r\n\r\n\t// --- Zoom Level\r\n\tprivate _zoomLevel: number = 0;\r\n\tprivate _lastZoomLevelChangeTime: number = 0;\r\n\tprivate readonly _onDidChangeZoomLevel = new Emitter();\r\n\r\n\tpublic readonly onDidChangeZoomLevel: Event = this._onDidChangeZoomLevel.event;\r\n\tpublic getZoomLevel(): number {\r\n\t\treturn this._zoomLevel;\r\n\t}\r\n\tpublic getTimeSinceLastZoomLevelChanged(): number {\r\n\t\treturn Date.now() - this._lastZoomLevelChangeTime;\r\n\t}\r\n\r\n\t// --- Zoom Factor\r\n\tprivate _zoomFactor: number = 1;\r\n\r\n\tpublic getZoomFactor(): number {\r\n\t\treturn this._zoomFactor;\r\n\t}\r\n\r\n\t// --- Pixel Ratio\r\n\tpublic getPixelRatio(): number {\r\n\t\tlet ctx: any = document.createElement('canvas').getContext('2d');\r\n\t\tlet dpr = window.devicePixelRatio || 1;\r\n\t\tlet bsr = ctx.webkitBackingStorePixelRatio ||\r\n\t\t\tctx.mozBackingStorePixelRatio ||\r\n\t\t\tctx.msBackingStorePixelRatio ||\r\n\t\t\tctx.oBackingStorePixelRatio ||\r\n\t\t\tctx.backingStorePixelRatio || 1;\r\n\t\treturn dpr / bsr;\r\n\t}\r\n}\r\nexport function getZoomLevel(): number {\r\n\treturn WindowManager.INSTANCE.getZoomLevel();\r\n}\r\n/** Returns the time (in ms) since the zoom level was changed */\r\nexport function getTimeSinceLastZoomLevelChanged(): number {\r\n\treturn WindowManager.INSTANCE.getTimeSinceLastZoomLevelChanged();\r\n}\r\nexport function onDidChangeZoomLevel(callback: (zoomLevel: number) => void): IDisposable {\r\n\treturn WindowManager.INSTANCE.onDidChangeZoomLevel(callback);\r\n}\r\n\r\n/** The zoom scale for an index, e.g. 1, 1.2, 1.4 */\r\nexport function getZoomFactor(): number {\r\n\treturn WindowManager.INSTANCE.getZoomFactor();\r\n}\r\n\r\nexport function getPixelRatio(): number {\r\n\treturn WindowManager.INSTANCE.getPixelRatio();\r\n}\r\n\r\nconst userAgent = navigator.userAgent;\r\n\r\nexport const isEdgeLegacy = (userAgent.indexOf('Edge/') >= 0);\r\nexport const isFirefox = (userAgent.indexOf('Firefox') >= 0);\r\nexport const isWebKit = (userAgent.indexOf('AppleWebKit') >= 0);\r\nexport const isChrome = (userAgent.indexOf('Chrome') >= 0);\r\nexport const isSafari = (!isChrome && (userAgent.indexOf('Safari') >= 0));\r\nexport const isWebkitWebView = (!isChrome && !isSafari && isWebKit);\r\nexport const isIPad = (userAgent.indexOf('iPad') >= 0 || (isSafari && navigator.maxTouchPoints > 0));\r\nexport const isEdgeLegacyWebView = isEdgeLegacy && (userAgent.indexOf('WebView/') >= 0);\r\nexport const isElectron = (userAgent.indexOf('Electron/') >= 0);\r\nexport const isStandalone = (window.matchMedia && window.matchMedia('(display-mode: standalone)').matches);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as browser from 'vs/base/browser/browser';\r\nimport * as platform from 'vs/base/common/platform';\r\n\r\nexport const enum KeyboardSupport {\r\n\tAlways,\r\n\tFullScreen,\r\n\tNone\r\n}\r\n\r\n/**\r\n * Browser feature we can support in current platform, browser and environment.\r\n */\r\nexport const BrowserFeatures = {\r\n\tclipboard: {\r\n\t\twriteText: (\r\n\t\t\tplatform.isNative\r\n\t\t\t|| (document.queryCommandSupported && document.queryCommandSupported('copy'))\r\n\t\t\t|| !!(navigator && navigator.clipboard && navigator.clipboard.writeText)\r\n\t\t),\r\n\t\treadText: (\r\n\t\t\tplatform.isNative\r\n\t\t\t|| !!(navigator && navigator.clipboard && navigator.clipboard.readText)\r\n\t\t),\r\n\t\trichText: (() => {\r\n\t\t\tif (browser.isEdgeLegacy) {\r\n\t\t\t\tlet index = navigator.userAgent.indexOf('Edge/');\r\n\t\t\t\tlet version = parseInt(navigator.userAgent.substring(index + 5, navigator.userAgent.indexOf('.', index)), 10);\r\n\r\n\t\t\t\tif (!version || (version >= 12 && version <= 16)) {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn true;\r\n\t\t})()\r\n\t},\r\n\tkeyboard: (() => {\r\n\t\tif (platform.isNative || browser.isStandalone) {\r\n\t\t\treturn KeyboardSupport.Always;\r\n\t\t}\r\n\r\n\t\tif ((navigator).keyboard || browser.isSafari) {\r\n\t\t\treturn KeyboardSupport.FullScreen;\r\n\t\t}\r\n\r\n\t\treturn KeyboardSupport.None;\r\n\t})(),\r\n\r\n\t// 'ontouchstart' in window always evaluates to true with typescript's modern typings. This causes `window` to be\r\n\t// `never` later in `window.navigator`. That's why we need the explicit `window as Window` cast\r\n\ttouch: 'ontouchstart' in window || navigator.maxTouchPoints > 0 || (window as Window).navigator.msMaxTouchPoints > 0,\r\n\tpointerEvents: window.PointerEvent && ('ontouchstart' in window || (window as Window).navigator.maxTouchPoints > 0 || navigator.maxTouchPoints > 0 || (window as Window).navigator.msMaxTouchPoints > 0)\r\n};\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Event as BaseEvent, Emitter } from 'vs/base/common/event';\r\n\r\nexport type EventHandler = HTMLElement | HTMLDocument | Window;\r\n\r\nexport interface IDomEvent {\r\n\t(element: EventHandler, type: K, useCapture?: boolean): BaseEvent;\r\n\t(element: EventHandler, type: string, useCapture?: boolean): BaseEvent;\r\n}\r\n\r\nexport const domEvent: IDomEvent = (element: EventHandler, type: string, useCapture?: boolean) => {\r\n\tconst fn = (e: Event) => emitter.fire(e);\r\n\tconst emitter = new Emitter({\r\n\t\tonFirstListenerAdd: () => {\r\n\t\t\telement.addEventListener(type, fn, useCapture);\r\n\t\t},\r\n\t\tonLastListenerRemove: () => {\r\n\t\t\telement.removeEventListener(type, fn, useCapture);\r\n\t\t}\r\n\t});\r\n\r\n\treturn emitter.event;\r\n};\r\n\r\nexport interface CancellableEvent {\r\n\tpreventDefault(): void;\r\n\tstopPropagation(): void;\r\n}\r\n\r\nexport function stop(event: BaseEvent): BaseEvent {\r\n\treturn BaseEvent.map(event, e => {\r\n\t\te.preventDefault();\r\n\t\te.stopPropagation();\r\n\t\treturn e;\r\n\t});\r\n}","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as browser from 'vs/base/browser/browser';\r\nimport { KeyCode, KeyCodeUtils, KeyMod, SimpleKeybinding } from 'vs/base/common/keyCodes';\r\nimport * as platform from 'vs/base/common/platform';\r\n\r\nlet KEY_CODE_MAP: { [keyCode: number]: KeyCode } = new Array(230);\r\nlet INVERSE_KEY_CODE_MAP: KeyCode[] = new Array(KeyCode.MAX_VALUE);\r\n\r\n(function () {\r\n\tfor (let i = 0; i < INVERSE_KEY_CODE_MAP.length; i++) {\r\n\t\tINVERSE_KEY_CODE_MAP[i] = -1;\r\n\t}\r\n\r\n\tfunction define(code: number, keyCode: KeyCode): void {\r\n\t\tKEY_CODE_MAP[code] = keyCode;\r\n\t\tINVERSE_KEY_CODE_MAP[keyCode] = code;\r\n\t}\r\n\r\n\tdefine(3, KeyCode.PauseBreak); // VK_CANCEL 0x03 Control-break processing\r\n\tdefine(8, KeyCode.Backspace);\r\n\tdefine(9, KeyCode.Tab);\r\n\tdefine(13, KeyCode.Enter);\r\n\tdefine(16, KeyCode.Shift);\r\n\tdefine(17, KeyCode.Ctrl);\r\n\tdefine(18, KeyCode.Alt);\r\n\tdefine(19, KeyCode.PauseBreak);\r\n\tdefine(20, KeyCode.CapsLock);\r\n\tdefine(27, KeyCode.Escape);\r\n\tdefine(32, KeyCode.Space);\r\n\tdefine(33, KeyCode.PageUp);\r\n\tdefine(34, KeyCode.PageDown);\r\n\tdefine(35, KeyCode.End);\r\n\tdefine(36, KeyCode.Home);\r\n\tdefine(37, KeyCode.LeftArrow);\r\n\tdefine(38, KeyCode.UpArrow);\r\n\tdefine(39, KeyCode.RightArrow);\r\n\tdefine(40, KeyCode.DownArrow);\r\n\tdefine(45, KeyCode.Insert);\r\n\tdefine(46, KeyCode.Delete);\r\n\r\n\tdefine(48, KeyCode.KEY_0);\r\n\tdefine(49, KeyCode.KEY_1);\r\n\tdefine(50, KeyCode.KEY_2);\r\n\tdefine(51, KeyCode.KEY_3);\r\n\tdefine(52, KeyCode.KEY_4);\r\n\tdefine(53, KeyCode.KEY_5);\r\n\tdefine(54, KeyCode.KEY_6);\r\n\tdefine(55, KeyCode.KEY_7);\r\n\tdefine(56, KeyCode.KEY_8);\r\n\tdefine(57, KeyCode.KEY_9);\r\n\r\n\tdefine(65, KeyCode.KEY_A);\r\n\tdefine(66, KeyCode.KEY_B);\r\n\tdefine(67, KeyCode.KEY_C);\r\n\tdefine(68, KeyCode.KEY_D);\r\n\tdefine(69, KeyCode.KEY_E);\r\n\tdefine(70, KeyCode.KEY_F);\r\n\tdefine(71, KeyCode.KEY_G);\r\n\tdefine(72, KeyCode.KEY_H);\r\n\tdefine(73, KeyCode.KEY_I);\r\n\tdefine(74, KeyCode.KEY_J);\r\n\tdefine(75, KeyCode.KEY_K);\r\n\tdefine(76, KeyCode.KEY_L);\r\n\tdefine(77, KeyCode.KEY_M);\r\n\tdefine(78, KeyCode.KEY_N);\r\n\tdefine(79, KeyCode.KEY_O);\r\n\tdefine(80, KeyCode.KEY_P);\r\n\tdefine(81, KeyCode.KEY_Q);\r\n\tdefine(82, KeyCode.KEY_R);\r\n\tdefine(83, KeyCode.KEY_S);\r\n\tdefine(84, KeyCode.KEY_T);\r\n\tdefine(85, KeyCode.KEY_U);\r\n\tdefine(86, KeyCode.KEY_V);\r\n\tdefine(87, KeyCode.KEY_W);\r\n\tdefine(88, KeyCode.KEY_X);\r\n\tdefine(89, KeyCode.KEY_Y);\r\n\tdefine(90, KeyCode.KEY_Z);\r\n\r\n\tdefine(93, KeyCode.ContextMenu);\r\n\r\n\tdefine(96, KeyCode.NUMPAD_0);\r\n\tdefine(97, KeyCode.NUMPAD_1);\r\n\tdefine(98, KeyCode.NUMPAD_2);\r\n\tdefine(99, KeyCode.NUMPAD_3);\r\n\tdefine(100, KeyCode.NUMPAD_4);\r\n\tdefine(101, KeyCode.NUMPAD_5);\r\n\tdefine(102, KeyCode.NUMPAD_6);\r\n\tdefine(103, KeyCode.NUMPAD_7);\r\n\tdefine(104, KeyCode.NUMPAD_8);\r\n\tdefine(105, KeyCode.NUMPAD_9);\r\n\tdefine(106, KeyCode.NUMPAD_MULTIPLY);\r\n\tdefine(107, KeyCode.NUMPAD_ADD);\r\n\tdefine(108, KeyCode.NUMPAD_SEPARATOR);\r\n\tdefine(109, KeyCode.NUMPAD_SUBTRACT);\r\n\tdefine(110, KeyCode.NUMPAD_DECIMAL);\r\n\tdefine(111, KeyCode.NUMPAD_DIVIDE);\r\n\r\n\tdefine(112, KeyCode.F1);\r\n\tdefine(113, KeyCode.F2);\r\n\tdefine(114, KeyCode.F3);\r\n\tdefine(115, KeyCode.F4);\r\n\tdefine(116, KeyCode.F5);\r\n\tdefine(117, KeyCode.F6);\r\n\tdefine(118, KeyCode.F7);\r\n\tdefine(119, KeyCode.F8);\r\n\tdefine(120, KeyCode.F9);\r\n\tdefine(121, KeyCode.F10);\r\n\tdefine(122, KeyCode.F11);\r\n\tdefine(123, KeyCode.F12);\r\n\tdefine(124, KeyCode.F13);\r\n\tdefine(125, KeyCode.F14);\r\n\tdefine(126, KeyCode.F15);\r\n\tdefine(127, KeyCode.F16);\r\n\tdefine(128, KeyCode.F17);\r\n\tdefine(129, KeyCode.F18);\r\n\tdefine(130, KeyCode.F19);\r\n\r\n\tdefine(144, KeyCode.NumLock);\r\n\tdefine(145, KeyCode.ScrollLock);\r\n\r\n\tdefine(186, KeyCode.US_SEMICOLON);\r\n\tdefine(187, KeyCode.US_EQUAL);\r\n\tdefine(188, KeyCode.US_COMMA);\r\n\tdefine(189, KeyCode.US_MINUS);\r\n\tdefine(190, KeyCode.US_DOT);\r\n\tdefine(191, KeyCode.US_SLASH);\r\n\tdefine(192, KeyCode.US_BACKTICK);\r\n\tdefine(193, KeyCode.ABNT_C1);\r\n\tdefine(194, KeyCode.ABNT_C2);\r\n\tdefine(219, KeyCode.US_OPEN_SQUARE_BRACKET);\r\n\tdefine(220, KeyCode.US_BACKSLASH);\r\n\tdefine(221, KeyCode.US_CLOSE_SQUARE_BRACKET);\r\n\tdefine(222, KeyCode.US_QUOTE);\r\n\tdefine(223, KeyCode.OEM_8);\r\n\r\n\tdefine(226, KeyCode.OEM_102);\r\n\r\n\t/**\r\n\t * https://lists.w3.org/Archives/Public/www-dom/2010JulSep/att-0182/keyCode-spec.html\r\n\t * If an Input Method Editor is processing key input and the event is keydown, return 229.\r\n\t */\r\n\tdefine(229, KeyCode.KEY_IN_COMPOSITION);\r\n\r\n\tif (browser.isFirefox) {\r\n\t\tdefine(59, KeyCode.US_SEMICOLON);\r\n\t\tdefine(107, KeyCode.US_EQUAL);\r\n\t\tdefine(109, KeyCode.US_MINUS);\r\n\t\tif (platform.isMacintosh) {\r\n\t\t\tdefine(224, KeyCode.Meta);\r\n\t\t}\r\n\t} else if (browser.isWebKit) {\r\n\t\tdefine(91, KeyCode.Meta);\r\n\t\tif (platform.isMacintosh) {\r\n\t\t\t// the two meta keys in the Mac have different key codes (91 and 93)\r\n\t\t\tdefine(93, KeyCode.Meta);\r\n\t\t} else {\r\n\t\t\tdefine(92, KeyCode.Meta);\r\n\t\t}\r\n\t}\r\n})();\r\n\r\nfunction extractKeyCode(e: KeyboardEvent): KeyCode {\r\n\tif (e.charCode) {\r\n\t\t// \"keypress\" events mostly\r\n\t\tlet char = String.fromCharCode(e.charCode).toUpperCase();\r\n\t\treturn KeyCodeUtils.fromString(char);\r\n\t}\r\n\treturn KEY_CODE_MAP[e.keyCode] || KeyCode.Unknown;\r\n}\r\n\r\nexport interface IKeyboardEvent {\r\n\r\n\treadonly _standardKeyboardEventBrand: true;\r\n\r\n\treadonly browserEvent: KeyboardEvent;\r\n\treadonly target: HTMLElement;\r\n\r\n\treadonly ctrlKey: boolean;\r\n\treadonly shiftKey: boolean;\r\n\treadonly altKey: boolean;\r\n\treadonly metaKey: boolean;\r\n\treadonly keyCode: KeyCode;\r\n\treadonly code: string;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\ttoKeybinding(): SimpleKeybinding;\r\n\tequals(keybinding: number): boolean;\r\n\r\n\tpreventDefault(): void;\r\n\tstopPropagation(): void;\r\n}\r\n\r\nconst ctrlKeyMod = (platform.isMacintosh ? KeyMod.WinCtrl : KeyMod.CtrlCmd);\r\nconst altKeyMod = KeyMod.Alt;\r\nconst shiftKeyMod = KeyMod.Shift;\r\nconst metaKeyMod = (platform.isMacintosh ? KeyMod.CtrlCmd : KeyMod.WinCtrl);\r\n\r\nexport class StandardKeyboardEvent implements IKeyboardEvent {\r\n\r\n\treadonly _standardKeyboardEventBrand = true;\r\n\r\n\tpublic readonly browserEvent: KeyboardEvent;\r\n\tpublic readonly target: HTMLElement;\r\n\r\n\tpublic readonly ctrlKey: boolean;\r\n\tpublic readonly shiftKey: boolean;\r\n\tpublic readonly altKey: boolean;\r\n\tpublic readonly metaKey: boolean;\r\n\tpublic readonly keyCode: KeyCode;\r\n\tpublic readonly code: string;\r\n\r\n\tprivate _asKeybinding: number;\r\n\tprivate _asRuntimeKeybinding: SimpleKeybinding;\r\n\r\n\tconstructor(source: KeyboardEvent) {\r\n\t\tlet e = source;\r\n\r\n\t\tthis.browserEvent = e;\r\n\t\tthis.target = e.target;\r\n\r\n\t\tthis.ctrlKey = e.ctrlKey;\r\n\t\tthis.shiftKey = e.shiftKey;\r\n\t\tthis.altKey = e.altKey;\r\n\t\tthis.metaKey = e.metaKey;\r\n\t\tthis.keyCode = extractKeyCode(e);\r\n\t\tthis.code = e.code;\r\n\r\n\t\t// console.info(e.type + \": keyCode: \" + e.keyCode + \", which: \" + e.which + \", charCode: \" + e.charCode + \", detail: \" + e.detail + \" ====> \" + this.keyCode + ' -- ' + KeyCode[this.keyCode]);\r\n\r\n\t\tthis.ctrlKey = this.ctrlKey || this.keyCode === KeyCode.Ctrl;\r\n\t\tthis.altKey = this.altKey || this.keyCode === KeyCode.Alt;\r\n\t\tthis.shiftKey = this.shiftKey || this.keyCode === KeyCode.Shift;\r\n\t\tthis.metaKey = this.metaKey || this.keyCode === KeyCode.Meta;\r\n\r\n\t\tthis._asKeybinding = this._computeKeybinding();\r\n\t\tthis._asRuntimeKeybinding = this._computeRuntimeKeybinding();\r\n\r\n\t\t// console.log(`code: ${e.code}, keyCode: ${e.keyCode}, key: ${e.key}`);\r\n\t}\r\n\r\n\tpublic preventDefault(): void {\r\n\t\tif (this.browserEvent && this.browserEvent.preventDefault) {\r\n\t\t\tthis.browserEvent.preventDefault();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic stopPropagation(): void {\r\n\t\tif (this.browserEvent && this.browserEvent.stopPropagation) {\r\n\t\t\tthis.browserEvent.stopPropagation();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic toKeybinding(): SimpleKeybinding {\r\n\t\treturn this._asRuntimeKeybinding;\r\n\t}\r\n\r\n\tpublic equals(other: number): boolean {\r\n\t\treturn this._asKeybinding === other;\r\n\t}\r\n\r\n\tprivate _computeKeybinding(): number {\r\n\t\tlet key = KeyCode.Unknown;\r\n\t\tif (this.keyCode !== KeyCode.Ctrl && this.keyCode !== KeyCode.Shift && this.keyCode !== KeyCode.Alt && this.keyCode !== KeyCode.Meta) {\r\n\t\t\tkey = this.keyCode;\r\n\t\t}\r\n\r\n\t\tlet result = 0;\r\n\t\tif (this.ctrlKey) {\r\n\t\t\tresult |= ctrlKeyMod;\r\n\t\t}\r\n\t\tif (this.altKey) {\r\n\t\t\tresult |= altKeyMod;\r\n\t\t}\r\n\t\tif (this.shiftKey) {\r\n\t\t\tresult |= shiftKeyMod;\r\n\t\t}\r\n\t\tif (this.metaKey) {\r\n\t\t\tresult |= metaKeyMod;\r\n\t\t}\r\n\t\tresult |= key;\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate _computeRuntimeKeybinding(): SimpleKeybinding {\r\n\t\tlet key = KeyCode.Unknown;\r\n\t\tif (this.keyCode !== KeyCode.Ctrl && this.keyCode !== KeyCode.Shift && this.keyCode !== KeyCode.Alt && this.keyCode !== KeyCode.Meta) {\r\n\t\t\tkey = this.keyCode;\r\n\t\t}\r\n\t\treturn new SimpleKeybinding(this.ctrlKey, this.shiftKey, this.altKey, this.metaKey, key);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as browser from 'vs/base/browser/browser';\r\nimport { IframeUtils } from 'vs/base/browser/iframe';\r\nimport * as platform from 'vs/base/common/platform';\r\n\r\nexport interface IMouseEvent {\r\n\treadonly browserEvent: MouseEvent;\r\n\treadonly leftButton: boolean;\r\n\treadonly middleButton: boolean;\r\n\treadonly rightButton: boolean;\r\n\treadonly buttons: number;\r\n\treadonly target: HTMLElement;\r\n\treadonly detail: number;\r\n\treadonly posx: number;\r\n\treadonly posy: number;\r\n\treadonly ctrlKey: boolean;\r\n\treadonly shiftKey: boolean;\r\n\treadonly altKey: boolean;\r\n\treadonly metaKey: boolean;\r\n\treadonly timestamp: number;\r\n\r\n\tpreventDefault(): void;\r\n\tstopPropagation(): void;\r\n}\r\n\r\nexport class StandardMouseEvent implements IMouseEvent {\r\n\r\n\tpublic readonly browserEvent: MouseEvent;\r\n\r\n\tpublic readonly leftButton: boolean;\r\n\tpublic readonly middleButton: boolean;\r\n\tpublic readonly rightButton: boolean;\r\n\tpublic readonly buttons: number;\r\n\tpublic readonly target: HTMLElement;\r\n\tpublic detail: number;\r\n\tpublic readonly posx: number;\r\n\tpublic readonly posy: number;\r\n\tpublic readonly ctrlKey: boolean;\r\n\tpublic readonly shiftKey: boolean;\r\n\tpublic readonly altKey: boolean;\r\n\tpublic readonly metaKey: boolean;\r\n\tpublic readonly timestamp: number;\r\n\r\n\tconstructor(e: MouseEvent) {\r\n\t\tthis.timestamp = Date.now();\r\n\t\tthis.browserEvent = e;\r\n\t\tthis.leftButton = e.button === 0;\r\n\t\tthis.middleButton = e.button === 1;\r\n\t\tthis.rightButton = e.button === 2;\r\n\t\tthis.buttons = e.buttons;\r\n\r\n\t\tthis.target = e.target;\r\n\r\n\t\tthis.detail = e.detail || 1;\r\n\t\tif (e.type === 'dblclick') {\r\n\t\t\tthis.detail = 2;\r\n\t\t}\r\n\t\tthis.ctrlKey = e.ctrlKey;\r\n\t\tthis.shiftKey = e.shiftKey;\r\n\t\tthis.altKey = e.altKey;\r\n\t\tthis.metaKey = e.metaKey;\r\n\r\n\t\tif (typeof e.pageX === 'number') {\r\n\t\t\tthis.posx = e.pageX;\r\n\t\t\tthis.posy = e.pageY;\r\n\t\t} else {\r\n\t\t\t// Probably hit by MSGestureEvent\r\n\t\t\tthis.posx = e.clientX + document.body.scrollLeft + document.documentElement!.scrollLeft;\r\n\t\t\tthis.posy = e.clientY + document.body.scrollTop + document.documentElement!.scrollTop;\r\n\t\t}\r\n\r\n\t\t// Find the position of the iframe this code is executing in relative to the iframe where the event was captured.\r\n\t\tlet iframeOffsets = IframeUtils.getPositionOfChildWindowRelativeToAncestorWindow(self, e.view);\r\n\t\tthis.posx -= iframeOffsets.left;\r\n\t\tthis.posy -= iframeOffsets.top;\r\n\t}\r\n\r\n\tpublic preventDefault(): void {\r\n\t\tthis.browserEvent.preventDefault();\r\n\t}\r\n\r\n\tpublic stopPropagation(): void {\r\n\t\tthis.browserEvent.stopPropagation();\r\n\t}\r\n}\r\n\r\nexport interface IMouseWheelEvent extends MouseEvent {\r\n\treadonly wheelDelta: number;\r\n\treadonly wheelDeltaX: number;\r\n\treadonly wheelDeltaY: number;\r\n\r\n\treadonly deltaX: number;\r\n\treadonly deltaY: number;\r\n\treadonly deltaZ: number;\r\n\treadonly deltaMode: number;\r\n}\r\n\r\ninterface IWebKitMouseWheelEvent {\r\n\twheelDeltaY: number;\r\n\twheelDeltaX: number;\r\n}\r\n\r\ninterface IGeckoMouseWheelEvent {\r\n\tHORIZONTAL_AXIS: number;\r\n\tVERTICAL_AXIS: number;\r\n\taxis: number;\r\n\tdetail: number;\r\n}\r\n\r\nexport class StandardWheelEvent {\r\n\r\n\tpublic readonly browserEvent: IMouseWheelEvent | null;\r\n\tpublic readonly deltaY: number;\r\n\tpublic readonly deltaX: number;\r\n\tpublic readonly target: Node;\r\n\r\n\tconstructor(e: IMouseWheelEvent | null, deltaX: number = 0, deltaY: number = 0) {\r\n\r\n\t\tthis.browserEvent = e || null;\r\n\t\tthis.target = e ? (e.target || (e).targetNode || e.srcElement) : null;\r\n\r\n\t\tthis.deltaY = deltaY;\r\n\t\tthis.deltaX = deltaX;\r\n\r\n\t\tif (e) {\r\n\t\t\t// Old (deprecated) wheel events\r\n\t\t\tlet e1 = e;\r\n\t\t\tlet e2 = e;\r\n\r\n\t\t\t// vertical delta scroll\r\n\t\t\tif (typeof e1.wheelDeltaY !== 'undefined') {\r\n\t\t\t\tthis.deltaY = e1.wheelDeltaY / 120;\r\n\t\t\t} else if (typeof e2.VERTICAL_AXIS !== 'undefined' && e2.axis === e2.VERTICAL_AXIS) {\r\n\t\t\t\tthis.deltaY = -e2.detail / 3;\r\n\t\t\t} else if (e.type === 'wheel') {\r\n\t\t\t\t// Modern wheel event\r\n\t\t\t\t// https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent\r\n\t\t\t\tconst ev = e;\r\n\r\n\t\t\t\tif (ev.deltaMode === ev.DOM_DELTA_LINE) {\r\n\t\t\t\t\t// the deltas are expressed in lines\r\n\t\t\t\t\tif (browser.isFirefox && !platform.isMacintosh) {\r\n\t\t\t\t\t\tthis.deltaY = -e.deltaY / 3;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tthis.deltaY = -e.deltaY;\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis.deltaY = -e.deltaY / 40;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// horizontal delta scroll\r\n\t\t\tif (typeof e1.wheelDeltaX !== 'undefined') {\r\n\t\t\t\tif (browser.isSafari && platform.isWindows) {\r\n\t\t\t\t\tthis.deltaX = - (e1.wheelDeltaX / 120);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis.deltaX = e1.wheelDeltaX / 120;\r\n\t\t\t\t}\r\n\t\t\t} else if (typeof e2.HORIZONTAL_AXIS !== 'undefined' && e2.axis === e2.HORIZONTAL_AXIS) {\r\n\t\t\t\tthis.deltaX = -e.detail / 3;\r\n\t\t\t} else if (e.type === 'wheel') {\r\n\t\t\t\t// Modern wheel event\r\n\t\t\t\t// https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent\r\n\t\t\t\tconst ev = e;\r\n\r\n\t\t\t\tif (ev.deltaMode === ev.DOM_DELTA_LINE) {\r\n\t\t\t\t\t// the deltas are expressed in lines\r\n\t\t\t\t\tif (browser.isFirefox && !platform.isMacintosh) {\r\n\t\t\t\t\t\tthis.deltaX = -e.deltaX / 3;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tthis.deltaX = -e.deltaX;\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis.deltaX = -e.deltaX / 40;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// Assume a vertical scroll if nothing else worked\r\n\t\t\tif (this.deltaY === 0 && this.deltaX === 0 && e.wheelDelta) {\r\n\t\t\t\tthis.deltaY = e.wheelDelta / 120;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic preventDefault(): void {\r\n\t\tif (this.browserEvent) {\r\n\t\t\tthis.browserEvent.preventDefault();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic stopPropagation(): void {\r\n\t\tif (this.browserEvent) {\r\n\t\t\tthis.browserEvent.stopPropagation();\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\n\r\nexport interface CancellationToken {\r\n\r\n\t/**\r\n\t * A flag signalling is cancellation has been requested.\r\n\t */\r\n\treadonly isCancellationRequested: boolean;\r\n\r\n\t/**\r\n\t * An event which fires when cancellation is requested. This event\r\n\t * only ever fires `once` as cancellation can only happen once. Listeners\r\n\t * that are registered after cancellation will be called (next event loop run),\r\n\t * but also only once.\r\n\t *\r\n\t * @event\r\n\t */\r\n\treadonly onCancellationRequested: (listener: (e: any) => any, thisArgs?: any, disposables?: IDisposable[]) => IDisposable;\r\n}\r\n\r\nconst shortcutEvent: Event = Object.freeze(function (callback, context?): IDisposable {\r\n\tconst handle = setTimeout(callback.bind(context), 0);\r\n\treturn { dispose() { clearTimeout(handle); } };\r\n});\r\n\r\nexport namespace CancellationToken {\r\n\r\n\texport function isCancellationToken(thing: unknown): thing is CancellationToken {\r\n\t\tif (thing === CancellationToken.None || thing === CancellationToken.Cancelled) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (thing instanceof MutableToken) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (!thing || typeof thing !== 'object') {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn typeof (thing as CancellationToken).isCancellationRequested === 'boolean'\r\n\t\t\t&& typeof (thing as CancellationToken).onCancellationRequested === 'function';\r\n\t}\r\n\r\n\r\n\texport const None: CancellationToken = Object.freeze({\r\n\t\tisCancellationRequested: false,\r\n\t\tonCancellationRequested: Event.None\r\n\t});\r\n\r\n\texport const Cancelled: CancellationToken = Object.freeze({\r\n\t\tisCancellationRequested: true,\r\n\t\tonCancellationRequested: shortcutEvent\r\n\t});\r\n}\r\n\r\nclass MutableToken implements CancellationToken {\r\n\r\n\tprivate _isCancelled: boolean = false;\r\n\tprivate _emitter: Emitter | null = null;\r\n\r\n\tpublic cancel() {\r\n\t\tif (!this._isCancelled) {\r\n\t\t\tthis._isCancelled = true;\r\n\t\t\tif (this._emitter) {\r\n\t\t\t\tthis._emitter.fire(undefined);\r\n\t\t\t\tthis.dispose();\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tget isCancellationRequested(): boolean {\r\n\t\treturn this._isCancelled;\r\n\t}\r\n\r\n\tget onCancellationRequested(): Event {\r\n\t\tif (this._isCancelled) {\r\n\t\t\treturn shortcutEvent;\r\n\t\t}\r\n\t\tif (!this._emitter) {\r\n\t\t\tthis._emitter = new Emitter();\r\n\t\t}\r\n\t\treturn this._emitter.event;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tif (this._emitter) {\r\n\t\t\tthis._emitter.dispose();\r\n\t\t\tthis._emitter = null;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class CancellationTokenSource {\r\n\r\n\tprivate _token?: CancellationToken = undefined;\r\n\tprivate _parentListener?: IDisposable = undefined;\r\n\r\n\tconstructor(parent?: CancellationToken) {\r\n\t\tthis._parentListener = parent && parent.onCancellationRequested(this.cancel, this);\r\n\t}\r\n\r\n\tget token(): CancellationToken {\r\n\t\tif (!this._token) {\r\n\t\t\t// be lazy and create the token only when\r\n\t\t\t// actually needed\r\n\t\t\tthis._token = new MutableToken();\r\n\t\t}\r\n\t\treturn this._token;\r\n\t}\r\n\r\n\tcancel(): void {\r\n\t\tif (!this._token) {\r\n\t\t\t// save an object by returning the default\r\n\t\t\t// cancelled token when cancellation happens\r\n\t\t\t// before someone asks for the token\r\n\t\t\tthis._token = CancellationToken.Cancelled;\r\n\r\n\t\t} else if (this._token instanceof MutableToken) {\r\n\t\t\t// actually cancel\r\n\t\t\tthis._token.cancel();\r\n\t\t}\r\n\t}\r\n\r\n\tdispose(cancel: boolean = false): void {\r\n\t\tif (cancel) {\r\n\t\t\tthis.cancel();\r\n\t\t}\r\n\t\tif (this._parentListener) {\r\n\t\t\tthis._parentListener.dispose();\r\n\t\t}\r\n\t\tif (!this._token) {\r\n\t\t\t// ensure to initialize with an empty token if we had none\r\n\t\t\tthis._token = CancellationToken.None;\r\n\r\n\t\t} else if (this._token instanceof MutableToken) {\r\n\t\t\t// actually dispose\r\n\t\t\tthis._token.dispose();\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\r\nimport * as errors from 'vs/base/common/errors';\r\nimport { IDisposable, toDisposable } from 'vs/base/common/lifecycle';\r\n\r\nexport function isThenable(obj: any): obj is Promise {\r\n\treturn obj && typeof (>obj).then === 'function';\r\n}\r\n\r\nexport interface CancelablePromise extends Promise {\r\n\tcancel(): void;\r\n}\r\n\r\nexport function createCancelablePromise(callback: (token: CancellationToken) => Promise): CancelablePromise {\r\n\tconst source = new CancellationTokenSource();\r\n\r\n\tconst thenable = callback(source.token);\r\n\tconst promise = new Promise((resolve, reject) => {\r\n\t\tsource.token.onCancellationRequested(() => {\r\n\t\t\treject(errors.canceled());\r\n\t\t});\r\n\t\tPromise.resolve(thenable).then(value => {\r\n\t\t\tsource.dispose();\r\n\t\t\tresolve(value);\r\n\t\t}, err => {\r\n\t\t\tsource.dispose();\r\n\t\t\treject(err);\r\n\t\t});\r\n\t});\r\n\r\n\treturn >new class {\r\n\t\tcancel() {\r\n\t\t\tsource.cancel();\r\n\t\t}\r\n\t\tthen(resolve?: ((value: T) => TResult1 | Promise) | undefined | null, reject?: ((reason: any) => TResult2 | Promise) | undefined | null): Promise {\r\n\t\t\treturn promise.then(resolve, reject);\r\n\t\t}\r\n\t\tcatch(reject?: ((reason: any) => TResult | Promise) | undefined | null): Promise {\r\n\t\t\treturn this.then(undefined, reject);\r\n\t\t}\r\n\t\tfinally(onfinally?: (() => void) | undefined | null): Promise {\r\n\t\t\treturn promise.finally(onfinally);\r\n\t\t}\r\n\t};\r\n}\r\n\r\nexport function raceCancellation(promise: Promise, token: CancellationToken): Promise;\r\nexport function raceCancellation(promise: Promise, token: CancellationToken, defaultValue: T): Promise;\r\nexport function raceCancellation(promise: Promise, token: CancellationToken, defaultValue?: T): Promise {\r\n\treturn Promise.race([promise, new Promise(resolve => token.onCancellationRequested(() => resolve(defaultValue)))]);\r\n}\r\n\r\nexport interface ITask {\r\n\t(): T;\r\n}\r\n\r\n/**\r\n * A helper to delay (debounce) execution of a task that is being requested often.\r\n *\r\n * Following the throttler, now imagine the mail man wants to optimize the number of\r\n * trips proactively. The trip itself can be long, so he decides not to make the trip\r\n * as soon as a letter is submitted. Instead he waits a while, in case more\r\n * letters are submitted. After said waiting period, if no letters were submitted, he\r\n * decides to make the trip. Imagine that N more letters were submitted after the first\r\n * one, all within a short period of time between each other. Even though N+1\r\n * submissions occurred, only 1 delivery was made.\r\n *\r\n * The delayer offers this behavior via the trigger() method, into which both the task\r\n * to be executed and the waiting period (delay) must be passed in as arguments. Following\r\n * the example:\r\n *\r\n * \t\tconst delayer = new Delayer(WAITING_PERIOD);\r\n * \t\tconst letters = [];\r\n *\r\n * \t\tfunction letterReceived(l) {\r\n * \t\t\tletters.push(l);\r\n * \t\t\tdelayer.trigger(() => { return makeTheTrip(); });\r\n * \t\t}\r\n */\r\nexport class Delayer implements IDisposable {\r\n\r\n\tprivate timeout: any;\r\n\tprivate completionPromise: Promise | null;\r\n\tprivate doResolve: ((value?: any | Promise) => void) | null;\r\n\tprivate doReject: ((err: any) => void) | null;\r\n\tprivate task: ITask> | null;\r\n\r\n\tconstructor(public defaultDelay: number) {\r\n\t\tthis.timeout = null;\r\n\t\tthis.completionPromise = null;\r\n\t\tthis.doResolve = null;\r\n\t\tthis.doReject = null;\r\n\t\tthis.task = null;\r\n\t}\r\n\r\n\ttrigger(task: ITask>, delay: number = this.defaultDelay): Promise {\r\n\t\tthis.task = task;\r\n\t\tthis.cancelTimeout();\r\n\r\n\t\tif (!this.completionPromise) {\r\n\t\t\tthis.completionPromise = new Promise((resolve, reject) => {\r\n\t\t\t\tthis.doResolve = resolve;\r\n\t\t\t\tthis.doReject = reject;\r\n\t\t\t}).then(() => {\r\n\t\t\t\tthis.completionPromise = null;\r\n\t\t\t\tthis.doResolve = null;\r\n\t\t\t\tif (this.task) {\r\n\t\t\t\t\tconst task = this.task;\r\n\t\t\t\t\tthis.task = null;\r\n\t\t\t\t\treturn task();\r\n\t\t\t\t}\r\n\t\t\t\treturn undefined;\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tthis.timeout = setTimeout(() => {\r\n\t\t\tthis.timeout = null;\r\n\t\t\tif (this.doResolve) {\r\n\t\t\t\tthis.doResolve(null);\r\n\t\t\t}\r\n\t\t}, delay);\r\n\r\n\t\treturn this.completionPromise;\r\n\t}\r\n\r\n\tisTriggered(): boolean {\r\n\t\treturn this.timeout !== null;\r\n\t}\r\n\r\n\tcancel(): void {\r\n\t\tthis.cancelTimeout();\r\n\r\n\t\tif (this.completionPromise) {\r\n\t\t\tif (this.doReject) {\r\n\t\t\t\tthis.doReject(errors.canceled());\r\n\t\t\t}\r\n\t\t\tthis.completionPromise = null;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate cancelTimeout(): void {\r\n\t\tif (this.timeout !== null) {\r\n\t\t\tclearTimeout(this.timeout);\r\n\t\t\tthis.timeout = null;\r\n\t\t}\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis.cancelTimeout();\r\n\t}\r\n}\r\n\r\nexport function timeout(millis: number): CancelablePromise;\r\nexport function timeout(millis: number, token: CancellationToken): Promise;\r\nexport function timeout(millis: number, token?: CancellationToken): CancelablePromise | Promise {\r\n\tif (!token) {\r\n\t\treturn createCancelablePromise(token => timeout(millis, token));\r\n\t}\r\n\r\n\treturn new Promise((resolve, reject) => {\r\n\t\tconst handle = setTimeout(resolve, millis);\r\n\t\ttoken.onCancellationRequested(() => {\r\n\t\t\tclearTimeout(handle);\r\n\t\t\treject(errors.canceled());\r\n\t\t});\r\n\t});\r\n}\r\n\r\nexport function disposableTimeout(handler: () => void, timeout = 0): IDisposable {\r\n\tconst timer = setTimeout(handler, timeout);\r\n\treturn toDisposable(() => clearTimeout(timer));\r\n}\r\n\r\nexport function first(promiseFactories: ITask>[], shouldStop: (t: T) => boolean = t => !!t, defaultValue: T | null = null): Promise {\r\n\tlet index = 0;\r\n\tconst len = promiseFactories.length;\r\n\r\n\tconst loop: () => Promise = () => {\r\n\t\tif (index >= len) {\r\n\t\t\treturn Promise.resolve(defaultValue);\r\n\t\t}\r\n\r\n\t\tconst factory = promiseFactories[index++];\r\n\t\tconst promise = Promise.resolve(factory());\r\n\r\n\t\treturn promise.then(result => {\r\n\t\t\tif (shouldStop(result)) {\r\n\t\t\t\treturn Promise.resolve(result);\r\n\t\t\t}\r\n\r\n\t\t\treturn loop();\r\n\t\t});\r\n\t};\r\n\r\n\treturn loop();\r\n}\r\n\r\nexport class TimeoutTimer implements IDisposable {\r\n\tprivate _token: any;\r\n\r\n\tconstructor();\r\n\tconstructor(runner: () => void, timeout: number);\r\n\tconstructor(runner?: () => void, timeout?: number) {\r\n\t\tthis._token = -1;\r\n\r\n\t\tif (typeof runner === 'function' && typeof timeout === 'number') {\r\n\t\t\tthis.setIfNotSet(runner, timeout);\r\n\t\t}\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis.cancel();\r\n\t}\r\n\r\n\tcancel(): void {\r\n\t\tif (this._token !== -1) {\r\n\t\t\tclearTimeout(this._token);\r\n\t\t\tthis._token = -1;\r\n\t\t}\r\n\t}\r\n\r\n\tcancelAndSet(runner: () => void, timeout: number): void {\r\n\t\tthis.cancel();\r\n\t\tthis._token = setTimeout(() => {\r\n\t\t\tthis._token = -1;\r\n\t\t\trunner();\r\n\t\t}, timeout);\r\n\t}\r\n\r\n\tsetIfNotSet(runner: () => void, timeout: number): void {\r\n\t\tif (this._token !== -1) {\r\n\t\t\t// timer is already set\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._token = setTimeout(() => {\r\n\t\t\tthis._token = -1;\r\n\t\t\trunner();\r\n\t\t}, timeout);\r\n\t}\r\n}\r\n\r\nexport class IntervalTimer implements IDisposable {\r\n\r\n\tprivate _token: any;\r\n\r\n\tconstructor() {\r\n\t\tthis._token = -1;\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis.cancel();\r\n\t}\r\n\r\n\tcancel(): void {\r\n\t\tif (this._token !== -1) {\r\n\t\t\tclearInterval(this._token);\r\n\t\t\tthis._token = -1;\r\n\t\t}\r\n\t}\r\n\r\n\tcancelAndSet(runner: () => void, interval: number): void {\r\n\t\tthis.cancel();\r\n\t\tthis._token = setInterval(() => {\r\n\t\t\trunner();\r\n\t\t}, interval);\r\n\t}\r\n}\r\n\r\nexport class RunOnceScheduler {\r\n\r\n\tprotected runner: ((...args: any[]) => void) | null;\r\n\r\n\tprivate timeoutToken: any;\r\n\tprivate timeout: number;\r\n\tprivate timeoutHandler: () => void;\r\n\r\n\tconstructor(runner: (...args: any[]) => void, delay: number) {\r\n\t\tthis.timeoutToken = -1;\r\n\t\tthis.runner = runner;\r\n\t\tthis.timeout = delay;\r\n\t\tthis.timeoutHandler = this.onTimeout.bind(this);\r\n\t}\r\n\r\n\t/**\r\n\t * Dispose RunOnceScheduler\r\n\t */\r\n\tdispose(): void {\r\n\t\tthis.cancel();\r\n\t\tthis.runner = null;\r\n\t}\r\n\r\n\t/**\r\n\t * Cancel current scheduled runner (if any).\r\n\t */\r\n\tcancel(): void {\r\n\t\tif (this.isScheduled()) {\r\n\t\t\tclearTimeout(this.timeoutToken);\r\n\t\t\tthis.timeoutToken = -1;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Cancel previous runner (if any) & schedule a new runner.\r\n\t */\r\n\tschedule(delay = this.timeout): void {\r\n\t\tthis.cancel();\r\n\t\tthis.timeoutToken = setTimeout(this.timeoutHandler, delay);\r\n\t}\r\n\r\n\tget delay(): number {\r\n\t\treturn this.timeout;\r\n\t}\r\n\r\n\tset delay(value: number) {\r\n\t\tthis.timeout = value;\r\n\t}\r\n\r\n\t/**\r\n\t * Returns true if scheduled.\r\n\t */\r\n\tisScheduled(): boolean {\r\n\t\treturn this.timeoutToken !== -1;\r\n\t}\r\n\r\n\tprivate onTimeout() {\r\n\t\tthis.timeoutToken = -1;\r\n\t\tif (this.runner) {\r\n\t\t\tthis.doRun();\r\n\t\t}\r\n\t}\r\n\r\n\tprotected doRun(): void {\r\n\t\tif (this.runner) {\r\n\t\t\tthis.runner();\r\n\t\t}\r\n\t}\r\n}\r\n\r\n//#region -- run on idle tricks ------------\r\n\r\nexport interface IdleDeadline {\r\n}\r\n/**\r\n * Execute the callback the next time the browser is idle\r\n */\r\nexport let runWhenIdle: (callback: (idle: IdleDeadline) => void, timeout?: number) => IDisposable;\r\n\r\ndeclare function requestIdleCallback(callback: (args: IdleDeadline) => void, options?: { timeout: number }): number;\r\ndeclare function cancelIdleCallback(handle: number): void;\r\n\r\n(function () {\r\n\tif (typeof requestIdleCallback !== 'function' || typeof cancelIdleCallback !== 'function') {\r\n\t\tconst dummyIdle: IdleDeadline = Object.freeze({\r\n\t\t\tdidTimeout: true,\r\n\t\t\ttimeRemaining() { return 15; }\r\n\t\t});\r\n\t\trunWhenIdle = (runner) => {\r\n\t\t\tconst handle = setTimeout(() => runner(dummyIdle));\r\n\t\t\tlet disposed = false;\r\n\t\t\treturn {\r\n\t\t\t\tdispose() {\r\n\t\t\t\t\tif (disposed) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tdisposed = true;\r\n\t\t\t\t\tclearTimeout(handle);\r\n\t\t\t\t}\r\n\t\t\t};\r\n\t\t};\r\n\t} else {\r\n\t\trunWhenIdle = (runner, timeout?) => {\r\n\t\t\tconst handle: number = requestIdleCallback(runner, typeof timeout === 'number' ? { timeout } : undefined);\r\n\t\t\tlet disposed = false;\r\n\t\t\treturn {\r\n\t\t\t\tdispose() {\r\n\t\t\t\t\tif (disposed) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tdisposed = true;\r\n\t\t\t\t\tcancelIdleCallback(handle);\r\n\t\t\t\t}\r\n\t\t\t};\r\n\t\t};\r\n\t}\r\n})();\r\n\r\n/**\r\n * An implementation of the \"idle-until-urgent\"-strategy as introduced\r\n * here: https://philipwalton.com/articles/idle-until-urgent/\r\n */\r\nexport class IdleValue {\r\n\r\n\tprivate readonly _executor: () => void;\r\n\tprivate readonly _handle: IDisposable;\r\n\r\n\tprivate _didRun: boolean = false;\r\n\tprivate _value?: T;\r\n\tprivate _error: any;\r\n\r\n\tconstructor(executor: () => T) {\r\n\t\tthis._executor = () => {\r\n\t\t\ttry {\r\n\t\t\t\tthis._value = executor();\r\n\t\t\t} catch (err) {\r\n\t\t\t\tthis._error = err;\r\n\t\t\t} finally {\r\n\t\t\t\tthis._didRun = true;\r\n\t\t\t}\r\n\t\t};\r\n\t\tthis._handle = runWhenIdle(() => this._executor());\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._handle.dispose();\r\n\t}\r\n\r\n\tget value(): T {\r\n\t\tif (!this._didRun) {\r\n\t\t\tthis._handle.dispose();\r\n\t\t\tthis._executor();\r\n\t\t}\r\n\t\tif (this._error) {\r\n\t\t\tthrow this._error;\r\n\t\t}\r\n\t\treturn this._value!;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { FastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { TimeoutTimer } from 'vs/base/common/async';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { ScrollbarVisibility } from 'vs/base/common/scrollable';\r\n\r\nexport class ScrollbarVisibilityController extends Disposable {\r\n\tprivate _visibility: ScrollbarVisibility;\r\n\tprivate _visibleClassName: string;\r\n\tprivate _invisibleClassName: string;\r\n\tprivate _domNode: FastDomNode | null;\r\n\tprivate _shouldBeVisible: boolean;\r\n\tprivate _isNeeded: boolean;\r\n\tprivate _isVisible: boolean;\r\n\tprivate _revealTimer: TimeoutTimer;\r\n\r\n\tconstructor(visibility: ScrollbarVisibility, visibleClassName: string, invisibleClassName: string) {\r\n\t\tsuper();\r\n\t\tthis._visibility = visibility;\r\n\t\tthis._visibleClassName = visibleClassName;\r\n\t\tthis._invisibleClassName = invisibleClassName;\r\n\t\tthis._domNode = null;\r\n\t\tthis._isVisible = false;\r\n\t\tthis._isNeeded = false;\r\n\t\tthis._shouldBeVisible = false;\r\n\t\tthis._revealTimer = this._register(new TimeoutTimer());\r\n\t}\r\n\r\n\t// ----------------- Hide / Reveal\r\n\r\n\tprivate applyVisibilitySetting(shouldBeVisible: boolean): boolean {\r\n\t\tif (this._visibility === ScrollbarVisibility.Hidden) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (this._visibility === ScrollbarVisibility.Visible) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn shouldBeVisible;\r\n\t}\r\n\r\n\tpublic setShouldBeVisible(rawShouldBeVisible: boolean): void {\r\n\t\tconst shouldBeVisible = this.applyVisibilitySetting(rawShouldBeVisible);\r\n\r\n\t\tif (this._shouldBeVisible !== shouldBeVisible) {\r\n\t\t\tthis._shouldBeVisible = shouldBeVisible;\r\n\t\t\tthis.ensureVisibility();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic setIsNeeded(isNeeded: boolean): void {\r\n\t\tif (this._isNeeded !== isNeeded) {\r\n\t\t\tthis._isNeeded = isNeeded;\r\n\t\t\tthis.ensureVisibility();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic setDomNode(domNode: FastDomNode): void {\r\n\t\tthis._domNode = domNode;\r\n\t\tthis._domNode.setClassName(this._invisibleClassName);\r\n\r\n\t\t// Now that the flags & the dom node are in a consistent state, ensure the Hidden/Visible configuration\r\n\t\tthis.setShouldBeVisible(false);\r\n\t}\r\n\r\n\tpublic ensureVisibility(): void {\r\n\r\n\t\tif (!this._isNeeded) {\r\n\t\t\t// Nothing to be rendered\r\n\t\t\tthis._hide(false);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this._shouldBeVisible) {\r\n\t\t\tthis._reveal();\r\n\t\t} else {\r\n\t\t\tthis._hide(true);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _reveal(): void {\r\n\t\tif (this._isVisible) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._isVisible = true;\r\n\r\n\t\t// The CSS animation doesn't play otherwise\r\n\t\tthis._revealTimer.setIfNotSet(() => {\r\n\t\t\tif (this._domNode) {\r\n\t\t\t\tthis._domNode.setClassName(this._visibleClassName);\r\n\t\t\t}\r\n\t\t}, 0);\r\n\t}\r\n\r\n\tprivate _hide(withFadeAway: boolean): void {\r\n\t\tthis._revealTimer.cancel();\r\n\t\tif (!this._isVisible) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._isVisible = false;\r\n\t\tif (this._domNode) {\r\n\t\t\tthis._domNode.setClassName(this._invisibleClassName + (withFadeAway ? ' fade' : ''));\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\n\r\nexport interface IIconRegistry {\r\n\treadonly all: IterableIterator;\r\n\treadonly onDidRegister: Event;\r\n\tget(id: string): Codicon | undefined;\r\n}\r\n\r\nclass Registry implements IIconRegistry {\r\n\r\n\tprivate readonly _icons = new Map();\r\n\tprivate readonly _onDidRegister = new Emitter();\r\n\r\n\tpublic add(icon: Codicon) {\r\n\t\tconst existing = this._icons.get(icon.id);\r\n\t\tif (!existing) {\r\n\t\t\tthis._icons.set(icon.id, icon);\r\n\t\t\tthis._onDidRegister.fire(icon);\r\n\t\t} else if (icon.description) {\r\n\t\t\texisting.description = icon.description;\r\n\t\t} else {\r\n\t\t\tconsole.error(`Duplicate registration of codicon ${icon.id}`);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic get(id: string): Codicon | undefined {\r\n\t\treturn this._icons.get(id);\r\n\t}\r\n\r\n\tpublic get all(): IterableIterator {\r\n\t\treturn this._icons.values();\r\n\t}\r\n\r\n\tpublic get onDidRegister(): Event {\r\n\t\treturn this._onDidRegister.event;\r\n\t}\r\n}\r\n\r\nconst _registry = new Registry();\r\n\r\nexport const iconRegistry: IIconRegistry = _registry;\r\n\r\nexport function registerCodicon(id: string, def: Codicon): Codicon {\r\n\treturn new Codicon(id, def);\r\n}\r\n\r\nexport class Codicon implements CSSIcon {\r\n\tconstructor(public readonly id: string, public readonly definition: Codicon | IconDefinition, public description?: string) {\r\n\t\t_registry.add(this);\r\n\t}\r\n\tpublic get classNames() { return 'codicon codicon-' + this.id; }\r\n\t// classNamesArray is useful for migrating to ES6 classlist\r\n\tpublic get classNamesArray() { return ['codicon', 'codicon-' + this.id]; }\r\n\tpublic get cssSelector() { return '.codicon.codicon-' + this.id; }\r\n}\r\n\r\nexport interface CSSIcon {\r\n\treadonly id: string;\r\n}\r\n\r\nexport namespace CSSIcon {\r\n\texport const iconIdRegex = /^(codicon\\/)?([a-z\\-]+)(?:~([a-z\\-]+))?$/i;\r\n\r\n\texport function asClassNameArray(icon: CSSIcon): string[] {\r\n\t\tif (icon instanceof Codicon) {\r\n\t\t\treturn ['codicon', 'codicon-' + icon.id];\r\n\t\t}\r\n\t\tconst match = iconIdRegex.exec(icon.id);\r\n\t\tif (!match) {\r\n\t\t\treturn asClassNameArray(Codicon.error);\r\n\t\t}\r\n\t\tlet [, , id, modifier] = match;\r\n\t\tconst classNames = ['codicon', 'codicon-' + id];\r\n\t\tif (modifier) {\r\n\t\t\tclassNames.push('codicon-modifier-' + modifier);\r\n\t\t}\r\n\t\treturn classNames;\r\n\t}\r\n\r\n\texport function asClassName(icon: CSSIcon): string {\r\n\t\treturn asClassNameArray(icon).join(' ');\r\n\t}\r\n\r\n\texport function asCSSSelector(icon: CSSIcon): string {\r\n\t\treturn '.' + asClassNameArray(icon).join('.');\r\n\t}\r\n}\r\n\r\n\r\n\r\ninterface IconDefinition {\r\n\tcharacter: string;\r\n}\r\n\r\nexport namespace Codicon {\r\n\r\n\t// built-in icons, with image name\r\n\texport const add = new Codicon('add', { character: '\\\\ea60' });\r\n\texport const plus = new Codicon('plus', { character: '\\\\ea60' });\r\n\texport const gistNew = new Codicon('gist-new', { character: '\\\\ea60' });\r\n\texport const repoCreate = new Codicon('repo-create', { character: '\\\\ea60' });\r\n\texport const lightbulb = new Codicon('lightbulb', { character: '\\\\ea61' });\r\n\texport const lightBulb = new Codicon('light-bulb', { character: '\\\\ea61' });\r\n\texport const repo = new Codicon('repo', { character: '\\\\ea62' });\r\n\texport const repoDelete = new Codicon('repo-delete', { character: '\\\\ea62' });\r\n\texport const gistFork = new Codicon('gist-fork', { character: '\\\\ea63' });\r\n\texport const repoForked = new Codicon('repo-forked', { character: '\\\\ea63' });\r\n\texport const gitPullRequest = new Codicon('git-pull-request', { character: '\\\\ea64' });\r\n\texport const gitPullRequestAbandoned = new Codicon('git-pull-request-abandoned', { character: '\\\\ea64' });\r\n\texport const recordKeys = new Codicon('record-keys', { character: '\\\\ea65' });\r\n\texport const keyboard = new Codicon('keyboard', { character: '\\\\ea65' });\r\n\texport const tag = new Codicon('tag', { character: '\\\\ea66' });\r\n\texport const tagAdd = new Codicon('tag-add', { character: '\\\\ea66' });\r\n\texport const tagRemove = new Codicon('tag-remove', { character: '\\\\ea66' });\r\n\texport const person = new Codicon('person', { character: '\\\\ea67' });\r\n\texport const personAdd = new Codicon('person-add', { character: '\\\\ea67' });\r\n\texport const personFollow = new Codicon('person-follow', { character: '\\\\ea67' });\r\n\texport const personOutline = new Codicon('person-outline', { character: '\\\\ea67' });\r\n\texport const personFilled = new Codicon('person-filled', { character: '\\\\ea67' });\r\n\texport const gitBranch = new Codicon('git-branch', { character: '\\\\ea68' });\r\n\texport const gitBranchCreate = new Codicon('git-branch-create', { character: '\\\\ea68' });\r\n\texport const gitBranchDelete = new Codicon('git-branch-delete', { character: '\\\\ea68' });\r\n\texport const sourceControl = new Codicon('source-control', { character: '\\\\ea68' });\r\n\texport const mirror = new Codicon('mirror', { character: '\\\\ea69' });\r\n\texport const mirrorPublic = new Codicon('mirror-public', { character: '\\\\ea69' });\r\n\texport const star = new Codicon('star', { character: '\\\\ea6a' });\r\n\texport const starAdd = new Codicon('star-add', { character: '\\\\ea6a' });\r\n\texport const starDelete = new Codicon('star-delete', { character: '\\\\ea6a' });\r\n\texport const starEmpty = new Codicon('star-empty', { character: '\\\\ea6a' });\r\n\texport const comment = new Codicon('comment', { character: '\\\\ea6b' });\r\n\texport const commentAdd = new Codicon('comment-add', { character: '\\\\ea6b' });\r\n\texport const alert = new Codicon('alert', { character: '\\\\ea6c' });\r\n\texport const warning = new Codicon('warning', { character: '\\\\ea6c' });\r\n\texport const search = new Codicon('search', { character: '\\\\ea6d' });\r\n\texport const searchSave = new Codicon('search-save', { character: '\\\\ea6d' });\r\n\texport const logOut = new Codicon('log-out', { character: '\\\\ea6e' });\r\n\texport const signOut = new Codicon('sign-out', { character: '\\\\ea6e' });\r\n\texport const logIn = new Codicon('log-in', { character: '\\\\ea6f' });\r\n\texport const signIn = new Codicon('sign-in', { character: '\\\\ea6f' });\r\n\texport const eye = new Codicon('eye', { character: '\\\\ea70' });\r\n\texport const eyeUnwatch = new Codicon('eye-unwatch', { character: '\\\\ea70' });\r\n\texport const eyeWatch = new Codicon('eye-watch', { character: '\\\\ea70' });\r\n\texport const circleFilled = new Codicon('circle-filled', { character: '\\\\ea71' });\r\n\texport const primitiveDot = new Codicon('primitive-dot', { character: '\\\\ea71' });\r\n\texport const closeDirty = new Codicon('close-dirty', { character: '\\\\ea71' });\r\n\texport const debugBreakpoint = new Codicon('debug-breakpoint', { character: '\\\\ea71' });\r\n\texport const debugBreakpointDisabled = new Codicon('debug-breakpoint-disabled', { character: '\\\\ea71' });\r\n\texport const debugHint = new Codicon('debug-hint', { character: '\\\\ea71' });\r\n\texport const primitiveSquare = new Codicon('primitive-square', { character: '\\\\ea72' });\r\n\texport const edit = new Codicon('edit', { character: '\\\\ea73' });\r\n\texport const pencil = new Codicon('pencil', { character: '\\\\ea73' });\r\n\texport const info = new Codicon('info', { character: '\\\\ea74' });\r\n\texport const issueOpened = new Codicon('issue-opened', { character: '\\\\ea74' });\r\n\texport const gistPrivate = new Codicon('gist-private', { character: '\\\\ea75' });\r\n\texport const gitForkPrivate = new Codicon('git-fork-private', { character: '\\\\ea75' });\r\n\texport const lock = new Codicon('lock', { character: '\\\\ea75' });\r\n\texport const mirrorPrivate = new Codicon('mirror-private', { character: '\\\\ea75' });\r\n\texport const close = new Codicon('close', { character: '\\\\ea76' });\r\n\texport const removeClose = new Codicon('remove-close', { character: '\\\\ea76' });\r\n\texport const x = new Codicon('x', { character: '\\\\ea76' });\r\n\texport const repoSync = new Codicon('repo-sync', { character: '\\\\ea77' });\r\n\texport const sync = new Codicon('sync', { character: '\\\\ea77' });\r\n\texport const clone = new Codicon('clone', { character: '\\\\ea78' });\r\n\texport const desktopDownload = new Codicon('desktop-download', { character: '\\\\ea78' });\r\n\texport const beaker = new Codicon('beaker', { character: '\\\\ea79' });\r\n\texport const microscope = new Codicon('microscope', { character: '\\\\ea79' });\r\n\texport const vm = new Codicon('vm', { character: '\\\\ea7a' });\r\n\texport const deviceDesktop = new Codicon('device-desktop', { character: '\\\\ea7a' });\r\n\texport const file = new Codicon('file', { character: '\\\\ea7b' });\r\n\texport const fileText = new Codicon('file-text', { character: '\\\\ea7b' });\r\n\texport const more = new Codicon('more', { character: '\\\\ea7c' });\r\n\texport const ellipsis = new Codicon('ellipsis', { character: '\\\\ea7c' });\r\n\texport const kebabHorizontal = new Codicon('kebab-horizontal', { character: '\\\\ea7c' });\r\n\texport const mailReply = new Codicon('mail-reply', { character: '\\\\ea7d' });\r\n\texport const reply = new Codicon('reply', { character: '\\\\ea7d' });\r\n\texport const organization = new Codicon('organization', { character: '\\\\ea7e' });\r\n\texport const organizationFilled = new Codicon('organization-filled', { character: '\\\\ea7e' });\r\n\texport const organizationOutline = new Codicon('organization-outline', { character: '\\\\ea7e' });\r\n\texport const newFile = new Codicon('new-file', { character: '\\\\ea7f' });\r\n\texport const fileAdd = new Codicon('file-add', { character: '\\\\ea7f' });\r\n\texport const newFolder = new Codicon('new-folder', { character: '\\\\ea80' });\r\n\texport const fileDirectoryCreate = new Codicon('file-directory-create', { character: '\\\\ea80' });\r\n\texport const trash = new Codicon('trash', { character: '\\\\ea81' });\r\n\texport const trashcan = new Codicon('trashcan', { character: '\\\\ea81' });\r\n\texport const history = new Codicon('history', { character: '\\\\ea82' });\r\n\texport const clock = new Codicon('clock', { character: '\\\\ea82' });\r\n\texport const folder = new Codicon('folder', { character: '\\\\ea83' });\r\n\texport const fileDirectory = new Codicon('file-directory', { character: '\\\\ea83' });\r\n\texport const symbolFolder = new Codicon('symbol-folder', { character: '\\\\ea83' });\r\n\texport const logoGithub = new Codicon('logo-github', { character: '\\\\ea84' });\r\n\texport const markGithub = new Codicon('mark-github', { character: '\\\\ea84' });\r\n\texport const github = new Codicon('github', { character: '\\\\ea84' });\r\n\texport const terminal = new Codicon('terminal', { character: '\\\\ea85' });\r\n\texport const console = new Codicon('console', { character: '\\\\ea85' });\r\n\texport const repl = new Codicon('repl', { character: '\\\\ea85' });\r\n\texport const zap = new Codicon('zap', { character: '\\\\ea86' });\r\n\texport const symbolEvent = new Codicon('symbol-event', { character: '\\\\ea86' });\r\n\texport const error = new Codicon('error', { character: '\\\\ea87' });\r\n\texport const stop = new Codicon('stop', { character: '\\\\ea87' });\r\n\texport const variable = new Codicon('variable', { character: '\\\\ea88' });\r\n\texport const symbolVariable = new Codicon('symbol-variable', { character: '\\\\ea88' });\r\n\texport const array = new Codicon('array', { character: '\\\\ea8a' });\r\n\texport const symbolArray = new Codicon('symbol-array', { character: '\\\\ea8a' });\r\n\texport const symbolModule = new Codicon('symbol-module', { character: '\\\\ea8b' });\r\n\texport const symbolPackage = new Codicon('symbol-package', { character: '\\\\ea8b' });\r\n\texport const symbolNamespace = new Codicon('symbol-namespace', { character: '\\\\ea8b' });\r\n\texport const symbolObject = new Codicon('symbol-object', { character: '\\\\ea8b' });\r\n\texport const symbolMethod = new Codicon('symbol-method', { character: '\\\\ea8c' });\r\n\texport const symbolFunction = new Codicon('symbol-function', { character: '\\\\ea8c' });\r\n\texport const symbolConstructor = new Codicon('symbol-constructor', { character: '\\\\ea8c' });\r\n\texport const symbolBoolean = new Codicon('symbol-boolean', { character: '\\\\ea8f' });\r\n\texport const symbolNull = new Codicon('symbol-null', { character: '\\\\ea8f' });\r\n\texport const symbolNumeric = new Codicon('symbol-numeric', { character: '\\\\ea90' });\r\n\texport const symbolNumber = new Codicon('symbol-number', { character: '\\\\ea90' });\r\n\texport const symbolStructure = new Codicon('symbol-structure', { character: '\\\\ea91' });\r\n\texport const symbolStruct = new Codicon('symbol-struct', { character: '\\\\ea91' });\r\n\texport const symbolParameter = new Codicon('symbol-parameter', { character: '\\\\ea92' });\r\n\texport const symbolTypeParameter = new Codicon('symbol-type-parameter', { character: '\\\\ea92' });\r\n\texport const symbolKey = new Codicon('symbol-key', { character: '\\\\ea93' });\r\n\texport const symbolText = new Codicon('symbol-text', { character: '\\\\ea93' });\r\n\texport const symbolReference = new Codicon('symbol-reference', { character: '\\\\ea94' });\r\n\texport const goToFile = new Codicon('go-to-file', { character: '\\\\ea94' });\r\n\texport const symbolEnum = new Codicon('symbol-enum', { character: '\\\\ea95' });\r\n\texport const symbolValue = new Codicon('symbol-value', { character: '\\\\ea95' });\r\n\texport const symbolRuler = new Codicon('symbol-ruler', { character: '\\\\ea96' });\r\n\texport const symbolUnit = new Codicon('symbol-unit', { character: '\\\\ea96' });\r\n\texport const activateBreakpoints = new Codicon('activate-breakpoints', { character: '\\\\ea97' });\r\n\texport const archive = new Codicon('archive', { character: '\\\\ea98' });\r\n\texport const arrowBoth = new Codicon('arrow-both', { character: '\\\\ea99' });\r\n\texport const arrowDown = new Codicon('arrow-down', { character: '\\\\ea9a' });\r\n\texport const arrowLeft = new Codicon('arrow-left', { character: '\\\\ea9b' });\r\n\texport const arrowRight = new Codicon('arrow-right', { character: '\\\\ea9c' });\r\n\texport const arrowSmallDown = new Codicon('arrow-small-down', { character: '\\\\ea9d' });\r\n\texport const arrowSmallLeft = new Codicon('arrow-small-left', { character: '\\\\ea9e' });\r\n\texport const arrowSmallRight = new Codicon('arrow-small-right', { character: '\\\\ea9f' });\r\n\texport const arrowSmallUp = new Codicon('arrow-small-up', { character: '\\\\eaa0' });\r\n\texport const arrowUp = new Codicon('arrow-up', { character: '\\\\eaa1' });\r\n\texport const bell = new Codicon('bell', { character: '\\\\eaa2' });\r\n\texport const bold = new Codicon('bold', { character: '\\\\eaa3' });\r\n\texport const book = new Codicon('book', { character: '\\\\eaa4' });\r\n\texport const bookmark = new Codicon('bookmark', { character: '\\\\eaa5' });\r\n\texport const debugBreakpointConditionalUnverified = new Codicon('debug-breakpoint-conditional-unverified', { character: '\\\\eaa6' });\r\n\texport const debugBreakpointConditional = new Codicon('debug-breakpoint-conditional', { character: '\\\\eaa7' });\r\n\texport const debugBreakpointConditionalDisabled = new Codicon('debug-breakpoint-conditional-disabled', { character: '\\\\eaa7' });\r\n\texport const debugBreakpointDataUnverified = new Codicon('debug-breakpoint-data-unverified', { character: '\\\\eaa8' });\r\n\texport const debugBreakpointData = new Codicon('debug-breakpoint-data', { character: '\\\\eaa9' });\r\n\texport const debugBreakpointDataDisabled = new Codicon('debug-breakpoint-data-disabled', { character: '\\\\eaa9' });\r\n\texport const debugBreakpointLogUnverified = new Codicon('debug-breakpoint-log-unverified', { character: '\\\\eaaa' });\r\n\texport const debugBreakpointLog = new Codicon('debug-breakpoint-log', { character: '\\\\eaab' });\r\n\texport const debugBreakpointLogDisabled = new Codicon('debug-breakpoint-log-disabled', { character: '\\\\eaab' });\r\n\texport const briefcase = new Codicon('briefcase', { character: '\\\\eaac' });\r\n\texport const broadcast = new Codicon('broadcast', { character: '\\\\eaad' });\r\n\texport const browser = new Codicon('browser', { character: '\\\\eaae' });\r\n\texport const bug = new Codicon('bug', { character: '\\\\eaaf' });\r\n\texport const calendar = new Codicon('calendar', { character: '\\\\eab0' });\r\n\texport const caseSensitive = new Codicon('case-sensitive', { character: '\\\\eab1' });\r\n\texport const check = new Codicon('check', { character: '\\\\eab2' });\r\n\texport const checklist = new Codicon('checklist', { character: '\\\\eab3' });\r\n\texport const chevronDown = new Codicon('chevron-down', { character: '\\\\eab4' });\r\n\texport const chevronLeft = new Codicon('chevron-left', { character: '\\\\eab5' });\r\n\texport const chevronRight = new Codicon('chevron-right', { character: '\\\\eab6' });\r\n\texport const chevronUp = new Codicon('chevron-up', { character: '\\\\eab7' });\r\n\texport const chromeClose = new Codicon('chrome-close', { character: '\\\\eab8' });\r\n\texport const chromeMaximize = new Codicon('chrome-maximize', { character: '\\\\eab9' });\r\n\texport const chromeMinimize = new Codicon('chrome-minimize', { character: '\\\\eaba' });\r\n\texport const chromeRestore = new Codicon('chrome-restore', { character: '\\\\eabb' });\r\n\texport const circleOutline = new Codicon('circle-outline', { character: '\\\\eabc' });\r\n\texport const debugBreakpointUnverified = new Codicon('debug-breakpoint-unverified', { character: '\\\\eabc' });\r\n\texport const circleSlash = new Codicon('circle-slash', { character: '\\\\eabd' });\r\n\texport const circuitBoard = new Codicon('circuit-board', { character: '\\\\eabe' });\r\n\texport const clearAll = new Codicon('clear-all', { character: '\\\\eabf' });\r\n\texport const clippy = new Codicon('clippy', { character: '\\\\eac0' });\r\n\texport const closeAll = new Codicon('close-all', { character: '\\\\eac1' });\r\n\texport const cloudDownload = new Codicon('cloud-download', { character: '\\\\eac2' });\r\n\texport const cloudUpload = new Codicon('cloud-upload', { character: '\\\\eac3' });\r\n\texport const code = new Codicon('code', { character: '\\\\eac4' });\r\n\texport const collapseAll = new Codicon('collapse-all', { character: '\\\\eac5' });\r\n\texport const colorMode = new Codicon('color-mode', { character: '\\\\eac6' });\r\n\texport const commentDiscussion = new Codicon('comment-discussion', { character: '\\\\eac7' });\r\n\texport const compareChanges = new Codicon('compare-changes', { character: '\\\\eafd' });\r\n\texport const creditCard = new Codicon('credit-card', { character: '\\\\eac9' });\r\n\texport const dash = new Codicon('dash', { character: '\\\\eacc' });\r\n\texport const dashboard = new Codicon('dashboard', { character: '\\\\eacd' });\r\n\texport const database = new Codicon('database', { character: '\\\\eace' });\r\n\texport const debugContinue = new Codicon('debug-continue', { character: '\\\\eacf' });\r\n\texport const debugDisconnect = new Codicon('debug-disconnect', { character: '\\\\ead0' });\r\n\texport const debugPause = new Codicon('debug-pause', { character: '\\\\ead1' });\r\n\texport const debugRestart = new Codicon('debug-restart', { character: '\\\\ead2' });\r\n\texport const debugStart = new Codicon('debug-start', { character: '\\\\ead3' });\r\n\texport const debugStepInto = new Codicon('debug-step-into', { character: '\\\\ead4' });\r\n\texport const debugStepOut = new Codicon('debug-step-out', { character: '\\\\ead5' });\r\n\texport const debugStepOver = new Codicon('debug-step-over', { character: '\\\\ead6' });\r\n\texport const debugStop = new Codicon('debug-stop', { character: '\\\\ead7' });\r\n\texport const debug = new Codicon('debug', { character: '\\\\ead8' });\r\n\texport const deviceCameraVideo = new Codicon('device-camera-video', { character: '\\\\ead9' });\r\n\texport const deviceCamera = new Codicon('device-camera', { character: '\\\\eada' });\r\n\texport const deviceMobile = new Codicon('device-mobile', { character: '\\\\eadb' });\r\n\texport const diffAdded = new Codicon('diff-added', { character: '\\\\eadc' });\r\n\texport const diffIgnored = new Codicon('diff-ignored', { character: '\\\\eadd' });\r\n\texport const diffModified = new Codicon('diff-modified', { character: '\\\\eade' });\r\n\texport const diffRemoved = new Codicon('diff-removed', { character: '\\\\eadf' });\r\n\texport const diffRenamed = new Codicon('diff-renamed', { character: '\\\\eae0' });\r\n\texport const diff = new Codicon('diff', { character: '\\\\eae1' });\r\n\texport const discard = new Codicon('discard', { character: '\\\\eae2' });\r\n\texport const editorLayout = new Codicon('editor-layout', { character: '\\\\eae3' });\r\n\texport const emptyWindow = new Codicon('empty-window', { character: '\\\\eae4' });\r\n\texport const exclude = new Codicon('exclude', { character: '\\\\eae5' });\r\n\texport const extensions = new Codicon('extensions', { character: '\\\\eae6' });\r\n\texport const eyeClosed = new Codicon('eye-closed', { character: '\\\\eae7' });\r\n\texport const fileBinary = new Codicon('file-binary', { character: '\\\\eae8' });\r\n\texport const fileCode = new Codicon('file-code', { character: '\\\\eae9' });\r\n\texport const fileMedia = new Codicon('file-media', { character: '\\\\eaea' });\r\n\texport const filePdf = new Codicon('file-pdf', { character: '\\\\eaeb' });\r\n\texport const fileSubmodule = new Codicon('file-submodule', { character: '\\\\eaec' });\r\n\texport const fileSymlinkDirectory = new Codicon('file-symlink-directory', { character: '\\\\eaed' });\r\n\texport const fileSymlinkFile = new Codicon('file-symlink-file', { character: '\\\\eaee' });\r\n\texport const fileZip = new Codicon('file-zip', { character: '\\\\eaef' });\r\n\texport const files = new Codicon('files', { character: '\\\\eaf0' });\r\n\texport const filter = new Codicon('filter', { character: '\\\\eaf1' });\r\n\texport const flame = new Codicon('flame', { character: '\\\\eaf2' });\r\n\texport const foldDown = new Codicon('fold-down', { character: '\\\\eaf3' });\r\n\texport const foldUp = new Codicon('fold-up', { character: '\\\\eaf4' });\r\n\texport const fold = new Codicon('fold', { character: '\\\\eaf5' });\r\n\texport const folderActive = new Codicon('folder-active', { character: '\\\\eaf6' });\r\n\texport const folderOpened = new Codicon('folder-opened', { character: '\\\\eaf7' });\r\n\texport const gear = new Codicon('gear', { character: '\\\\eaf8' });\r\n\texport const gift = new Codicon('gift', { character: '\\\\eaf9' });\r\n\texport const gistSecret = new Codicon('gist-secret', { character: '\\\\eafa' });\r\n\texport const gist = new Codicon('gist', { character: '\\\\eafb' });\r\n\texport const gitCommit = new Codicon('git-commit', { character: '\\\\eafc' });\r\n\texport const gitCompare = new Codicon('git-compare', { character: '\\\\eafd' });\r\n\texport const gitMerge = new Codicon('git-merge', { character: '\\\\eafe' });\r\n\texport const githubAction = new Codicon('github-action', { character: '\\\\eaff' });\r\n\texport const githubAlt = new Codicon('github-alt', { character: '\\\\eb00' });\r\n\texport const globe = new Codicon('globe', { character: '\\\\eb01' });\r\n\texport const grabber = new Codicon('grabber', { character: '\\\\eb02' });\r\n\texport const graph = new Codicon('graph', { character: '\\\\eb03' });\r\n\texport const gripper = new Codicon('gripper', { character: '\\\\eb04' });\r\n\texport const heart = new Codicon('heart', { character: '\\\\eb05' });\r\n\texport const home = new Codicon('home', { character: '\\\\eb06' });\r\n\texport const horizontalRule = new Codicon('horizontal-rule', { character: '\\\\eb07' });\r\n\texport const hubot = new Codicon('hubot', { character: '\\\\eb08' });\r\n\texport const inbox = new Codicon('inbox', { character: '\\\\eb09' });\r\n\texport const issueClosed = new Codicon('issue-closed', { character: '\\\\eb0a' });\r\n\texport const issueReopened = new Codicon('issue-reopened', { character: '\\\\eb0b' });\r\n\texport const issues = new Codicon('issues', { character: '\\\\eb0c' });\r\n\texport const italic = new Codicon('italic', { character: '\\\\eb0d' });\r\n\texport const jersey = new Codicon('jersey', { character: '\\\\eb0e' });\r\n\texport const json = new Codicon('json', { character: '\\\\eb0f' });\r\n\texport const kebabVertical = new Codicon('kebab-vertical', { character: '\\\\eb10' });\r\n\texport const key = new Codicon('key', { character: '\\\\eb11' });\r\n\texport const law = new Codicon('law', { character: '\\\\eb12' });\r\n\texport const lightbulbAutofix = new Codicon('lightbulb-autofix', { character: '\\\\eb13' });\r\n\texport const linkExternal = new Codicon('link-external', { character: '\\\\eb14' });\r\n\texport const link = new Codicon('link', { character: '\\\\eb15' });\r\n\texport const listOrdered = new Codicon('list-ordered', { character: '\\\\eb16' });\r\n\texport const listUnordered = new Codicon('list-unordered', { character: '\\\\eb17' });\r\n\texport const liveShare = new Codicon('live-share', { character: '\\\\eb18' });\r\n\texport const loading = new Codicon('loading', { character: '\\\\eb19' });\r\n\texport const location = new Codicon('location', { character: '\\\\eb1a' });\r\n\texport const mailRead = new Codicon('mail-read', { character: '\\\\eb1b' });\r\n\texport const mail = new Codicon('mail', { character: '\\\\eb1c' });\r\n\texport const markdown = new Codicon('markdown', { character: '\\\\eb1d' });\r\n\texport const megaphone = new Codicon('megaphone', { character: '\\\\eb1e' });\r\n\texport const mention = new Codicon('mention', { character: '\\\\eb1f' });\r\n\texport const milestone = new Codicon('milestone', { character: '\\\\eb20' });\r\n\texport const mortarBoard = new Codicon('mortar-board', { character: '\\\\eb21' });\r\n\texport const move = new Codicon('move', { character: '\\\\eb22' });\r\n\texport const multipleWindows = new Codicon('multiple-windows', { character: '\\\\eb23' });\r\n\texport const mute = new Codicon('mute', { character: '\\\\eb24' });\r\n\texport const noNewline = new Codicon('no-newline', { character: '\\\\eb25' });\r\n\texport const note = new Codicon('note', { character: '\\\\eb26' });\r\n\texport const octoface = new Codicon('octoface', { character: '\\\\eb27' });\r\n\texport const openPreview = new Codicon('open-preview', { character: '\\\\eb28' });\r\n\texport const package_ = new Codicon('package', { character: '\\\\eb29' });\r\n\texport const paintcan = new Codicon('paintcan', { character: '\\\\eb2a' });\r\n\texport const pin = new Codicon('pin', { character: '\\\\eb2b' });\r\n\texport const play = new Codicon('play', { character: '\\\\eb2c' });\r\n\texport const run = new Codicon('run', { character: '\\\\eb2c' });\r\n\texport const plug = new Codicon('plug', { character: '\\\\eb2d' });\r\n\texport const preserveCase = new Codicon('preserve-case', { character: '\\\\eb2e' });\r\n\texport const preview = new Codicon('preview', { character: '\\\\eb2f' });\r\n\texport const project = new Codicon('project', { character: '\\\\eb30' });\r\n\texport const pulse = new Codicon('pulse', { character: '\\\\eb31' });\r\n\texport const question = new Codicon('question', { character: '\\\\eb32' });\r\n\texport const quote = new Codicon('quote', { character: '\\\\eb33' });\r\n\texport const radioTower = new Codicon('radio-tower', { character: '\\\\eb34' });\r\n\texport const reactions = new Codicon('reactions', { character: '\\\\eb35' });\r\n\texport const references = new Codicon('references', { character: '\\\\eb36' });\r\n\texport const refresh = new Codicon('refresh', { character: '\\\\eb37' });\r\n\texport const regex = new Codicon('regex', { character: '\\\\eb38' });\r\n\texport const remoteExplorer = new Codicon('remote-explorer', { character: '\\\\eb39' });\r\n\texport const remote = new Codicon('remote', { character: '\\\\eb3a' });\r\n\texport const remove = new Codicon('remove', { character: '\\\\eb3b' });\r\n\texport const replaceAll = new Codicon('replace-all', { character: '\\\\eb3c' });\r\n\texport const replace = new Codicon('replace', { character: '\\\\eb3d' });\r\n\texport const repoClone = new Codicon('repo-clone', { character: '\\\\eb3e' });\r\n\texport const repoForcePush = new Codicon('repo-force-push', { character: '\\\\eb3f' });\r\n\texport const repoPull = new Codicon('repo-pull', { character: '\\\\eb40' });\r\n\texport const repoPush = new Codicon('repo-push', { character: '\\\\eb41' });\r\n\texport const report = new Codicon('report', { character: '\\\\eb42' });\r\n\texport const requestChanges = new Codicon('request-changes', { character: '\\\\eb43' });\r\n\texport const rocket = new Codicon('rocket', { character: '\\\\eb44' });\r\n\texport const rootFolderOpened = new Codicon('root-folder-opened', { character: '\\\\eb45' });\r\n\texport const rootFolder = new Codicon('root-folder', { character: '\\\\eb46' });\r\n\texport const rss = new Codicon('rss', { character: '\\\\eb47' });\r\n\texport const ruby = new Codicon('ruby', { character: '\\\\eb48' });\r\n\texport const saveAll = new Codicon('save-all', { character: '\\\\eb49' });\r\n\texport const saveAs = new Codicon('save-as', { character: '\\\\eb4a' });\r\n\texport const save = new Codicon('save', { character: '\\\\eb4b' });\r\n\texport const screenFull = new Codicon('screen-full', { character: '\\\\eb4c' });\r\n\texport const screenNormal = new Codicon('screen-normal', { character: '\\\\eb4d' });\r\n\texport const searchStop = new Codicon('search-stop', { character: '\\\\eb4e' });\r\n\texport const server = new Codicon('server', { character: '\\\\eb50' });\r\n\texport const settingsGear = new Codicon('settings-gear', { character: '\\\\eb51' });\r\n\texport const settings = new Codicon('settings', { character: '\\\\eb52' });\r\n\texport const shield = new Codicon('shield', { character: '\\\\eb53' });\r\n\texport const smiley = new Codicon('smiley', { character: '\\\\eb54' });\r\n\texport const sortPrecedence = new Codicon('sort-precedence', { character: '\\\\eb55' });\r\n\texport const splitHorizontal = new Codicon('split-horizontal', { character: '\\\\eb56' });\r\n\texport const splitVertical = new Codicon('split-vertical', { character: '\\\\eb57' });\r\n\texport const squirrel = new Codicon('squirrel', { character: '\\\\eb58' });\r\n\texport const starFull = new Codicon('star-full', { character: '\\\\eb59' });\r\n\texport const starHalf = new Codicon('star-half', { character: '\\\\eb5a' });\r\n\texport const symbolClass = new Codicon('symbol-class', { character: '\\\\eb5b' });\r\n\texport const symbolColor = new Codicon('symbol-color', { character: '\\\\eb5c' });\r\n\texport const symbolConstant = new Codicon('symbol-constant', { character: '\\\\eb5d' });\r\n\texport const symbolEnumMember = new Codicon('symbol-enum-member', { character: '\\\\eb5e' });\r\n\texport const symbolField = new Codicon('symbol-field', { character: '\\\\eb5f' });\r\n\texport const symbolFile = new Codicon('symbol-file', { character: '\\\\eb60' });\r\n\texport const symbolInterface = new Codicon('symbol-interface', { character: '\\\\eb61' });\r\n\texport const symbolKeyword = new Codicon('symbol-keyword', { character: '\\\\eb62' });\r\n\texport const symbolMisc = new Codicon('symbol-misc', { character: '\\\\eb63' });\r\n\texport const symbolOperator = new Codicon('symbol-operator', { character: '\\\\eb64' });\r\n\texport const symbolProperty = new Codicon('symbol-property', { character: '\\\\eb65' });\r\n\texport const wrench = new Codicon('wrench', { character: '\\\\eb65' });\r\n\texport const wrenchSubaction = new Codicon('wrench-subaction', { character: '\\\\eb65' });\r\n\texport const symbolSnippet = new Codicon('symbol-snippet', { character: '\\\\eb66' });\r\n\texport const tasklist = new Codicon('tasklist', { character: '\\\\eb67' });\r\n\texport const telescope = new Codicon('telescope', { character: '\\\\eb68' });\r\n\texport const textSize = new Codicon('text-size', { character: '\\\\eb69' });\r\n\texport const threeBars = new Codicon('three-bars', { character: '\\\\eb6a' });\r\n\texport const thumbsdown = new Codicon('thumbsdown', { character: '\\\\eb6b' });\r\n\texport const thumbsup = new Codicon('thumbsup', { character: '\\\\eb6c' });\r\n\texport const tools = new Codicon('tools', { character: '\\\\eb6d' });\r\n\texport const triangleDown = new Codicon('triangle-down', { character: '\\\\eb6e' });\r\n\texport const triangleLeft = new Codicon('triangle-left', { character: '\\\\eb6f' });\r\n\texport const triangleRight = new Codicon('triangle-right', { character: '\\\\eb70' });\r\n\texport const triangleUp = new Codicon('triangle-up', { character: '\\\\eb71' });\r\n\texport const twitter = new Codicon('twitter', { character: '\\\\eb72' });\r\n\texport const unfold = new Codicon('unfold', { character: '\\\\eb73' });\r\n\texport const unlock = new Codicon('unlock', { character: '\\\\eb74' });\r\n\texport const unmute = new Codicon('unmute', { character: '\\\\eb75' });\r\n\texport const unverified = new Codicon('unverified', { character: '\\\\eb76' });\r\n\texport const verified = new Codicon('verified', { character: '\\\\eb77' });\r\n\texport const versions = new Codicon('versions', { character: '\\\\eb78' });\r\n\texport const vmActive = new Codicon('vm-active', { character: '\\\\eb79' });\r\n\texport const vmOutline = new Codicon('vm-outline', { character: '\\\\eb7a' });\r\n\texport const vmRunning = new Codicon('vm-running', { character: '\\\\eb7b' });\r\n\texport const watch = new Codicon('watch', { character: '\\\\eb7c' });\r\n\texport const whitespace = new Codicon('whitespace', { character: '\\\\eb7d' });\r\n\texport const wholeWord = new Codicon('whole-word', { character: '\\\\eb7e' });\r\n\texport const window = new Codicon('window', { character: '\\\\eb7f' });\r\n\texport const wordWrap = new Codicon('word-wrap', { character: '\\\\eb80' });\r\n\texport const zoomIn = new Codicon('zoom-in', { character: '\\\\eb81' });\r\n\texport const zoomOut = new Codicon('zoom-out', { character: '\\\\eb82' });\r\n\texport const listFilter = new Codicon('list-filter', { character: '\\\\eb83' });\r\n\texport const listFlat = new Codicon('list-flat', { character: '\\\\eb84' });\r\n\texport const listSelection = new Codicon('list-selection', { character: '\\\\eb85' });\r\n\texport const selection = new Codicon('selection', { character: '\\\\eb85' });\r\n\texport const listTree = new Codicon('list-tree', { character: '\\\\eb86' });\r\n\texport const debugBreakpointFunctionUnverified = new Codicon('debug-breakpoint-function-unverified', { character: '\\\\eb87' });\r\n\texport const debugBreakpointFunction = new Codicon('debug-breakpoint-function', { character: '\\\\eb88' });\r\n\texport const debugBreakpointFunctionDisabled = new Codicon('debug-breakpoint-function-disabled', { character: '\\\\eb88' });\r\n\texport const debugStackframeActive = new Codicon('debug-stackframe-active', { character: '\\\\eb89' });\r\n\texport const debugStackframeDot = new Codicon('debug-stackframe-dot', { character: '\\\\eb8a' });\r\n\texport const debugStackframe = new Codicon('debug-stackframe', { character: '\\\\eb8b' });\r\n\texport const debugStackframeFocused = new Codicon('debug-stackframe-focused', { character: '\\\\eb8b' });\r\n\texport const debugBreakpointUnsupported = new Codicon('debug-breakpoint-unsupported', { character: '\\\\eb8c' });\r\n\texport const symbolString = new Codicon('symbol-string', { character: '\\\\eb8d' });\r\n\texport const debugReverseContinue = new Codicon('debug-reverse-continue', { character: '\\\\eb8e' });\r\n\texport const debugStepBack = new Codicon('debug-step-back', { character: '\\\\eb8f' });\r\n\texport const debugRestartFrame = new Codicon('debug-restart-frame', { character: '\\\\eb90' });\r\n\texport const callIncoming = new Codicon('call-incoming', { character: '\\\\eb92' });\r\n\texport const callOutgoing = new Codicon('call-outgoing', { character: '\\\\eb93' });\r\n\texport const menu = new Codicon('menu', { character: '\\\\eb94' });\r\n\texport const expandAll = new Codicon('expand-all', { character: '\\\\eb95' });\r\n\texport const feedback = new Codicon('feedback', { character: '\\\\eb96' });\r\n\texport const groupByRefType = new Codicon('group-by-ref-type', { character: '\\\\eb97' });\r\n\texport const ungroupByRefType = new Codicon('ungroup-by-ref-type', { character: '\\\\eb98' });\r\n\texport const account = new Codicon('account', { character: '\\\\eb99' });\r\n\texport const bellDot = new Codicon('bell-dot', { character: '\\\\eb9a' });\r\n\texport const debugConsole = new Codicon('debug-console', { character: '\\\\eb9b' });\r\n\texport const library = new Codicon('library', { character: '\\\\eb9c' });\r\n\texport const output = new Codicon('output', { character: '\\\\eb9d' });\r\n\texport const runAll = new Codicon('run-all', { character: '\\\\eb9e' });\r\n\texport const syncIgnored = new Codicon('sync-ignored', { character: '\\\\eb9f' });\r\n\texport const pinned = new Codicon('pinned', { character: '\\\\eba0' });\r\n\texport const githubInverted = new Codicon('github-inverted', { character: '\\\\eba1' });\r\n\texport const debugAlt = new Codicon('debug-alt', { character: '\\\\eb91' });\r\n\texport const serverProcess = new Codicon('server-process', { character: '\\\\eba2' });\r\n\texport const serverEnvironment = new Codicon('server-environment', { character: '\\\\eba3' });\r\n\texport const pass = new Codicon('pass', { character: '\\\\eba4' });\r\n\texport const stopCircle = new Codicon('stop-circle', { character: '\\\\eba5' });\r\n\texport const playCircle = new Codicon('play-circle', { character: '\\\\eba6' });\r\n\texport const record = new Codicon('record', { character: '\\\\eba7' });\r\n\texport const debugAltSmall = new Codicon('debug-alt-small', { character: '\\\\eba8' });\r\n\texport const vmConnect = new Codicon('vm-connect', { character: '\\\\eba9' });\r\n\texport const cloud = new Codicon('cloud', { character: '\\\\ebaa' });\r\n\texport const merge = new Codicon('merge', { character: '\\\\ebab' });\r\n\texport const exportIcon = new Codicon('export', { character: '\\\\ebac' });\r\n\texport const graphLeft = new Codicon('graph-left', { character: '\\\\ebad' });\r\n\texport const magnet = new Codicon('magnet', { character: '\\\\ebae' });\r\n\texport const notebook = new Codicon('notebook', { character: '\\\\ebaf' });\r\n\texport const redo = new Codicon('redo', { character: '\\\\ebb0' });\r\n\texport const checkAll = new Codicon('check-all', { character: '\\\\ebb1' });\r\n\texport const pinnedDirty = new Codicon('pinned-dirty', { character: '\\\\ebb2' });\r\n\texport const passFilled = new Codicon('pass-filled', { character: '\\\\ebb3' });\r\n\texport const circleLargeFilled = new Codicon('circle-large-filled', { character: '\\\\ebb4' });\r\n\texport const circleLargeOutline = new Codicon('circle-large-outline', { character: '\\\\ebb5' });\r\n\texport const combine = new Codicon('combine', { character: '\\\\ebb6' });\r\n\texport const gather = new Codicon('gather', { character: '\\\\ebb6' });\r\n\r\n\texport const dropDownButton = new Codicon('drop-down-button', Codicon.chevronDown.definition);\r\n}\r\n\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Codicon, registerCodicon } from 'vs/base/common/codicons';\r\n\r\nexport const treeItemExpandedIcon = registerCodicon('tree-item-expanded', Codicon.chevronDown); // collapsed is done with rotation\r\n\r\nexport const treeFilterOnTypeOnIcon = registerCodicon('tree-filter-on-type-on', Codicon.listFilter);\r\nexport const treeFilterOnTypeOffIcon = registerCodicon('tree-filter-on-type-off', Codicon.listSelection);\r\nexport const treeFilterClearIcon = registerCodicon('tree-filter-clear', Codicon.close);\r\n\r\nexport const treeItemLoadingIcon = registerCodicon('tree-item-loading', Codicon.loading);\r\n","\r\nimport { IdleValue } from 'vs/base/common/async';\r\n\r\n// When comparing large numbers of strings, such as in sorting large arrays, is better for\r\n// performance to create an Intl.Collator object and use the function provided by its compare\r\n// property than it is to use String.prototype.localeCompare()\r\n\r\n// A collator with numeric sorting enabled, and no sensitivity to case or to accents\r\nconst intlFileNameCollatorBaseNumeric: IdleValue<{ collator: Intl.Collator, collatorIsNumeric: boolean }> = new IdleValue(() => {\r\n\tconst collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });\r\n\treturn {\r\n\t\tcollator: collator,\r\n\t\tcollatorIsNumeric: collator.resolvedOptions().numeric\r\n\t};\r\n});/** Compares filenames without distinguishing the name from the extension. Disambiguates by unicode comparison. */\r\nexport function compareFileNames(one: string | null, other: string | null, caseSensitive = false): number {\r\n\tconst a = one || '';\r\n\tconst b = other || '';\r\n\tconst result = intlFileNameCollatorBaseNumeric.value.collator.compare(a, b);\r\n\r\n\t// Using the numeric option in the collator will\r\n\t// make compare(`foo1`, `foo01`) === 0. We must disambiguate.\r\n\tif (intlFileNameCollatorBaseNumeric.value.collatorIsNumeric && result === 0 && a !== b) {\r\n\t\treturn a < b ? -1 : 1;\r\n\t}\r\n\r\n\treturn result;\r\n}\r\n\r\nexport function compareAnything(one: string, other: string, lookFor: string): number {\r\n\tconst elementAName = one.toLowerCase();\r\n\tconst elementBName = other.toLowerCase();\r\n\r\n\t// Sort prefix matches over non prefix matches\r\n\tconst prefixCompare = compareByPrefix(one, other, lookFor);\r\n\tif (prefixCompare) {\r\n\t\treturn prefixCompare;\r\n\t}\r\n\r\n\t// Sort suffix matches over non suffix matches\r\n\tconst elementASuffixMatch = elementAName.endsWith(lookFor);\r\n\tconst elementBSuffixMatch = elementBName.endsWith(lookFor);\r\n\tif (elementASuffixMatch !== elementBSuffixMatch) {\r\n\t\treturn elementASuffixMatch ? -1 : 1;\r\n\t}\r\n\r\n\t// Understand file names\r\n\tconst r = compareFileNames(elementAName, elementBName);\r\n\tif (r !== 0) {\r\n\t\treturn r;\r\n\t}\r\n\r\n\t// Compare by name\r\n\treturn elementAName.localeCompare(elementBName);\r\n}\r\n\r\nexport function compareByPrefix(one: string, other: string, lookFor: string): number {\r\n\tconst elementAName = one.toLowerCase();\r\n\tconst elementBName = other.toLowerCase();\r\n\r\n\t// Sort prefix matches over non prefix matches\r\n\tconst elementAPrefixMatch = elementAName.startsWith(lookFor);\r\n\tconst elementBPrefixMatch = elementBName.startsWith(lookFor);\r\n\tif (elementAPrefixMatch !== elementBPrefixMatch) {\r\n\t\treturn elementAPrefixMatch ? -1 : 1;\r\n\t}\r\n\r\n\t// Same prefix: Sort shorter matches to the top to have those on top that match more precisely\r\n\telse if (elementAPrefixMatch && elementBPrefixMatch) {\r\n\t\tif (elementAName.length < elementBName.length) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\r\n\t\tif (elementAName.length > elementBName.length) {\r\n\t\t\treturn 1;\r\n\t\t}\r\n\t}\r\n\r\n\treturn 0;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\r\n\r\nexport const enum ScrollbarVisibility {\r\n\tAuto = 1,\r\n\tHidden = 2,\r\n\tVisible = 3\r\n}\r\n\r\nexport interface ScrollEvent {\r\n\tinSmoothScrolling: boolean;\r\n\r\n\toldWidth: number;\r\n\toldScrollWidth: number;\r\n\toldScrollLeft: number;\r\n\r\n\twidth: number;\r\n\tscrollWidth: number;\r\n\tscrollLeft: number;\r\n\r\n\toldHeight: number;\r\n\toldScrollHeight: number;\r\n\toldScrollTop: number;\r\n\r\n\theight: number;\r\n\tscrollHeight: number;\r\n\tscrollTop: number;\r\n\r\n\twidthChanged: boolean;\r\n\tscrollWidthChanged: boolean;\r\n\tscrollLeftChanged: boolean;\r\n\r\n\theightChanged: boolean;\r\n\tscrollHeightChanged: boolean;\r\n\tscrollTopChanged: boolean;\r\n}\r\n\r\nexport class ScrollState implements IScrollDimensions, IScrollPosition {\r\n\t_scrollStateBrand: void;\r\n\r\n\tpublic readonly rawScrollLeft: number;\r\n\tpublic readonly rawScrollTop: number;\r\n\r\n\tpublic readonly width: number;\r\n\tpublic readonly scrollWidth: number;\r\n\tpublic readonly scrollLeft: number;\r\n\tpublic readonly height: number;\r\n\tpublic readonly scrollHeight: number;\r\n\tpublic readonly scrollTop: number;\r\n\r\n\tconstructor(\r\n\t\twidth: number,\r\n\t\tscrollWidth: number,\r\n\t\tscrollLeft: number,\r\n\t\theight: number,\r\n\t\tscrollHeight: number,\r\n\t\tscrollTop: number\r\n\t) {\r\n\t\twidth = width | 0;\r\n\t\tscrollWidth = scrollWidth | 0;\r\n\t\tscrollLeft = scrollLeft | 0;\r\n\t\theight = height | 0;\r\n\t\tscrollHeight = scrollHeight | 0;\r\n\t\tscrollTop = scrollTop | 0;\r\n\r\n\t\tthis.rawScrollLeft = scrollLeft; // before validation\r\n\t\tthis.rawScrollTop = scrollTop; // before validation\r\n\r\n\t\tif (width < 0) {\r\n\t\t\twidth = 0;\r\n\t\t}\r\n\t\tif (scrollLeft + width > scrollWidth) {\r\n\t\t\tscrollLeft = scrollWidth - width;\r\n\t\t}\r\n\t\tif (scrollLeft < 0) {\r\n\t\t\tscrollLeft = 0;\r\n\t\t}\r\n\r\n\t\tif (height < 0) {\r\n\t\t\theight = 0;\r\n\t\t}\r\n\t\tif (scrollTop + height > scrollHeight) {\r\n\t\t\tscrollTop = scrollHeight - height;\r\n\t\t}\r\n\t\tif (scrollTop < 0) {\r\n\t\t\tscrollTop = 0;\r\n\t\t}\r\n\r\n\t\tthis.width = width;\r\n\t\tthis.scrollWidth = scrollWidth;\r\n\t\tthis.scrollLeft = scrollLeft;\r\n\t\tthis.height = height;\r\n\t\tthis.scrollHeight = scrollHeight;\r\n\t\tthis.scrollTop = scrollTop;\r\n\t}\r\n\r\n\tpublic equals(other: ScrollState): boolean {\r\n\t\treturn (\r\n\t\t\tthis.rawScrollLeft === other.rawScrollLeft\r\n\t\t\t&& this.rawScrollTop === other.rawScrollTop\r\n\t\t\t&& this.width === other.width\r\n\t\t\t&& this.scrollWidth === other.scrollWidth\r\n\t\t\t&& this.scrollLeft === other.scrollLeft\r\n\t\t\t&& this.height === other.height\r\n\t\t\t&& this.scrollHeight === other.scrollHeight\r\n\t\t\t&& this.scrollTop === other.scrollTop\r\n\t\t);\r\n\t}\r\n\r\n\tpublic withScrollDimensions(update: INewScrollDimensions, useRawScrollPositions: boolean): ScrollState {\r\n\t\treturn new ScrollState(\r\n\t\t\t(typeof update.width !== 'undefined' ? update.width : this.width),\r\n\t\t\t(typeof update.scrollWidth !== 'undefined' ? update.scrollWidth : this.scrollWidth),\r\n\t\t\tuseRawScrollPositions ? this.rawScrollLeft : this.scrollLeft,\r\n\t\t\t(typeof update.height !== 'undefined' ? update.height : this.height),\r\n\t\t\t(typeof update.scrollHeight !== 'undefined' ? update.scrollHeight : this.scrollHeight),\r\n\t\t\tuseRawScrollPositions ? this.rawScrollTop : this.scrollTop\r\n\t\t);\r\n\t}\r\n\r\n\tpublic withScrollPosition(update: INewScrollPosition): ScrollState {\r\n\t\treturn new ScrollState(\r\n\t\t\tthis.width,\r\n\t\t\tthis.scrollWidth,\r\n\t\t\t(typeof update.scrollLeft !== 'undefined' ? update.scrollLeft : this.rawScrollLeft),\r\n\t\t\tthis.height,\r\n\t\t\tthis.scrollHeight,\r\n\t\t\t(typeof update.scrollTop !== 'undefined' ? update.scrollTop : this.rawScrollTop)\r\n\t\t);\r\n\t}\r\n\r\n\tpublic createScrollEvent(previous: ScrollState, inSmoothScrolling: boolean): ScrollEvent {\r\n\t\tconst widthChanged = (this.width !== previous.width);\r\n\t\tconst scrollWidthChanged = (this.scrollWidth !== previous.scrollWidth);\r\n\t\tconst scrollLeftChanged = (this.scrollLeft !== previous.scrollLeft);\r\n\r\n\t\tconst heightChanged = (this.height !== previous.height);\r\n\t\tconst scrollHeightChanged = (this.scrollHeight !== previous.scrollHeight);\r\n\t\tconst scrollTopChanged = (this.scrollTop !== previous.scrollTop);\r\n\r\n\t\treturn {\r\n\t\t\tinSmoothScrolling: inSmoothScrolling,\r\n\t\t\toldWidth: previous.width,\r\n\t\t\toldScrollWidth: previous.scrollWidth,\r\n\t\t\toldScrollLeft: previous.scrollLeft,\r\n\r\n\t\t\twidth: this.width,\r\n\t\t\tscrollWidth: this.scrollWidth,\r\n\t\t\tscrollLeft: this.scrollLeft,\r\n\r\n\t\t\toldHeight: previous.height,\r\n\t\t\toldScrollHeight: previous.scrollHeight,\r\n\t\t\toldScrollTop: previous.scrollTop,\r\n\r\n\t\t\theight: this.height,\r\n\t\t\tscrollHeight: this.scrollHeight,\r\n\t\t\tscrollTop: this.scrollTop,\r\n\r\n\t\t\twidthChanged: widthChanged,\r\n\t\t\tscrollWidthChanged: scrollWidthChanged,\r\n\t\t\tscrollLeftChanged: scrollLeftChanged,\r\n\r\n\t\t\theightChanged: heightChanged,\r\n\t\t\tscrollHeightChanged: scrollHeightChanged,\r\n\t\t\tscrollTopChanged: scrollTopChanged,\r\n\t\t};\r\n\t}\r\n\r\n}\r\n\r\nexport interface IScrollDimensions {\r\n\treadonly width: number;\r\n\treadonly scrollWidth: number;\r\n\treadonly height: number;\r\n\treadonly scrollHeight: number;\r\n}\r\nexport interface INewScrollDimensions {\r\n\twidth?: number;\r\n\tscrollWidth?: number;\r\n\theight?: number;\r\n\tscrollHeight?: number;\r\n}\r\n\r\nexport interface IScrollPosition {\r\n\treadonly scrollLeft: number;\r\n\treadonly scrollTop: number;\r\n}\r\nexport interface ISmoothScrollPosition {\r\n\treadonly scrollLeft: number;\r\n\treadonly scrollTop: number;\r\n\r\n\treadonly width: number;\r\n\treadonly height: number;\r\n}\r\nexport interface INewScrollPosition {\r\n\tscrollLeft?: number;\r\n\tscrollTop?: number;\r\n}\r\n\r\nexport class Scrollable extends Disposable {\r\n\r\n\t_scrollableBrand: void;\r\n\r\n\tprivate _smoothScrollDuration: number;\r\n\tprivate readonly _scheduleAtNextAnimationFrame: (callback: () => void) => IDisposable;\r\n\tprivate _state: ScrollState;\r\n\tprivate _smoothScrolling: SmoothScrollingOperation | null;\r\n\r\n\tprivate _onScroll = this._register(new Emitter());\r\n\tpublic readonly onScroll: Event = this._onScroll.event;\r\n\r\n\tconstructor(smoothScrollDuration: number, scheduleAtNextAnimationFrame: (callback: () => void) => IDisposable) {\r\n\t\tsuper();\r\n\r\n\t\tthis._smoothScrollDuration = smoothScrollDuration;\r\n\t\tthis._scheduleAtNextAnimationFrame = scheduleAtNextAnimationFrame;\r\n\t\tthis._state = new ScrollState(0, 0, 0, 0, 0, 0);\r\n\t\tthis._smoothScrolling = null;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tif (this._smoothScrolling) {\r\n\t\t\tthis._smoothScrolling.dispose();\r\n\t\t\tthis._smoothScrolling = null;\r\n\t\t}\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tpublic setSmoothScrollDuration(smoothScrollDuration: number): void {\r\n\t\tthis._smoothScrollDuration = smoothScrollDuration;\r\n\t}\r\n\r\n\tpublic validateScrollPosition(scrollPosition: INewScrollPosition): IScrollPosition {\r\n\t\treturn this._state.withScrollPosition(scrollPosition);\r\n\t}\r\n\r\n\tpublic getScrollDimensions(): IScrollDimensions {\r\n\t\treturn this._state;\r\n\t}\r\n\r\n\tpublic setScrollDimensions(dimensions: INewScrollDimensions, useRawScrollPositions: boolean): void {\r\n\t\tconst newState = this._state.withScrollDimensions(dimensions, useRawScrollPositions);\r\n\t\tthis._setState(newState, Boolean(this._smoothScrolling));\r\n\r\n\t\t// Validate outstanding animated scroll position target\r\n\t\tif (this._smoothScrolling) {\r\n\t\t\tthis._smoothScrolling.acceptScrollDimensions(this._state);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the final scroll position that the instance will have once the smooth scroll animation concludes.\r\n\t * If no scroll animation is occurring, it will return the current scroll position instead.\r\n\t */\r\n\tpublic getFutureScrollPosition(): IScrollPosition {\r\n\t\tif (this._smoothScrolling) {\r\n\t\t\treturn this._smoothScrolling.to;\r\n\t\t}\r\n\t\treturn this._state;\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the current scroll position.\r\n\t * Note: This result might be an intermediate scroll position, as there might be an ongoing smooth scroll animation.\r\n\t */\r\n\tpublic getCurrentScrollPosition(): IScrollPosition {\r\n\t\treturn this._state;\r\n\t}\r\n\r\n\tpublic setScrollPositionNow(update: INewScrollPosition): void {\r\n\t\t// no smooth scrolling requested\r\n\t\tconst newState = this._state.withScrollPosition(update);\r\n\r\n\t\t// Terminate any outstanding smooth scrolling\r\n\t\tif (this._smoothScrolling) {\r\n\t\t\tthis._smoothScrolling.dispose();\r\n\t\t\tthis._smoothScrolling = null;\r\n\t\t}\r\n\r\n\t\tthis._setState(newState, false);\r\n\t}\r\n\r\n\tpublic setScrollPositionSmooth(update: INewScrollPosition, reuseAnimation?: boolean): void {\r\n\t\tif (this._smoothScrollDuration === 0) {\r\n\t\t\t// Smooth scrolling not supported.\r\n\t\t\treturn this.setScrollPositionNow(update);\r\n\t\t}\r\n\r\n\t\tif (this._smoothScrolling) {\r\n\t\t\t// Combine our pending scrollLeft/scrollTop with incoming scrollLeft/scrollTop\r\n\t\t\tupdate = {\r\n\t\t\t\tscrollLeft: (typeof update.scrollLeft === 'undefined' ? this._smoothScrolling.to.scrollLeft : update.scrollLeft),\r\n\t\t\t\tscrollTop: (typeof update.scrollTop === 'undefined' ? this._smoothScrolling.to.scrollTop : update.scrollTop)\r\n\t\t\t};\r\n\r\n\t\t\t// Validate `update`\r\n\t\t\tconst validTarget = this._state.withScrollPosition(update);\r\n\r\n\t\t\tif (this._smoothScrolling.to.scrollLeft === validTarget.scrollLeft && this._smoothScrolling.to.scrollTop === validTarget.scrollTop) {\r\n\t\t\t\t// No need to interrupt or extend the current animation since we're going to the same place\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tlet newSmoothScrolling: SmoothScrollingOperation;\r\n\t\t\tif (reuseAnimation) {\r\n\t\t\t\tnewSmoothScrolling = new SmoothScrollingOperation(this._smoothScrolling.from, validTarget, this._smoothScrolling.startTime, this._smoothScrolling.duration);\r\n\t\t\t} else {\r\n\t\t\t\tnewSmoothScrolling = this._smoothScrolling.combine(this._state, validTarget, this._smoothScrollDuration);\r\n\t\t\t}\r\n\t\t\tthis._smoothScrolling.dispose();\r\n\t\t\tthis._smoothScrolling = newSmoothScrolling;\r\n\t\t} else {\r\n\t\t\t// Validate `update`\r\n\t\t\tconst validTarget = this._state.withScrollPosition(update);\r\n\r\n\t\t\tthis._smoothScrolling = SmoothScrollingOperation.start(this._state, validTarget, this._smoothScrollDuration);\r\n\t\t}\r\n\r\n\t\t// Begin smooth scrolling animation\r\n\t\tthis._smoothScrolling.animationFrameDisposable = this._scheduleAtNextAnimationFrame(() => {\r\n\t\t\tif (!this._smoothScrolling) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tthis._smoothScrolling.animationFrameDisposable = null;\r\n\t\t\tthis._performSmoothScrolling();\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _performSmoothScrolling(): void {\r\n\t\tif (!this._smoothScrolling) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst update = this._smoothScrolling.tick();\r\n\t\tconst newState = this._state.withScrollPosition(update);\r\n\r\n\t\tthis._setState(newState, true);\r\n\r\n\t\tif (!this._smoothScrolling) {\r\n\t\t\t// Looks like someone canceled the smooth scrolling\r\n\t\t\t// from the scroll event handler\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (update.isDone) {\r\n\t\t\tthis._smoothScrolling.dispose();\r\n\t\t\tthis._smoothScrolling = null;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// Continue smooth scrolling animation\r\n\t\tthis._smoothScrolling.animationFrameDisposable = this._scheduleAtNextAnimationFrame(() => {\r\n\t\t\tif (!this._smoothScrolling) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tthis._smoothScrolling.animationFrameDisposable = null;\r\n\t\t\tthis._performSmoothScrolling();\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _setState(newState: ScrollState, inSmoothScrolling: boolean): void {\r\n\t\tconst oldState = this._state;\r\n\t\tif (oldState.equals(newState)) {\r\n\t\t\t// no change\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._state = newState;\r\n\t\tthis._onScroll.fire(this._state.createScrollEvent(oldState, inSmoothScrolling));\r\n\t}\r\n}\r\n\r\nexport class SmoothScrollingUpdate {\r\n\r\n\tpublic readonly scrollLeft: number;\r\n\tpublic readonly scrollTop: number;\r\n\tpublic readonly isDone: boolean;\r\n\r\n\tconstructor(scrollLeft: number, scrollTop: number, isDone: boolean) {\r\n\t\tthis.scrollLeft = scrollLeft;\r\n\t\tthis.scrollTop = scrollTop;\r\n\t\tthis.isDone = isDone;\r\n\t}\r\n\r\n}\r\n\r\nexport interface IAnimation {\r\n\t(completion: number): number;\r\n}\r\n\r\nfunction createEaseOutCubic(from: number, to: number): IAnimation {\r\n\tconst delta = to - from;\r\n\treturn function (completion: number): number {\r\n\t\treturn from + delta * easeOutCubic(completion);\r\n\t};\r\n}\r\n\r\nfunction createComposed(a: IAnimation, b: IAnimation, cut: number): IAnimation {\r\n\treturn function (completion: number): number {\r\n\t\tif (completion < cut) {\r\n\t\t\treturn a(completion / cut);\r\n\t\t}\r\n\t\treturn b((completion - cut) / (1 - cut));\r\n\t};\r\n}\r\n\r\nexport class SmoothScrollingOperation {\r\n\r\n\tpublic readonly from: ISmoothScrollPosition;\r\n\tpublic to: ISmoothScrollPosition;\r\n\tpublic readonly duration: number;\r\n\tpublic readonly startTime: number;\r\n\tpublic animationFrameDisposable: IDisposable | null;\r\n\r\n\tprivate scrollLeft!: IAnimation;\r\n\tprivate scrollTop!: IAnimation;\r\n\r\n\tconstructor(from: ISmoothScrollPosition, to: ISmoothScrollPosition, startTime: number, duration: number) {\r\n\t\tthis.from = from;\r\n\t\tthis.to = to;\r\n\t\tthis.duration = duration;\r\n\t\tthis.startTime = startTime;\r\n\r\n\t\tthis.animationFrameDisposable = null;\r\n\r\n\t\tthis._initAnimations();\r\n\t}\r\n\r\n\tprivate _initAnimations(): void {\r\n\t\tthis.scrollLeft = this._initAnimation(this.from.scrollLeft, this.to.scrollLeft, this.to.width);\r\n\t\tthis.scrollTop = this._initAnimation(this.from.scrollTop, this.to.scrollTop, this.to.height);\r\n\t}\r\n\r\n\tprivate _initAnimation(from: number, to: number, viewportSize: number): IAnimation {\r\n\t\tconst delta = Math.abs(from - to);\r\n\t\tif (delta > 2.5 * viewportSize) {\r\n\t\t\tlet stop1: number, stop2: number;\r\n\t\t\tif (from < to) {\r\n\t\t\t\t// scroll to 75% of the viewportSize\r\n\t\t\t\tstop1 = from + 0.75 * viewportSize;\r\n\t\t\t\tstop2 = to - 0.75 * viewportSize;\r\n\t\t\t} else {\r\n\t\t\t\tstop1 = from - 0.75 * viewportSize;\r\n\t\t\t\tstop2 = to + 0.75 * viewportSize;\r\n\t\t\t}\r\n\t\t\treturn createComposed(createEaseOutCubic(from, stop1), createEaseOutCubic(stop2, to), 0.33);\r\n\t\t}\r\n\t\treturn createEaseOutCubic(from, to);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tif (this.animationFrameDisposable !== null) {\r\n\t\t\tthis.animationFrameDisposable.dispose();\r\n\t\t\tthis.animationFrameDisposable = null;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic acceptScrollDimensions(state: ScrollState): void {\r\n\t\tthis.to = state.withScrollPosition(this.to);\r\n\t\tthis._initAnimations();\r\n\t}\r\n\r\n\tpublic tick(): SmoothScrollingUpdate {\r\n\t\treturn this._tick(Date.now());\r\n\t}\r\n\r\n\tprotected _tick(now: number): SmoothScrollingUpdate {\r\n\t\tconst completion = (now - this.startTime) / this.duration;\r\n\r\n\t\tif (completion < 1) {\r\n\t\t\tconst newScrollLeft = this.scrollLeft(completion);\r\n\t\t\tconst newScrollTop = this.scrollTop(completion);\r\n\t\t\treturn new SmoothScrollingUpdate(newScrollLeft, newScrollTop, false);\r\n\t\t}\r\n\r\n\t\treturn new SmoothScrollingUpdate(this.to.scrollLeft, this.to.scrollTop, true);\r\n\t}\r\n\r\n\tpublic combine(from: ISmoothScrollPosition, to: ISmoothScrollPosition, duration: number): SmoothScrollingOperation {\r\n\t\treturn SmoothScrollingOperation.start(from, to, duration);\r\n\t}\r\n\r\n\tpublic static start(from: ISmoothScrollPosition, to: ISmoothScrollPosition, duration: number): SmoothScrollingOperation {\r\n\t\t// +10 / -10 : pretend the animation already started for a quicker response to a scroll request\r\n\t\tduration = duration + 10;\r\n\t\tconst startTime = Date.now() - 10;\r\n\r\n\t\treturn new SmoothScrollingOperation(from, to, startTime, duration);\r\n\t}\r\n}\r\n\r\nfunction easeInCubic(t: number) {\r\n\treturn Math.pow(t, 3);\r\n}\r\n\r\nfunction easeOutCubic(t: number) {\r\n\treturn 1 - easeInCubic(1 - t);\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport { Constants } from 'vs/base/common/uint';\r\n\r\nexport function isFalsyOrWhitespace(str: string | undefined): boolean {\r\n\tif (!str || typeof str !== 'string') {\r\n\t\treturn true;\r\n\t}\r\n\treturn str.trim().length === 0;\r\n}\r\n\r\nconst _formatRegexp = /{(\\d+)}/g;\r\n\r\n/**\r\n * Helper to produce a string with a variable number of arguments. Insert variable segments\r\n * into the string using the {n} notation where N is the index of the argument following the string.\r\n * @param value string to which formatting is applied\r\n * @param args replacements for {n}-entries\r\n */\r\nexport function format(value: string, ...args: any[]): string {\r\n\tif (args.length === 0) {\r\n\t\treturn value;\r\n\t}\r\n\treturn value.replace(_formatRegexp, function (match, group) {\r\n\t\tconst idx = parseInt(group, 10);\r\n\t\treturn isNaN(idx) || idx < 0 || idx >= args.length ?\r\n\t\t\tmatch :\r\n\t\t\targs[idx];\r\n\t});\r\n}\r\n\r\n/**\r\n * Converts HTML characters inside the string to use entities instead. Makes the string safe from\r\n * being used e.g. in HTMLElement.innerHTML.\r\n */\r\nexport function escape(html: string): string {\r\n\treturn html.replace(/[<>&]/g, function (match) {\r\n\t\tswitch (match) {\r\n\t\t\tcase '<': return '<';\r\n\t\t\tcase '>': return '>';\r\n\t\t\tcase '&': return '&';\r\n\t\t\tdefault: return match;\r\n\t\t}\r\n\t});\r\n}\r\n\r\n/**\r\n * Escapes regular expression characters in a given string\r\n */\r\nexport function escapeRegExpCharacters(value: string): string {\r\n\treturn value.replace(/[\\\\\\{\\}\\*\\+\\?\\|\\^\\$\\.\\[\\]\\(\\)]/g, '\\\\$&');\r\n}\r\n\r\n/**\r\n * Removes all occurrences of needle from the beginning and end of haystack.\r\n * @param haystack string to trim\r\n * @param needle the thing to trim (default is a blank)\r\n */\r\nexport function trim(haystack: string, needle: string = ' '): string {\r\n\tconst trimmed = ltrim(haystack, needle);\r\n\treturn rtrim(trimmed, needle);\r\n}\r\n\r\n/**\r\n * Removes all occurrences of needle from the beginning of haystack.\r\n * @param haystack string to trim\r\n * @param needle the thing to trim\r\n */\r\nexport function ltrim(haystack: string, needle: string): string {\r\n\tif (!haystack || !needle) {\r\n\t\treturn haystack;\r\n\t}\r\n\r\n\tconst needleLen = needle.length;\r\n\tif (needleLen === 0 || haystack.length === 0) {\r\n\t\treturn haystack;\r\n\t}\r\n\r\n\tlet offset = 0;\r\n\r\n\twhile (haystack.indexOf(needle, offset) === offset) {\r\n\t\toffset = offset + needleLen;\r\n\t}\r\n\treturn haystack.substring(offset);\r\n}\r\n\r\n/**\r\n * Removes all occurrences of needle from the end of haystack.\r\n * @param haystack string to trim\r\n * @param needle the thing to trim\r\n */\r\nexport function rtrim(haystack: string, needle: string): string {\r\n\tif (!haystack || !needle) {\r\n\t\treturn haystack;\r\n\t}\r\n\r\n\tconst needleLen = needle.length,\r\n\t\thaystackLen = haystack.length;\r\n\r\n\tif (needleLen === 0 || haystackLen === 0) {\r\n\t\treturn haystack;\r\n\t}\r\n\r\n\tlet offset = haystackLen,\r\n\t\tidx = -1;\r\n\r\n\twhile (true) {\r\n\t\tidx = haystack.lastIndexOf(needle, offset - 1);\r\n\t\tif (idx === -1 || idx + needleLen !== offset) {\r\n\t\t\tbreak;\r\n\t\t}\r\n\t\tif (idx === 0) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\toffset = idx;\r\n\t}\r\n\r\n\treturn haystack.substring(0, offset);\r\n}\r\n\r\nexport function convertSimple2RegExpPattern(pattern: string): string {\r\n\treturn pattern.replace(/[\\-\\\\\\{\\}\\+\\?\\|\\^\\$\\.\\,\\[\\]\\(\\)\\#\\s]/g, '\\\\$&').replace(/[\\*]/g, '.*');\r\n}\r\n\r\nexport function stripWildcards(pattern: string): string {\r\n\treturn pattern.replace(/\\*/g, '');\r\n}\r\n\r\nexport interface RegExpOptions {\r\n\tmatchCase?: boolean;\r\n\twholeWord?: boolean;\r\n\tmultiline?: boolean;\r\n\tglobal?: boolean;\r\n\tunicode?: boolean;\r\n}\r\n\r\nexport function createRegExp(searchString: string, isRegex: boolean, options: RegExpOptions = {}): RegExp {\r\n\tif (!searchString) {\r\n\t\tthrow new Error('Cannot create regex from empty string');\r\n\t}\r\n\tif (!isRegex) {\r\n\t\tsearchString = escapeRegExpCharacters(searchString);\r\n\t}\r\n\tif (options.wholeWord) {\r\n\t\tif (!/\\B/.test(searchString.charAt(0))) {\r\n\t\t\tsearchString = '\\\\b' + searchString;\r\n\t\t}\r\n\t\tif (!/\\B/.test(searchString.charAt(searchString.length - 1))) {\r\n\t\t\tsearchString = searchString + '\\\\b';\r\n\t\t}\r\n\t}\r\n\tlet modifiers = '';\r\n\tif (options.global) {\r\n\t\tmodifiers += 'g';\r\n\t}\r\n\tif (!options.matchCase) {\r\n\t\tmodifiers += 'i';\r\n\t}\r\n\tif (options.multiline) {\r\n\t\tmodifiers += 'm';\r\n\t}\r\n\tif (options.unicode) {\r\n\t\tmodifiers += 'u';\r\n\t}\r\n\r\n\treturn new RegExp(searchString, modifiers);\r\n}\r\n\r\nexport function regExpLeadsToEndlessLoop(regexp: RegExp): boolean {\r\n\t// Exit early if it's one of these special cases which are meant to match\r\n\t// against an empty string\r\n\tif (regexp.source === '^' || regexp.source === '^$' || regexp.source === '$' || regexp.source === '^\\\\s*$') {\r\n\t\treturn false;\r\n\t}\r\n\r\n\t// We check against an empty string. If the regular expression doesn't advance\r\n\t// (e.g. ends in an endless loop) it will match an empty string.\r\n\tconst match = regexp.exec('');\r\n\treturn !!(match && regexp.lastIndex === 0);\r\n}\r\n\r\nexport function regExpFlags(regexp: RegExp): string {\r\n\treturn (regexp.global ? 'g' : '')\r\n\t\t+ (regexp.ignoreCase ? 'i' : '')\r\n\t\t+ (regexp.multiline ? 'm' : '')\r\n\t\t+ ((regexp as any /* standalone editor compilation */).unicode ? 'u' : '');\r\n}\r\n\r\nexport function splitLines(str: string): string[] {\r\n\treturn str.split(/\\r\\n|\\r|\\n/);\r\n}\r\n\r\n/**\r\n * Returns first index of the string that is not whitespace.\r\n * If string is empty or contains only whitespaces, returns -1\r\n */\r\nexport function firstNonWhitespaceIndex(str: string): number {\r\n\tfor (let i = 0, len = str.length; i < len; i++) {\r\n\t\tconst chCode = str.charCodeAt(i);\r\n\t\tif (chCode !== CharCode.Space && chCode !== CharCode.Tab) {\r\n\t\t\treturn i;\r\n\t\t}\r\n\t}\r\n\treturn -1;\r\n}\r\n\r\n/**\r\n * Returns the leading whitespace of the string.\r\n * If the string contains only whitespaces, returns entire string\r\n */\r\nexport function getLeadingWhitespace(str: string, start: number = 0, end: number = str.length): string {\r\n\tfor (let i = start; i < end; i++) {\r\n\t\tconst chCode = str.charCodeAt(i);\r\n\t\tif (chCode !== CharCode.Space && chCode !== CharCode.Tab) {\r\n\t\t\treturn str.substring(start, i);\r\n\t\t}\r\n\t}\r\n\treturn str.substring(start, end);\r\n}\r\n\r\n/**\r\n * Returns last index of the string that is not whitespace.\r\n * If string is empty or contains only whitespaces, returns -1\r\n */\r\nexport function lastNonWhitespaceIndex(str: string, startIndex: number = str.length - 1): number {\r\n\tfor (let i = startIndex; i >= 0; i--) {\r\n\t\tconst chCode = str.charCodeAt(i);\r\n\t\tif (chCode !== CharCode.Space && chCode !== CharCode.Tab) {\r\n\t\t\treturn i;\r\n\t\t}\r\n\t}\r\n\treturn -1;\r\n}\r\n\r\nexport function compare(a: string, b: string): number {\r\n\tif (a < b) {\r\n\t\treturn -1;\r\n\t} else if (a > b) {\r\n\t\treturn 1;\r\n\t} else {\r\n\t\treturn 0;\r\n\t}\r\n}\r\n\r\nexport function compareSubstring(a: string, b: string, aStart: number = 0, aEnd: number = a.length, bStart: number = 0, bEnd: number = b.length): number {\r\n\tfor (; aStart < aEnd && bStart < bEnd; aStart++, bStart++) {\r\n\t\tlet codeA = a.charCodeAt(aStart);\r\n\t\tlet codeB = b.charCodeAt(bStart);\r\n\t\tif (codeA < codeB) {\r\n\t\t\treturn -1;\r\n\t\t} else if (codeA > codeB) {\r\n\t\t\treturn 1;\r\n\t\t}\r\n\t}\r\n\tconst aLen = aEnd - aStart;\r\n\tconst bLen = bEnd - bStart;\r\n\tif (aLen < bLen) {\r\n\t\treturn -1;\r\n\t} else if (aLen > bLen) {\r\n\t\treturn 1;\r\n\t}\r\n\treturn 0;\r\n}\r\n\r\nexport function compareIgnoreCase(a: string, b: string): number {\r\n\treturn compareSubstringIgnoreCase(a, b, 0, a.length, 0, b.length);\r\n}\r\n\r\nexport function compareSubstringIgnoreCase(a: string, b: string, aStart: number = 0, aEnd: number = a.length, bStart: number = 0, bEnd: number = b.length): number {\r\n\r\n\tfor (; aStart < aEnd && bStart < bEnd; aStart++, bStart++) {\r\n\r\n\t\tlet codeA = a.charCodeAt(aStart);\r\n\t\tlet codeB = b.charCodeAt(bStart);\r\n\r\n\t\tif (codeA === codeB) {\r\n\t\t\t// equal\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tconst diff = codeA - codeB;\r\n\t\tif (diff === 32 && isUpperAsciiLetter(codeB)) { //codeB =[65-90] && codeA =[97-122]\r\n\t\t\tcontinue;\r\n\r\n\t\t} else if (diff === -32 && isUpperAsciiLetter(codeA)) { //codeB =[97-122] && codeA =[65-90]\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tif (isLowerAsciiLetter(codeA) && isLowerAsciiLetter(codeB)) {\r\n\t\t\t//\r\n\t\t\treturn diff;\r\n\r\n\t\t} else {\r\n\t\t\treturn compareSubstring(a.toLowerCase(), b.toLowerCase(), aStart, aEnd, bStart, bEnd);\r\n\t\t}\r\n\t}\r\n\r\n\tconst aLen = aEnd - aStart;\r\n\tconst bLen = bEnd - bStart;\r\n\r\n\tif (aLen < bLen) {\r\n\t\treturn -1;\r\n\t} else if (aLen > bLen) {\r\n\t\treturn 1;\r\n\t}\r\n\r\n\treturn 0;\r\n}\r\n\r\nexport function isLowerAsciiLetter(code: number): boolean {\r\n\treturn code >= CharCode.a && code <= CharCode.z;\r\n}\r\n\r\nexport function isUpperAsciiLetter(code: number): boolean {\r\n\treturn code >= CharCode.A && code <= CharCode.Z;\r\n}\r\n\r\nfunction isAsciiLetter(code: number): boolean {\r\n\treturn isLowerAsciiLetter(code) || isUpperAsciiLetter(code);\r\n}\r\n\r\nexport function equalsIgnoreCase(a: string, b: string): boolean {\r\n\treturn a.length === b.length && doEqualsIgnoreCase(a, b);\r\n}\r\n\r\nfunction doEqualsIgnoreCase(a: string, b: string, stopAt = a.length): boolean {\r\n\tfor (let i = 0; i < stopAt; i++) {\r\n\t\tconst codeA = a.charCodeAt(i);\r\n\t\tconst codeB = b.charCodeAt(i);\r\n\r\n\t\tif (codeA === codeB) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\t// a-z A-Z\r\n\t\tif (isAsciiLetter(codeA) && isAsciiLetter(codeB)) {\r\n\t\t\tconst diff = Math.abs(codeA - codeB);\r\n\t\t\tif (diff !== 0 && diff !== 32) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Any other charcode\r\n\t\telse {\r\n\t\t\tif (String.fromCharCode(codeA).toLowerCase() !== String.fromCharCode(codeB).toLowerCase()) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\treturn true;\r\n}\r\n\r\nexport function startsWithIgnoreCase(str: string, candidate: string): boolean {\r\n\tconst candidateLength = candidate.length;\r\n\tif (candidate.length > str.length) {\r\n\t\treturn false;\r\n\t}\r\n\r\n\treturn doEqualsIgnoreCase(str, candidate, candidateLength);\r\n}\r\n\r\n/**\r\n * @returns the length of the common prefix of the two strings.\r\n */\r\nexport function commonPrefixLength(a: string, b: string): number {\r\n\r\n\tlet i: number,\r\n\t\tlen = Math.min(a.length, b.length);\r\n\r\n\tfor (i = 0; i < len; i++) {\r\n\t\tif (a.charCodeAt(i) !== b.charCodeAt(i)) {\r\n\t\t\treturn i;\r\n\t\t}\r\n\t}\r\n\r\n\treturn len;\r\n}\r\n\r\n/**\r\n * @returns the length of the common suffix of the two strings.\r\n */\r\nexport function commonSuffixLength(a: string, b: string): number {\r\n\r\n\tlet i: number,\r\n\t\tlen = Math.min(a.length, b.length);\r\n\r\n\tconst aLastIndex = a.length - 1;\r\n\tconst bLastIndex = b.length - 1;\r\n\r\n\tfor (i = 0; i < len; i++) {\r\n\t\tif (a.charCodeAt(aLastIndex - i) !== b.charCodeAt(bLastIndex - i)) {\r\n\t\t\treturn i;\r\n\t\t}\r\n\t}\r\n\r\n\treturn len;\r\n}\r\n\r\n/**\r\n * See http://en.wikipedia.org/wiki/Surrogate_pair\r\n */\r\nexport function isHighSurrogate(charCode: number): boolean {\r\n\treturn (0xD800 <= charCode && charCode <= 0xDBFF);\r\n}\r\n\r\n/**\r\n * See http://en.wikipedia.org/wiki/Surrogate_pair\r\n */\r\nexport function isLowSurrogate(charCode: number): boolean {\r\n\treturn (0xDC00 <= charCode && charCode <= 0xDFFF);\r\n}\r\n\r\n/**\r\n * See http://en.wikipedia.org/wiki/Surrogate_pair\r\n */\r\nexport function computeCodePoint(highSurrogate: number, lowSurrogate: number): number {\r\n\treturn ((highSurrogate - 0xD800) << 10) + (lowSurrogate - 0xDC00) + 0x10000;\r\n}\r\n\r\n/**\r\n * get the code point that begins at offset `offset`\r\n */\r\nexport function getNextCodePoint(str: string, len: number, offset: number): number {\r\n\tconst charCode = str.charCodeAt(offset);\r\n\tif (isHighSurrogate(charCode) && offset + 1 < len) {\r\n\t\tconst nextCharCode = str.charCodeAt(offset + 1);\r\n\t\tif (isLowSurrogate(nextCharCode)) {\r\n\t\t\treturn computeCodePoint(charCode, nextCharCode);\r\n\t\t}\r\n\t}\r\n\treturn charCode;\r\n}\r\n\r\n/**\r\n * get the code point that ends right before offset `offset`\r\n */\r\nfunction getPrevCodePoint(str: string, offset: number): number {\r\n\tconst charCode = str.charCodeAt(offset - 1);\r\n\tif (isLowSurrogate(charCode) && offset > 1) {\r\n\t\tconst prevCharCode = str.charCodeAt(offset - 2);\r\n\t\tif (isHighSurrogate(prevCharCode)) {\r\n\t\t\treturn computeCodePoint(prevCharCode, charCode);\r\n\t\t}\r\n\t}\r\n\treturn charCode;\r\n}\r\n\r\nexport function nextCharLength(str: string, offset: number): number {\r\n\tconst graphemeBreakTree = GraphemeBreakTree.getInstance();\r\n\tconst initialOffset = offset;\r\n\tconst len = str.length;\r\n\r\n\tconst initialCodePoint = getNextCodePoint(str, len, offset);\r\n\toffset += (initialCodePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1);\r\n\r\n\tlet graphemeBreakType = graphemeBreakTree.getGraphemeBreakType(initialCodePoint);\r\n\twhile (offset < len) {\r\n\t\tconst nextCodePoint = getNextCodePoint(str, len, offset);\r\n\t\tconst nextGraphemeBreakType = graphemeBreakTree.getGraphemeBreakType(nextCodePoint);\r\n\t\tif (breakBetweenGraphemeBreakType(graphemeBreakType, nextGraphemeBreakType)) {\r\n\t\t\tbreak;\r\n\t\t}\r\n\t\toffset += (nextCodePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1);\r\n\t\tgraphemeBreakType = nextGraphemeBreakType;\r\n\t}\r\n\r\n\treturn (offset - initialOffset);\r\n}\r\n\r\nexport function prevCharLength(str: string, offset: number): number {\r\n\tconst graphemeBreakTree = GraphemeBreakTree.getInstance();\r\n\tconst initialOffset = offset;\r\n\r\n\tconst initialCodePoint = getPrevCodePoint(str, offset);\r\n\toffset -= (initialCodePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1);\r\n\r\n\tlet graphemeBreakType = graphemeBreakTree.getGraphemeBreakType(initialCodePoint);\r\n\twhile (offset > 0) {\r\n\t\tconst prevCodePoint = getPrevCodePoint(str, offset);\r\n\t\tconst prevGraphemeBreakType = graphemeBreakTree.getGraphemeBreakType(prevCodePoint);\r\n\t\tif (breakBetweenGraphemeBreakType(prevGraphemeBreakType, graphemeBreakType)) {\r\n\t\t\tbreak;\r\n\t\t}\r\n\t\toffset -= (prevCodePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1);\r\n\t\tgraphemeBreakType = prevGraphemeBreakType;\r\n\t}\r\n\r\n\treturn (initialOffset - offset);\r\n}\r\n\r\n/**\r\n * A manual decoding of a UTF8 string.\r\n * Use only in environments which do not offer native conversion methods!\r\n */\r\nexport function decodeUTF8(buffer: Uint8Array): string {\r\n\t// https://en.wikipedia.org/wiki/UTF-8\r\n\r\n\tconst len = buffer.byteLength;\r\n\tconst result: string[] = [];\r\n\tlet offset = 0;\r\n\twhile (offset < len) {\r\n\t\tconst v0 = buffer[offset];\r\n\t\tlet codePoint: number;\r\n\t\tif (v0 >= 0b11110000 && offset + 3 < len) {\r\n\t\t\t// 4 bytes\r\n\t\t\tcodePoint = (\r\n\t\t\t\t(((buffer[offset++] & 0b00000111) << 18) >>> 0)\r\n\t\t\t\t| (((buffer[offset++] & 0b00111111) << 12) >>> 0)\r\n\t\t\t\t| (((buffer[offset++] & 0b00111111) << 6) >>> 0)\r\n\t\t\t\t| (((buffer[offset++] & 0b00111111) << 0) >>> 0)\r\n\t\t\t);\r\n\t\t} else if (v0 >= 0b11100000 && offset + 2 < len) {\r\n\t\t\t// 3 bytes\r\n\t\t\tcodePoint = (\r\n\t\t\t\t(((buffer[offset++] & 0b00001111) << 12) >>> 0)\r\n\t\t\t\t| (((buffer[offset++] & 0b00111111) << 6) >>> 0)\r\n\t\t\t\t| (((buffer[offset++] & 0b00111111) << 0) >>> 0)\r\n\t\t\t);\r\n\t\t} else if (v0 >= 0b11000000 && offset + 1 < len) {\r\n\t\t\t// 2 bytes\r\n\t\t\tcodePoint = (\r\n\t\t\t\t(((buffer[offset++] & 0b00011111) << 6) >>> 0)\r\n\t\t\t\t| (((buffer[offset++] & 0b00111111) << 0) >>> 0)\r\n\t\t\t);\r\n\t\t} else {\r\n\t\t\t// 1 byte\r\n\t\t\tcodePoint = buffer[offset++];\r\n\t\t}\r\n\r\n\t\tif ((codePoint >= 0 && codePoint <= 0xD7FF) || (codePoint >= 0xE000 && codePoint <= 0xFFFF)) {\r\n\t\t\t// Basic Multilingual Plane\r\n\t\t\tresult.push(String.fromCharCode(codePoint));\r\n\t\t} else if (codePoint >= 0x010000 && codePoint <= 0x10FFFF) {\r\n\t\t\t// Supplementary Planes\r\n\t\t\tconst uPrime = codePoint - 0x10000;\r\n\t\t\tconst w1 = 0xD800 + ((uPrime & 0b11111111110000000000) >>> 10);\r\n\t\t\tconst w2 = 0xDC00 + ((uPrime & 0b00000000001111111111) >>> 0);\r\n\t\t\tresult.push(String.fromCharCode(w1));\r\n\t\t\tresult.push(String.fromCharCode(w2));\r\n\t\t} else {\r\n\t\t\t// illegal code point\r\n\t\t\tresult.push(String.fromCharCode(0xFFFD));\r\n\t\t}\r\n\t}\r\n\r\n\treturn result.join('');\r\n}\r\n\r\n/**\r\n * Generated using https://github.com/alexandrudima/unicode-utils/blob/master/generate-rtl-test.js\r\n */\r\nconst CONTAINS_RTL = /(?:[\\u05BE\\u05C0\\u05C3\\u05C6\\u05D0-\\u05F4\\u0608\\u060B\\u060D\\u061B-\\u064A\\u066D-\\u066F\\u0671-\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1-\\u07EA\\u07F4\\u07F5\\u07FA-\\u0815\\u081A\\u0824\\u0828\\u0830-\\u0858\\u085E-\\u08BD\\u200F\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFD3D\\uFD50-\\uFDFC\\uFE70-\\uFEFC]|\\uD802[\\uDC00-\\uDD1B\\uDD20-\\uDE00\\uDE10-\\uDE33\\uDE40-\\uDEE4\\uDEEB-\\uDF35\\uDF40-\\uDFFF]|\\uD803[\\uDC00-\\uDCFF]|\\uD83A[\\uDC00-\\uDCCF\\uDD00-\\uDD43\\uDD50-\\uDFFF]|\\uD83B[\\uDC00-\\uDEBB])/;\r\n\r\n/**\r\n * Returns true if `str` contains any Unicode character that is classified as \"R\" or \"AL\".\r\n */\r\nexport function containsRTL(str: string): boolean {\r\n\treturn CONTAINS_RTL.test(str);\r\n}\r\n\r\n/**\r\n * Generated using https://github.com/alexandrudima/unicode-utils/blob/master/generate-emoji-test.js\r\n */\r\nconst CONTAINS_EMOJI = /(?:[\\u231A\\u231B\\u23F0\\u23F3\\u2600-\\u27BF\\u2B50\\u2B55]|\\uD83C[\\uDDE6-\\uDDFF\\uDF00-\\uDFFF]|\\uD83D[\\uDC00-\\uDE4F\\uDE80-\\uDEFC\\uDFE0-\\uDFEB]|\\uD83E[\\uDD00-\\uDDFF\\uDE70-\\uDE73\\uDE78-\\uDE82\\uDE90-\\uDE95])/;\r\n\r\nexport function containsEmoji(str: string): boolean {\r\n\treturn CONTAINS_EMOJI.test(str);\r\n}\r\n\r\nconst IS_BASIC_ASCII = /^[\\t\\n\\r\\x20-\\x7E]*$/;\r\n/**\r\n * Returns true if `str` contains only basic ASCII characters in the range 32 - 126 (including 32 and 126) or \\n, \\r, \\t\r\n */\r\nexport function isBasicASCII(str: string): boolean {\r\n\treturn IS_BASIC_ASCII.test(str);\r\n}\r\n\r\nexport const UNUSUAL_LINE_TERMINATORS = /[\\u2028\\u2029]/; // LINE SEPARATOR (LS) or PARAGRAPH SEPARATOR (PS)\r\n/**\r\n * Returns true if `str` contains unusual line terminators, like LS or PS\r\n */\r\nexport function containsUnusualLineTerminators(str: string): boolean {\r\n\treturn UNUSUAL_LINE_TERMINATORS.test(str);\r\n}\r\n\r\nexport function containsFullWidthCharacter(str: string): boolean {\r\n\tfor (let i = 0, len = str.length; i < len; i++) {\r\n\t\tif (isFullWidthCharacter(str.charCodeAt(i))) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t}\r\n\treturn false;\r\n}\r\n\r\nexport function isFullWidthCharacter(charCode: number): boolean {\r\n\t// Do a cheap trick to better support wrapping of wide characters, treat them as 2 columns\r\n\t// http://jrgraphix.net/research/unicode_blocks.php\r\n\t// 2E80 — 2EFF CJK Radicals Supplement\r\n\t// 2F00 — 2FDF Kangxi Radicals\r\n\t// 2FF0 — 2FFF Ideographic Description Characters\r\n\t// 3000 — 303F CJK Symbols and Punctuation\r\n\t// 3040 — 309F Hiragana\r\n\t// 30A0 — 30FF Katakana\r\n\t// 3100 — 312F Bopomofo\r\n\t// 3130 — 318F Hangul Compatibility Jamo\r\n\t// 3190 — 319F Kanbun\r\n\t// 31A0 — 31BF Bopomofo Extended\r\n\t// 31F0 — 31FF Katakana Phonetic Extensions\r\n\t// 3200 — 32FF Enclosed CJK Letters and Months\r\n\t// 3300 — 33FF CJK Compatibility\r\n\t// 3400 — 4DBF CJK Unified Ideographs Extension A\r\n\t// 4DC0 — 4DFF Yijing Hexagram Symbols\r\n\t// 4E00 — 9FFF CJK Unified Ideographs\r\n\t// A000 — A48F Yi Syllables\r\n\t// A490 — A4CF Yi Radicals\r\n\t// AC00 — D7AF Hangul Syllables\r\n\t// [IGNORE] D800 — DB7F High Surrogates\r\n\t// [IGNORE] DB80 — DBFF High Private Use Surrogates\r\n\t// [IGNORE] DC00 — DFFF Low Surrogates\r\n\t// [IGNORE] E000 — F8FF Private Use Area\r\n\t// F900 — FAFF CJK Compatibility Ideographs\r\n\t// [IGNORE] FB00 — FB4F Alphabetic Presentation Forms\r\n\t// [IGNORE] FB50 — FDFF Arabic Presentation Forms-A\r\n\t// [IGNORE] FE00 — FE0F Variation Selectors\r\n\t// [IGNORE] FE20 — FE2F Combining Half Marks\r\n\t// [IGNORE] FE30 — FE4F CJK Compatibility Forms\r\n\t// [IGNORE] FE50 — FE6F Small Form Variants\r\n\t// [IGNORE] FE70 — FEFF Arabic Presentation Forms-B\r\n\t// FF00 — FFEF Halfwidth and Fullwidth Forms\r\n\t// [https://en.wikipedia.org/wiki/Halfwidth_and_fullwidth_forms]\r\n\t// of which FF01 - FF5E fullwidth ASCII of 21 to 7E\r\n\t// [IGNORE] and FF65 - FFDC halfwidth of Katakana and Hangul\r\n\t// [IGNORE] FFF0 — FFFF Specials\r\n\tcharCode = +charCode; // @perf\r\n\treturn (\r\n\t\t(charCode >= 0x2E80 && charCode <= 0xD7AF)\r\n\t\t|| (charCode >= 0xF900 && charCode <= 0xFAFF)\r\n\t\t|| (charCode >= 0xFF01 && charCode <= 0xFF5E)\r\n\t);\r\n}\r\n\r\n/**\r\n * A fast function (therefore imprecise) to check if code points are emojis.\r\n * Generated using https://github.com/alexandrudima/unicode-utils/blob/master/generate-emoji-test.js\r\n */\r\nexport function isEmojiImprecise(x: number): boolean {\r\n\treturn (\r\n\t\t(x >= 0x1F1E6 && x <= 0x1F1FF) || (x >= 9728 && x <= 10175) || (x >= 127744 && x <= 128591)\r\n\t\t|| (x >= 128640 && x <= 128764) || (x >= 128992 && x <= 129003) || (x >= 129280 && x <= 129535)\r\n\t\t|| (x >= 129648 && x <= 129651) || (x >= 129656 && x <= 129666) || (x >= 129680 && x <= 129685)\r\n\t);\r\n}\r\n\r\n// -- UTF-8 BOM\r\n\r\nexport const UTF8_BOM_CHARACTER = String.fromCharCode(CharCode.UTF8_BOM);\r\n\r\nexport function startsWithUTF8BOM(str: string): boolean {\r\n\treturn !!(str && str.length > 0 && str.charCodeAt(0) === CharCode.UTF8_BOM);\r\n}\r\n\r\nexport function containsUppercaseCharacter(target: string, ignoreEscapedChars = false): boolean {\r\n\tif (!target) {\r\n\t\treturn false;\r\n\t}\r\n\r\n\tif (ignoreEscapedChars) {\r\n\t\ttarget = target.replace(/\\\\./g, '');\r\n\t}\r\n\r\n\treturn target.toLowerCase() !== target;\r\n}\r\n\r\n/**\r\n * Produces 'a'-'z', followed by 'A'-'Z'... followed by 'a'-'z', etc.\r\n */\r\nexport function singleLetterHash(n: number): string {\r\n\tconst LETTERS_CNT = (CharCode.Z - CharCode.A + 1);\r\n\r\n\tn = n % (2 * LETTERS_CNT);\r\n\r\n\tif (n < LETTERS_CNT) {\r\n\t\treturn String.fromCharCode(CharCode.a + n);\r\n\t}\r\n\r\n\treturn String.fromCharCode(CharCode.A + n - LETTERS_CNT);\r\n}\r\n\r\n//#region Unicode Grapheme Break\r\n\r\nexport function getGraphemeBreakType(codePoint: number): GraphemeBreakType {\r\n\tconst graphemeBreakTree = GraphemeBreakTree.getInstance();\r\n\treturn graphemeBreakTree.getGraphemeBreakType(codePoint);\r\n}\r\n\r\nexport function breakBetweenGraphemeBreakType(breakTypeA: GraphemeBreakType, breakTypeB: GraphemeBreakType): boolean {\r\n\t// http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundary_Rules\r\n\r\n\t// !!! Let's make the common case a bit faster\r\n\tif (breakTypeA === GraphemeBreakType.Other) {\r\n\t\t// see https://www.unicode.org/Public/13.0.0/ucd/auxiliary/GraphemeBreakTest-13.0.0d10.html#table\r\n\t\treturn (breakTypeB !== GraphemeBreakType.Extend && breakTypeB !== GraphemeBreakType.SpacingMark);\r\n\t}\r\n\r\n\t// Do not break between a CR and LF. Otherwise, break before and after controls.\r\n\t// GB3 CR × LF\r\n\t// GB4 (Control | CR | LF) ÷\r\n\t// GB5 ÷ (Control | CR | LF)\r\n\tif (breakTypeA === GraphemeBreakType.CR) {\r\n\t\tif (breakTypeB === GraphemeBreakType.LF) {\r\n\t\t\treturn false; // GB3\r\n\t\t}\r\n\t}\r\n\tif (breakTypeA === GraphemeBreakType.Control || breakTypeA === GraphemeBreakType.CR || breakTypeA === GraphemeBreakType.LF) {\r\n\t\treturn true; // GB4\r\n\t}\r\n\tif (breakTypeB === GraphemeBreakType.Control || breakTypeB === GraphemeBreakType.CR || breakTypeB === GraphemeBreakType.LF) {\r\n\t\treturn true; // GB5\r\n\t}\r\n\r\n\t// Do not break Hangul syllable sequences.\r\n\t// GB6 L × (L | V | LV | LVT)\r\n\t// GB7 (LV | V) × (V | T)\r\n\t// GB8 (LVT | T) × T\r\n\tif (breakTypeA === GraphemeBreakType.L) {\r\n\t\tif (breakTypeB === GraphemeBreakType.L || breakTypeB === GraphemeBreakType.V || breakTypeB === GraphemeBreakType.LV || breakTypeB === GraphemeBreakType.LVT) {\r\n\t\t\treturn false; // GB6\r\n\t\t}\r\n\t}\r\n\tif (breakTypeA === GraphemeBreakType.LV || breakTypeA === GraphemeBreakType.V) {\r\n\t\tif (breakTypeB === GraphemeBreakType.V || breakTypeB === GraphemeBreakType.T) {\r\n\t\t\treturn false; // GB7\r\n\t\t}\r\n\t}\r\n\tif (breakTypeA === GraphemeBreakType.LVT || breakTypeA === GraphemeBreakType.T) {\r\n\t\tif (breakTypeB === GraphemeBreakType.T) {\r\n\t\t\treturn false; // GB8\r\n\t\t}\r\n\t}\r\n\r\n\t// Do not break before extending characters or ZWJ.\r\n\t// GB9 × (Extend | ZWJ)\r\n\tif (breakTypeB === GraphemeBreakType.Extend || breakTypeB === GraphemeBreakType.ZWJ) {\r\n\t\treturn false; // GB9\r\n\t}\r\n\r\n\t// The GB9a and GB9b rules only apply to extended grapheme clusters:\r\n\t// Do not break before SpacingMarks, or after Prepend characters.\r\n\t// GB9a × SpacingMark\r\n\t// GB9b Prepend ×\r\n\tif (breakTypeB === GraphemeBreakType.SpacingMark) {\r\n\t\treturn false; // GB9a\r\n\t}\r\n\tif (breakTypeA === GraphemeBreakType.Prepend) {\r\n\t\treturn false; // GB9b\r\n\t}\r\n\r\n\t// Do not break within emoji modifier sequences or emoji zwj sequences.\r\n\t// GB11 \\p{Extended_Pictographic} Extend* ZWJ × \\p{Extended_Pictographic}\r\n\tif (breakTypeA === GraphemeBreakType.ZWJ && breakTypeB === GraphemeBreakType.Extended_Pictographic) {\r\n\t\t// Note: we are not implementing the rule entirely here to avoid introducing states\r\n\t\treturn false; // GB11\r\n\t}\r\n\r\n\t// GB12 sot (RI RI)* RI × RI\r\n\t// GB13 [^RI] (RI RI)* RI × RI\r\n\tif (breakTypeA === GraphemeBreakType.Regional_Indicator && breakTypeB === GraphemeBreakType.Regional_Indicator) {\r\n\t\t// Note: we are not implementing the rule entirely here to avoid introducing states\r\n\t\treturn false; // GB12 & GB13\r\n\t}\r\n\r\n\t// GB999 Any ÷ Any\r\n\treturn true;\r\n}\r\n\r\nexport const enum GraphemeBreakType {\r\n\tOther = 0,\r\n\tPrepend = 1,\r\n\tCR = 2,\r\n\tLF = 3,\r\n\tControl = 4,\r\n\tExtend = 5,\r\n\tRegional_Indicator = 6,\r\n\tSpacingMark = 7,\r\n\tL = 8,\r\n\tV = 9,\r\n\tT = 10,\r\n\tLV = 11,\r\n\tLVT = 12,\r\n\tZWJ = 13,\r\n\tExtended_Pictographic = 14\r\n}\r\n\r\nclass GraphemeBreakTree {\r\n\r\n\tprivate static _INSTANCE: GraphemeBreakTree | null = null;\r\n\tpublic static getInstance(): GraphemeBreakTree {\r\n\t\tif (!GraphemeBreakTree._INSTANCE) {\r\n\t\t\tGraphemeBreakTree._INSTANCE = new GraphemeBreakTree();\r\n\t\t}\r\n\t\treturn GraphemeBreakTree._INSTANCE;\r\n\t}\r\n\r\n\tprivate readonly _data: number[];\r\n\r\n\tconstructor() {\r\n\t\tthis._data = getGraphemeBreakRawData();\r\n\t}\r\n\r\n\tpublic getGraphemeBreakType(codePoint: number): GraphemeBreakType {\r\n\t\t// !!! Let's make 7bit ASCII a bit faster: 0..31\r\n\t\tif (codePoint < 32) {\r\n\t\t\tif (codePoint === CharCode.LineFeed) {\r\n\t\t\t\treturn GraphemeBreakType.LF;\r\n\t\t\t}\r\n\t\t\tif (codePoint === CharCode.CarriageReturn) {\r\n\t\t\t\treturn GraphemeBreakType.CR;\r\n\t\t\t}\r\n\t\t\treturn GraphemeBreakType.Control;\r\n\t\t}\r\n\t\t// !!! Let's make 7bit ASCII a bit faster: 32..126\r\n\t\tif (codePoint < 127) {\r\n\t\t\treturn GraphemeBreakType.Other;\r\n\t\t}\r\n\r\n\t\tconst data = this._data;\r\n\t\tconst nodeCount = data.length / 3;\r\n\t\tlet nodeIndex = 1;\r\n\t\twhile (nodeIndex <= nodeCount) {\r\n\t\t\tif (codePoint < data[3 * nodeIndex]) {\r\n\t\t\t\t// go left\r\n\t\t\t\tnodeIndex = 2 * nodeIndex;\r\n\t\t\t} else if (codePoint > data[3 * nodeIndex + 1]) {\r\n\t\t\t\t// go right\r\n\t\t\t\tnodeIndex = 2 * nodeIndex + 1;\r\n\t\t\t} else {\r\n\t\t\t\t// hit\r\n\t\t\t\treturn data[3 * nodeIndex + 2];\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn GraphemeBreakType.Other;\r\n\t}\r\n}\r\n\r\nfunction getGraphemeBreakRawData(): number[] {\r\n\t// generated using https://github.com/alexandrudima/unicode-utils/blob/master/generate-grapheme-break.js\r\n\treturn JSON.parse('[0,0,0,51592,51592,11,44424,44424,11,72251,72254,5,7150,7150,7,48008,48008,11,55176,55176,11,128420,128420,14,3276,3277,5,9979,9980,14,46216,46216,11,49800,49800,11,53384,53384,11,70726,70726,5,122915,122916,5,129320,129327,14,2558,2558,5,5906,5908,5,9762,9763,14,43360,43388,8,45320,45320,11,47112,47112,11,48904,48904,11,50696,50696,11,52488,52488,11,54280,54280,11,70082,70083,1,71350,71350,7,73111,73111,5,127892,127893,14,128726,128727,14,129473,129474,14,2027,2035,5,2901,2902,5,3784,3789,5,6754,6754,5,8418,8420,5,9877,9877,14,11088,11088,14,44008,44008,5,44872,44872,11,45768,45768,11,46664,46664,11,47560,47560,11,48456,48456,11,49352,49352,11,50248,50248,11,51144,51144,11,52040,52040,11,52936,52936,11,53832,53832,11,54728,54728,11,69811,69814,5,70459,70460,5,71096,71099,7,71998,71998,5,72874,72880,5,119149,119149,7,127374,127374,14,128335,128335,14,128482,128482,14,128765,128767,14,129399,129400,14,129680,129685,14,1476,1477,5,2377,2380,7,2759,2760,5,3137,3140,7,3458,3459,7,4153,4154,5,6432,6434,5,6978,6978,5,7675,7679,5,9723,9726,14,9823,9823,14,9919,9923,14,10035,10036,14,42736,42737,5,43596,43596,5,44200,44200,11,44648,44648,11,45096,45096,11,45544,45544,11,45992,45992,11,46440,46440,11,46888,46888,11,47336,47336,11,47784,47784,11,48232,48232,11,48680,48680,11,49128,49128,11,49576,49576,11,50024,50024,11,50472,50472,11,50920,50920,11,51368,51368,11,51816,51816,11,52264,52264,11,52712,52712,11,53160,53160,11,53608,53608,11,54056,54056,11,54504,54504,11,54952,54952,11,68108,68111,5,69933,69940,5,70197,70197,7,70498,70499,7,70845,70845,5,71229,71229,5,71727,71735,5,72154,72155,5,72344,72345,5,73023,73029,5,94095,94098,5,121403,121452,5,126981,127182,14,127538,127546,14,127990,127990,14,128391,128391,14,128445,128449,14,128500,128505,14,128752,128752,14,129160,129167,14,129356,129356,14,129432,129442,14,129648,129651,14,129751,131069,14,173,173,4,1757,1757,1,2274,2274,1,2494,2494,5,2641,2641,5,2876,2876,5,3014,3016,7,3262,3262,7,3393,3396,5,3570,3571,7,3968,3972,5,4228,4228,7,6086,6086,5,6679,6680,5,6912,6915,5,7080,7081,5,7380,7392,5,8252,8252,14,9096,9096,14,9748,9749,14,9784,9786,14,9833,9850,14,9890,9894,14,9938,9938,14,9999,9999,14,10085,10087,14,12349,12349,14,43136,43137,7,43454,43456,7,43755,43755,7,44088,44088,11,44312,44312,11,44536,44536,11,44760,44760,11,44984,44984,11,45208,45208,11,45432,45432,11,45656,45656,11,45880,45880,11,46104,46104,11,46328,46328,11,46552,46552,11,46776,46776,11,47000,47000,11,47224,47224,11,47448,47448,11,47672,47672,11,47896,47896,11,48120,48120,11,48344,48344,11,48568,48568,11,48792,48792,11,49016,49016,11,49240,49240,11,49464,49464,11,49688,49688,11,49912,49912,11,50136,50136,11,50360,50360,11,50584,50584,11,50808,50808,11,51032,51032,11,51256,51256,11,51480,51480,11,51704,51704,11,51928,51928,11,52152,52152,11,52376,52376,11,52600,52600,11,52824,52824,11,53048,53048,11,53272,53272,11,53496,53496,11,53720,53720,11,53944,53944,11,54168,54168,11,54392,54392,11,54616,54616,11,54840,54840,11,55064,55064,11,65438,65439,5,69633,69633,5,69837,69837,1,70018,70018,7,70188,70190,7,70368,70370,7,70465,70468,7,70712,70719,5,70835,70840,5,70850,70851,5,71132,71133,5,71340,71340,7,71458,71461,5,71985,71989,7,72002,72002,7,72193,72202,5,72281,72283,5,72766,72766,7,72885,72886,5,73104,73105,5,92912,92916,5,113824,113827,4,119173,119179,5,121505,121519,5,125136,125142,5,127279,127279,14,127489,127490,14,127570,127743,14,127900,127901,14,128254,128254,14,128369,128370,14,128400,128400,14,128425,128432,14,128468,128475,14,128489,128494,14,128715,128720,14,128745,128745,14,128759,128760,14,129004,129023,14,129296,129304,14,129340,129342,14,129388,129392,14,129404,129407,14,129454,129455,14,129485,129487,14,129659,129663,14,129719,129727,14,917536,917631,5,13,13,2,1160,1161,5,1564,1564,4,1807,1807,1,2085,2087,5,2363,2363,7,2402,2403,5,2507,2508,7,2622,2624,7,2691,2691,7,2786,2787,5,2881,2884,5,3006,3006,5,3072,3072,5,3170,3171,5,3267,3268,7,3330,3331,7,3406,3406,1,3538,3540,5,3655,3662,5,3897,3897,5,4038,4038,5,4184,4185,5,4352,4447,8,6068,6069,5,6155,6157,5,6448,6449,7,6742,6742,5,6783,6783,5,6966,6970,5,7042,7042,7,7143,7143,7,7212,7219,5,7412,7412,5,8206,8207,4,8294,8303,4,8596,8601,14,9410,9410,14,9742,9742,14,9757,9757,14,9770,9770,14,9794,9794,14,9828,9828,14,9855,9855,14,9882,9882,14,9900,9903,14,9929,9933,14,9963,9967,14,9987,9988,14,10006,10006,14,10062,10062,14,10175,10175,14,11744,11775,5,42607,42607,5,43043,43044,7,43263,43263,5,43444,43445,7,43569,43570,5,43698,43700,5,43766,43766,5,44032,44032,11,44144,44144,11,44256,44256,11,44368,44368,11,44480,44480,11,44592,44592,11,44704,44704,11,44816,44816,11,44928,44928,11,45040,45040,11,45152,45152,11,45264,45264,11,45376,45376,11,45488,45488,11,45600,45600,11,45712,45712,11,45824,45824,11,45936,45936,11,46048,46048,11,46160,46160,11,46272,46272,11,46384,46384,11,46496,46496,11,46608,46608,11,46720,46720,11,46832,46832,11,46944,46944,11,47056,47056,11,47168,47168,11,47280,47280,11,47392,47392,11,47504,47504,11,47616,47616,11,47728,47728,11,47840,47840,11,47952,47952,11,48064,48064,11,48176,48176,11,48288,48288,11,48400,48400,11,48512,48512,11,48624,48624,11,48736,48736,11,48848,48848,11,48960,48960,11,49072,49072,11,49184,49184,11,49296,49296,11,49408,49408,11,49520,49520,11,49632,49632,11,49744,49744,11,49856,49856,11,49968,49968,11,50080,50080,11,50192,50192,11,50304,50304,11,50416,50416,11,50528,50528,11,50640,50640,11,50752,50752,11,50864,50864,11,50976,50976,11,51088,51088,11,51200,51200,11,51312,51312,11,51424,51424,11,51536,51536,11,51648,51648,11,51760,51760,11,51872,51872,11,51984,51984,11,52096,52096,11,52208,52208,11,52320,52320,11,52432,52432,11,52544,52544,11,52656,52656,11,52768,52768,11,52880,52880,11,52992,52992,11,53104,53104,11,53216,53216,11,53328,53328,11,53440,53440,11,53552,53552,11,53664,53664,11,53776,53776,11,53888,53888,11,54000,54000,11,54112,54112,11,54224,54224,11,54336,54336,11,54448,54448,11,54560,54560,11,54672,54672,11,54784,54784,11,54896,54896,11,55008,55008,11,55120,55120,11,64286,64286,5,66272,66272,5,68900,68903,5,69762,69762,7,69817,69818,5,69927,69931,5,70003,70003,5,70070,70078,5,70094,70094,7,70194,70195,7,70206,70206,5,70400,70401,5,70463,70463,7,70475,70477,7,70512,70516,5,70722,70724,5,70832,70832,5,70842,70842,5,70847,70848,5,71088,71089,7,71102,71102,7,71219,71226,5,71231,71232,5,71342,71343,7,71453,71455,5,71463,71467,5,71737,71738,5,71995,71996,5,72000,72000,7,72145,72147,7,72160,72160,5,72249,72249,7,72273,72278,5,72330,72342,5,72752,72758,5,72850,72871,5,72882,72883,5,73018,73018,5,73031,73031,5,73109,73109,5,73461,73462,7,94031,94031,5,94192,94193,7,119142,119142,7,119155,119162,4,119362,119364,5,121476,121476,5,122888,122904,5,123184,123190,5,126976,126979,14,127184,127231,14,127344,127345,14,127405,127461,14,127514,127514,14,127561,127567,14,127778,127779,14,127896,127896,14,127985,127986,14,127995,127999,5,128326,128328,14,128360,128366,14,128378,128378,14,128394,128397,14,128405,128406,14,128422,128423,14,128435,128443,14,128453,128464,14,128479,128480,14,128484,128487,14,128496,128498,14,128640,128709,14,128723,128724,14,128736,128741,14,128747,128748,14,128755,128755,14,128762,128762,14,128981,128991,14,129096,129103,14,129292,129292,14,129311,129311,14,129329,129330,14,129344,129349,14,129360,129374,14,129394,129394,14,129402,129402,14,129413,129425,14,129445,129450,14,129466,129471,14,129483,129483,14,129511,129535,14,129653,129655,14,129667,129670,14,129705,129711,14,129731,129743,14,917505,917505,4,917760,917999,5,10,10,3,127,159,4,768,879,5,1471,1471,5,1536,1541,1,1648,1648,5,1767,1768,5,1840,1866,5,2070,2073,5,2137,2139,5,2307,2307,7,2366,2368,7,2382,2383,7,2434,2435,7,2497,2500,5,2519,2519,5,2563,2563,7,2631,2632,5,2677,2677,5,2750,2752,7,2763,2764,7,2817,2817,5,2879,2879,5,2891,2892,7,2914,2915,5,3008,3008,5,3021,3021,5,3076,3076,5,3146,3149,5,3202,3203,7,3264,3265,7,3271,3272,7,3298,3299,5,3390,3390,5,3402,3404,7,3426,3427,5,3535,3535,5,3544,3550,7,3635,3635,7,3763,3763,7,3893,3893,5,3953,3966,5,3981,3991,5,4145,4145,7,4157,4158,5,4209,4212,5,4237,4237,5,4520,4607,10,5970,5971,5,6071,6077,5,6089,6099,5,6277,6278,5,6439,6440,5,6451,6456,7,6683,6683,5,6744,6750,5,6765,6770,7,6846,6846,5,6964,6964,5,6972,6972,5,7019,7027,5,7074,7077,5,7083,7085,5,7146,7148,7,7154,7155,7,7222,7223,5,7394,7400,5,7416,7417,5,8204,8204,5,8233,8233,4,8288,8292,4,8413,8416,5,8482,8482,14,8986,8987,14,9193,9203,14,9654,9654,14,9733,9733,14,9745,9745,14,9752,9752,14,9760,9760,14,9766,9766,14,9774,9775,14,9792,9792,14,9800,9811,14,9825,9826,14,9831,9831,14,9852,9853,14,9872,9873,14,9880,9880,14,9885,9887,14,9896,9897,14,9906,9916,14,9926,9927,14,9936,9936,14,9941,9960,14,9974,9974,14,9982,9985,14,9992,9997,14,10002,10002,14,10017,10017,14,10055,10055,14,10071,10071,14,10145,10145,14,11013,11015,14,11503,11505,5,12334,12335,5,12951,12951,14,42612,42621,5,43014,43014,5,43047,43047,7,43204,43205,5,43335,43345,5,43395,43395,7,43450,43451,7,43561,43566,5,43573,43574,5,43644,43644,5,43710,43711,5,43758,43759,7,44005,44005,5,44012,44012,7,44060,44060,11,44116,44116,11,44172,44172,11,44228,44228,11,44284,44284,11,44340,44340,11,44396,44396,11,44452,44452,11,44508,44508,11,44564,44564,11,44620,44620,11,44676,44676,11,44732,44732,11,44788,44788,11,44844,44844,11,44900,44900,11,44956,44956,11,45012,45012,11,45068,45068,11,45124,45124,11,45180,45180,11,45236,45236,11,45292,45292,11,45348,45348,11,45404,45404,11,45460,45460,11,45516,45516,11,45572,45572,11,45628,45628,11,45684,45684,11,45740,45740,11,45796,45796,11,45852,45852,11,45908,45908,11,45964,45964,11,46020,46020,11,46076,46076,11,46132,46132,11,46188,46188,11,46244,46244,11,46300,46300,11,46356,46356,11,46412,46412,11,46468,46468,11,46524,46524,11,46580,46580,11,46636,46636,11,46692,46692,11,46748,46748,11,46804,46804,11,46860,46860,11,46916,46916,11,46972,46972,11,47028,47028,11,47084,47084,11,47140,47140,11,47196,47196,11,47252,47252,11,47308,47308,11,47364,47364,11,47420,47420,11,47476,47476,11,47532,47532,11,47588,47588,11,47644,47644,11,47700,47700,11,47756,47756,11,47812,47812,11,47868,47868,11,47924,47924,11,47980,47980,11,48036,48036,11,48092,48092,11,48148,48148,11,48204,48204,11,48260,48260,11,48316,48316,11,48372,48372,11,48428,48428,11,48484,48484,11,48540,48540,11,48596,48596,11,48652,48652,11,48708,48708,11,48764,48764,11,48820,48820,11,48876,48876,11,48932,48932,11,48988,48988,11,49044,49044,11,49100,49100,11,49156,49156,11,49212,49212,11,49268,49268,11,49324,49324,11,49380,49380,11,49436,49436,11,49492,49492,11,49548,49548,11,49604,49604,11,49660,49660,11,49716,49716,11,49772,49772,11,49828,49828,11,49884,49884,11,49940,49940,11,49996,49996,11,50052,50052,11,50108,50108,11,50164,50164,11,50220,50220,11,50276,50276,11,50332,50332,11,50388,50388,11,50444,50444,11,50500,50500,11,50556,50556,11,50612,50612,11,50668,50668,11,50724,50724,11,50780,50780,11,50836,50836,11,50892,50892,11,50948,50948,11,51004,51004,11,51060,51060,11,51116,51116,11,51172,51172,11,51228,51228,11,51284,51284,11,51340,51340,11,51396,51396,11,51452,51452,11,51508,51508,11,51564,51564,11,51620,51620,11,51676,51676,11,51732,51732,11,51788,51788,11,51844,51844,11,51900,51900,11,51956,51956,11,52012,52012,11,52068,52068,11,52124,52124,11,52180,52180,11,52236,52236,11,52292,52292,11,52348,52348,11,52404,52404,11,52460,52460,11,52516,52516,11,52572,52572,11,52628,52628,11,52684,52684,11,52740,52740,11,52796,52796,11,52852,52852,11,52908,52908,11,52964,52964,11,53020,53020,11,53076,53076,11,53132,53132,11,53188,53188,11,53244,53244,11,53300,53300,11,53356,53356,11,53412,53412,11,53468,53468,11,53524,53524,11,53580,53580,11,53636,53636,11,53692,53692,11,53748,53748,11,53804,53804,11,53860,53860,11,53916,53916,11,53972,53972,11,54028,54028,11,54084,54084,11,54140,54140,11,54196,54196,11,54252,54252,11,54308,54308,11,54364,54364,11,54420,54420,11,54476,54476,11,54532,54532,11,54588,54588,11,54644,54644,11,54700,54700,11,54756,54756,11,54812,54812,11,54868,54868,11,54924,54924,11,54980,54980,11,55036,55036,11,55092,55092,11,55148,55148,11,55216,55238,9,65056,65071,5,65529,65531,4,68097,68099,5,68159,68159,5,69446,69456,5,69688,69702,5,69808,69810,7,69815,69816,7,69821,69821,1,69888,69890,5,69932,69932,7,69957,69958,7,70016,70017,5,70067,70069,7,70079,70080,7,70089,70092,5,70095,70095,5,70191,70193,5,70196,70196,5,70198,70199,5,70367,70367,5,70371,70378,5,70402,70403,7,70462,70462,5,70464,70464,5,70471,70472,7,70487,70487,5,70502,70508,5,70709,70711,7,70720,70721,7,70725,70725,7,70750,70750,5,70833,70834,7,70841,70841,7,70843,70844,7,70846,70846,7,70849,70849,7,71087,71087,5,71090,71093,5,71100,71101,5,71103,71104,5,71216,71218,7,71227,71228,7,71230,71230,7,71339,71339,5,71341,71341,5,71344,71349,5,71351,71351,5,71456,71457,7,71462,71462,7,71724,71726,7,71736,71736,7,71984,71984,5,71991,71992,7,71997,71997,7,71999,71999,1,72001,72001,1,72003,72003,5,72148,72151,5,72156,72159,7,72164,72164,7,72243,72248,5,72250,72250,1,72263,72263,5,72279,72280,7,72324,72329,1,72343,72343,7,72751,72751,7,72760,72765,5,72767,72767,5,72873,72873,7,72881,72881,7,72884,72884,7,73009,73014,5,73020,73021,5,73030,73030,1,73098,73102,7,73107,73108,7,73110,73110,7,73459,73460,5,78896,78904,4,92976,92982,5,94033,94087,7,94180,94180,5,113821,113822,5,119141,119141,5,119143,119145,5,119150,119154,5,119163,119170,5,119210,119213,5,121344,121398,5,121461,121461,5,121499,121503,5,122880,122886,5,122907,122913,5,122918,122922,5,123628,123631,5,125252,125258,5,126980,126980,14,127183,127183,14,127245,127247,14,127340,127343,14,127358,127359,14,127377,127386,14,127462,127487,6,127491,127503,14,127535,127535,14,127548,127551,14,127568,127569,14,127744,127777,14,127780,127891,14,127894,127895,14,127897,127899,14,127902,127984,14,127987,127989,14,127991,127994,14,128000,128253,14,128255,128317,14,128329,128334,14,128336,128359,14,128367,128368,14,128371,128377,14,128379,128390,14,128392,128393,14,128398,128399,14,128401,128404,14,128407,128419,14,128421,128421,14,128424,128424,14,128433,128434,14,128444,128444,14,128450,128452,14,128465,128467,14,128476,128478,14,128481,128481,14,128483,128483,14,128488,128488,14,128495,128495,14,128499,128499,14,128506,128591,14,128710,128714,14,128721,128722,14,128725,128725,14,128728,128735,14,128742,128744,14,128746,128746,14,128749,128751,14,128753,128754,14,128756,128758,14,128761,128761,14,128763,128764,14,128884,128895,14,128992,129003,14,129036,129039,14,129114,129119,14,129198,129279,14,129293,129295,14,129305,129310,14,129312,129319,14,129328,129328,14,129331,129338,14,129343,129343,14,129351,129355,14,129357,129359,14,129375,129387,14,129393,129393,14,129395,129398,14,129401,129401,14,129403,129403,14,129408,129412,14,129426,129431,14,129443,129444,14,129451,129453,14,129456,129465,14,129472,129472,14,129475,129482,14,129484,129484,14,129488,129510,14,129536,129647,14,129652,129652,14,129656,129658,14,129664,129666,14,129671,129679,14,129686,129704,14,129712,129718,14,129728,129730,14,129744,129750,14,917504,917504,4,917506,917535,4,917632,917759,4,918000,921599,4,0,9,4,11,12,4,14,31,4,169,169,14,174,174,14,1155,1159,5,1425,1469,5,1473,1474,5,1479,1479,5,1552,1562,5,1611,1631,5,1750,1756,5,1759,1764,5,1770,1773,5,1809,1809,5,1958,1968,5,2045,2045,5,2075,2083,5,2089,2093,5,2259,2273,5,2275,2306,5,2362,2362,5,2364,2364,5,2369,2376,5,2381,2381,5,2385,2391,5,2433,2433,5,2492,2492,5,2495,2496,7,2503,2504,7,2509,2509,5,2530,2531,5,2561,2562,5,2620,2620,5,2625,2626,5,2635,2637,5,2672,2673,5,2689,2690,5,2748,2748,5,2753,2757,5,2761,2761,7,2765,2765,5,2810,2815,5,2818,2819,7,2878,2878,5,2880,2880,7,2887,2888,7,2893,2893,5,2903,2903,5,2946,2946,5,3007,3007,7,3009,3010,7,3018,3020,7,3031,3031,5,3073,3075,7,3134,3136,5,3142,3144,5,3157,3158,5,3201,3201,5,3260,3260,5,3263,3263,5,3266,3266,5,3270,3270,5,3274,3275,7,3285,3286,5,3328,3329,5,3387,3388,5,3391,3392,7,3398,3400,7,3405,3405,5,3415,3415,5,3457,3457,5,3530,3530,5,3536,3537,7,3542,3542,5,3551,3551,5,3633,3633,5,3636,3642,5,3761,3761,5,3764,3772,5,3864,3865,5,3895,3895,5,3902,3903,7,3967,3967,7,3974,3975,5,3993,4028,5,4141,4144,5,4146,4151,5,4155,4156,7,4182,4183,7,4190,4192,5,4226,4226,5,4229,4230,5,4253,4253,5,4448,4519,9,4957,4959,5,5938,5940,5,6002,6003,5,6070,6070,7,6078,6085,7,6087,6088,7,6109,6109,5,6158,6158,4,6313,6313,5,6435,6438,7,6441,6443,7,6450,6450,5,6457,6459,5,6681,6682,7,6741,6741,7,6743,6743,7,6752,6752,5,6757,6764,5,6771,6780,5,6832,6845,5,6847,6848,5,6916,6916,7,6965,6965,5,6971,6971,7,6973,6977,7,6979,6980,7,7040,7041,5,7073,7073,7,7078,7079,7,7082,7082,7,7142,7142,5,7144,7145,5,7149,7149,5,7151,7153,5,7204,7211,7,7220,7221,7,7376,7378,5,7393,7393,7,7405,7405,5,7415,7415,7,7616,7673,5,8203,8203,4,8205,8205,13,8232,8232,4,8234,8238,4,8265,8265,14,8293,8293,4,8400,8412,5,8417,8417,5,8421,8432,5,8505,8505,14,8617,8618,14,9000,9000,14,9167,9167,14,9208,9210,14,9642,9643,14,9664,9664,14,9728,9732,14,9735,9741,14,9743,9744,14,9746,9746,14,9750,9751,14,9753,9756,14,9758,9759,14,9761,9761,14,9764,9765,14,9767,9769,14,9771,9773,14,9776,9783,14,9787,9791,14,9793,9793,14,9795,9799,14,9812,9822,14,9824,9824,14,9827,9827,14,9829,9830,14,9832,9832,14,9851,9851,14,9854,9854,14,9856,9861,14,9874,9876,14,9878,9879,14,9881,9881,14,9883,9884,14,9888,9889,14,9895,9895,14,9898,9899,14,9904,9905,14,9917,9918,14,9924,9925,14,9928,9928,14,9934,9935,14,9937,9937,14,9939,9940,14,9961,9962,14,9968,9973,14,9975,9978,14,9981,9981,14,9986,9986,14,9989,9989,14,9998,9998,14,10000,10001,14,10004,10004,14,10013,10013,14,10024,10024,14,10052,10052,14,10060,10060,14,10067,10069,14,10083,10084,14,10133,10135,14,10160,10160,14,10548,10549,14,11035,11036,14,11093,11093,14,11647,11647,5,12330,12333,5,12336,12336,14,12441,12442,5,12953,12953,14,42608,42610,5,42654,42655,5,43010,43010,5,43019,43019,5,43045,43046,5,43052,43052,5,43188,43203,7,43232,43249,5,43302,43309,5,43346,43347,7,43392,43394,5,43443,43443,5,43446,43449,5,43452,43453,5,43493,43493,5,43567,43568,7,43571,43572,7,43587,43587,5,43597,43597,7,43696,43696,5,43703,43704,5,43713,43713,5,43756,43757,5,43765,43765,7,44003,44004,7,44006,44007,7,44009,44010,7,44013,44013,5,44033,44059,12,44061,44087,12,44089,44115,12,44117,44143,12,44145,44171,12,44173,44199,12,44201,44227,12,44229,44255,12,44257,44283,12,44285,44311,12,44313,44339,12,44341,44367,12,44369,44395,12,44397,44423,12,44425,44451,12,44453,44479,12,44481,44507,12,44509,44535,12,44537,44563,12,44565,44591,12,44593,44619,12,44621,44647,12,44649,44675,12,44677,44703,12,44705,44731,12,44733,44759,12,44761,44787,12,44789,44815,12,44817,44843,12,44845,44871,12,44873,44899,12,44901,44927,12,44929,44955,12,44957,44983,12,44985,45011,12,45013,45039,12,45041,45067,12,45069,45095,12,45097,45123,12,45125,45151,12,45153,45179,12,45181,45207,12,45209,45235,12,45237,45263,12,45265,45291,12,45293,45319,12,45321,45347,12,45349,45375,12,45377,45403,12,45405,45431,12,45433,45459,12,45461,45487,12,45489,45515,12,45517,45543,12,45545,45571,12,45573,45599,12,45601,45627,12,45629,45655,12,45657,45683,12,45685,45711,12,45713,45739,12,45741,45767,12,45769,45795,12,45797,45823,12,45825,45851,12,45853,45879,12,45881,45907,12,45909,45935,12,45937,45963,12,45965,45991,12,45993,46019,12,46021,46047,12,46049,46075,12,46077,46103,12,46105,46131,12,46133,46159,12,46161,46187,12,46189,46215,12,46217,46243,12,46245,46271,12,46273,46299,12,46301,46327,12,46329,46355,12,46357,46383,12,46385,46411,12,46413,46439,12,46441,46467,12,46469,46495,12,46497,46523,12,46525,46551,12,46553,46579,12,46581,46607,12,46609,46635,12,46637,46663,12,46665,46691,12,46693,46719,12,46721,46747,12,46749,46775,12,46777,46803,12,46805,46831,12,46833,46859,12,46861,46887,12,46889,46915,12,46917,46943,12,46945,46971,12,46973,46999,12,47001,47027,12,47029,47055,12,47057,47083,12,47085,47111,12,47113,47139,12,47141,47167,12,47169,47195,12,47197,47223,12,47225,47251,12,47253,47279,12,47281,47307,12,47309,47335,12,47337,47363,12,47365,47391,12,47393,47419,12,47421,47447,12,47449,47475,12,47477,47503,12,47505,47531,12,47533,47559,12,47561,47587,12,47589,47615,12,47617,47643,12,47645,47671,12,47673,47699,12,47701,47727,12,47729,47755,12,47757,47783,12,47785,47811,12,47813,47839,12,47841,47867,12,47869,47895,12,47897,47923,12,47925,47951,12,47953,47979,12,47981,48007,12,48009,48035,12,48037,48063,12,48065,48091,12,48093,48119,12,48121,48147,12,48149,48175,12,48177,48203,12,48205,48231,12,48233,48259,12,48261,48287,12,48289,48315,12,48317,48343,12,48345,48371,12,48373,48399,12,48401,48427,12,48429,48455,12,48457,48483,12,48485,48511,12,48513,48539,12,48541,48567,12,48569,48595,12,48597,48623,12,48625,48651,12,48653,48679,12,48681,48707,12,48709,48735,12,48737,48763,12,48765,48791,12,48793,48819,12,48821,48847,12,48849,48875,12,48877,48903,12,48905,48931,12,48933,48959,12,48961,48987,12,48989,49015,12,49017,49043,12,49045,49071,12,49073,49099,12,49101,49127,12,49129,49155,12,49157,49183,12,49185,49211,12,49213,49239,12,49241,49267,12,49269,49295,12,49297,49323,12,49325,49351,12,49353,49379,12,49381,49407,12,49409,49435,12,49437,49463,12,49465,49491,12,49493,49519,12,49521,49547,12,49549,49575,12,49577,49603,12,49605,49631,12,49633,49659,12,49661,49687,12,49689,49715,12,49717,49743,12,49745,49771,12,49773,49799,12,49801,49827,12,49829,49855,12,49857,49883,12,49885,49911,12,49913,49939,12,49941,49967,12,49969,49995,12,49997,50023,12,50025,50051,12,50053,50079,12,50081,50107,12,50109,50135,12,50137,50163,12,50165,50191,12,50193,50219,12,50221,50247,12,50249,50275,12,50277,50303,12,50305,50331,12,50333,50359,12,50361,50387,12,50389,50415,12,50417,50443,12,50445,50471,12,50473,50499,12,50501,50527,12,50529,50555,12,50557,50583,12,50585,50611,12,50613,50639,12,50641,50667,12,50669,50695,12,50697,50723,12,50725,50751,12,50753,50779,12,50781,50807,12,50809,50835,12,50837,50863,12,50865,50891,12,50893,50919,12,50921,50947,12,50949,50975,12,50977,51003,12,51005,51031,12,51033,51059,12,51061,51087,12,51089,51115,12,51117,51143,12,51145,51171,12,51173,51199,12,51201,51227,12,51229,51255,12,51257,51283,12,51285,51311,12,51313,51339,12,51341,51367,12,51369,51395,12,51397,51423,12,51425,51451,12,51453,51479,12,51481,51507,12,51509,51535,12,51537,51563,12,51565,51591,12,51593,51619,12,51621,51647,12,51649,51675,12,51677,51703,12,51705,51731,12,51733,51759,12,51761,51787,12,51789,51815,12,51817,51843,12,51845,51871,12,51873,51899,12,51901,51927,12,51929,51955,12,51957,51983,12,51985,52011,12,52013,52039,12,52041,52067,12,52069,52095,12,52097,52123,12,52125,52151,12,52153,52179,12,52181,52207,12,52209,52235,12,52237,52263,12,52265,52291,12,52293,52319,12,52321,52347,12,52349,52375,12,52377,52403,12,52405,52431,12,52433,52459,12,52461,52487,12,52489,52515,12,52517,52543,12,52545,52571,12,52573,52599,12,52601,52627,12,52629,52655,12,52657,52683,12,52685,52711,12,52713,52739,12,52741,52767,12,52769,52795,12,52797,52823,12,52825,52851,12,52853,52879,12,52881,52907,12,52909,52935,12,52937,52963,12,52965,52991,12,52993,53019,12,53021,53047,12,53049,53075,12,53077,53103,12,53105,53131,12,53133,53159,12,53161,53187,12,53189,53215,12,53217,53243,12,53245,53271,12,53273,53299,12,53301,53327,12,53329,53355,12,53357,53383,12,53385,53411,12,53413,53439,12,53441,53467,12,53469,53495,12,53497,53523,12,53525,53551,12,53553,53579,12,53581,53607,12,53609,53635,12,53637,53663,12,53665,53691,12,53693,53719,12,53721,53747,12,53749,53775,12,53777,53803,12,53805,53831,12,53833,53859,12,53861,53887,12,53889,53915,12,53917,53943,12,53945,53971,12,53973,53999,12,54001,54027,12,54029,54055,12,54057,54083,12,54085,54111,12,54113,54139,12,54141,54167,12,54169,54195,12,54197,54223,12,54225,54251,12,54253,54279,12,54281,54307,12,54309,54335,12,54337,54363,12,54365,54391,12,54393,54419,12,54421,54447,12,54449,54475,12,54477,54503,12,54505,54531,12,54533,54559,12,54561,54587,12,54589,54615,12,54617,54643,12,54645,54671,12,54673,54699,12,54701,54727,12,54729,54755,12,54757,54783,12,54785,54811,12,54813,54839,12,54841,54867,12,54869,54895,12,54897,54923,12,54925,54951,12,54953,54979,12,54981,55007,12,55009,55035,12,55037,55063,12,55065,55091,12,55093,55119,12,55121,55147,12,55149,55175,12,55177,55203,12,55243,55291,10,65024,65039,5,65279,65279,4,65520,65528,4,66045,66045,5,66422,66426,5,68101,68102,5,68152,68154,5,68325,68326,5,69291,69292,5,69632,69632,7,69634,69634,7,69759,69761,5]');\r\n}\r\n\r\n//#endregion\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as strings from 'vs/base/common/strings';\r\n\r\ndeclare const Buffer: any;\r\n\r\nconst hasBuffer = (typeof Buffer !== 'undefined');\r\nconst hasTextDecoder = (typeof TextDecoder !== 'undefined');\r\nlet textDecoder: TextDecoder | null;\r\n\r\nexport class VSBuffer {\r\n\r\n\tstatic wrap(actual: Uint8Array): VSBuffer {\r\n\t\tif (hasBuffer && !(Buffer.isBuffer(actual))) {\r\n\t\t\t// https://nodejs.org/dist/latest-v10.x/docs/api/buffer.html#buffer_class_method_buffer_from_arraybuffer_byteoffset_length\r\n\t\t\t// Create a zero-copy Buffer wrapper around the ArrayBuffer pointed to by the Uint8Array\r\n\t\t\tactual = Buffer.from(actual.buffer, actual.byteOffset, actual.byteLength);\r\n\t\t}\r\n\t\treturn new VSBuffer(actual);\r\n\t}\r\n\r\n\treadonly buffer: Uint8Array;\r\n\treadonly byteLength: number;\r\n\r\n\tprivate constructor(buffer: Uint8Array) {\r\n\t\tthis.buffer = buffer;\r\n\t\tthis.byteLength = this.buffer.byteLength;\r\n\t}\r\n\r\n\ttoString(): string {\r\n\t\tif (hasBuffer) {\r\n\t\t\treturn this.buffer.toString();\r\n\t\t} else if (hasTextDecoder) {\r\n\t\t\tif (!textDecoder) {\r\n\t\t\t\ttextDecoder = new TextDecoder();\r\n\t\t\t}\r\n\t\t\treturn textDecoder.decode(this.buffer);\r\n\t\t} else {\r\n\t\t\treturn strings.decodeUTF8(this.buffer);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport function readUInt16LE(source: Uint8Array, offset: number): number {\r\n\treturn (\r\n\t\t((source[offset + 0] << 0) >>> 0) |\r\n\t\t((source[offset + 1] << 8) >>> 0)\r\n\t);\r\n}\r\n\r\nexport function writeUInt16LE(destination: Uint8Array, value: number, offset: number): void {\r\n\tdestination[offset + 0] = (value & 0b11111111);\r\n\tvalue = value >>> 8;\r\n\tdestination[offset + 1] = (value & 0b11111111);\r\n}\r\n\r\nexport function readUInt32BE(source: Uint8Array, offset: number): number {\r\n\treturn (\r\n\t\tsource[offset] * 2 ** 24\r\n\t\t+ source[offset + 1] * 2 ** 16\r\n\t\t+ source[offset + 2] * 2 ** 8\r\n\t\t+ source[offset + 3]\r\n\t);\r\n}\r\n\r\nexport function writeUInt32BE(destination: Uint8Array, value: number, offset: number): void {\r\n\tdestination[offset + 3] = value;\r\n\tvalue = value >>> 8;\r\n\tdestination[offset + 2] = value;\r\n\tvalue = value >>> 8;\r\n\tdestination[offset + 1] = value;\r\n\tvalue = value >>> 8;\r\n\tdestination[offset] = value;\r\n}\r\n\r\nexport function readUInt8(source: Uint8Array, offset: number): number {\r\n\treturn source[offset];\r\n}\r\n\r\nexport function writeUInt8(destination: Uint8Array, value: number, offset: number): void {\r\n\tdestination[offset] = value;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { isWindows } from 'vs/base/common/platform';\r\nimport { startsWithIgnoreCase } from 'vs/base/common/strings';\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport { sep, posix, normalize } from 'vs/base/common/path';\r\n\r\n/**\r\n * Takes a Windows OS path and changes backward slashes to forward slashes.\r\n * This should only be done for OS paths from Windows (or user provided paths potentially from Windows).\r\n * Using it on a Linux or MaxOS path might change it.\r\n */\r\nexport function toSlashes(osPath: string) {\r\n\treturn osPath.replace(/[\\\\/]/g, posix.sep);\r\n}\r\n\r\nexport function isEqualOrParent(base: string, parentCandidate: string, ignoreCase?: boolean, separator = sep): boolean {\r\n\tif (base === parentCandidate) {\r\n\t\treturn true;\r\n\t}\r\n\r\n\tif (!base || !parentCandidate) {\r\n\t\treturn false;\r\n\t}\r\n\r\n\tif (parentCandidate.length > base.length) {\r\n\t\treturn false;\r\n\t}\r\n\r\n\tif (ignoreCase) {\r\n\t\tconst beginsWith = startsWithIgnoreCase(base, parentCandidate);\r\n\t\tif (!beginsWith) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tif (parentCandidate.length === base.length) {\r\n\t\t\treturn true; // same path, different casing\r\n\t\t}\r\n\r\n\t\tlet sepOffset = parentCandidate.length;\r\n\t\tif (parentCandidate.charAt(parentCandidate.length - 1) === separator) {\r\n\t\t\tsepOffset--; // adjust the expected sep offset in case our candidate already ends in separator character\r\n\t\t}\r\n\r\n\t\treturn base.charAt(sepOffset) === separator;\r\n\t}\r\n\r\n\tif (parentCandidate.charAt(parentCandidate.length - 1) !== separator) {\r\n\t\tparentCandidate += separator;\r\n\t}\r\n\r\n\treturn base.indexOf(parentCandidate) === 0;\r\n}\r\n\r\nexport function isWindowsDriveLetter(char0: number): boolean {\r\n\treturn char0 >= CharCode.A && char0 <= CharCode.Z || char0 >= CharCode.a && char0 <= CharCode.z;\r\n}\r\n\r\nexport function isRootOrDriveLetter(path: string): boolean {\r\n\tconst pathNormalized = normalize(path);\r\n\r\n\tif (isWindows) {\r\n\t\tif (path.length > 3) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\treturn hasDriveLetter(pathNormalized) &&\r\n\t\t\t(path.length === 2 || pathNormalized.charCodeAt(2) === CharCode.Backslash);\r\n\t}\r\n\r\n\treturn pathNormalized === posix.sep;\r\n}\r\n\r\nexport function hasDriveLetter(path: string): boolean {\r\n\tif (isWindows) {\r\n\t\treturn isWindowsDriveLetter(path.charCodeAt(0)) && path.charCodeAt(1) === CharCode.Colon;\r\n\t}\r\n\r\n\treturn false;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as strings from 'vs/base/common/strings';\r\n\r\n/**\r\n * Return a hash value for an object.\r\n */\r\nexport function hash(obj: any): number {\r\n\treturn doHash(obj, 0);\r\n}\r\n\r\nexport function doHash(obj: any, hashVal: number): number {\r\n\tswitch (typeof obj) {\r\n\t\tcase 'object':\r\n\t\t\tif (obj === null) {\r\n\t\t\t\treturn numberHash(349, hashVal);\r\n\t\t\t} else if (Array.isArray(obj)) {\r\n\t\t\t\treturn arrayHash(obj, hashVal);\r\n\t\t\t}\r\n\t\t\treturn objectHash(obj, hashVal);\r\n\t\tcase 'string':\r\n\t\t\treturn stringHash(obj, hashVal);\r\n\t\tcase 'boolean':\r\n\t\t\treturn booleanHash(obj, hashVal);\r\n\t\tcase 'number':\r\n\t\t\treturn numberHash(obj, hashVal);\r\n\t\tcase 'undefined':\r\n\t\t\treturn numberHash(937, hashVal);\r\n\t\tdefault:\r\n\t\t\treturn numberHash(617, hashVal);\r\n\t}\r\n}\r\n\r\nfunction numberHash(val: number, initialHashVal: number): number {\r\n\treturn (((initialHashVal << 5) - initialHashVal) + val) | 0; // hashVal * 31 + ch, keep as int32\r\n}\r\n\r\nfunction booleanHash(b: boolean, initialHashVal: number): number {\r\n\treturn numberHash(b ? 433 : 863, initialHashVal);\r\n}\r\n\r\nexport function stringHash(s: string, hashVal: number) {\r\n\thashVal = numberHash(149417, hashVal);\r\n\tfor (let i = 0, length = s.length; i < length; i++) {\r\n\t\thashVal = numberHash(s.charCodeAt(i), hashVal);\r\n\t}\r\n\treturn hashVal;\r\n}\r\n\r\nfunction arrayHash(arr: any[], initialHashVal: number): number {\r\n\tinitialHashVal = numberHash(104579, initialHashVal);\r\n\treturn arr.reduce((hashVal, item) => doHash(item, hashVal), initialHashVal);\r\n}\r\n\r\nfunction objectHash(obj: any, initialHashVal: number): number {\r\n\tinitialHashVal = numberHash(181387, initialHashVal);\r\n\treturn Object.keys(obj).sort().reduce((hashVal, key) => {\r\n\t\thashVal = stringHash(key, hashVal);\r\n\t\treturn doHash(obj[key], hashVal);\r\n\t}, initialHashVal);\r\n}\r\n\r\nconst enum SHA1Constant {\r\n\tBLOCK_SIZE = 64, // 512 / 8\r\n\tUNICODE_REPLACEMENT = 0xFFFD,\r\n}\r\n\r\nfunction leftRotate(value: number, bits: number, totalBits: number = 32): number {\r\n\t// delta + bits = totalBits\r\n\tconst delta = totalBits - bits;\r\n\r\n\t// All ones, expect `delta` zeros aligned to the right\r\n\tconst mask = ~((1 << delta) - 1);\r\n\r\n\t// Join (value left-shifted `bits` bits) with (masked value right-shifted `delta` bits)\r\n\treturn ((value << bits) | ((mask & value) >>> delta)) >>> 0;\r\n}\r\n\r\nfunction fill(dest: Uint8Array, index: number = 0, count: number = dest.byteLength, value: number = 0): void {\r\n\tfor (let i = 0; i < count; i++) {\r\n\t\tdest[index + i] = value;\r\n\t}\r\n}\r\n\r\nfunction leftPad(value: string, length: number, char: string = '0'): string {\r\n\twhile (value.length < length) {\r\n\t\tvalue = char + value;\r\n\t}\r\n\treturn value;\r\n}\r\n\r\nexport function toHexString(buffer: ArrayBuffer): string;\r\nexport function toHexString(value: number, bitsize?: number): string;\r\nexport function toHexString(bufferOrValue: ArrayBuffer | number, bitsize: number = 32): string {\r\n\tif (bufferOrValue instanceof ArrayBuffer) {\r\n\t\treturn Array.from(new Uint8Array(bufferOrValue)).map(b => b.toString(16).padStart(2, '0')).join('');\r\n\t}\r\n\r\n\treturn leftPad((bufferOrValue >>> 0).toString(16), bitsize / 4);\r\n}\r\n\r\n/**\r\n * A SHA1 implementation that works with strings and does not allocate.\r\n */\r\nexport class StringSHA1 {\r\n\tprivate static _bigBlock32 = new DataView(new ArrayBuffer(320)); // 80 * 4 = 320\r\n\r\n\tprivate _h0 = 0x67452301;\r\n\tprivate _h1 = 0xEFCDAB89;\r\n\tprivate _h2 = 0x98BADCFE;\r\n\tprivate _h3 = 0x10325476;\r\n\tprivate _h4 = 0xC3D2E1F0;\r\n\r\n\tprivate readonly _buff: Uint8Array;\r\n\tprivate readonly _buffDV: DataView;\r\n\tprivate _buffLen: number;\r\n\tprivate _totalLen: number;\r\n\tprivate _leftoverHighSurrogate: number;\r\n\tprivate _finished: boolean;\r\n\r\n\tconstructor() {\r\n\t\tthis._buff = new Uint8Array(SHA1Constant.BLOCK_SIZE + 3 /* to fit any utf-8 */);\r\n\t\tthis._buffDV = new DataView(this._buff.buffer);\r\n\t\tthis._buffLen = 0;\r\n\t\tthis._totalLen = 0;\r\n\t\tthis._leftoverHighSurrogate = 0;\r\n\t\tthis._finished = false;\r\n\t}\r\n\r\n\tpublic update(str: string): void {\r\n\t\tconst strLen = str.length;\r\n\t\tif (strLen === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst buff = this._buff;\r\n\t\tlet buffLen = this._buffLen;\r\n\t\tlet leftoverHighSurrogate = this._leftoverHighSurrogate;\r\n\t\tlet charCode: number;\r\n\t\tlet offset: number;\r\n\r\n\t\tif (leftoverHighSurrogate !== 0) {\r\n\t\t\tcharCode = leftoverHighSurrogate;\r\n\t\t\toffset = -1;\r\n\t\t\tleftoverHighSurrogate = 0;\r\n\t\t} else {\r\n\t\t\tcharCode = str.charCodeAt(0);\r\n\t\t\toffset = 0;\r\n\t\t}\r\n\r\n\t\twhile (true) {\r\n\t\t\tlet codePoint = charCode;\r\n\t\t\tif (strings.isHighSurrogate(charCode)) {\r\n\t\t\t\tif (offset + 1 < strLen) {\r\n\t\t\t\t\tconst nextCharCode = str.charCodeAt(offset + 1);\r\n\t\t\t\t\tif (strings.isLowSurrogate(nextCharCode)) {\r\n\t\t\t\t\t\toffset++;\r\n\t\t\t\t\t\tcodePoint = strings.computeCodePoint(charCode, nextCharCode);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t// illegal => unicode replacement character\r\n\t\t\t\t\t\tcodePoint = SHA1Constant.UNICODE_REPLACEMENT;\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// last character is a surrogate pair\r\n\t\t\t\t\tleftoverHighSurrogate = charCode;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t} else if (strings.isLowSurrogate(charCode)) {\r\n\t\t\t\t// illegal => unicode replacement character\r\n\t\t\t\tcodePoint = SHA1Constant.UNICODE_REPLACEMENT;\r\n\t\t\t}\r\n\r\n\t\t\tbuffLen = this._push(buff, buffLen, codePoint);\r\n\t\t\toffset++;\r\n\t\t\tif (offset < strLen) {\r\n\t\t\t\tcharCode = str.charCodeAt(offset);\r\n\t\t\t} else {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._buffLen = buffLen;\r\n\t\tthis._leftoverHighSurrogate = leftoverHighSurrogate;\r\n\t}\r\n\r\n\tprivate _push(buff: Uint8Array, buffLen: number, codePoint: number): number {\r\n\t\tif (codePoint < 0x0080) {\r\n\t\t\tbuff[buffLen++] = codePoint;\r\n\t\t} else if (codePoint < 0x0800) {\r\n\t\t\tbuff[buffLen++] = 0b11000000 | ((codePoint & 0b00000000000000000000011111000000) >>> 6);\r\n\t\t\tbuff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0);\r\n\t\t} else if (codePoint < 0x10000) {\r\n\t\t\tbuff[buffLen++] = 0b11100000 | ((codePoint & 0b00000000000000001111000000000000) >>> 12);\r\n\t\t\tbuff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000000000111111000000) >>> 6);\r\n\t\t\tbuff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0);\r\n\t\t} else {\r\n\t\t\tbuff[buffLen++] = 0b11110000 | ((codePoint & 0b00000000000111000000000000000000) >>> 18);\r\n\t\t\tbuff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000111111000000000000) >>> 12);\r\n\t\t\tbuff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000000000111111000000) >>> 6);\r\n\t\t\tbuff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0);\r\n\t\t}\r\n\r\n\t\tif (buffLen >= SHA1Constant.BLOCK_SIZE) {\r\n\t\t\tthis._step();\r\n\t\t\tbuffLen -= SHA1Constant.BLOCK_SIZE;\r\n\t\t\tthis._totalLen += SHA1Constant.BLOCK_SIZE;\r\n\t\t\t// take last 3 in case of UTF8 overflow\r\n\t\t\tbuff[0] = buff[SHA1Constant.BLOCK_SIZE + 0];\r\n\t\t\tbuff[1] = buff[SHA1Constant.BLOCK_SIZE + 1];\r\n\t\t\tbuff[2] = buff[SHA1Constant.BLOCK_SIZE + 2];\r\n\t\t}\r\n\r\n\t\treturn buffLen;\r\n\t}\r\n\r\n\tpublic digest(): string {\r\n\t\tif (!this._finished) {\r\n\t\t\tthis._finished = true;\r\n\t\t\tif (this._leftoverHighSurrogate) {\r\n\t\t\t\t// illegal => unicode replacement character\r\n\t\t\t\tthis._leftoverHighSurrogate = 0;\r\n\t\t\t\tthis._buffLen = this._push(this._buff, this._buffLen, SHA1Constant.UNICODE_REPLACEMENT);\r\n\t\t\t}\r\n\t\t\tthis._totalLen += this._buffLen;\r\n\t\t\tthis._wrapUp();\r\n\t\t}\r\n\r\n\t\treturn toHexString(this._h0) + toHexString(this._h1) + toHexString(this._h2) + toHexString(this._h3) + toHexString(this._h4);\r\n\t}\r\n\r\n\tprivate _wrapUp(): void {\r\n\t\tthis._buff[this._buffLen++] = 0x80;\r\n\t\tfill(this._buff, this._buffLen);\r\n\r\n\t\tif (this._buffLen > 56) {\r\n\t\t\tthis._step();\r\n\t\t\tfill(this._buff);\r\n\t\t}\r\n\r\n\t\t// this will fit because the mantissa can cover up to 52 bits\r\n\t\tconst ml = 8 * this._totalLen;\r\n\r\n\t\tthis._buffDV.setUint32(56, Math.floor(ml / 4294967296), false);\r\n\t\tthis._buffDV.setUint32(60, ml % 4294967296, false);\r\n\r\n\t\tthis._step();\r\n\t}\r\n\r\n\tprivate _step(): void {\r\n\t\tconst bigBlock32 = StringSHA1._bigBlock32;\r\n\t\tconst data = this._buffDV;\r\n\r\n\t\tfor (let j = 0; j < 64 /* 16*4 */; j += 4) {\r\n\t\t\tbigBlock32.setUint32(j, data.getUint32(j, false), false);\r\n\t\t}\r\n\r\n\t\tfor (let j = 64; j < 320 /* 80*4 */; j += 4) {\r\n\t\t\tbigBlock32.setUint32(j, leftRotate((bigBlock32.getUint32(j - 12, false) ^ bigBlock32.getUint32(j - 32, false) ^ bigBlock32.getUint32(j - 56, false) ^ bigBlock32.getUint32(j - 64, false)), 1), false);\r\n\t\t}\r\n\r\n\t\tlet a = this._h0;\r\n\t\tlet b = this._h1;\r\n\t\tlet c = this._h2;\r\n\t\tlet d = this._h3;\r\n\t\tlet e = this._h4;\r\n\r\n\t\tlet f: number, k: number;\r\n\t\tlet temp: number;\r\n\r\n\t\tfor (let j = 0; j < 80; j++) {\r\n\t\t\tif (j < 20) {\r\n\t\t\t\tf = (b & c) | ((~b) & d);\r\n\t\t\t\tk = 0x5A827999;\r\n\t\t\t} else if (j < 40) {\r\n\t\t\t\tf = b ^ c ^ d;\r\n\t\t\t\tk = 0x6ED9EBA1;\r\n\t\t\t} else if (j < 60) {\r\n\t\t\t\tf = (b & c) | (b & d) | (c & d);\r\n\t\t\t\tk = 0x8F1BBCDC;\r\n\t\t\t} else {\r\n\t\t\t\tf = b ^ c ^ d;\r\n\t\t\t\tk = 0xCA62C1D6;\r\n\t\t\t}\r\n\r\n\t\t\ttemp = (leftRotate(a, 5) + f + e + k + bigBlock32.getUint32(j * 4, false)) & 0xffffffff;\r\n\t\t\te = d;\r\n\t\t\td = c;\r\n\t\t\tc = leftRotate(b, 30);\r\n\t\t\tb = a;\r\n\t\t\ta = temp;\r\n\t\t}\r\n\r\n\t\tthis._h0 = (this._h0 + a) & 0xffffffff;\r\n\t\tthis._h1 = (this._h1 + b) & 0xffffffff;\r\n\t\tthis._h2 = (this._h2 + c) & 0xffffffff;\r\n\t\tthis._h3 = (this._h3 + d) & 0xffffffff;\r\n\t\tthis._h4 = (this._h4 + e) & 0xffffffff;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { DiffChange } from 'vs/base/common/diff/diffChange';\r\nimport { stringHash } from 'vs/base/common/hash';\r\nimport { Constants } from 'vs/base/common/uint';\r\n\r\nexport class StringDiffSequence implements ISequence {\r\n\r\n\tconstructor(private source: string) { }\r\n\r\n\tgetElements(): Int32Array | number[] | string[] {\r\n\t\tconst source = this.source;\r\n\t\tconst characters = new Int32Array(source.length);\r\n\t\tfor (let i = 0, len = source.length; i < len; i++) {\r\n\t\t\tcharacters[i] = source.charCodeAt(i);\r\n\t\t}\r\n\t\treturn characters;\r\n\t}\r\n}\r\n\r\nexport function stringDiff(original: string, modified: string, pretty: boolean): IDiffChange[] {\r\n\treturn new LcsDiff(new StringDiffSequence(original), new StringDiffSequence(modified)).ComputeDiff(pretty).changes;\r\n}\r\n\r\nexport interface ISequence {\r\n\tgetElements(): Int32Array | number[] | string[];\r\n}\r\n\r\nexport interface IDiffChange {\r\n\t/**\r\n\t * The position of the first element in the original sequence which\r\n\t * this change affects.\r\n\t */\r\n\toriginalStart: number;\r\n\r\n\t/**\r\n\t * The number of elements from the original sequence which were\r\n\t * affected.\r\n\t */\r\n\toriginalLength: number;\r\n\r\n\t/**\r\n\t * The position of the first element in the modified sequence which\r\n\t * this change affects.\r\n\t */\r\n\tmodifiedStart: number;\r\n\r\n\t/**\r\n\t * The number of elements from the modified sequence which were\r\n\t * affected (added).\r\n\t */\r\n\tmodifiedLength: number;\r\n}\r\n\r\nexport interface IContinueProcessingPredicate {\r\n\t(furthestOriginalIndex: number, matchLengthOfLongest: number): boolean;\r\n}\r\n\r\nexport interface IDiffResult {\r\n\tquitEarly: boolean;\r\n\tchanges: IDiffChange[];\r\n}\r\n\r\n//\r\n// The code below has been ported from a C# implementation in VS\r\n//\r\n\r\nexport class Debug {\r\n\r\n\tpublic static Assert(condition: boolean, message: string): void {\r\n\t\tif (!condition) {\r\n\t\t\tthrow new Error(message);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class MyArray {\r\n\t/**\r\n\t * Copies a range of elements from an Array starting at the specified source index and pastes\r\n\t * them to another Array starting at the specified destination index. The length and the indexes\r\n\t * are specified as 64-bit integers.\r\n\t * sourceArray:\r\n\t *\t\tThe Array that contains the data to copy.\r\n\t * sourceIndex:\r\n\t *\t\tA 64-bit integer that represents the index in the sourceArray at which copying begins.\r\n\t * destinationArray:\r\n\t *\t\tThe Array that receives the data.\r\n\t * destinationIndex:\r\n\t *\t\tA 64-bit integer that represents the index in the destinationArray at which storing begins.\r\n\t * length:\r\n\t *\t\tA 64-bit integer that represents the number of elements to copy.\r\n\t */\r\n\tpublic static Copy(sourceArray: any[], sourceIndex: number, destinationArray: any[], destinationIndex: number, length: number) {\r\n\t\tfor (let i = 0; i < length; i++) {\r\n\t\t\tdestinationArray[destinationIndex + i] = sourceArray[sourceIndex + i];\r\n\t\t}\r\n\t}\r\n\tpublic static Copy2(sourceArray: Int32Array, sourceIndex: number, destinationArray: Int32Array, destinationIndex: number, length: number) {\r\n\t\tfor (let i = 0; i < length; i++) {\r\n\t\t\tdestinationArray[destinationIndex + i] = sourceArray[sourceIndex + i];\r\n\t\t}\r\n\t}\r\n}\r\n\r\n//*****************************************************************************\r\n// LcsDiff.cs\r\n//\r\n// An implementation of the difference algorithm described in\r\n// \"An O(ND) Difference Algorithm and its variations\" by Eugene W. Myers\r\n//\r\n// Copyright (C) 2008 Microsoft Corporation @minifier_do_not_preserve\r\n//*****************************************************************************\r\n\r\n// Our total memory usage for storing history is (worst-case):\r\n// 2 * [(MaxDifferencesHistory + 1) * (MaxDifferencesHistory + 1) - 1] * sizeof(int)\r\n// 2 * [1448*1448 - 1] * 4 = 16773624 = 16MB\r\nconst enum LocalConstants {\r\n\tMaxDifferencesHistory = 1447\r\n}\r\n\r\n/**\r\n * A utility class which helps to create the set of DiffChanges from\r\n * a difference operation. This class accepts original DiffElements and\r\n * modified DiffElements that are involved in a particular change. The\r\n * MarktNextChange() method can be called to mark the separation between\r\n * distinct changes. At the end, the Changes property can be called to retrieve\r\n * the constructed changes.\r\n */\r\nclass DiffChangeHelper {\r\n\r\n\tprivate m_changes: DiffChange[];\r\n\tprivate m_originalStart: number;\r\n\tprivate m_modifiedStart: number;\r\n\tprivate m_originalCount: number;\r\n\tprivate m_modifiedCount: number;\r\n\r\n\t/**\r\n\t * Constructs a new DiffChangeHelper for the given DiffSequences.\r\n\t */\r\n\tconstructor() {\r\n\t\tthis.m_changes = [];\r\n\t\tthis.m_originalStart = Constants.MAX_SAFE_SMALL_INTEGER;\r\n\t\tthis.m_modifiedStart = Constants.MAX_SAFE_SMALL_INTEGER;\r\n\t\tthis.m_originalCount = 0;\r\n\t\tthis.m_modifiedCount = 0;\r\n\t}\r\n\r\n\t/**\r\n\t * Marks the beginning of the next change in the set of differences.\r\n\t */\r\n\tpublic MarkNextChange(): void {\r\n\t\t// Only add to the list if there is something to add\r\n\t\tif (this.m_originalCount > 0 || this.m_modifiedCount > 0) {\r\n\t\t\t// Add the new change to our list\r\n\t\t\tthis.m_changes.push(new DiffChange(this.m_originalStart, this.m_originalCount,\r\n\t\t\t\tthis.m_modifiedStart, this.m_modifiedCount));\r\n\t\t}\r\n\r\n\t\t// Reset for the next change\r\n\t\tthis.m_originalCount = 0;\r\n\t\tthis.m_modifiedCount = 0;\r\n\t\tthis.m_originalStart = Constants.MAX_SAFE_SMALL_INTEGER;\r\n\t\tthis.m_modifiedStart = Constants.MAX_SAFE_SMALL_INTEGER;\r\n\t}\r\n\r\n\t/**\r\n\t * Adds the original element at the given position to the elements\r\n\t * affected by the current change. The modified index gives context\r\n\t * to the change position with respect to the original sequence.\r\n\t * @param originalIndex The index of the original element to add.\r\n\t * @param modifiedIndex The index of the modified element that provides corresponding position in the modified sequence.\r\n\t */\r\n\tpublic AddOriginalElement(originalIndex: number, modifiedIndex: number) {\r\n\t\t// The 'true' start index is the smallest of the ones we've seen\r\n\t\tthis.m_originalStart = Math.min(this.m_originalStart, originalIndex);\r\n\t\tthis.m_modifiedStart = Math.min(this.m_modifiedStart, modifiedIndex);\r\n\r\n\t\tthis.m_originalCount++;\r\n\t}\r\n\r\n\t/**\r\n\t * Adds the modified element at the given position to the elements\r\n\t * affected by the current change. The original index gives context\r\n\t * to the change position with respect to the modified sequence.\r\n\t * @param originalIndex The index of the original element that provides corresponding position in the original sequence.\r\n\t * @param modifiedIndex The index of the modified element to add.\r\n\t */\r\n\tpublic AddModifiedElement(originalIndex: number, modifiedIndex: number): void {\r\n\t\t// The 'true' start index is the smallest of the ones we've seen\r\n\t\tthis.m_originalStart = Math.min(this.m_originalStart, originalIndex);\r\n\t\tthis.m_modifiedStart = Math.min(this.m_modifiedStart, modifiedIndex);\r\n\r\n\t\tthis.m_modifiedCount++;\r\n\t}\r\n\r\n\t/**\r\n\t * Retrieves all of the changes marked by the class.\r\n\t */\r\n\tpublic getChanges(): DiffChange[] {\r\n\t\tif (this.m_originalCount > 0 || this.m_modifiedCount > 0) {\r\n\t\t\t// Finish up on whatever is left\r\n\t\t\tthis.MarkNextChange();\r\n\t\t}\r\n\r\n\t\treturn this.m_changes;\r\n\t}\r\n\r\n\t/**\r\n\t * Retrieves all of the changes marked by the class in the reverse order\r\n\t */\r\n\tpublic getReverseChanges(): DiffChange[] {\r\n\t\tif (this.m_originalCount > 0 || this.m_modifiedCount > 0) {\r\n\t\t\t// Finish up on whatever is left\r\n\t\t\tthis.MarkNextChange();\r\n\t\t}\r\n\r\n\t\tthis.m_changes.reverse();\r\n\t\treturn this.m_changes;\r\n\t}\r\n\r\n}\r\n\r\n/**\r\n * An implementation of the difference algorithm described in\r\n * \"An O(ND) Difference Algorithm and its variations\" by Eugene W. Myers\r\n */\r\nexport class LcsDiff {\r\n\r\n\tprivate readonly ContinueProcessingPredicate: IContinueProcessingPredicate | null;\r\n\r\n\tprivate readonly _hasStrings: boolean;\r\n\tprivate readonly _originalStringElements: string[];\r\n\tprivate readonly _originalElementsOrHash: Int32Array;\r\n\tprivate readonly _modifiedStringElements: string[];\r\n\tprivate readonly _modifiedElementsOrHash: Int32Array;\r\n\r\n\tprivate m_forwardHistory: Int32Array[];\r\n\tprivate m_reverseHistory: Int32Array[];\r\n\r\n\t/**\r\n\t * Constructs the DiffFinder\r\n\t */\r\n\tconstructor(originalSequence: ISequence, modifiedSequence: ISequence, continueProcessingPredicate: IContinueProcessingPredicate | null = null) {\r\n\t\tthis.ContinueProcessingPredicate = continueProcessingPredicate;\r\n\r\n\t\tconst [originalStringElements, originalElementsOrHash, originalHasStrings] = LcsDiff._getElements(originalSequence);\r\n\t\tconst [modifiedStringElements, modifiedElementsOrHash, modifiedHasStrings] = LcsDiff._getElements(modifiedSequence);\r\n\r\n\t\tthis._hasStrings = (originalHasStrings && modifiedHasStrings);\r\n\t\tthis._originalStringElements = originalStringElements;\r\n\t\tthis._originalElementsOrHash = originalElementsOrHash;\r\n\t\tthis._modifiedStringElements = modifiedStringElements;\r\n\t\tthis._modifiedElementsOrHash = modifiedElementsOrHash;\r\n\r\n\t\tthis.m_forwardHistory = [];\r\n\t\tthis.m_reverseHistory = [];\r\n\t}\r\n\r\n\tprivate static _isStringArray(arr: Int32Array | number[] | string[]): arr is string[] {\r\n\t\treturn (arr.length > 0 && typeof arr[0] === 'string');\r\n\t}\r\n\r\n\tprivate static _getElements(sequence: ISequence): [string[], Int32Array, boolean] {\r\n\t\tconst elements = sequence.getElements();\r\n\r\n\t\tif (LcsDiff._isStringArray(elements)) {\r\n\t\t\tconst hashes = new Int32Array(elements.length);\r\n\t\t\tfor (let i = 0, len = elements.length; i < len; i++) {\r\n\t\t\t\thashes[i] = stringHash(elements[i], 0);\r\n\t\t\t}\r\n\t\t\treturn [elements, hashes, true];\r\n\t\t}\r\n\r\n\t\tif (elements instanceof Int32Array) {\r\n\t\t\treturn [[], elements, false];\r\n\t\t}\r\n\r\n\t\treturn [[], new Int32Array(elements), false];\r\n\t}\r\n\r\n\tprivate ElementsAreEqual(originalIndex: number, newIndex: number): boolean {\r\n\t\tif (this._originalElementsOrHash[originalIndex] !== this._modifiedElementsOrHash[newIndex]) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn (this._hasStrings ? this._originalStringElements[originalIndex] === this._modifiedStringElements[newIndex] : true);\r\n\t}\r\n\r\n\tprivate OriginalElementsAreEqual(index1: number, index2: number): boolean {\r\n\t\tif (this._originalElementsOrHash[index1] !== this._originalElementsOrHash[index2]) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn (this._hasStrings ? this._originalStringElements[index1] === this._originalStringElements[index2] : true);\r\n\t}\r\n\r\n\tprivate ModifiedElementsAreEqual(index1: number, index2: number): boolean {\r\n\t\tif (this._modifiedElementsOrHash[index1] !== this._modifiedElementsOrHash[index2]) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn (this._hasStrings ? this._modifiedStringElements[index1] === this._modifiedStringElements[index2] : true);\r\n\t}\r\n\r\n\tpublic ComputeDiff(pretty: boolean): IDiffResult {\r\n\t\treturn this._ComputeDiff(0, this._originalElementsOrHash.length - 1, 0, this._modifiedElementsOrHash.length - 1, pretty);\r\n\t}\r\n\r\n\t/**\r\n\t * Computes the differences between the original and modified input\r\n\t * sequences on the bounded range.\r\n\t * @returns An array of the differences between the two input sequences.\r\n\t */\r\n\tprivate _ComputeDiff(originalStart: number, originalEnd: number, modifiedStart: number, modifiedEnd: number, pretty: boolean): IDiffResult {\r\n\t\tconst quitEarlyArr = [false];\r\n\t\tlet changes = this.ComputeDiffRecursive(originalStart, originalEnd, modifiedStart, modifiedEnd, quitEarlyArr);\r\n\r\n\t\tif (pretty) {\r\n\t\t\t// We have to clean up the computed diff to be more intuitive\r\n\t\t\t// but it turns out this cannot be done correctly until the entire set\r\n\t\t\t// of diffs have been computed\r\n\t\t\tchanges = this.PrettifyChanges(changes);\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tquitEarly: quitEarlyArr[0],\r\n\t\t\tchanges: changes\r\n\t\t};\r\n\t}\r\n\r\n\t/**\r\n\t * Private helper method which computes the differences on the bounded range\r\n\t * recursively.\r\n\t * @returns An array of the differences between the two input sequences.\r\n\t */\r\n\tprivate ComputeDiffRecursive(originalStart: number, originalEnd: number, modifiedStart: number, modifiedEnd: number, quitEarlyArr: boolean[]): DiffChange[] {\r\n\t\tquitEarlyArr[0] = false;\r\n\r\n\t\t// Find the start of the differences\r\n\t\twhile (originalStart <= originalEnd && modifiedStart <= modifiedEnd && this.ElementsAreEqual(originalStart, modifiedStart)) {\r\n\t\t\toriginalStart++;\r\n\t\t\tmodifiedStart++;\r\n\t\t}\r\n\r\n\t\t// Find the end of the differences\r\n\t\twhile (originalEnd >= originalStart && modifiedEnd >= modifiedStart && this.ElementsAreEqual(originalEnd, modifiedEnd)) {\r\n\t\t\toriginalEnd--;\r\n\t\t\tmodifiedEnd--;\r\n\t\t}\r\n\r\n\t\t// In the special case where we either have all insertions or all deletions or the sequences are identical\r\n\t\tif (originalStart > originalEnd || modifiedStart > modifiedEnd) {\r\n\t\t\tlet changes: DiffChange[];\r\n\r\n\t\t\tif (modifiedStart <= modifiedEnd) {\r\n\t\t\t\tDebug.Assert(originalStart === originalEnd + 1, 'originalStart should only be one more than originalEnd');\r\n\r\n\t\t\t\t// All insertions\r\n\t\t\t\tchanges = [\r\n\t\t\t\t\tnew DiffChange(originalStart, 0, modifiedStart, modifiedEnd - modifiedStart + 1)\r\n\t\t\t\t];\r\n\t\t\t} else if (originalStart <= originalEnd) {\r\n\t\t\t\tDebug.Assert(modifiedStart === modifiedEnd + 1, 'modifiedStart should only be one more than modifiedEnd');\r\n\r\n\t\t\t\t// All deletions\r\n\t\t\t\tchanges = [\r\n\t\t\t\t\tnew DiffChange(originalStart, originalEnd - originalStart + 1, modifiedStart, 0)\r\n\t\t\t\t];\r\n\t\t\t} else {\r\n\t\t\t\tDebug.Assert(originalStart === originalEnd + 1, 'originalStart should only be one more than originalEnd');\r\n\t\t\t\tDebug.Assert(modifiedStart === modifiedEnd + 1, 'modifiedStart should only be one more than modifiedEnd');\r\n\r\n\t\t\t\t// Identical sequences - No differences\r\n\t\t\t\tchanges = [];\r\n\t\t\t}\r\n\r\n\t\t\treturn changes;\r\n\t\t}\r\n\r\n\t\t// This problem can be solved using the Divide-And-Conquer technique.\r\n\t\tconst midOriginalArr = [0];\r\n\t\tconst midModifiedArr = [0];\r\n\t\tconst result = this.ComputeRecursionPoint(originalStart, originalEnd, modifiedStart, modifiedEnd, midOriginalArr, midModifiedArr, quitEarlyArr);\r\n\r\n\t\tconst midOriginal = midOriginalArr[0];\r\n\t\tconst midModified = midModifiedArr[0];\r\n\r\n\t\tif (result !== null) {\r\n\t\t\t// Result is not-null when there was enough memory to compute the changes while\r\n\t\t\t// searching for the recursion point\r\n\t\t\treturn result;\r\n\t\t} else if (!quitEarlyArr[0]) {\r\n\t\t\t// We can break the problem down recursively by finding the changes in the\r\n\t\t\t// First Half: (originalStart, modifiedStart) to (midOriginal, midModified)\r\n\t\t\t// Second Half: (midOriginal + 1, minModified + 1) to (originalEnd, modifiedEnd)\r\n\t\t\t// NOTE: ComputeDiff() is inclusive, therefore the second range starts on the next point\r\n\r\n\t\t\tconst leftChanges = this.ComputeDiffRecursive(originalStart, midOriginal, modifiedStart, midModified, quitEarlyArr);\r\n\t\t\tlet rightChanges: DiffChange[] = [];\r\n\r\n\t\t\tif (!quitEarlyArr[0]) {\r\n\t\t\t\trightChanges = this.ComputeDiffRecursive(midOriginal + 1, originalEnd, midModified + 1, modifiedEnd, quitEarlyArr);\r\n\t\t\t} else {\r\n\t\t\t\t// We did't have time to finish the first half, so we don't have time to compute this half.\r\n\t\t\t\t// Consider the entire rest of the sequence different.\r\n\t\t\t\trightChanges = [\r\n\t\t\t\t\tnew DiffChange(midOriginal + 1, originalEnd - (midOriginal + 1) + 1, midModified + 1, modifiedEnd - (midModified + 1) + 1)\r\n\t\t\t\t];\r\n\t\t\t}\r\n\r\n\t\t\treturn this.ConcatenateChanges(leftChanges, rightChanges);\r\n\t\t}\r\n\r\n\t\t// If we hit here, we quit early, and so can't return anything meaningful\r\n\t\treturn [\r\n\t\t\tnew DiffChange(originalStart, originalEnd - originalStart + 1, modifiedStart, modifiedEnd - modifiedStart + 1)\r\n\t\t];\r\n\t}\r\n\r\n\tprivate WALKTRACE(diagonalForwardBase: number, diagonalForwardStart: number, diagonalForwardEnd: number, diagonalForwardOffset: number,\r\n\t\tdiagonalReverseBase: number, diagonalReverseStart: number, diagonalReverseEnd: number, diagonalReverseOffset: number,\r\n\t\tforwardPoints: Int32Array, reversePoints: Int32Array,\r\n\t\toriginalIndex: number, originalEnd: number, midOriginalArr: number[],\r\n\t\tmodifiedIndex: number, modifiedEnd: number, midModifiedArr: number[],\r\n\t\tdeltaIsEven: boolean, quitEarlyArr: boolean[]\r\n\t): DiffChange[] {\r\n\t\tlet forwardChanges: DiffChange[] | null = null;\r\n\t\tlet reverseChanges: DiffChange[] | null = null;\r\n\r\n\t\t// First, walk backward through the forward diagonals history\r\n\t\tlet changeHelper = new DiffChangeHelper();\r\n\t\tlet diagonalMin = diagonalForwardStart;\r\n\t\tlet diagonalMax = diagonalForwardEnd;\r\n\t\tlet diagonalRelative = (midOriginalArr[0] - midModifiedArr[0]) - diagonalForwardOffset;\r\n\t\tlet lastOriginalIndex = Constants.MIN_SAFE_SMALL_INTEGER;\r\n\t\tlet historyIndex = this.m_forwardHistory.length - 1;\r\n\r\n\t\tdo {\r\n\t\t\t// Get the diagonal index from the relative diagonal number\r\n\t\t\tconst diagonal = diagonalRelative + diagonalForwardBase;\r\n\r\n\t\t\t// Figure out where we came from\r\n\t\t\tif (diagonal === diagonalMin || (diagonal < diagonalMax && forwardPoints[diagonal - 1] < forwardPoints[diagonal + 1])) {\r\n\t\t\t\t// Vertical line (the element is an insert)\r\n\t\t\t\toriginalIndex = forwardPoints[diagonal + 1];\r\n\t\t\t\tmodifiedIndex = originalIndex - diagonalRelative - diagonalForwardOffset;\r\n\t\t\t\tif (originalIndex < lastOriginalIndex) {\r\n\t\t\t\t\tchangeHelper.MarkNextChange();\r\n\t\t\t\t}\r\n\t\t\t\tlastOriginalIndex = originalIndex;\r\n\t\t\t\tchangeHelper.AddModifiedElement(originalIndex + 1, modifiedIndex);\r\n\t\t\t\tdiagonalRelative = (diagonal + 1) - diagonalForwardBase; //Setup for the next iteration\r\n\t\t\t} else {\r\n\t\t\t\t// Horizontal line (the element is a deletion)\r\n\t\t\t\toriginalIndex = forwardPoints[diagonal - 1] + 1;\r\n\t\t\t\tmodifiedIndex = originalIndex - diagonalRelative - diagonalForwardOffset;\r\n\t\t\t\tif (originalIndex < lastOriginalIndex) {\r\n\t\t\t\t\tchangeHelper.MarkNextChange();\r\n\t\t\t\t}\r\n\t\t\t\tlastOriginalIndex = originalIndex - 1;\r\n\t\t\t\tchangeHelper.AddOriginalElement(originalIndex, modifiedIndex + 1);\r\n\t\t\t\tdiagonalRelative = (diagonal - 1) - diagonalForwardBase; //Setup for the next iteration\r\n\t\t\t}\r\n\r\n\t\t\tif (historyIndex >= 0) {\r\n\t\t\t\tforwardPoints = this.m_forwardHistory[historyIndex];\r\n\t\t\t\tdiagonalForwardBase = forwardPoints[0]; //We stored this in the first spot\r\n\t\t\t\tdiagonalMin = 1;\r\n\t\t\t\tdiagonalMax = forwardPoints.length - 1;\r\n\t\t\t}\r\n\t\t} while (--historyIndex >= -1);\r\n\r\n\t\t// Ironically, we get the forward changes as the reverse of the\r\n\t\t// order we added them since we technically added them backwards\r\n\t\tforwardChanges = changeHelper.getReverseChanges();\r\n\r\n\t\tif (quitEarlyArr[0]) {\r\n\t\t\t// TODO: Calculate a partial from the reverse diagonals.\r\n\t\t\t// For now, just assume everything after the midOriginal/midModified point is a diff\r\n\r\n\t\t\tlet originalStartPoint = midOriginalArr[0] + 1;\r\n\t\t\tlet modifiedStartPoint = midModifiedArr[0] + 1;\r\n\r\n\t\t\tif (forwardChanges !== null && forwardChanges.length > 0) {\r\n\t\t\t\tconst lastForwardChange = forwardChanges[forwardChanges.length - 1];\r\n\t\t\t\toriginalStartPoint = Math.max(originalStartPoint, lastForwardChange.getOriginalEnd());\r\n\t\t\t\tmodifiedStartPoint = Math.max(modifiedStartPoint, lastForwardChange.getModifiedEnd());\r\n\t\t\t}\r\n\r\n\t\t\treverseChanges = [\r\n\t\t\t\tnew DiffChange(originalStartPoint, originalEnd - originalStartPoint + 1,\r\n\t\t\t\t\tmodifiedStartPoint, modifiedEnd - modifiedStartPoint + 1)\r\n\t\t\t];\r\n\t\t} else {\r\n\t\t\t// Now walk backward through the reverse diagonals history\r\n\t\t\tchangeHelper = new DiffChangeHelper();\r\n\t\t\tdiagonalMin = diagonalReverseStart;\r\n\t\t\tdiagonalMax = diagonalReverseEnd;\r\n\t\t\tdiagonalRelative = (midOriginalArr[0] - midModifiedArr[0]) - diagonalReverseOffset;\r\n\t\t\tlastOriginalIndex = Constants.MAX_SAFE_SMALL_INTEGER;\r\n\t\t\thistoryIndex = (deltaIsEven) ? this.m_reverseHistory.length - 1 : this.m_reverseHistory.length - 2;\r\n\r\n\t\t\tdo {\r\n\t\t\t\t// Get the diagonal index from the relative diagonal number\r\n\t\t\t\tconst diagonal = diagonalRelative + diagonalReverseBase;\r\n\r\n\t\t\t\t// Figure out where we came from\r\n\t\t\t\tif (diagonal === diagonalMin || (diagonal < diagonalMax && reversePoints[diagonal - 1] >= reversePoints[diagonal + 1])) {\r\n\t\t\t\t\t// Horizontal line (the element is a deletion))\r\n\t\t\t\t\toriginalIndex = reversePoints[diagonal + 1] - 1;\r\n\t\t\t\t\tmodifiedIndex = originalIndex - diagonalRelative - diagonalReverseOffset;\r\n\t\t\t\t\tif (originalIndex > lastOriginalIndex) {\r\n\t\t\t\t\t\tchangeHelper.MarkNextChange();\r\n\t\t\t\t\t}\r\n\t\t\t\t\tlastOriginalIndex = originalIndex + 1;\r\n\t\t\t\t\tchangeHelper.AddOriginalElement(originalIndex + 1, modifiedIndex + 1);\r\n\t\t\t\t\tdiagonalRelative = (diagonal + 1) - diagonalReverseBase; //Setup for the next iteration\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// Vertical line (the element is an insertion)\r\n\t\t\t\t\toriginalIndex = reversePoints[diagonal - 1];\r\n\t\t\t\t\tmodifiedIndex = originalIndex - diagonalRelative - diagonalReverseOffset;\r\n\t\t\t\t\tif (originalIndex > lastOriginalIndex) {\r\n\t\t\t\t\t\tchangeHelper.MarkNextChange();\r\n\t\t\t\t\t}\r\n\t\t\t\t\tlastOriginalIndex = originalIndex;\r\n\t\t\t\t\tchangeHelper.AddModifiedElement(originalIndex + 1, modifiedIndex + 1);\r\n\t\t\t\t\tdiagonalRelative = (diagonal - 1) - diagonalReverseBase; //Setup for the next iteration\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (historyIndex >= 0) {\r\n\t\t\t\t\treversePoints = this.m_reverseHistory[historyIndex];\r\n\t\t\t\t\tdiagonalReverseBase = reversePoints[0]; //We stored this in the first spot\r\n\t\t\t\t\tdiagonalMin = 1;\r\n\t\t\t\t\tdiagonalMax = reversePoints.length - 1;\r\n\t\t\t\t}\r\n\t\t\t} while (--historyIndex >= -1);\r\n\r\n\t\t\t// There are cases where the reverse history will find diffs that\r\n\t\t\t// are correct, but not intuitive, so we need shift them.\r\n\t\t\treverseChanges = changeHelper.getChanges();\r\n\t\t}\r\n\r\n\t\treturn this.ConcatenateChanges(forwardChanges, reverseChanges);\r\n\t}\r\n\r\n\t/**\r\n\t * Given the range to compute the diff on, this method finds the point:\r\n\t * (midOriginal, midModified)\r\n\t * that exists in the middle of the LCS of the two sequences and\r\n\t * is the point at which the LCS problem may be broken down recursively.\r\n\t * This method will try to keep the LCS trace in memory. If the LCS recursion\r\n\t * point is calculated and the full trace is available in memory, then this method\r\n\t * will return the change list.\r\n\t * @param originalStart The start bound of the original sequence range\r\n\t * @param originalEnd The end bound of the original sequence range\r\n\t * @param modifiedStart The start bound of the modified sequence range\r\n\t * @param modifiedEnd The end bound of the modified sequence range\r\n\t * @param midOriginal The middle point of the original sequence range\r\n\t * @param midModified The middle point of the modified sequence range\r\n\t * @returns The diff changes, if available, otherwise null\r\n\t */\r\n\tprivate ComputeRecursionPoint(originalStart: number, originalEnd: number, modifiedStart: number, modifiedEnd: number, midOriginalArr: number[], midModifiedArr: number[], quitEarlyArr: boolean[]) {\r\n\t\tlet originalIndex = 0, modifiedIndex = 0;\r\n\t\tlet diagonalForwardStart = 0, diagonalForwardEnd = 0;\r\n\t\tlet diagonalReverseStart = 0, diagonalReverseEnd = 0;\r\n\r\n\t\t// To traverse the edit graph and produce the proper LCS, our actual\r\n\t\t// start position is just outside the given boundary\r\n\t\toriginalStart--;\r\n\t\tmodifiedStart--;\r\n\r\n\t\t// We set these up to make the compiler happy, but they will\r\n\t\t// be replaced before we return with the actual recursion point\r\n\t\tmidOriginalArr[0] = 0;\r\n\t\tmidModifiedArr[0] = 0;\r\n\r\n\t\t// Clear out the history\r\n\t\tthis.m_forwardHistory = [];\r\n\t\tthis.m_reverseHistory = [];\r\n\r\n\t\t// Each cell in the two arrays corresponds to a diagonal in the edit graph.\r\n\t\t// The integer value in the cell represents the originalIndex of the furthest\r\n\t\t// reaching point found so far that ends in that diagonal.\r\n\t\t// The modifiedIndex can be computed mathematically from the originalIndex and the diagonal number.\r\n\t\tconst maxDifferences = (originalEnd - originalStart) + (modifiedEnd - modifiedStart);\r\n\t\tconst numDiagonals = maxDifferences + 1;\r\n\t\tconst forwardPoints = new Int32Array(numDiagonals);\r\n\t\tconst reversePoints = new Int32Array(numDiagonals);\r\n\t\t// diagonalForwardBase: Index into forwardPoints of the diagonal which passes through (originalStart, modifiedStart)\r\n\t\t// diagonalReverseBase: Index into reversePoints of the diagonal which passes through (originalEnd, modifiedEnd)\r\n\t\tconst diagonalForwardBase = (modifiedEnd - modifiedStart);\r\n\t\tconst diagonalReverseBase = (originalEnd - originalStart);\r\n\t\t// diagonalForwardOffset: Geometric offset which allows modifiedIndex to be computed from originalIndex and the\r\n\t\t// diagonal number (relative to diagonalForwardBase)\r\n\t\t// diagonalReverseOffset: Geometric offset which allows modifiedIndex to be computed from originalIndex and the\r\n\t\t// diagonal number (relative to diagonalReverseBase)\r\n\t\tconst diagonalForwardOffset = (originalStart - modifiedStart);\r\n\t\tconst diagonalReverseOffset = (originalEnd - modifiedEnd);\r\n\r\n\t\t// delta: The difference between the end diagonal and the start diagonal. This is used to relate diagonal numbers\r\n\t\t// relative to the start diagonal with diagonal numbers relative to the end diagonal.\r\n\t\t// The Even/Oddn-ness of this delta is important for determining when we should check for overlap\r\n\t\tconst delta = diagonalReverseBase - diagonalForwardBase;\r\n\t\tconst deltaIsEven = (delta % 2 === 0);\r\n\r\n\t\t// Here we set up the start and end points as the furthest points found so far\r\n\t\t// in both the forward and reverse directions, respectively\r\n\t\tforwardPoints[diagonalForwardBase] = originalStart;\r\n\t\treversePoints[diagonalReverseBase] = originalEnd;\r\n\r\n\t\t// Remember if we quit early, and thus need to do a best-effort result instead of a real result.\r\n\t\tquitEarlyArr[0] = false;\r\n\r\n\r\n\r\n\t\t// A couple of points:\r\n\t\t// --With this method, we iterate on the number of differences between the two sequences.\r\n\t\t// The more differences there actually are, the longer this will take.\r\n\t\t// --Also, as the number of differences increases, we have to search on diagonals further\r\n\t\t// away from the reference diagonal (which is diagonalForwardBase for forward, diagonalReverseBase for reverse).\r\n\t\t// --We extend on even diagonals (relative to the reference diagonal) only when numDifferences\r\n\t\t// is even and odd diagonals only when numDifferences is odd.\r\n\t\tfor (let numDifferences = 1; numDifferences <= (maxDifferences / 2) + 1; numDifferences++) {\r\n\t\t\tlet furthestOriginalIndex = 0;\r\n\t\t\tlet furthestModifiedIndex = 0;\r\n\r\n\t\t\t// Run the algorithm in the forward direction\r\n\t\t\tdiagonalForwardStart = this.ClipDiagonalBound(diagonalForwardBase - numDifferences, numDifferences, diagonalForwardBase, numDiagonals);\r\n\t\t\tdiagonalForwardEnd = this.ClipDiagonalBound(diagonalForwardBase + numDifferences, numDifferences, diagonalForwardBase, numDiagonals);\r\n\t\t\tfor (let diagonal = diagonalForwardStart; diagonal <= diagonalForwardEnd; diagonal += 2) {\r\n\t\t\t\t// STEP 1: We extend the furthest reaching point in the present diagonal\r\n\t\t\t\t// by looking at the diagonals above and below and picking the one whose point\r\n\t\t\t\t// is further away from the start point (originalStart, modifiedStart)\r\n\t\t\t\tif (diagonal === diagonalForwardStart || (diagonal < diagonalForwardEnd && forwardPoints[diagonal - 1] < forwardPoints[diagonal + 1])) {\r\n\t\t\t\t\toriginalIndex = forwardPoints[diagonal + 1];\r\n\t\t\t\t} else {\r\n\t\t\t\t\toriginalIndex = forwardPoints[diagonal - 1] + 1;\r\n\t\t\t\t}\r\n\t\t\t\tmodifiedIndex = originalIndex - (diagonal - diagonalForwardBase) - diagonalForwardOffset;\r\n\r\n\t\t\t\t// Save the current originalIndex so we can test for false overlap in step 3\r\n\t\t\t\tconst tempOriginalIndex = originalIndex;\r\n\r\n\t\t\t\t// STEP 2: We can continue to extend the furthest reaching point in the present diagonal\r\n\t\t\t\t// so long as the elements are equal.\r\n\t\t\t\twhile (originalIndex < originalEnd && modifiedIndex < modifiedEnd && this.ElementsAreEqual(originalIndex + 1, modifiedIndex + 1)) {\r\n\t\t\t\t\toriginalIndex++;\r\n\t\t\t\t\tmodifiedIndex++;\r\n\t\t\t\t}\r\n\t\t\t\tforwardPoints[diagonal] = originalIndex;\r\n\r\n\t\t\t\tif (originalIndex + modifiedIndex > furthestOriginalIndex + furthestModifiedIndex) {\r\n\t\t\t\t\tfurthestOriginalIndex = originalIndex;\r\n\t\t\t\t\tfurthestModifiedIndex = modifiedIndex;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// STEP 3: If delta is odd (overlap first happens on forward when delta is odd)\r\n\t\t\t\t// and diagonal is in the range of reverse diagonals computed for numDifferences-1\r\n\t\t\t\t// (the previous iteration; we haven't computed reverse diagonals for numDifferences yet)\r\n\t\t\t\t// then check for overlap.\r\n\t\t\t\tif (!deltaIsEven && Math.abs(diagonal - diagonalReverseBase) <= (numDifferences - 1)) {\r\n\t\t\t\t\tif (originalIndex >= reversePoints[diagonal]) {\r\n\t\t\t\t\t\tmidOriginalArr[0] = originalIndex;\r\n\t\t\t\t\t\tmidModifiedArr[0] = modifiedIndex;\r\n\r\n\t\t\t\t\t\tif (tempOriginalIndex <= reversePoints[diagonal] && LocalConstants.MaxDifferencesHistory > 0 && numDifferences <= (LocalConstants.MaxDifferencesHistory + 1)) {\r\n\t\t\t\t\t\t\t// BINGO! We overlapped, and we have the full trace in memory!\r\n\t\t\t\t\t\t\treturn this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset,\r\n\t\t\t\t\t\t\t\tdiagonalReverseBase, diagonalReverseStart, diagonalReverseEnd, diagonalReverseOffset,\r\n\t\t\t\t\t\t\t\tforwardPoints, reversePoints,\r\n\t\t\t\t\t\t\t\toriginalIndex, originalEnd, midOriginalArr,\r\n\t\t\t\t\t\t\t\tmodifiedIndex, modifiedEnd, midModifiedArr,\r\n\t\t\t\t\t\t\t\tdeltaIsEven, quitEarlyArr\r\n\t\t\t\t\t\t\t);\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t// Either false overlap, or we didn't have enough memory for the full trace\r\n\t\t\t\t\t\t\t// Just return the recursion point\r\n\t\t\t\t\t\t\treturn null;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// Check to see if we should be quitting early, before moving on to the next iteration.\r\n\t\t\tconst matchLengthOfLongest = ((furthestOriginalIndex - originalStart) + (furthestModifiedIndex - modifiedStart) - numDifferences) / 2;\r\n\r\n\t\t\tif (this.ContinueProcessingPredicate !== null && !this.ContinueProcessingPredicate(furthestOriginalIndex, matchLengthOfLongest)) {\r\n\t\t\t\t// We can't finish, so skip ahead to generating a result from what we have.\r\n\t\t\t\tquitEarlyArr[0] = true;\r\n\r\n\t\t\t\t// Use the furthest distance we got in the forward direction.\r\n\t\t\t\tmidOriginalArr[0] = furthestOriginalIndex;\r\n\t\t\t\tmidModifiedArr[0] = furthestModifiedIndex;\r\n\r\n\t\t\t\tif (matchLengthOfLongest > 0 && LocalConstants.MaxDifferencesHistory > 0 && numDifferences <= (LocalConstants.MaxDifferencesHistory + 1)) {\r\n\t\t\t\t\t// Enough of the history is in memory to walk it backwards\r\n\t\t\t\t\treturn this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset,\r\n\t\t\t\t\t\tdiagonalReverseBase, diagonalReverseStart, diagonalReverseEnd, diagonalReverseOffset,\r\n\t\t\t\t\t\tforwardPoints, reversePoints,\r\n\t\t\t\t\t\toriginalIndex, originalEnd, midOriginalArr,\r\n\t\t\t\t\t\tmodifiedIndex, modifiedEnd, midModifiedArr,\r\n\t\t\t\t\t\tdeltaIsEven, quitEarlyArr\r\n\t\t\t\t\t);\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// We didn't actually remember enough of the history.\r\n\r\n\t\t\t\t\t//Since we are quiting the diff early, we need to shift back the originalStart and modified start\r\n\t\t\t\t\t//back into the boundary limits since we decremented their value above beyond the boundary limit.\r\n\t\t\t\t\toriginalStart++;\r\n\t\t\t\t\tmodifiedStart++;\r\n\r\n\t\t\t\t\treturn [\r\n\t\t\t\t\t\tnew DiffChange(originalStart, originalEnd - originalStart + 1,\r\n\t\t\t\t\t\t\tmodifiedStart, modifiedEnd - modifiedStart + 1)\r\n\t\t\t\t\t];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// Run the algorithm in the reverse direction\r\n\t\t\tdiagonalReverseStart = this.ClipDiagonalBound(diagonalReverseBase - numDifferences, numDifferences, diagonalReverseBase, numDiagonals);\r\n\t\t\tdiagonalReverseEnd = this.ClipDiagonalBound(diagonalReverseBase + numDifferences, numDifferences, diagonalReverseBase, numDiagonals);\r\n\t\t\tfor (let diagonal = diagonalReverseStart; diagonal <= diagonalReverseEnd; diagonal += 2) {\r\n\t\t\t\t// STEP 1: We extend the furthest reaching point in the present diagonal\r\n\t\t\t\t// by looking at the diagonals above and below and picking the one whose point\r\n\t\t\t\t// is further away from the start point (originalEnd, modifiedEnd)\r\n\t\t\t\tif (diagonal === diagonalReverseStart || (diagonal < diagonalReverseEnd && reversePoints[diagonal - 1] >= reversePoints[diagonal + 1])) {\r\n\t\t\t\t\toriginalIndex = reversePoints[diagonal + 1] - 1;\r\n\t\t\t\t} else {\r\n\t\t\t\t\toriginalIndex = reversePoints[diagonal - 1];\r\n\t\t\t\t}\r\n\t\t\t\tmodifiedIndex = originalIndex - (diagonal - diagonalReverseBase) - diagonalReverseOffset;\r\n\r\n\t\t\t\t// Save the current originalIndex so we can test for false overlap\r\n\t\t\t\tconst tempOriginalIndex = originalIndex;\r\n\r\n\t\t\t\t// STEP 2: We can continue to extend the furthest reaching point in the present diagonal\r\n\t\t\t\t// as long as the elements are equal.\r\n\t\t\t\twhile (originalIndex > originalStart && modifiedIndex > modifiedStart && this.ElementsAreEqual(originalIndex, modifiedIndex)) {\r\n\t\t\t\t\toriginalIndex--;\r\n\t\t\t\t\tmodifiedIndex--;\r\n\t\t\t\t}\r\n\t\t\t\treversePoints[diagonal] = originalIndex;\r\n\r\n\t\t\t\t// STEP 4: If delta is even (overlap first happens on reverse when delta is even)\r\n\t\t\t\t// and diagonal is in the range of forward diagonals computed for numDifferences\r\n\t\t\t\t// then check for overlap.\r\n\t\t\t\tif (deltaIsEven && Math.abs(diagonal - diagonalForwardBase) <= numDifferences) {\r\n\t\t\t\t\tif (originalIndex <= forwardPoints[diagonal]) {\r\n\t\t\t\t\t\tmidOriginalArr[0] = originalIndex;\r\n\t\t\t\t\t\tmidModifiedArr[0] = modifiedIndex;\r\n\r\n\t\t\t\t\t\tif (tempOriginalIndex >= forwardPoints[diagonal] && LocalConstants.MaxDifferencesHistory > 0 && numDifferences <= (LocalConstants.MaxDifferencesHistory + 1)) {\r\n\t\t\t\t\t\t\t// BINGO! We overlapped, and we have the full trace in memory!\r\n\t\t\t\t\t\t\treturn this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset,\r\n\t\t\t\t\t\t\t\tdiagonalReverseBase, diagonalReverseStart, diagonalReverseEnd, diagonalReverseOffset,\r\n\t\t\t\t\t\t\t\tforwardPoints, reversePoints,\r\n\t\t\t\t\t\t\t\toriginalIndex, originalEnd, midOriginalArr,\r\n\t\t\t\t\t\t\t\tmodifiedIndex, modifiedEnd, midModifiedArr,\r\n\t\t\t\t\t\t\t\tdeltaIsEven, quitEarlyArr\r\n\t\t\t\t\t\t\t);\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t// Either false overlap, or we didn't have enough memory for the full trace\r\n\t\t\t\t\t\t\t// Just return the recursion point\r\n\t\t\t\t\t\t\treturn null;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// Save current vectors to history before the next iteration\r\n\t\t\tif (numDifferences <= LocalConstants.MaxDifferencesHistory) {\r\n\t\t\t\t// We are allocating space for one extra int, which we fill with\r\n\t\t\t\t// the index of the diagonal base index\r\n\t\t\t\tlet temp = new Int32Array(diagonalForwardEnd - diagonalForwardStart + 2);\r\n\t\t\t\ttemp[0] = diagonalForwardBase - diagonalForwardStart + 1;\r\n\t\t\t\tMyArray.Copy2(forwardPoints, diagonalForwardStart, temp, 1, diagonalForwardEnd - diagonalForwardStart + 1);\r\n\t\t\t\tthis.m_forwardHistory.push(temp);\r\n\r\n\t\t\t\ttemp = new Int32Array(diagonalReverseEnd - diagonalReverseStart + 2);\r\n\t\t\t\ttemp[0] = diagonalReverseBase - diagonalReverseStart + 1;\r\n\t\t\t\tMyArray.Copy2(reversePoints, diagonalReverseStart, temp, 1, diagonalReverseEnd - diagonalReverseStart + 1);\r\n\t\t\t\tthis.m_reverseHistory.push(temp);\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// If we got here, then we have the full trace in history. We just have to convert it to a change list\r\n\t\t// NOTE: This part is a bit messy\r\n\t\treturn this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset,\r\n\t\t\tdiagonalReverseBase, diagonalReverseStart, diagonalReverseEnd, diagonalReverseOffset,\r\n\t\t\tforwardPoints, reversePoints,\r\n\t\t\toriginalIndex, originalEnd, midOriginalArr,\r\n\t\t\tmodifiedIndex, modifiedEnd, midModifiedArr,\r\n\t\t\tdeltaIsEven, quitEarlyArr\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * Shifts the given changes to provide a more intuitive diff.\r\n\t * While the first element in a diff matches the first element after the diff,\r\n\t * we shift the diff down.\r\n\t *\r\n\t * @param changes The list of changes to shift\r\n\t * @returns The shifted changes\r\n\t */\r\n\tprivate PrettifyChanges(changes: DiffChange[]): DiffChange[] {\r\n\r\n\t\t// Shift all the changes down first\r\n\t\tfor (let i = 0; i < changes.length; i++) {\r\n\t\t\tconst change = changes[i];\r\n\t\t\tconst originalStop = (i < changes.length - 1) ? changes[i + 1].originalStart : this._originalElementsOrHash.length;\r\n\t\t\tconst modifiedStop = (i < changes.length - 1) ? changes[i + 1].modifiedStart : this._modifiedElementsOrHash.length;\r\n\t\t\tconst checkOriginal = change.originalLength > 0;\r\n\t\t\tconst checkModified = change.modifiedLength > 0;\r\n\r\n\t\t\twhile (change.originalStart + change.originalLength < originalStop &&\r\n\t\t\t\tchange.modifiedStart + change.modifiedLength < modifiedStop &&\r\n\t\t\t\t(!checkOriginal || this.OriginalElementsAreEqual(change.originalStart, change.originalStart + change.originalLength)) &&\r\n\t\t\t\t(!checkModified || this.ModifiedElementsAreEqual(change.modifiedStart, change.modifiedStart + change.modifiedLength))) {\r\n\t\t\t\tchange.originalStart++;\r\n\t\t\t\tchange.modifiedStart++;\r\n\t\t\t}\r\n\r\n\t\t\tlet mergedChangeArr: Array = [null];\r\n\t\t\tif (i < changes.length - 1 && this.ChangesOverlap(changes[i], changes[i + 1], mergedChangeArr)) {\r\n\t\t\t\tchanges[i] = mergedChangeArr[0]!;\r\n\t\t\t\tchanges.splice(i + 1, 1);\r\n\t\t\t\ti--;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Shift changes back up until we hit empty or whitespace-only lines\r\n\t\tfor (let i = changes.length - 1; i >= 0; i--) {\r\n\t\t\tconst change = changes[i];\r\n\r\n\t\t\tlet originalStop = 0;\r\n\t\t\tlet modifiedStop = 0;\r\n\t\t\tif (i > 0) {\r\n\t\t\t\tconst prevChange = changes[i - 1];\r\n\t\t\t\tif (prevChange.originalLength > 0) {\r\n\t\t\t\t\toriginalStop = prevChange.originalStart + prevChange.originalLength;\r\n\t\t\t\t}\r\n\t\t\t\tif (prevChange.modifiedLength > 0) {\r\n\t\t\t\t\tmodifiedStop = prevChange.modifiedStart + prevChange.modifiedLength;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tconst checkOriginal = change.originalLength > 0;\r\n\t\t\tconst checkModified = change.modifiedLength > 0;\r\n\r\n\t\t\tlet bestDelta = 0;\r\n\t\t\tlet bestScore = this._boundaryScore(change.originalStart, change.originalLength, change.modifiedStart, change.modifiedLength);\r\n\r\n\t\t\tfor (let delta = 1; ; delta++) {\r\n\t\t\t\tconst originalStart = change.originalStart - delta;\r\n\t\t\t\tconst modifiedStart = change.modifiedStart - delta;\r\n\r\n\t\t\t\tif (originalStart < originalStop || modifiedStart < modifiedStop) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (checkOriginal && !this.OriginalElementsAreEqual(originalStart, originalStart + change.originalLength)) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (checkModified && !this.ModifiedElementsAreEqual(modifiedStart, modifiedStart + change.modifiedLength)) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst score = this._boundaryScore(originalStart, change.originalLength, modifiedStart, change.modifiedLength);\r\n\r\n\t\t\t\tif (score > bestScore) {\r\n\t\t\t\t\tbestScore = score;\r\n\t\t\t\t\tbestDelta = delta;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tchange.originalStart -= bestDelta;\r\n\t\t\tchange.modifiedStart -= bestDelta;\r\n\t\t}\r\n\r\n\t\t// There could be multiple longest common substrings.\r\n\t\t// Give preference to the ones containing longer lines\r\n\t\tif (this._hasStrings) {\r\n\t\t\tfor (let i = 1, len = changes.length; i < len; i++) {\r\n\t\t\t\tconst aChange = changes[i - 1];\r\n\t\t\t\tconst bChange = changes[i];\r\n\t\t\t\tconst matchedLength = bChange.originalStart - aChange.originalStart - aChange.originalLength;\r\n\t\t\t\tconst aOriginalStart = aChange.originalStart;\r\n\t\t\t\tconst bOriginalEnd = bChange.originalStart + bChange.originalLength;\r\n\t\t\t\tconst abOriginalLength = bOriginalEnd - aOriginalStart;\r\n\t\t\t\tconst aModifiedStart = aChange.modifiedStart;\r\n\t\t\t\tconst bModifiedEnd = bChange.modifiedStart + bChange.modifiedLength;\r\n\t\t\t\tconst abModifiedLength = bModifiedEnd - aModifiedStart;\r\n\t\t\t\t// Avoid wasting a lot of time with these searches\r\n\t\t\t\tif (matchedLength < 5 && abOriginalLength < 20 && abModifiedLength < 20) {\r\n\t\t\t\t\tconst t = this._findBetterContiguousSequence(\r\n\t\t\t\t\t\taOriginalStart, abOriginalLength,\r\n\t\t\t\t\t\taModifiedStart, abModifiedLength,\r\n\t\t\t\t\t\tmatchedLength\r\n\t\t\t\t\t);\r\n\t\t\t\t\tif (t) {\r\n\t\t\t\t\t\tconst [originalMatchStart, modifiedMatchStart] = t;\r\n\t\t\t\t\t\tif (originalMatchStart !== aChange.originalStart + aChange.originalLength || modifiedMatchStart !== aChange.modifiedStart + aChange.modifiedLength) {\r\n\t\t\t\t\t\t\t// switch to another sequence that has a better score\r\n\t\t\t\t\t\t\taChange.originalLength = originalMatchStart - aChange.originalStart;\r\n\t\t\t\t\t\t\taChange.modifiedLength = modifiedMatchStart - aChange.modifiedStart;\r\n\t\t\t\t\t\t\tbChange.originalStart = originalMatchStart + matchedLength;\r\n\t\t\t\t\t\t\tbChange.modifiedStart = modifiedMatchStart + matchedLength;\r\n\t\t\t\t\t\t\tbChange.originalLength = bOriginalEnd - bChange.originalStart;\r\n\t\t\t\t\t\t\tbChange.modifiedLength = bModifiedEnd - bChange.modifiedStart;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn changes;\r\n\t}\r\n\r\n\tprivate _findBetterContiguousSequence(originalStart: number, originalLength: number, modifiedStart: number, modifiedLength: number, desiredLength: number): [number, number] | null {\r\n\t\tif (originalLength < desiredLength || modifiedLength < desiredLength) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tconst originalMax = originalStart + originalLength - desiredLength + 1;\r\n\t\tconst modifiedMax = modifiedStart + modifiedLength - desiredLength + 1;\r\n\t\tlet bestScore = 0;\r\n\t\tlet bestOriginalStart = 0;\r\n\t\tlet bestModifiedStart = 0;\r\n\t\tfor (let i = originalStart; i < originalMax; i++) {\r\n\t\t\tfor (let j = modifiedStart; j < modifiedMax; j++) {\r\n\t\t\t\tconst score = this._contiguousSequenceScore(i, j, desiredLength);\r\n\t\t\t\tif (score > 0 && score > bestScore) {\r\n\t\t\t\t\tbestScore = score;\r\n\t\t\t\t\tbestOriginalStart = i;\r\n\t\t\t\t\tbestModifiedStart = j;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (bestScore > 0) {\r\n\t\t\treturn [bestOriginalStart, bestModifiedStart];\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate _contiguousSequenceScore(originalStart: number, modifiedStart: number, length: number): number {\r\n\t\tlet score = 0;\r\n\t\tfor (let l = 0; l < length; l++) {\r\n\t\t\tif (!this.ElementsAreEqual(originalStart + l, modifiedStart + l)) {\r\n\t\t\t\treturn 0;\r\n\t\t\t}\r\n\t\t\tscore += this._originalStringElements[originalStart + l].length;\r\n\t\t}\r\n\t\treturn score;\r\n\t}\r\n\r\n\tprivate _OriginalIsBoundary(index: number): boolean {\r\n\t\tif (index <= 0 || index >= this._originalElementsOrHash.length - 1) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn (this._hasStrings && /^\\s*$/.test(this._originalStringElements[index]));\r\n\t}\r\n\r\n\tprivate _OriginalRegionIsBoundary(originalStart: number, originalLength: number): boolean {\r\n\t\tif (this._OriginalIsBoundary(originalStart) || this._OriginalIsBoundary(originalStart - 1)) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (originalLength > 0) {\r\n\t\t\tconst originalEnd = originalStart + originalLength;\r\n\t\t\tif (this._OriginalIsBoundary(originalEnd - 1) || this._OriginalIsBoundary(originalEnd)) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tprivate _ModifiedIsBoundary(index: number): boolean {\r\n\t\tif (index <= 0 || index >= this._modifiedElementsOrHash.length - 1) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn (this._hasStrings && /^\\s*$/.test(this._modifiedStringElements[index]));\r\n\t}\r\n\r\n\tprivate _ModifiedRegionIsBoundary(modifiedStart: number, modifiedLength: number): boolean {\r\n\t\tif (this._ModifiedIsBoundary(modifiedStart) || this._ModifiedIsBoundary(modifiedStart - 1)) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (modifiedLength > 0) {\r\n\t\t\tconst modifiedEnd = modifiedStart + modifiedLength;\r\n\t\t\tif (this._ModifiedIsBoundary(modifiedEnd - 1) || this._ModifiedIsBoundary(modifiedEnd)) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tprivate _boundaryScore(originalStart: number, originalLength: number, modifiedStart: number, modifiedLength: number): number {\r\n\t\tconst originalScore = (this._OriginalRegionIsBoundary(originalStart, originalLength) ? 1 : 0);\r\n\t\tconst modifiedScore = (this._ModifiedRegionIsBoundary(modifiedStart, modifiedLength) ? 1 : 0);\r\n\t\treturn (originalScore + modifiedScore);\r\n\t}\r\n\r\n\t/**\r\n\t * Concatenates the two input DiffChange lists and returns the resulting\r\n\t * list.\r\n\t * @param The left changes\r\n\t * @param The right changes\r\n\t * @returns The concatenated list\r\n\t */\r\n\tprivate ConcatenateChanges(left: DiffChange[], right: DiffChange[]): DiffChange[] {\r\n\t\tlet mergedChangeArr: DiffChange[] = [];\r\n\r\n\t\tif (left.length === 0 || right.length === 0) {\r\n\t\t\treturn (right.length > 0) ? right : left;\r\n\t\t} else if (this.ChangesOverlap(left[left.length - 1], right[0], mergedChangeArr)) {\r\n\t\t\t// Since we break the problem down recursively, it is possible that we\r\n\t\t\t// might recurse in the middle of a change thereby splitting it into\r\n\t\t\t// two changes. Here in the combining stage, we detect and fuse those\r\n\t\t\t// changes back together\r\n\t\t\tconst result = new Array(left.length + right.length - 1);\r\n\t\t\tMyArray.Copy(left, 0, result, 0, left.length - 1);\r\n\t\t\tresult[left.length - 1] = mergedChangeArr[0];\r\n\t\t\tMyArray.Copy(right, 1, result, left.length, right.length - 1);\r\n\r\n\t\t\treturn result;\r\n\t\t} else {\r\n\t\t\tconst result = new Array(left.length + right.length);\r\n\t\t\tMyArray.Copy(left, 0, result, 0, left.length);\r\n\t\t\tMyArray.Copy(right, 0, result, left.length, right.length);\r\n\r\n\t\t\treturn result;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Returns true if the two changes overlap and can be merged into a single\r\n\t * change\r\n\t * @param left The left change\r\n\t * @param right The right change\r\n\t * @param mergedChange The merged change if the two overlap, null otherwise\r\n\t * @returns True if the two changes overlap\r\n\t */\r\n\tprivate ChangesOverlap(left: DiffChange, right: DiffChange, mergedChangeArr: Array): boolean {\r\n\t\tDebug.Assert(left.originalStart <= right.originalStart, 'Left change is not less than or equal to right change');\r\n\t\tDebug.Assert(left.modifiedStart <= right.modifiedStart, 'Left change is not less than or equal to right change');\r\n\r\n\t\tif (left.originalStart + left.originalLength >= right.originalStart || left.modifiedStart + left.modifiedLength >= right.modifiedStart) {\r\n\t\t\tconst originalStart = left.originalStart;\r\n\t\t\tlet originalLength = left.originalLength;\r\n\t\t\tconst modifiedStart = left.modifiedStart;\r\n\t\t\tlet modifiedLength = left.modifiedLength;\r\n\r\n\t\t\tif (left.originalStart + left.originalLength >= right.originalStart) {\r\n\t\t\t\toriginalLength = right.originalStart + right.originalLength - left.originalStart;\r\n\t\t\t}\r\n\t\t\tif (left.modifiedStart + left.modifiedLength >= right.modifiedStart) {\r\n\t\t\t\tmodifiedLength = right.modifiedStart + right.modifiedLength - left.modifiedStart;\r\n\t\t\t}\r\n\r\n\t\t\tmergedChangeArr[0] = new DiffChange(originalStart, originalLength, modifiedStart, modifiedLength);\r\n\t\t\treturn true;\r\n\t\t} else {\r\n\t\t\tmergedChangeArr[0] = null;\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Helper method used to clip a diagonal index to the range of valid\r\n\t * diagonals. This also decides whether or not the diagonal index,\r\n\t * if it exceeds the boundary, should be clipped to the boundary or clipped\r\n\t * one inside the boundary depending on the Even/Odd status of the boundary\r\n\t * and numDifferences.\r\n\t * @param diagonal The index of the diagonal to clip.\r\n\t * @param numDifferences The current number of differences being iterated upon.\r\n\t * @param diagonalBaseIndex The base reference diagonal.\r\n\t * @param numDiagonals The total number of diagonals.\r\n\t * @returns The clipped diagonal index.\r\n\t */\r\n\tprivate ClipDiagonalBound(diagonal: number, numDifferences: number, diagonalBaseIndex: number, numDiagonals: number): number {\r\n\t\tif (diagonal >= 0 && diagonal < numDiagonals) {\r\n\t\t\t// Nothing to clip, its in range\r\n\t\t\treturn diagonal;\r\n\t\t}\r\n\r\n\t\t// diagonalsBelow: The number of diagonals below the reference diagonal\r\n\t\t// diagonalsAbove: The number of diagonals above the reference diagonal\r\n\t\tconst diagonalsBelow = diagonalBaseIndex;\r\n\t\tconst diagonalsAbove = numDiagonals - diagonalBaseIndex - 1;\r\n\t\tconst diffEven = (numDifferences % 2 === 0);\r\n\r\n\t\tif (diagonal < 0) {\r\n\t\t\tconst lowerBoundEven = (diagonalsBelow % 2 === 0);\r\n\t\t\treturn (diffEven === lowerBoundEven) ? 0 : 1;\r\n\t\t} else {\r\n\t\t\tconst upperBoundEven = (diagonalsAbove % 2 === 0);\r\n\t\t\treturn (diffEven === upperBoundEven) ? numDiagonals - 1 : numDiagonals - 2;\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IIdentityProvider } from 'vs/base/browser/ui/list/list';\r\nimport { ICollapseStateChangeEvent, ITreeElement, ITreeFilter, ITreeFilterDataResult, ITreeModel, ITreeNode, TreeVisibility, ITreeModelSpliceEvent, TreeError } from 'vs/base/browser/ui/tree/tree';\r\nimport { tail2 } from 'vs/base/common/arrays';\r\nimport { LcsDiff } from 'vs/base/common/diff/diff';\r\nimport { Emitter, Event, EventBufferer } from 'vs/base/common/event';\r\nimport { Iterable } from 'vs/base/common/iterator';\r\nimport { ISpliceable } from 'vs/base/common/sequence';\r\n\r\n// Exported for tests\r\nexport interface IIndexTreeNode extends ITreeNode {\r\n\treadonly parent: IIndexTreeNode | undefined;\r\n\treadonly children: IIndexTreeNode[];\r\n\tvisibleChildrenCount: number;\r\n\tvisibleChildIndex: number;\r\n\tcollapsible: boolean;\r\n\tcollapsed: boolean;\r\n\trenderNodeCount: number;\r\n\tvisibility: TreeVisibility;\r\n\tvisible: boolean;\r\n\tfilterData: TFilterData | undefined;\r\n}\r\n\r\nexport function isFilterResult(obj: any): obj is ITreeFilterDataResult {\r\n\treturn typeof obj === 'object' && 'visibility' in obj && 'data' in obj;\r\n}\r\n\r\nexport function getVisibleState(visibility: boolean | TreeVisibility): TreeVisibility {\r\n\tswitch (visibility) {\r\n\t\tcase true: return TreeVisibility.Visible;\r\n\t\tcase false: return TreeVisibility.Hidden;\r\n\t\tdefault: return visibility;\r\n\t}\r\n}\r\n\r\nexport interface IIndexTreeModelOptions {\r\n\treadonly collapseByDefault?: boolean; // defaults to false\r\n\treadonly filter?: ITreeFilter;\r\n\treadonly autoExpandSingleChildren?: boolean;\r\n}\r\n\r\nexport interface IIndexTreeModelSpliceOptions {\r\n\t/**\r\n\t * If set, child updates will recurse the given number of levels even if\r\n\t * items in the splice operation are unchanged. `Infinity` is a valid value.\r\n\t */\r\n\treadonly diffDepth?: number;\r\n\r\n\t/**\r\n\t * Identity provider used to optimize splice() calls in the IndexTree. If\r\n\t * this is not present, optimized splicing is not enabled.\r\n\t *\r\n\t * Warning: if this is present, calls to `setChildren()` will not replace\r\n\t * or update nodes if their identity is the same, even if the elements are\r\n\t * different. For this, you should call `rerender()`.\r\n\t */\r\n\treadonly diffIdentityProvider?: IIdentityProvider;\r\n\r\n\t/**\r\n\t * Callback for when a node is created.\r\n\t */\r\n\tonDidCreateNode?: (node: ITreeNode) => void;\r\n\r\n\t/**\r\n\t * Callback for when a node is deleted.\r\n\t */\r\n\tonDidDeleteNode?: (node: ITreeNode) => void\r\n}\r\n\r\ninterface CollapsibleStateUpdate {\r\n\treadonly collapsible: boolean;\r\n}\r\n\r\ninterface CollapsedStateUpdate {\r\n\treadonly collapsed: boolean;\r\n\treadonly recursive: boolean;\r\n}\r\n\r\ntype CollapseStateUpdate = CollapsibleStateUpdate | CollapsedStateUpdate;\r\n\r\nfunction isCollapsibleStateUpdate(update: CollapseStateUpdate): update is CollapsibleStateUpdate {\r\n\treturn typeof (update as any).collapsible === 'boolean';\r\n}\r\n\r\nexport interface IList extends ISpliceable {\r\n\tupdateElementHeight(index: number, height: number): void;\r\n}\r\n\r\nexport class IndexTreeModel, TFilterData = void> implements ITreeModel {\r\n\r\n\treadonly rootRef = [];\r\n\r\n\tprivate root: IIndexTreeNode;\r\n\tprivate eventBufferer = new EventBufferer();\r\n\r\n\tprivate readonly _onDidChangeCollapseState = new Emitter>();\r\n\treadonly onDidChangeCollapseState: Event> = this.eventBufferer.wrapEvent(this._onDidChangeCollapseState.event);\r\n\r\n\tprivate readonly _onDidChangeRenderNodeCount = new Emitter>();\r\n\treadonly onDidChangeRenderNodeCount: Event> = this.eventBufferer.wrapEvent(this._onDidChangeRenderNodeCount.event);\r\n\r\n\tprivate collapseByDefault: boolean;\r\n\tprivate filter?: ITreeFilter;\r\n\tprivate autoExpandSingleChildren: boolean;\r\n\r\n\tprivate readonly _onDidSplice = new Emitter>();\r\n\treadonly onDidSplice = this._onDidSplice.event;\r\n\r\n\tconstructor(\r\n\t\tprivate user: string,\r\n\t\tprivate list: IList>,\r\n\t\trootElement: T,\r\n\t\toptions: IIndexTreeModelOptions = {}\r\n\t) {\r\n\t\tthis.collapseByDefault = typeof options.collapseByDefault === 'undefined' ? false : options.collapseByDefault;\r\n\t\tthis.filter = options.filter;\r\n\t\tthis.autoExpandSingleChildren = typeof options.autoExpandSingleChildren === 'undefined' ? false : options.autoExpandSingleChildren;\r\n\r\n\t\tthis.root = {\r\n\t\t\tparent: undefined,\r\n\t\t\telement: rootElement,\r\n\t\t\tchildren: [],\r\n\t\t\tdepth: 0,\r\n\t\t\tvisibleChildrenCount: 0,\r\n\t\t\tvisibleChildIndex: -1,\r\n\t\t\tcollapsible: false,\r\n\t\t\tcollapsed: false,\r\n\t\t\trenderNodeCount: 0,\r\n\t\t\tvisibility: TreeVisibility.Visible,\r\n\t\t\tvisible: true,\r\n\t\t\tfilterData: undefined\r\n\t\t};\r\n\t}\r\n\r\n\tsplice(\r\n\t\tlocation: number[],\r\n\t\tdeleteCount: number,\r\n\t\ttoInsert: Iterable> = Iterable.empty(),\r\n\t\toptions: IIndexTreeModelSpliceOptions = {},\r\n\t): void {\r\n\t\tif (location.length === 0) {\r\n\t\t\tthrow new TreeError(this.user, 'Invalid tree location');\r\n\t\t}\r\n\r\n\t\tif (options.diffIdentityProvider) {\r\n\t\t\tthis.spliceSmart(options.diffIdentityProvider, location, deleteCount, toInsert, options);\r\n\t\t} else {\r\n\t\t\tthis.spliceSimple(location, deleteCount, toInsert, options);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate spliceSmart(\r\n\t\tidentity: IIdentityProvider,\r\n\t\tlocation: number[],\r\n\t\tdeleteCount: number,\r\n\t\ttoInsertIterable: Iterable> = Iterable.empty(),\r\n\t\toptions: IIndexTreeModelSpliceOptions,\r\n\t\trecurseLevels = options.diffDepth ?? 0,\r\n\t) {\r\n\t\tconst { parentNode } = this.getParentNodeWithListIndex(location);\r\n\t\tconst toInsert = [...toInsertIterable];\r\n\t\tconst index = location[location.length - 1];\r\n\t\tconst diff = new LcsDiff(\r\n\t\t\t{ getElements: () => parentNode.children.map(e => identity.getId(e.element).toString()) },\r\n\t\t\t{\r\n\t\t\t\tgetElements: () => [\r\n\t\t\t\t\t...parentNode.children.slice(0, index),\r\n\t\t\t\t\t...toInsert,\r\n\t\t\t\t\t...parentNode.children.slice(index + deleteCount),\r\n\t\t\t\t].map(e => identity.getId(e.element).toString())\r\n\t\t\t},\r\n\t\t).ComputeDiff(false);\r\n\r\n\t\t// if we were given a 'best effort' diff, use default behavior\r\n\t\tif (diff.quitEarly) {\r\n\t\t\treturn this.spliceSimple(location, deleteCount, toInsert, options);\r\n\t\t}\r\n\r\n\t\tconst locationPrefix = location.slice(0, -1);\r\n\t\tconst recurseSplice = (fromOriginal: number, fromModified: number, count: number) => {\r\n\t\t\tif (recurseLevels > 0) {\r\n\t\t\t\tfor (let i = 0; i < count; i++) {\r\n\t\t\t\t\tfromOriginal--;\r\n\t\t\t\t\tfromModified--;\r\n\t\t\t\t\tthis.spliceSmart(\r\n\t\t\t\t\t\tidentity,\r\n\t\t\t\t\t\t[...locationPrefix, fromOriginal, 0],\r\n\t\t\t\t\t\tNumber.MAX_SAFE_INTEGER,\r\n\t\t\t\t\t\ttoInsert[fromModified].children,\r\n\t\t\t\t\t\toptions,\r\n\t\t\t\t\t\trecurseLevels - 1,\r\n\t\t\t\t\t);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tlet lastStartO = Math.min(parentNode.children.length, index + deleteCount);\r\n\t\tlet lastStartM = toInsert.length;\r\n\t\tfor (const change of diff.changes.sort((a, b) => b.originalStart - a.originalStart)) {\r\n\t\t\trecurseSplice(lastStartO, lastStartM, lastStartO - (change.originalStart + change.originalLength));\r\n\t\t\tlastStartO = change.originalStart;\r\n\t\t\tlastStartM = change.modifiedStart - index;\r\n\r\n\t\t\tthis.spliceSimple(\r\n\t\t\t\t[...locationPrefix, lastStartO],\r\n\t\t\t\tchange.originalLength,\r\n\t\t\t\tIterable.slice(toInsert, lastStartM, lastStartM + change.modifiedLength),\r\n\t\t\t\toptions,\r\n\t\t\t);\r\n\t\t}\r\n\r\n\t\t// at this point, startO === startM === count since any remaining prefix should match\r\n\t\trecurseSplice(lastStartO, lastStartM, lastStartO);\r\n\t}\r\n\r\n\tprivate spliceSimple(\r\n\t\tlocation: number[],\r\n\t\tdeleteCount: number,\r\n\t\ttoInsert: Iterable> = Iterable.empty(),\r\n\t\t{ onDidCreateNode, onDidDeleteNode }: IIndexTreeModelSpliceOptions,\r\n\t) {\r\n\t\tconst { parentNode, listIndex, revealed, visible } = this.getParentNodeWithListIndex(location);\r\n\t\tconst treeListElementsToInsert: ITreeNode[] = [];\r\n\t\tconst nodesToInsertIterator = Iterable.map(toInsert, el => this.createTreeNode(el, parentNode, parentNode.visible ? TreeVisibility.Visible : TreeVisibility.Hidden, revealed, treeListElementsToInsert, onDidCreateNode));\r\n\r\n\t\tconst lastIndex = location[location.length - 1];\r\n\t\tconst lastHadChildren = parentNode.children.length > 0;\r\n\r\n\t\t// figure out what's the visible child start index right before the\r\n\t\t// splice point\r\n\t\tlet visibleChildStartIndex = 0;\r\n\r\n\t\tfor (let i = lastIndex; i >= 0 && i < parentNode.children.length; i--) {\r\n\t\t\tconst child = parentNode.children[i];\r\n\r\n\t\t\tif (child.visible) {\r\n\t\t\t\tvisibleChildStartIndex = child.visibleChildIndex;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst nodesToInsert: IIndexTreeNode[] = [];\r\n\t\tlet insertedVisibleChildrenCount = 0;\r\n\t\tlet renderNodeCount = 0;\r\n\r\n\t\tfor (const child of nodesToInsertIterator) {\r\n\t\t\tnodesToInsert.push(child);\r\n\t\t\trenderNodeCount += child.renderNodeCount;\r\n\r\n\t\t\tif (child.visible) {\r\n\t\t\t\tchild.visibleChildIndex = visibleChildStartIndex + insertedVisibleChildrenCount++;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst deletedNodes = parentNode.children.splice(lastIndex, deleteCount, ...nodesToInsert);\r\n\r\n\t\t// figure out what is the count of deleted visible children\r\n\t\tlet deletedVisibleChildrenCount = 0;\r\n\r\n\t\tfor (const child of deletedNodes) {\r\n\t\t\tif (child.visible) {\r\n\t\t\t\tdeletedVisibleChildrenCount++;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// and adjust for all visible children after the splice point\r\n\t\tif (deletedVisibleChildrenCount !== 0) {\r\n\t\t\tfor (let i = lastIndex + nodesToInsert.length; i < parentNode.children.length; i++) {\r\n\t\t\t\tconst child = parentNode.children[i];\r\n\r\n\t\t\t\tif (child.visible) {\r\n\t\t\t\t\tchild.visibleChildIndex -= deletedVisibleChildrenCount;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// update parent's visible children count\r\n\t\tparentNode.visibleChildrenCount += insertedVisibleChildrenCount - deletedVisibleChildrenCount;\r\n\r\n\t\tif (revealed && visible) {\r\n\t\t\tconst visibleDeleteCount = deletedNodes.reduce((r, node) => r + (node.visible ? node.renderNodeCount : 0), 0);\r\n\r\n\t\t\tthis._updateAncestorsRenderNodeCount(parentNode, renderNodeCount - visibleDeleteCount);\r\n\t\t\tthis.list.splice(listIndex, visibleDeleteCount, treeListElementsToInsert);\r\n\t\t}\r\n\r\n\t\tif (deletedNodes.length > 0 && onDidDeleteNode) {\r\n\t\t\tconst visit = (node: ITreeNode) => {\r\n\t\t\t\tonDidDeleteNode(node);\r\n\t\t\t\tnode.children.forEach(visit);\r\n\t\t\t};\r\n\r\n\t\t\tdeletedNodes.forEach(visit);\r\n\t\t}\r\n\r\n\t\tconst currentlyHasChildren = parentNode.children.length > 0;\r\n\t\tif (lastHadChildren !== currentlyHasChildren) {\r\n\t\t\tthis.setCollapsible(location.slice(0, -1), currentlyHasChildren);\r\n\t\t}\r\n\r\n\t\tthis._onDidSplice.fire({ insertedNodes: nodesToInsert, deletedNodes });\r\n\r\n\t\tlet node: IIndexTreeNode | undefined = parentNode;\r\n\r\n\t\twhile (node) {\r\n\t\t\tif (node.visibility === TreeVisibility.Recurse) {\r\n\t\t\t\tthis.refilter();\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tnode = node.parent;\r\n\t\t}\r\n\t}\r\n\r\n\trerender(location: number[]): void {\r\n\t\tif (location.length === 0) {\r\n\t\t\tthrow new TreeError(this.user, 'Invalid tree location');\r\n\t\t}\r\n\r\n\t\tconst { node, listIndex, revealed } = this.getTreeNodeWithListIndex(location);\r\n\r\n\t\tif (node.visible && revealed) {\r\n\t\t\tthis.list.splice(listIndex, 1, [node]);\r\n\t\t}\r\n\t}\r\n\r\n\thas(location: number[]): boolean {\r\n\t\treturn this.hasTreeNode(location);\r\n\t}\r\n\r\n\tgetListIndex(location: number[]): number {\r\n\t\tconst { listIndex, visible, revealed } = this.getTreeNodeWithListIndex(location);\r\n\t\treturn visible && revealed ? listIndex : -1;\r\n\t}\r\n\r\n\tgetListRenderCount(location: number[]): number {\r\n\t\treturn this.getTreeNode(location).renderNodeCount;\r\n\t}\r\n\r\n\tisCollapsible(location: number[]): boolean {\r\n\t\treturn this.getTreeNode(location).collapsible;\r\n\t}\r\n\r\n\tsetCollapsible(location: number[], collapsible?: boolean): boolean {\r\n\t\tconst node = this.getTreeNode(location);\r\n\r\n\t\tif (typeof collapsible === 'undefined') {\r\n\t\t\tcollapsible = !node.collapsible;\r\n\t\t}\r\n\r\n\t\tconst update: CollapsibleStateUpdate = { collapsible };\r\n\t\treturn this.eventBufferer.bufferEvents(() => this._setCollapseState(location, update));\r\n\t}\r\n\r\n\tisCollapsed(location: number[]): boolean {\r\n\t\treturn this.getTreeNode(location).collapsed;\r\n\t}\r\n\r\n\tsetCollapsed(location: number[], collapsed?: boolean, recursive?: boolean): boolean {\r\n\t\tconst node = this.getTreeNode(location);\r\n\r\n\t\tif (typeof collapsed === 'undefined') {\r\n\t\t\tcollapsed = !node.collapsed;\r\n\t\t}\r\n\r\n\t\tconst update: CollapsedStateUpdate = { collapsed, recursive: recursive || false };\r\n\t\treturn this.eventBufferer.bufferEvents(() => this._setCollapseState(location, update));\r\n\t}\r\n\r\n\tprivate _setCollapseState(location: number[], update: CollapseStateUpdate): boolean {\r\n\t\tconst { node, listIndex, revealed } = this.getTreeNodeWithListIndex(location);\r\n\r\n\t\tconst result = this._setListNodeCollapseState(node, listIndex, revealed, update);\r\n\r\n\t\tif (node !== this.root && this.autoExpandSingleChildren && result && !isCollapsibleStateUpdate(update) && node.collapsible && !node.collapsed && !update.recursive) {\r\n\t\t\tlet onlyVisibleChildIndex = -1;\r\n\r\n\t\t\tfor (let i = 0; i < node.children.length; i++) {\r\n\t\t\t\tconst child = node.children[i];\r\n\r\n\t\t\t\tif (child.visible) {\r\n\t\t\t\t\tif (onlyVisibleChildIndex > -1) {\r\n\t\t\t\t\t\tonlyVisibleChildIndex = -1;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tonlyVisibleChildIndex = i;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (onlyVisibleChildIndex > -1) {\r\n\t\t\t\tthis._setCollapseState([...location, onlyVisibleChildIndex], update);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate _setListNodeCollapseState(node: IIndexTreeNode, listIndex: number, revealed: boolean, update: CollapseStateUpdate): boolean {\r\n\t\tconst result = this._setNodeCollapseState(node, update, false);\r\n\r\n\t\tif (!revealed || !node.visible || !result) {\r\n\t\t\treturn result;\r\n\t\t}\r\n\r\n\t\tconst previousRenderNodeCount = node.renderNodeCount;\r\n\t\tconst toInsert = this.updateNodeAfterCollapseChange(node);\r\n\t\tconst deleteCount = previousRenderNodeCount - (listIndex === -1 ? 0 : 1);\r\n\t\tthis.list.splice(listIndex + 1, deleteCount, toInsert.slice(1));\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate _setNodeCollapseState(node: IIndexTreeNode, update: CollapseStateUpdate, deep: boolean): boolean {\r\n\t\tlet result: boolean;\r\n\r\n\t\tif (node === this.root) {\r\n\t\t\tresult = false;\r\n\t\t} else {\r\n\t\t\tif (isCollapsibleStateUpdate(update)) {\r\n\t\t\t\tresult = node.collapsible !== update.collapsible;\r\n\t\t\t\tnode.collapsible = update.collapsible;\r\n\t\t\t} else if (!node.collapsible) {\r\n\t\t\t\tresult = false;\r\n\t\t\t} else {\r\n\t\t\t\tresult = node.collapsed !== update.collapsed;\r\n\t\t\t\tnode.collapsed = update.collapsed;\r\n\t\t\t}\r\n\r\n\t\t\tif (result) {\r\n\t\t\t\tthis._onDidChangeCollapseState.fire({ node, deep });\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!isCollapsibleStateUpdate(update) && update.recursive) {\r\n\t\t\tfor (const child of node.children) {\r\n\t\t\t\tresult = this._setNodeCollapseState(child, update, true) || result;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\texpandTo(location: number[]): void {\r\n\t\tthis.eventBufferer.bufferEvents(() => {\r\n\t\t\tlet node = this.getTreeNode(location);\r\n\r\n\t\t\twhile (node.parent) {\r\n\t\t\t\tnode = node.parent;\r\n\t\t\t\tlocation = location.slice(0, location.length - 1);\r\n\r\n\t\t\t\tif (node.collapsed) {\r\n\t\t\t\t\tthis._setCollapseState(location, { collapsed: false, recursive: false });\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\trefilter(): void {\r\n\t\tconst previousRenderNodeCount = this.root.renderNodeCount;\r\n\t\tconst toInsert = this.updateNodeAfterFilterChange(this.root);\r\n\t\tthis.list.splice(0, previousRenderNodeCount, toInsert);\r\n\t}\r\n\r\n\tprivate createTreeNode(\r\n\t\ttreeElement: ITreeElement,\r\n\t\tparent: IIndexTreeNode,\r\n\t\tparentVisibility: TreeVisibility,\r\n\t\trevealed: boolean,\r\n\t\ttreeListElements: ITreeNode[],\r\n\t\tonDidCreateNode?: (node: ITreeNode) => void\r\n\t): IIndexTreeNode {\r\n\t\tconst node: IIndexTreeNode = {\r\n\t\t\tparent,\r\n\t\t\telement: treeElement.element,\r\n\t\t\tchildren: [],\r\n\t\t\tdepth: parent.depth + 1,\r\n\t\t\tvisibleChildrenCount: 0,\r\n\t\t\tvisibleChildIndex: -1,\r\n\t\t\tcollapsible: typeof treeElement.collapsible === 'boolean' ? treeElement.collapsible : (typeof treeElement.collapsed !== 'undefined'),\r\n\t\t\tcollapsed: typeof treeElement.collapsed === 'undefined' ? this.collapseByDefault : treeElement.collapsed,\r\n\t\t\trenderNodeCount: 1,\r\n\t\t\tvisibility: TreeVisibility.Visible,\r\n\t\t\tvisible: true,\r\n\t\t\tfilterData: undefined\r\n\t\t};\r\n\r\n\t\tconst visibility = this._filterNode(node, parentVisibility);\r\n\t\tnode.visibility = visibility;\r\n\r\n\t\tif (revealed) {\r\n\t\t\ttreeListElements.push(node);\r\n\t\t}\r\n\r\n\t\tconst childElements = treeElement.children || Iterable.empty();\r\n\t\tconst childRevealed = revealed && visibility !== TreeVisibility.Hidden && !node.collapsed;\r\n\t\tconst childNodes = Iterable.map(childElements, el => this.createTreeNode(el, node, visibility, childRevealed, treeListElements, onDidCreateNode));\r\n\r\n\t\tlet visibleChildrenCount = 0;\r\n\t\tlet renderNodeCount = 1;\r\n\r\n\t\tfor (const child of childNodes) {\r\n\t\t\tnode.children.push(child);\r\n\t\t\trenderNodeCount += child.renderNodeCount;\r\n\r\n\t\t\tif (child.visible) {\r\n\t\t\t\tchild.visibleChildIndex = visibleChildrenCount++;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tnode.collapsible = node.collapsible || node.children.length > 0;\r\n\t\tnode.visibleChildrenCount = visibleChildrenCount;\r\n\t\tnode.visible = visibility === TreeVisibility.Recurse ? visibleChildrenCount > 0 : (visibility === TreeVisibility.Visible);\r\n\r\n\t\tif (!node.visible) {\r\n\t\t\tnode.renderNodeCount = 0;\r\n\r\n\t\t\tif (revealed) {\r\n\t\t\t\ttreeListElements.pop();\r\n\t\t\t}\r\n\t\t} else if (!node.collapsed) {\r\n\t\t\tnode.renderNodeCount = renderNodeCount;\r\n\t\t}\r\n\r\n\t\tif (onDidCreateNode) {\r\n\t\t\tonDidCreateNode(node);\r\n\t\t}\r\n\r\n\t\treturn node;\r\n\t}\r\n\r\n\tprivate updateNodeAfterCollapseChange(node: IIndexTreeNode): ITreeNode[] {\r\n\t\tconst previousRenderNodeCount = node.renderNodeCount;\r\n\t\tconst result: ITreeNode[] = [];\r\n\r\n\t\tthis._updateNodeAfterCollapseChange(node, result);\r\n\t\tthis._updateAncestorsRenderNodeCount(node.parent, result.length - previousRenderNodeCount);\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate _updateNodeAfterCollapseChange(node: IIndexTreeNode, result: ITreeNode[]): number {\r\n\t\tif (node.visible === false) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tresult.push(node);\r\n\t\tnode.renderNodeCount = 1;\r\n\r\n\t\tif (!node.collapsed) {\r\n\t\t\tfor (const child of node.children) {\r\n\t\t\t\tnode.renderNodeCount += this._updateNodeAfterCollapseChange(child, result);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._onDidChangeRenderNodeCount.fire(node);\r\n\t\treturn node.renderNodeCount;\r\n\t}\r\n\r\n\tprivate updateNodeAfterFilterChange(node: IIndexTreeNode): ITreeNode[] {\r\n\t\tconst previousRenderNodeCount = node.renderNodeCount;\r\n\t\tconst result: ITreeNode[] = [];\r\n\r\n\t\tthis._updateNodeAfterFilterChange(node, node.visible ? TreeVisibility.Visible : TreeVisibility.Hidden, result);\r\n\t\tthis._updateAncestorsRenderNodeCount(node.parent, result.length - previousRenderNodeCount);\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate _updateNodeAfterFilterChange(node: IIndexTreeNode, parentVisibility: TreeVisibility, result: ITreeNode[], revealed = true): boolean {\r\n\t\tlet visibility: TreeVisibility;\r\n\r\n\t\tif (node !== this.root) {\r\n\t\t\tvisibility = this._filterNode(node, parentVisibility);\r\n\r\n\t\t\tif (visibility === TreeVisibility.Hidden) {\r\n\t\t\t\tnode.visible = false;\r\n\t\t\t\tnode.renderNodeCount = 0;\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\tif (revealed) {\r\n\t\t\t\tresult.push(node);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst resultStartLength = result.length;\r\n\t\tnode.renderNodeCount = node === this.root ? 0 : 1;\r\n\r\n\t\tlet hasVisibleDescendants = false;\r\n\t\tif (!node.collapsed || visibility! !== TreeVisibility.Hidden) {\r\n\t\t\tlet visibleChildIndex = 0;\r\n\r\n\t\t\tfor (const child of node.children) {\r\n\t\t\t\thasVisibleDescendants = this._updateNodeAfterFilterChange(child, visibility!, result, revealed && !node.collapsed) || hasVisibleDescendants;\r\n\r\n\t\t\t\tif (child.visible) {\r\n\t\t\t\t\tchild.visibleChildIndex = visibleChildIndex++;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tnode.visibleChildrenCount = visibleChildIndex;\r\n\t\t} else {\r\n\t\t\tnode.visibleChildrenCount = 0;\r\n\t\t}\r\n\r\n\t\tif (node !== this.root) {\r\n\t\t\tnode.visible = visibility! === TreeVisibility.Recurse ? hasVisibleDescendants : (visibility! === TreeVisibility.Visible);\r\n\t\t}\r\n\r\n\t\tif (!node.visible) {\r\n\t\t\tnode.renderNodeCount = 0;\r\n\r\n\t\t\tif (revealed) {\r\n\t\t\t\tresult.pop();\r\n\t\t\t}\r\n\t\t} else if (!node.collapsed) {\r\n\t\t\tnode.renderNodeCount += result.length - resultStartLength;\r\n\t\t}\r\n\r\n\t\tthis._onDidChangeRenderNodeCount.fire(node);\r\n\t\treturn node.visible;\r\n\t}\r\n\r\n\tprivate _updateAncestorsRenderNodeCount(node: IIndexTreeNode | undefined, diff: number): void {\r\n\t\tif (diff === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\twhile (node) {\r\n\t\t\tnode.renderNodeCount += diff;\r\n\t\t\tthis._onDidChangeRenderNodeCount.fire(node);\r\n\t\t\tnode = node.parent;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _filterNode(node: IIndexTreeNode, parentVisibility: TreeVisibility): TreeVisibility {\r\n\t\tconst result = this.filter ? this.filter.filter(node.element, parentVisibility) : TreeVisibility.Visible;\r\n\r\n\t\tif (typeof result === 'boolean') {\r\n\t\t\tnode.filterData = undefined;\r\n\t\t\treturn result ? TreeVisibility.Visible : TreeVisibility.Hidden;\r\n\t\t} else if (isFilterResult(result)) {\r\n\t\t\tnode.filterData = result.data;\r\n\t\t\treturn getVisibleState(result.visibility);\r\n\t\t} else {\r\n\t\t\tnode.filterData = undefined;\r\n\t\t\treturn getVisibleState(result);\r\n\t\t}\r\n\t}\r\n\r\n\t// cheap\r\n\tprivate hasTreeNode(location: number[], node: IIndexTreeNode = this.root): boolean {\r\n\t\tif (!location || location.length === 0) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tconst [index, ...rest] = location;\r\n\r\n\t\tif (index < 0 || index > node.children.length) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\treturn this.hasTreeNode(rest, node.children[index]);\r\n\t}\r\n\r\n\t// cheap\r\n\tprivate getTreeNode(location: number[], node: IIndexTreeNode = this.root): IIndexTreeNode {\r\n\t\tif (!location || location.length === 0) {\r\n\t\t\treturn node;\r\n\t\t}\r\n\r\n\t\tconst [index, ...rest] = location;\r\n\r\n\t\tif (index < 0 || index > node.children.length) {\r\n\t\t\tthrow new TreeError(this.user, 'Invalid tree location');\r\n\t\t}\r\n\r\n\t\treturn this.getTreeNode(rest, node.children[index]);\r\n\t}\r\n\r\n\t// expensive\r\n\tprivate getTreeNodeWithListIndex(location: number[]): { node: IIndexTreeNode, listIndex: number, revealed: boolean, visible: boolean } {\r\n\t\tif (location.length === 0) {\r\n\t\t\treturn { node: this.root, listIndex: -1, revealed: true, visible: false };\r\n\t\t}\r\n\r\n\t\tconst { parentNode, listIndex, revealed, visible } = this.getParentNodeWithListIndex(location);\r\n\t\tconst index = location[location.length - 1];\r\n\r\n\t\tif (index < 0 || index > parentNode.children.length) {\r\n\t\t\tthrow new TreeError(this.user, 'Invalid tree location');\r\n\t\t}\r\n\r\n\t\tconst node = parentNode.children[index];\r\n\r\n\t\treturn { node, listIndex, revealed, visible: visible && node.visible };\r\n\t}\r\n\r\n\tprivate getParentNodeWithListIndex(location: number[], node: IIndexTreeNode = this.root, listIndex: number = 0, revealed = true, visible = true): { parentNode: IIndexTreeNode; listIndex: number; revealed: boolean; visible: boolean; } {\r\n\t\tconst [index, ...rest] = location;\r\n\r\n\t\tif (index < 0 || index > node.children.length) {\r\n\t\t\tthrow new TreeError(this.user, 'Invalid tree location');\r\n\t\t}\r\n\r\n\t\t// TODO@joao perf!\r\n\t\tfor (let i = 0; i < index; i++) {\r\n\t\t\tlistIndex += node.children[i].renderNodeCount;\r\n\t\t}\r\n\r\n\t\trevealed = revealed && !node.collapsed;\r\n\t\tvisible = visible && node.visible;\r\n\r\n\t\tif (rest.length === 0) {\r\n\t\t\treturn { parentNode: node, listIndex, revealed, visible };\r\n\t\t}\r\n\r\n\t\treturn this.getParentNodeWithListIndex(rest, node.children[index], listIndex + 1, revealed, visible);\r\n\t}\r\n\r\n\tgetNode(location: number[] = []): ITreeNode {\r\n\t\treturn this.getTreeNode(location);\r\n\t}\r\n\r\n\t// TODO@joao perf!\r\n\tgetNodeLocation(node: ITreeNode): number[] {\r\n\t\tconst location: number[] = [];\r\n\t\tlet indexTreeNode = node as IIndexTreeNode; // typing woes\r\n\r\n\t\twhile (indexTreeNode.parent) {\r\n\t\t\tlocation.push(indexTreeNode.parent.children.indexOf(indexTreeNode));\r\n\t\t\tindexTreeNode = indexTreeNode.parent;\r\n\t\t}\r\n\r\n\t\treturn location.reverse();\r\n\t}\r\n\r\n\tgetParentNodeLocation(location: number[]): number[] | undefined {\r\n\t\tif (location.length === 0) {\r\n\t\t\treturn undefined;\r\n\t\t} else if (location.length === 1) {\r\n\t\t\treturn [];\r\n\t\t} else {\r\n\t\t\treturn tail2(location)[0];\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Iterable } from 'vs/base/common/iterator';\r\nimport { IndexTreeModel, IIndexTreeModelOptions, IList, IIndexTreeModelSpliceOptions } from 'vs/base/browser/ui/tree/indexTreeModel';\r\nimport { Event } from 'vs/base/common/event';\r\nimport { ITreeModel, ITreeNode, ITreeElement, ITreeSorter, ICollapseStateChangeEvent, ITreeModelSpliceEvent, TreeError } from 'vs/base/browser/ui/tree/tree';\r\nimport { IIdentityProvider } from 'vs/base/browser/ui/list/list';\r\nimport { mergeSort } from 'vs/base/common/arrays';\r\n\r\nexport interface IObjectTreeModel, TFilterData extends NonNullable = void> extends ITreeModel {\r\n\tsetChildren(element: T | null, children: Iterable> | undefined, options?: IObjectTreeModelSetChildrenOptions): void;\r\n}\r\n\r\nexport interface IObjectTreeModelSetChildrenOptions extends IIndexTreeModelSpliceOptions {\r\n}\r\n\r\nexport interface IObjectTreeModelOptions extends IIndexTreeModelOptions {\r\n\treadonly sorter?: ITreeSorter;\r\n\treadonly identityProvider?: IIdentityProvider;\r\n}\r\n\r\nexport class ObjectTreeModel, TFilterData extends NonNullable = void> implements IObjectTreeModel {\r\n\r\n\treadonly rootRef = null;\r\n\r\n\tprivate model: IndexTreeModel;\r\n\tprivate nodes = new Map>();\r\n\tprivate readonly nodesByIdentity = new Map>();\r\n\tprivate readonly identityProvider?: IIdentityProvider;\r\n\tprivate sorter?: ITreeSorter<{ element: T; }>;\r\n\r\n\treadonly onDidSplice: Event>;\r\n\treadonly onDidChangeCollapseState: Event>;\r\n\treadonly onDidChangeRenderNodeCount: Event>;\r\n\r\n\tconstructor(\r\n\t\tprivate user: string,\r\n\t\tlist: IList>,\r\n\t\toptions: IObjectTreeModelOptions = {}\r\n\t) {\r\n\t\tthis.model = new IndexTreeModel(user, list, null, options);\r\n\t\tthis.onDidSplice = this.model.onDidSplice;\r\n\t\tthis.onDidChangeCollapseState = this.model.onDidChangeCollapseState as Event>;\r\n\t\tthis.onDidChangeRenderNodeCount = this.model.onDidChangeRenderNodeCount as Event>;\r\n\r\n\t\tif (options.sorter) {\r\n\t\t\tthis.sorter = {\r\n\t\t\t\tcompare(a, b) {\r\n\t\t\t\t\treturn options.sorter!.compare(a.element, b.element);\r\n\t\t\t\t}\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tthis.identityProvider = options.identityProvider;\r\n\t}\r\n\r\n\tsetChildren(\r\n\t\telement: T | null,\r\n\t\tchildren: Iterable> = Iterable.empty(),\r\n\t\toptions: IObjectTreeModelSetChildrenOptions = {},\r\n\t): void {\r\n\t\tconst location = this.getElementLocation(element);\r\n\t\tthis._setChildren(location, this.preserveCollapseState(children), options);\r\n\t}\r\n\r\n\tprivate _setChildren(\r\n\t\tlocation: number[],\r\n\t\tchildren: Iterable> = Iterable.empty(),\r\n\t\toptions: IObjectTreeModelSetChildrenOptions,\r\n\t): void {\r\n\t\tconst insertedElements = new Set();\r\n\t\tconst insertedElementIds = new Set();\r\n\r\n\t\tconst onDidCreateNode = (node: ITreeNode) => {\r\n\t\t\tif (node.element === null) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst tnode = node as ITreeNode;\r\n\r\n\t\t\tinsertedElements.add(tnode.element);\r\n\t\t\tthis.nodes.set(tnode.element, tnode);\r\n\r\n\t\t\tif (this.identityProvider) {\r\n\t\t\t\tconst id = this.identityProvider.getId(tnode.element).toString();\r\n\t\t\t\tinsertedElementIds.add(id);\r\n\t\t\t\tthis.nodesByIdentity.set(id, tnode);\r\n\t\t\t}\r\n\r\n\t\t\toptions.onDidCreateNode?.(tnode);\r\n\t\t};\r\n\r\n\t\tconst onDidDeleteNode = (node: ITreeNode) => {\r\n\t\t\tif (node.element === null) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst tnode = node as ITreeNode;\r\n\r\n\t\t\tif (!insertedElements.has(tnode.element)) {\r\n\t\t\t\tthis.nodes.delete(tnode.element);\r\n\t\t\t}\r\n\r\n\t\t\tif (this.identityProvider) {\r\n\t\t\t\tconst id = this.identityProvider.getId(tnode.element).toString();\r\n\t\t\t\tif (!insertedElementIds.has(id)) {\r\n\t\t\t\t\tthis.nodesByIdentity.delete(id);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\toptions.onDidDeleteNode?.(tnode);\r\n\t\t};\r\n\r\n\t\tthis.model.splice(\r\n\t\t\t[...location, 0],\r\n\t\t\tNumber.MAX_VALUE,\r\n\t\t\tchildren,\r\n\t\t\t{ ...options, onDidCreateNode, onDidDeleteNode }\r\n\t\t);\r\n\t}\r\n\r\n\tprivate preserveCollapseState(elements: Iterable> = Iterable.empty()): Iterable> {\r\n\t\tif (this.sorter) {\r\n\t\t\telements = mergeSort([...elements], this.sorter.compare.bind(this.sorter));\r\n\t\t}\r\n\r\n\t\treturn Iterable.map(elements, treeElement => {\r\n\t\t\tlet node = this.nodes.get(treeElement.element);\r\n\r\n\t\t\tif (!node && this.identityProvider) {\r\n\t\t\t\tconst id = this.identityProvider.getId(treeElement.element).toString();\r\n\t\t\t\tnode = this.nodesByIdentity.get(id);\r\n\t\t\t}\r\n\r\n\t\t\tif (!node) {\r\n\t\t\t\treturn {\r\n\t\t\t\t\t...treeElement,\r\n\t\t\t\t\tchildren: this.preserveCollapseState(treeElement.children)\r\n\t\t\t\t};\r\n\t\t\t}\r\n\r\n\t\t\tconst collapsible = typeof treeElement.collapsible === 'boolean' ? treeElement.collapsible : node.collapsible;\r\n\t\t\tconst collapsed = typeof treeElement.collapsed !== 'undefined' ? treeElement.collapsed : node.collapsed;\r\n\r\n\t\t\treturn {\r\n\t\t\t\t...treeElement,\r\n\t\t\t\tcollapsible,\r\n\t\t\t\tcollapsed,\r\n\t\t\t\tchildren: this.preserveCollapseState(treeElement.children)\r\n\t\t\t};\r\n\t\t});\r\n\t}\r\n\r\n\trerender(element: T | null): void {\r\n\t\tconst location = this.getElementLocation(element);\r\n\t\tthis.model.rerender(location);\r\n\t}\r\n\r\n\thas(element: T | null): boolean {\r\n\t\treturn this.nodes.has(element);\r\n\t}\r\n\r\n\tgetListIndex(element: T | null): number {\r\n\t\tconst location = this.getElementLocation(element);\r\n\t\treturn this.model.getListIndex(location);\r\n\t}\r\n\r\n\tgetListRenderCount(element: T | null): number {\r\n\t\tconst location = this.getElementLocation(element);\r\n\t\treturn this.model.getListRenderCount(location);\r\n\t}\r\n\r\n\tisCollapsible(element: T | null): boolean {\r\n\t\tconst location = this.getElementLocation(element);\r\n\t\treturn this.model.isCollapsible(location);\r\n\t}\r\n\r\n\tsetCollapsible(element: T | null, collapsible?: boolean): boolean {\r\n\t\tconst location = this.getElementLocation(element);\r\n\t\treturn this.model.setCollapsible(location, collapsible);\r\n\t}\r\n\r\n\tisCollapsed(element: T | null): boolean {\r\n\t\tconst location = this.getElementLocation(element);\r\n\t\treturn this.model.isCollapsed(location);\r\n\t}\r\n\r\n\tsetCollapsed(element: T | null, collapsed?: boolean, recursive?: boolean): boolean {\r\n\t\tconst location = this.getElementLocation(element);\r\n\t\treturn this.model.setCollapsed(location, collapsed, recursive);\r\n\t}\r\n\r\n\texpandTo(element: T | null): void {\r\n\t\tconst location = this.getElementLocation(element);\r\n\t\tthis.model.expandTo(location);\r\n\t}\r\n\r\n\trefilter(): void {\r\n\t\tthis.model.refilter();\r\n\t}\r\n\r\n\tgetNode(element: T | null = null): ITreeNode {\r\n\t\tif (element === null) {\r\n\t\t\treturn this.model.getNode(this.model.rootRef);\r\n\t\t}\r\n\r\n\t\tconst node = this.nodes.get(element);\r\n\r\n\t\tif (!node) {\r\n\t\t\tthrow new TreeError(this.user, `Tree element not found: ${element}`);\r\n\t\t}\r\n\r\n\t\treturn node;\r\n\t}\r\n\r\n\tgetNodeLocation(node: ITreeNode): T | null {\r\n\t\treturn node.element;\r\n\t}\r\n\r\n\tgetParentNodeLocation(element: T | null): T | null {\r\n\t\tif (element === null) {\r\n\t\t\tthrow new TreeError(this.user, `Invalid getParentNodeLocation call`);\r\n\t\t}\r\n\r\n\t\tconst node = this.nodes.get(element);\r\n\r\n\t\tif (!node) {\r\n\t\t\tthrow new TreeError(this.user, `Tree element not found: ${element}`);\r\n\t\t}\r\n\r\n\t\tconst location = this.model.getNodeLocation(node);\r\n\t\tconst parentLocation = this.model.getParentNodeLocation(location);\r\n\t\tconst parent = this.model.getNode(parentLocation);\r\n\r\n\t\treturn parent.element;\r\n\t}\r\n\r\n\tprivate getElementLocation(element: T | null): number[] {\r\n\t\tif (element === null) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tconst node = this.nodes.get(element);\r\n\r\n\t\tif (!node) {\r\n\t\t\tthrow new TreeError(this.user, `Tree element not found: ${element}`);\r\n\t\t}\r\n\r\n\t\treturn this.model.getNodeLocation(node);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Iterable } from 'vs/base/common/iterator';\r\nimport { Event } from 'vs/base/common/event';\r\nimport { ITreeModel, ITreeNode, ITreeElement, ICollapseStateChangeEvent, ITreeModelSpliceEvent, TreeError, TreeFilterResult, TreeVisibility, WeakMapper } from 'vs/base/browser/ui/tree/tree';\r\nimport { IObjectTreeModelOptions, ObjectTreeModel, IObjectTreeModel, IObjectTreeModelSetChildrenOptions } from 'vs/base/browser/ui/tree/objectTreeModel';\r\nimport { IIndexTreeModelSpliceOptions, IList } from 'vs/base/browser/ui/tree/indexTreeModel';\r\nimport { IIdentityProvider } from 'vs/base/browser/ui/list/list';\r\n\r\n// Exported only for test reasons, do not use directly\r\nexport interface ICompressedTreeElement extends ITreeElement {\r\n\treadonly children?: Iterable>;\r\n\treadonly incompressible?: boolean;\r\n}\r\n\r\n// Exported only for test reasons, do not use directly\r\nexport interface ICompressedTreeNode {\r\n\treadonly elements: T[];\r\n\treadonly incompressible: boolean;\r\n}\r\n\r\nfunction noCompress(element: ICompressedTreeElement): ITreeElement> {\r\n\tconst elements = [element.element];\r\n\tconst incompressible = element.incompressible || false;\r\n\r\n\treturn {\r\n\t\telement: { elements, incompressible },\r\n\t\tchildren: Iterable.map(Iterable.from(element.children), noCompress),\r\n\t\tcollapsible: element.collapsible,\r\n\t\tcollapsed: element.collapsed\r\n\t};\r\n}\r\n\r\n// Exported only for test reasons, do not use directly\r\nexport function compress(element: ICompressedTreeElement): ITreeElement> {\r\n\tconst elements = [element.element];\r\n\tconst incompressible = element.incompressible || false;\r\n\r\n\tlet childrenIterator: Iterable>;\r\n\tlet children: ICompressedTreeElement[];\r\n\r\n\twhile (true) {\r\n\t\t[children, childrenIterator] = Iterable.consume(Iterable.from(element.children), 2);\r\n\r\n\t\tif (children.length !== 1) {\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tif (children[0].incompressible) {\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\telement = children[0];\r\n\t\telements.push(element.element);\r\n\t}\r\n\r\n\treturn {\r\n\t\telement: { elements, incompressible },\r\n\t\tchildren: Iterable.map(Iterable.concat(children, childrenIterator), compress),\r\n\t\tcollapsible: element.collapsible,\r\n\t\tcollapsed: element.collapsed\r\n\t};\r\n}\r\n\r\nfunction _decompress(element: ITreeElement>, index = 0): ICompressedTreeElement {\r\n\tlet children: Iterable>;\r\n\r\n\tif (index < element.element.elements.length - 1) {\r\n\t\tchildren = [_decompress(element, index + 1)];\r\n\t} else {\r\n\t\tchildren = Iterable.map(Iterable.from(element.children), el => _decompress(el, 0));\r\n\t}\r\n\r\n\tif (index === 0 && element.element.incompressible) {\r\n\t\treturn {\r\n\t\t\telement: element.element.elements[index],\r\n\t\t\tchildren,\r\n\t\t\tincompressible: true,\r\n\t\t\tcollapsible: element.collapsible,\r\n\t\t\tcollapsed: element.collapsed\r\n\t\t};\r\n\t}\r\n\r\n\treturn {\r\n\t\telement: element.element.elements[index],\r\n\t\tchildren,\r\n\t\tcollapsible: element.collapsible,\r\n\t\tcollapsed: element.collapsed\r\n\t};\r\n}\r\n\r\n// Exported only for test reasons, do not use directly\r\nexport function decompress(element: ITreeElement>): ICompressedTreeElement {\r\n\treturn _decompress(element, 0);\r\n}\r\n\r\nfunction splice(treeElement: ICompressedTreeElement, element: T, children: Iterable>): ICompressedTreeElement {\r\n\tif (treeElement.element === element) {\r\n\t\treturn { ...treeElement, children };\r\n\t}\r\n\r\n\treturn { ...treeElement, children: Iterable.map(Iterable.from(treeElement.children), e => splice(e, element, children)) };\r\n}\r\n\r\ninterface ICompressedObjectTreeModelOptions extends IObjectTreeModelOptions, TFilterData> {\r\n\treadonly compressionEnabled?: boolean;\r\n}\r\n\r\nconst wrapIdentityProvider = (base: IIdentityProvider): IIdentityProvider> => ({\r\n\tgetId(node) {\r\n\t\treturn node.elements.map(e => base.getId(e).toString()).join('\\0');\r\n\t}\r\n});\r\n\r\n// Exported only for test reasons, do not use directly\r\nexport class CompressedObjectTreeModel, TFilterData extends NonNullable = void> implements ITreeModel | null, TFilterData, T | null> {\r\n\r\n\treadonly rootRef = null;\r\n\r\n\tget onDidSplice(): Event | null, TFilterData>> { return this.model.onDidSplice; }\r\n\tget onDidChangeCollapseState(): Event, TFilterData>> { return this.model.onDidChangeCollapseState; }\r\n\tget onDidChangeRenderNodeCount(): Event, TFilterData>> { return this.model.onDidChangeRenderNodeCount; }\r\n\r\n\tprivate model: ObjectTreeModel, TFilterData>;\r\n\tprivate nodes = new Map>();\r\n\tprivate enabled: boolean;\r\n\tprivate readonly identityProvider?: IIdentityProvider>;\r\n\r\n\tconstructor(\r\n\t\tprivate user: string,\r\n\t\tlist: IList, TFilterData>>,\r\n\t\toptions: ICompressedObjectTreeModelOptions = {}\r\n\t) {\r\n\t\tthis.model = new ObjectTreeModel(user, list, options);\r\n\t\tthis.enabled = typeof options.compressionEnabled === 'undefined' ? true : options.compressionEnabled;\r\n\t\tthis.identityProvider = options.identityProvider;\r\n\t}\r\n\r\n\tsetChildren(\r\n\t\telement: T | null,\r\n\t\tchildren: Iterable> = Iterable.empty(),\r\n\t\toptions: IObjectTreeModelSetChildrenOptions,\r\n\t): void {\r\n\t\t// Diffs must be deem, since the compression can affect nested elements.\r\n\t\t// @see https://github.com/microsoft/vscode/pull/114237#issuecomment-759425034\r\n\r\n\t\tconst diffIdentityProvider = options.diffIdentityProvider && wrapIdentityProvider(options.diffIdentityProvider);\r\n\t\tif (element === null) {\r\n\t\t\tconst compressedChildren = Iterable.map(children, this.enabled ? compress : noCompress);\r\n\t\t\tthis._setChildren(null, compressedChildren, { diffIdentityProvider, diffDepth: Infinity });\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst compressedNode = this.nodes.get(element);\r\n\r\n\t\tif (!compressedNode) {\r\n\t\t\tthrow new Error('Unknown compressed tree node');\r\n\t\t}\r\n\r\n\t\tconst node = this.model.getNode(compressedNode) as ITreeNode, TFilterData>;\r\n\t\tconst compressedParentNode = this.model.getParentNodeLocation(compressedNode);\r\n\t\tconst parent = this.model.getNode(compressedParentNode) as ITreeNode, TFilterData>;\r\n\r\n\t\tconst decompressedElement = decompress(node);\r\n\t\tconst splicedElement = splice(decompressedElement, element, children);\r\n\t\tconst recompressedElement = (this.enabled ? compress : noCompress)(splicedElement);\r\n\r\n\t\tconst parentChildren = parent.children\r\n\t\t\t.map(child => child === node ? recompressedElement : child);\r\n\r\n\t\tthis._setChildren(parent.element, parentChildren, {\r\n\t\t\tdiffIdentityProvider,\r\n\t\t\tdiffDepth: node.depth - parent.depth,\r\n\t\t});\r\n\t}\r\n\r\n\tsetCompressionEnabled(enabled: boolean): void {\r\n\t\tif (enabled === this.enabled) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.enabled = enabled;\r\n\r\n\t\tconst root = this.model.getNode();\r\n\t\tconst rootChildren = root.children as ITreeNode>[];\r\n\t\tconst decompressedRootChildren = Iterable.map(rootChildren, decompress);\r\n\t\tconst recompressedRootChildren = Iterable.map(decompressedRootChildren, enabled ? compress : noCompress);\r\n\r\n\t\t// it should be safe to always use deep diff mode here if an identity\r\n\t\t// provider is available, since we know the raw nodes are unchanged.\r\n\t\tthis._setChildren(null, recompressedRootChildren, {\r\n\t\t\tdiffIdentityProvider: this.identityProvider,\r\n\t\t\tdiffDepth: Infinity,\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _setChildren(\r\n\t\tnode: ICompressedTreeNode | null,\r\n\t\tchildren: Iterable>>,\r\n\t\toptions: IIndexTreeModelSpliceOptions, TFilterData>,\r\n\t): void {\r\n\t\tconst insertedElements = new Set();\r\n\t\tconst onDidCreateNode = (node: ITreeNode, TFilterData>) => {\r\n\t\t\tfor (const element of node.element.elements) {\r\n\t\t\t\tinsertedElements.add(element);\r\n\t\t\t\tthis.nodes.set(element, node.element);\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tconst onDidDeleteNode = (node: ITreeNode, TFilterData>) => {\r\n\t\t\tfor (const element of node.element.elements) {\r\n\t\t\t\tif (!insertedElements.has(element)) {\r\n\t\t\t\t\tthis.nodes.delete(element);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tthis.model.setChildren(node, children, { ...options, onDidCreateNode, onDidDeleteNode });\r\n\t}\r\n\r\n\thas(element: T | null): boolean {\r\n\t\treturn this.nodes.has(element);\r\n\t}\r\n\r\n\tgetListIndex(location: T | null): number {\r\n\t\tconst node = this.getCompressedNode(location);\r\n\t\treturn this.model.getListIndex(node);\r\n\t}\r\n\r\n\tgetListRenderCount(location: T | null): number {\r\n\t\tconst node = this.getCompressedNode(location);\r\n\t\treturn this.model.getListRenderCount(node);\r\n\t}\r\n\r\n\tgetNode(location?: T | null | undefined): ITreeNode | null, TFilterData> {\r\n\t\tif (typeof location === 'undefined') {\r\n\t\t\treturn this.model.getNode();\r\n\t\t}\r\n\r\n\t\tconst node = this.getCompressedNode(location);\r\n\t\treturn this.model.getNode(node);\r\n\t}\r\n\r\n\t// TODO: review this\r\n\tgetNodeLocation(node: ITreeNode, TFilterData>): T | null {\r\n\t\tconst compressedNode = this.model.getNodeLocation(node);\r\n\r\n\t\tif (compressedNode === null) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\treturn compressedNode.elements[compressedNode.elements.length - 1];\r\n\t}\r\n\r\n\t// TODO: review this\r\n\tgetParentNodeLocation(location: T | null): T | null {\r\n\t\tconst compressedNode = this.getCompressedNode(location);\r\n\t\tconst parentNode = this.model.getParentNodeLocation(compressedNode);\r\n\r\n\t\tif (parentNode === null) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\treturn parentNode.elements[parentNode.elements.length - 1];\r\n\t}\r\n\r\n\tisCollapsible(location: T | null): boolean {\r\n\t\tconst compressedNode = this.getCompressedNode(location);\r\n\t\treturn this.model.isCollapsible(compressedNode);\r\n\t}\r\n\r\n\tsetCollapsible(location: T | null, collapsible?: boolean): boolean {\r\n\t\tconst compressedNode = this.getCompressedNode(location);\r\n\t\treturn this.model.setCollapsible(compressedNode, collapsible);\r\n\t}\r\n\r\n\tisCollapsed(location: T | null): boolean {\r\n\t\tconst compressedNode = this.getCompressedNode(location);\r\n\t\treturn this.model.isCollapsed(compressedNode);\r\n\t}\r\n\r\n\tsetCollapsed(location: T | null, collapsed?: boolean | undefined, recursive?: boolean | undefined): boolean {\r\n\t\tconst compressedNode = this.getCompressedNode(location);\r\n\t\treturn this.model.setCollapsed(compressedNode, collapsed, recursive);\r\n\t}\r\n\r\n\texpandTo(location: T | null): void {\r\n\t\tconst compressedNode = this.getCompressedNode(location);\r\n\t\tthis.model.expandTo(compressedNode);\r\n\t}\r\n\r\n\trerender(location: T | null): void {\r\n\t\tconst compressedNode = this.getCompressedNode(location);\r\n\t\tthis.model.rerender(compressedNode);\r\n\t}\r\n\r\n\trefilter(): void {\r\n\t\tthis.model.refilter();\r\n\t}\r\n\r\n\tgetCompressedNode(element: T | null): ICompressedTreeNode | null {\r\n\t\tif (element === null) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst node = this.nodes.get(element);\r\n\r\n\t\tif (!node) {\r\n\t\t\tthrow new TreeError(this.user, `Tree element not found: ${element}`);\r\n\t\t}\r\n\r\n\t\treturn node;\r\n\t}\r\n}\r\n\r\n// Compressible Object Tree\r\n\r\nexport type ElementMapper = (elements: T[]) => T;\r\nexport const DefaultElementMapper: ElementMapper = elements => elements[elements.length - 1];\r\n\r\nexport type CompressedNodeUnwrapper = (node: ICompressedTreeNode) => T;\r\ntype CompressedNodeWeakMapper = WeakMapper | null, TFilterData>, ITreeNode>;\r\n\r\nclass CompressedTreeNodeWrapper implements ITreeNode {\r\n\r\n\tget element(): T | null { return this.node.element === null ? null : this.unwrapper(this.node.element); }\r\n\tget children(): ITreeNode[] { return this.node.children.map(node => new CompressedTreeNodeWrapper(this.unwrapper, node)); }\r\n\tget depth(): number { return this.node.depth; }\r\n\tget visibleChildrenCount(): number { return this.node.visibleChildrenCount; }\r\n\tget visibleChildIndex(): number { return this.node.visibleChildIndex; }\r\n\tget collapsible(): boolean { return this.node.collapsible; }\r\n\tget collapsed(): boolean { return this.node.collapsed; }\r\n\tget visible(): boolean { return this.node.visible; }\r\n\tget filterData(): TFilterData | undefined { return this.node.filterData; }\r\n\r\n\tconstructor(\r\n\t\tprivate unwrapper: CompressedNodeUnwrapper,\r\n\t\tprivate node: ITreeNode | null, TFilterData>\r\n\t) { }\r\n}\r\n\r\nfunction mapList(nodeMapper: CompressedNodeWeakMapper, list: IList>): IList, TFilterData>> {\r\n\treturn {\r\n\t\tsplice(start: number, deleteCount: number, toInsert: ITreeNode, TFilterData>[]): void {\r\n\t\t\tlist.splice(start, deleteCount, toInsert.map(node => nodeMapper.map(node)) as ITreeNode[]);\r\n\t\t},\r\n\t\tupdateElementHeight(index: number, height: number): void {\r\n\t\t\tlist.updateElementHeight(index, height);\r\n\t\t}\r\n\t};\r\n}\r\n\r\nfunction mapOptions(compressedNodeUnwrapper: CompressedNodeUnwrapper, options: ICompressibleObjectTreeModelOptions): ICompressedObjectTreeModelOptions {\r\n\treturn {\r\n\t\t...options,\r\n\t\tidentityProvider: options.identityProvider && {\r\n\t\t\tgetId(node: ICompressedTreeNode): { toString(): string; } {\r\n\t\t\t\treturn options.identityProvider!.getId(compressedNodeUnwrapper(node));\r\n\t\t\t}\r\n\t\t},\r\n\t\tsorter: options.sorter && {\r\n\t\t\tcompare(node: ICompressedTreeNode, otherNode: ICompressedTreeNode): number {\r\n\t\t\t\treturn options.sorter!.compare(node.elements[0], otherNode.elements[0]);\r\n\t\t\t}\r\n\t\t},\r\n\t\tfilter: options.filter && {\r\n\t\t\tfilter(node: ICompressedTreeNode, parentVisibility: TreeVisibility): TreeFilterResult {\r\n\t\t\t\treturn options.filter!.filter(compressedNodeUnwrapper(node), parentVisibility);\r\n\t\t\t}\r\n\t\t}\r\n\t};\r\n}\r\n\r\nexport interface ICompressibleObjectTreeModelOptions extends IObjectTreeModelOptions {\r\n\treadonly elementMapper?: ElementMapper;\r\n}\r\n\r\nexport class CompressibleObjectTreeModel, TFilterData extends NonNullable = void> implements IObjectTreeModel {\r\n\r\n\treadonly rootRef = null;\r\n\r\n\tget onDidSplice(): Event> {\r\n\t\treturn Event.map(this.model.onDidSplice, ({ insertedNodes, deletedNodes }) => ({\r\n\t\t\tinsertedNodes: insertedNodes.map(node => this.nodeMapper.map(node)),\r\n\t\t\tdeletedNodes: deletedNodes.map(node => this.nodeMapper.map(node)),\r\n\t\t}));\r\n\t}\r\n\r\n\tget onDidChangeCollapseState(): Event> {\r\n\t\treturn Event.map(this.model.onDidChangeCollapseState, ({ node, deep }) => ({\r\n\t\t\tnode: this.nodeMapper.map(node),\r\n\t\t\tdeep\r\n\t\t}));\r\n\t}\r\n\r\n\tget onDidChangeRenderNodeCount(): Event> {\r\n\t\treturn Event.map(this.model.onDidChangeRenderNodeCount, node => this.nodeMapper.map(node));\r\n\t}\r\n\r\n\tprivate elementMapper: ElementMapper;\r\n\tprivate nodeMapper: CompressedNodeWeakMapper;\r\n\tprivate model: CompressedObjectTreeModel;\r\n\r\n\tconstructor(\r\n\t\tuser: string,\r\n\t\tlist: IList>,\r\n\t\toptions: ICompressibleObjectTreeModelOptions = {}\r\n\t) {\r\n\t\tthis.elementMapper = options.elementMapper || DefaultElementMapper;\r\n\t\tconst compressedNodeUnwrapper: CompressedNodeUnwrapper = node => this.elementMapper(node.elements);\r\n\t\tthis.nodeMapper = new WeakMapper(node => new CompressedTreeNodeWrapper(compressedNodeUnwrapper, node));\r\n\r\n\t\tthis.model = new CompressedObjectTreeModel(user, mapList(this.nodeMapper, list), mapOptions(compressedNodeUnwrapper, options));\r\n\t}\r\n\r\n\tsetChildren(\r\n\t\telement: T | null,\r\n\t\tchildren: Iterable> = Iterable.empty(),\r\n\t\toptions: IObjectTreeModelSetChildrenOptions = {},\r\n\t): void {\r\n\t\tthis.model.setChildren(element, children, options);\r\n\t}\r\n\r\n\tsetCompressionEnabled(enabled: boolean): void {\r\n\t\tthis.model.setCompressionEnabled(enabled);\r\n\t}\r\n\r\n\thas(location: T | null): boolean {\r\n\t\treturn this.model.has(location);\r\n\t}\r\n\r\n\tgetListIndex(location: T | null): number {\r\n\t\treturn this.model.getListIndex(location);\r\n\t}\r\n\r\n\tgetListRenderCount(location: T | null): number {\r\n\t\treturn this.model.getListRenderCount(location);\r\n\t}\r\n\r\n\tgetNode(location?: T | null | undefined): ITreeNode {\r\n\t\treturn this.nodeMapper.map(this.model.getNode(location));\r\n\t}\r\n\r\n\tgetNodeLocation(node: ITreeNode): T | null {\r\n\t\treturn node.element;\r\n\t}\r\n\r\n\tgetParentNodeLocation(location: T | null): T | null {\r\n\t\treturn this.model.getParentNodeLocation(location);\r\n\t}\r\n\r\n\tisCollapsible(location: T | null): boolean {\r\n\t\treturn this.model.isCollapsible(location);\r\n\t}\r\n\r\n\tsetCollapsible(location: T | null, collapsed?: boolean): boolean {\r\n\t\treturn this.model.setCollapsible(location, collapsed);\r\n\t}\r\n\r\n\tisCollapsed(location: T | null): boolean {\r\n\t\treturn this.model.isCollapsed(location);\r\n\t}\r\n\r\n\tsetCollapsed(location: T | null, collapsed?: boolean | undefined, recursive?: boolean | undefined): boolean {\r\n\t\treturn this.model.setCollapsed(location, collapsed, recursive);\r\n\t}\r\n\r\n\texpandTo(location: T | null): void {\r\n\t\treturn this.model.expandTo(location);\r\n\t}\r\n\r\n\trerender(location: T | null): void {\r\n\t\treturn this.model.rerender(location);\r\n\t}\r\n\r\n\trefilter(): void {\r\n\t\treturn this.model.refilter();\r\n\t}\r\n\r\n\tgetCompressedTreeNode(location: T | null = null): ITreeNode | null, TFilterData> {\r\n\t\treturn this.model.getNode(location);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as strings from './strings';\r\n\r\nexport function buildReplaceStringWithCasePreserved(matches: string[] | null, pattern: string): string {\r\n\tif (matches && (matches[0] !== '')) {\r\n\t\tconst containsHyphens = validateSpecificSpecialCharacter(matches, pattern, '-');\r\n\t\tconst containsUnderscores = validateSpecificSpecialCharacter(matches, pattern, '_');\r\n\t\tif (containsHyphens && !containsUnderscores) {\r\n\t\t\treturn buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '-');\r\n\t\t} else if (!containsHyphens && containsUnderscores) {\r\n\t\t\treturn buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '_');\r\n\t\t}\r\n\t\tif (matches[0].toUpperCase() === matches[0]) {\r\n\t\t\treturn pattern.toUpperCase();\r\n\t\t} else if (matches[0].toLowerCase() === matches[0]) {\r\n\t\t\treturn pattern.toLowerCase();\r\n\t\t} else if (strings.containsUppercaseCharacter(matches[0][0]) && pattern.length > 0) {\r\n\t\t\treturn pattern[0].toUpperCase() + pattern.substr(1);\r\n\t\t} else {\r\n\t\t\t// we don't understand its pattern yet.\r\n\t\t\treturn pattern;\r\n\t\t}\r\n\t} else {\r\n\t\treturn pattern;\r\n\t}\r\n}\r\n\r\nfunction validateSpecificSpecialCharacter(matches: string[], pattern: string, specialCharacter: string): boolean {\r\n\tconst doesContainSpecialCharacter = matches[0].indexOf(specialCharacter) !== -1 && pattern.indexOf(specialCharacter) !== -1;\r\n\treturn doesContainSpecialCharacter && matches[0].split(specialCharacter).length === pattern.split(specialCharacter).length;\r\n}\r\n\r\nfunction buildReplaceStringForSpecificSpecialCharacter(matches: string[], pattern: string, specialCharacter: string): string {\r\n\tconst splitPatternAtSpecialCharacter = pattern.split(specialCharacter);\r\n\tconst splitMatchAtSpecialCharacter = matches[0].split(specialCharacter);\r\n\tlet replaceString: string = '';\r\n\tsplitPatternAtSpecialCharacter.forEach((splitValue, index) => {\r\n\t\treplaceString += buildReplaceStringWithCasePreserved([splitMatchAtSpecialCharacter[index]], splitValue) + specialCharacter;\r\n\t});\r\n\r\n\treturn replaceString.slice(0, -1);\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as strings from 'vs/base/common/strings';\r\n\r\nenum Severity {\r\n\tIgnore = 0,\r\n\tInfo = 1,\r\n\tWarning = 2,\r\n\tError = 3\r\n}\r\n\r\nnamespace Severity {\r\n\r\n\tconst _error = 'error';\r\n\tconst _warning = 'warning';\r\n\tconst _warn = 'warn';\r\n\tconst _info = 'info';\r\n\r\n\t/**\r\n\t * Parses 'error', 'warning', 'warn', 'info' in call casings\r\n\t * and falls back to ignore.\r\n\t */\r\n\texport function fromValue(value: string): Severity {\r\n\t\tif (!value) {\r\n\t\t\treturn Severity.Ignore;\r\n\t\t}\r\n\r\n\t\tif (strings.equalsIgnoreCase(_error, value)) {\r\n\t\t\treturn Severity.Error;\r\n\t\t}\r\n\r\n\t\tif (strings.equalsIgnoreCase(_warning, value) || strings.equalsIgnoreCase(_warn, value)) {\r\n\t\t\treturn Severity.Warning;\r\n\t\t}\r\n\r\n\t\tif (strings.equalsIgnoreCase(_info, value)) {\r\n\t\t\treturn Severity.Info;\r\n\t\t}\r\n\t\treturn Severity.Ignore;\r\n\t}\r\n}\r\n\r\nexport default Severity;\r\n","\r\n\r\n/**\r\n * @returns whether the provided parameter is a JavaScript Array or not.\r\n */\r\nexport function isArray(array: T | {}): array is T extends readonly any[] ? (unknown extends T ? never : readonly any[]) : any[] {\r\n\treturn Array.isArray(array);\r\n}\r\n\r\n/**\r\n * @returns whether the provided parameter is a JavaScript String or not.\r\n */\r\nexport function isString(str: any): str is string {\r\n\treturn (typeof str === 'string');\r\n}\r\n\r\n/**\r\n *\r\n * @returns whether the provided parameter is of type `object` but **not**\r\n *\t`null`, an `array`, a `regexp`, nor a `date`.\r\n */\r\nexport function isObject(obj: any): obj is Object {\r\n\t// The method can't do a type cast since there are type (like strings) which\r\n\t// are subclasses of any put not positvely matched by the function. Hence type\r\n\t// narrowing results in wrong results.\r\n\treturn typeof obj === 'object'\r\n\t\t&& obj !== null\r\n\t\t&& !Array.isArray(obj)\r\n\t\t&& !(obj instanceof RegExp)\r\n\t\t&& !(obj instanceof Date);\r\n}\r\n\r\n/**\r\n * In **contrast** to just checking `typeof` this will return `false` for `NaN`.\r\n * @returns whether the provided parameter is a JavaScript Number or not.\r\n */\r\nexport function isNumber(obj: any): obj is number {\r\n\treturn (typeof obj === 'number' && !isNaN(obj));\r\n}\r\n\r\n/**\r\n * @returns whether the provided parameter is a JavaScript Boolean or not.\r\n */\r\nexport function isBoolean(obj: any): obj is boolean {\r\n\treturn (obj === true || obj === false);\r\n}\r\n\r\n/**\r\n * @returns whether the provided parameter is undefined.\r\n */\r\nexport function isUndefined(obj: any): obj is undefined {\r\n\treturn (typeof obj === 'undefined');\r\n}\r\n\r\n/**\r\n * @returns whether the provided parameter is undefined or null.\r\n */\r\nexport function isUndefinedOrNull(obj: any): obj is undefined | null {\r\n\treturn (isUndefined(obj) || obj === null);\r\n}\r\n\r\n\r\nexport function assertType(condition: any, type?: string): asserts condition {\r\n\tif (!condition) {\r\n\t\tthrow new Error(type ? `Unexpected type, expected '${type}'` : 'Unexpected type');\r\n\t}\r\n}\r\n\r\n/**\r\n * Asserts that the argument passed in is neither undefined nor null.\r\n */\r\nexport function assertIsDefined(arg: T | null | undefined): T {\r\n\tif (isUndefinedOrNull(arg)) {\r\n\t\tthrow new Error('Assertion Failed: argument is undefined or null');\r\n\t}\r\n\r\n\treturn arg;\r\n}\r\n\r\n/**\r\n * @returns whether the provided parameter is a JavaScript Function or not.\r\n */\r\nexport function isFunction(obj: any): obj is Function {\r\n\treturn (typeof obj === 'function');\r\n}\r\n\r\nexport type TypeConstraint = string | Function;\r\n\r\nexport function validateConstraints(args: any[], constraints: Array): void {\r\n\tconst len = Math.min(args.length, constraints.length);\r\n\tfor (let i = 0; i < len; i++) {\r\n\t\tvalidateConstraint(args[i], constraints[i]);\r\n\t}\r\n}\r\n\r\nexport function validateConstraint(arg: any, constraint: TypeConstraint | undefined): void {\r\n\r\n\tif (isString(constraint)) {\r\n\t\tif (typeof arg !== constraint) {\r\n\t\t\tthrow new Error(`argument does not match constraint: typeof ${constraint}`);\r\n\t\t}\r\n\t} else if (isFunction(constraint)) {\r\n\t\ttry {\r\n\t\t\tif (arg instanceof constraint) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t} catch {\r\n\t\t\t// ignore\r\n\t\t}\r\n\t\tif (!isUndefinedOrNull(arg) && arg.constructor === constraint) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (constraint.length === 1 && constraint.call(undefined, arg) === true) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthrow new Error(`argument does not match one of these constraints: arg instanceof constraint, arg.constructor === constraint, nor constraint(arg) === true`);\r\n\t}\r\n}\r\n\r\nexport function getAllPropertyNames(obj: object): string[] {\r\n\tlet res: string[] = [];\r\n\tlet proto = Object.getPrototypeOf(obj);\r\n\twhile (Object.prototype !== proto) {\r\n\t\tres = res.concat(Object.getOwnPropertyNames(proto));\r\n\t\tproto = Object.getPrototypeOf(proto);\r\n\t}\r\n\treturn res;\r\n}\r\n\r\nexport function getAllMethodNames(obj: object): string[] {\r\n\tconst methods: string[] = [];\r\n\tfor (const prop of getAllPropertyNames(obj)) {\r\n\t\tif (typeof (obj as any)[prop] === 'function') {\r\n\t\t\tmethods.push(prop);\r\n\t\t}\r\n\t}\r\n\treturn methods;\r\n}\r\n\r\nexport function createProxyObject(methodNames: string[], invoke: (method: string, args: any[]) => any): T {\r\n\tconst createProxyMethod = (method: string): () => any => {\r\n\t\treturn function () {\r\n\t\t\tconst args = Array.prototype.slice.call(arguments, 0);\r\n\t\t\treturn invoke(method, args);\r\n\t\t};\r\n\t};\r\n\r\n\tlet result = {} as T;\r\n\tfor (const methodName of methodNames) {\r\n\t\t(result)[methodName] = createProxyMethod(methodName);\r\n\t}\r\n\treturn result;\r\n}\r\n\r\n/**\r\n * Converts null to undefined, passes all other values through.\r\n */\r\nexport function withNullAsUndefined(x: T | null): T | undefined {\r\n\treturn x === null ? undefined : x;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { isObject, isUndefinedOrNull, isArray } from 'vs/base/common/types';\r\n\r\nexport function deepClone(obj: T): T {\r\n\tif (!obj || typeof obj !== 'object') {\r\n\t\treturn obj;\r\n\t}\r\n\tif (obj instanceof RegExp) {\r\n\t\t// See https://github.com/microsoft/TypeScript/issues/10990\r\n\t\treturn obj as any;\r\n\t}\r\n\tconst result: any = Array.isArray(obj) ? [] : {};\r\n\tObject.keys(obj).forEach((key: string) => {\r\n\t\tif ((obj)[key] && typeof (obj)[key] === 'object') {\r\n\t\t\tresult[key] = deepClone((obj)[key]);\r\n\t\t} else {\r\n\t\t\tresult[key] = (obj)[key];\r\n\t\t}\r\n\t});\r\n\treturn result;\r\n}\r\n\r\nexport function deepFreeze(obj: T): T {\r\n\tif (!obj || typeof obj !== 'object') {\r\n\t\treturn obj;\r\n\t}\r\n\tconst stack: any[] = [obj];\r\n\twhile (stack.length > 0) {\r\n\t\tconst obj = stack.shift();\r\n\t\tObject.freeze(obj);\r\n\t\tfor (const key in obj) {\r\n\t\t\tif (_hasOwnProperty.call(obj, key)) {\r\n\t\t\t\tconst prop = obj[key];\r\n\t\t\t\tif (typeof prop === 'object' && !Object.isFrozen(prop)) {\r\n\t\t\t\t\tstack.push(prop);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn obj;\r\n}\r\n\r\nconst _hasOwnProperty = Object.prototype.hasOwnProperty;\r\n\r\nexport function cloneAndChange(obj: any, changer: (orig: any) => any): any {\r\n\treturn _cloneAndChange(obj, changer, new Set());\r\n}\r\n\r\nfunction _cloneAndChange(obj: any, changer: (orig: any) => any, seen: Set): any {\r\n\tif (isUndefinedOrNull(obj)) {\r\n\t\treturn obj;\r\n\t}\r\n\r\n\tconst changed = changer(obj);\r\n\tif (typeof changed !== 'undefined') {\r\n\t\treturn changed;\r\n\t}\r\n\r\n\tif (isArray(obj)) {\r\n\t\tconst r1: any[] = [];\r\n\t\tfor (const e of obj) {\r\n\t\t\tr1.push(_cloneAndChange(e, changer, seen));\r\n\t\t}\r\n\t\treturn r1;\r\n\t}\r\n\r\n\tif (isObject(obj)) {\r\n\t\tif (seen.has(obj)) {\r\n\t\t\tthrow new Error('Cannot clone recursive data-structure');\r\n\t\t}\r\n\t\tseen.add(obj);\r\n\t\tconst r2 = {};\r\n\t\tfor (let i2 in obj) {\r\n\t\t\tif (_hasOwnProperty.call(obj, i2)) {\r\n\t\t\t\t(r2 as any)[i2] = _cloneAndChange(obj[i2], changer, seen);\r\n\t\t\t}\r\n\t\t}\r\n\t\tseen.delete(obj);\r\n\t\treturn r2;\r\n\t}\r\n\r\n\treturn obj;\r\n}\r\n\r\n/**\r\n * Copies all properties of source into destination. The optional parameter \"overwrite\" allows to control\r\n * if existing properties on the destination should be overwritten or not. Defaults to true (overwrite).\r\n */\r\nexport function mixin(destination: any, source: any, overwrite: boolean = true): any {\r\n\tif (!isObject(destination)) {\r\n\t\treturn source;\r\n\t}\r\n\r\n\tif (isObject(source)) {\r\n\t\tObject.keys(source).forEach(key => {\r\n\t\t\tif (key in destination) {\r\n\t\t\t\tif (overwrite) {\r\n\t\t\t\t\tif (isObject(destination[key]) && isObject(source[key])) {\r\n\t\t\t\t\t\tmixin(destination[key], source[key], overwrite);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tdestination[key] = source[key];\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tdestination[key] = source[key];\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\treturn destination;\r\n}\r\n\r\nexport function equals(one: any, other: any): boolean {\r\n\tif (one === other) {\r\n\t\treturn true;\r\n\t}\r\n\tif (one === null || one === undefined || other === null || other === undefined) {\r\n\t\treturn false;\r\n\t}\r\n\tif (typeof one !== typeof other) {\r\n\t\treturn false;\r\n\t}\r\n\tif (typeof one !== 'object') {\r\n\t\treturn false;\r\n\t}\r\n\tif ((Array.isArray(one)) !== (Array.isArray(other))) {\r\n\t\treturn false;\r\n\t}\r\n\r\n\tlet i: number;\r\n\tlet key: string;\r\n\r\n\tif (Array.isArray(one)) {\r\n\t\tif (one.length !== other.length) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tfor (i = 0; i < one.length; i++) {\r\n\t\t\tif (!equals(one[i], other[i])) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\t} else {\r\n\t\tconst oneKeys: string[] = [];\r\n\r\n\t\tfor (key in one) {\r\n\t\t\toneKeys.push(key);\r\n\t\t}\r\n\t\toneKeys.sort();\r\n\t\tconst otherKeys: string[] = [];\r\n\t\tfor (key in other) {\r\n\t\t\totherKeys.push(key);\r\n\t\t}\r\n\t\totherKeys.sort();\r\n\t\tif (!equals(oneKeys, otherKeys)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tfor (i = 0; i < oneKeys.length; i++) {\r\n\t\t\tif (!equals(one[oneKeys[i]], other[oneKeys[i]])) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn true;\r\n}\r\n\r\nexport function getOrDefault(obj: T, fn: (obj: T) => R | undefined, defaultValue: R): R {\r\n\tconst result = fn(obj);\r\n\treturn typeof result === 'undefined' ? defaultValue : result;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nexport const enum Constants {\r\n\t/**\r\n\t * MAX SMI (SMall Integer) as defined in v8.\r\n\t * one bit is lost for boxing/unboxing flag.\r\n\t * one bit is lost for sign flag.\r\n\t * See https://thibaultlaurens.github.io/javascript/2013/04/29/how-the-v8-engine-works/#tagged-values\r\n\t */\r\n\tMAX_SAFE_SMALL_INTEGER = 1 << 30,\r\n\r\n\t/**\r\n\t * MIN SMI (SMall Integer) as defined in v8.\r\n\t * one bit is lost for boxing/unboxing flag.\r\n\t * one bit is lost for sign flag.\r\n\t * See https://thibaultlaurens.github.io/javascript/2013/04/29/how-the-v8-engine-works/#tagged-values\r\n\t */\r\n\tMIN_SAFE_SMALL_INTEGER = -(1 << 30),\r\n\r\n\t/**\r\n\t * Max unsigned integer that fits on 8 bits.\r\n\t */\r\n\tMAX_UINT_8 = 255, // 2^8 - 1\r\n\r\n\t/**\r\n\t * Max unsigned integer that fits on 16 bits.\r\n\t */\r\n\tMAX_UINT_16 = 65535, // 2^16 - 1\r\n\r\n\t/**\r\n\t * Max unsigned integer that fits on 32 bits.\r\n\t */\r\n\tMAX_UINT_32 = 4294967295, // 2^32 - 1\r\n\r\n\tUNICODE_SUPPLEMENTARY_PLANE_BEGIN = 0x010000\r\n}\r\n\r\nexport function toUint8(v: number): number {\r\n\tif (v < 0) {\r\n\t\treturn 0;\r\n\t}\r\n\tif (v > Constants.MAX_UINT_8) {\r\n\t\treturn Constants.MAX_UINT_8;\r\n\t}\r\n\treturn v | 0;\r\n}\r\n\r\nexport function toUint32(v: number): number {\r\n\tif (v < 0) {\r\n\t\treturn 0;\r\n\t}\r\n\tif (v > Constants.MAX_UINT_32) {\r\n\t\treturn Constants.MAX_UINT_32;\r\n\t}\r\n\treturn v | 0;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { isWindows } from 'vs/base/common/platform';\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport * as paths from 'vs/base/common/path';\r\n\r\nconst _schemePattern = /^\\w[\\w\\d+.-]*$/;\r\nconst _singleSlashStart = /^\\//;\r\nconst _doubleSlashStart = /^\\/\\//;\r\n\r\nfunction _validateUri(ret: URI, _strict?: boolean): void {\r\n\r\n\t// scheme, must be set\r\n\tif (!ret.scheme && _strict) {\r\n\t\tthrow new Error(`[UriError]: Scheme is missing: {scheme: \"\", authority: \"${ret.authority}\", path: \"${ret.path}\", query: \"${ret.query}\", fragment: \"${ret.fragment}\"}`);\r\n\t}\r\n\r\n\t// scheme, https://tools.ietf.org/html/rfc3986#section-3.1\r\n\t// ALPHA *( ALPHA / DIGIT / \"+\" / \"-\" / \".\" )\r\n\tif (ret.scheme && !_schemePattern.test(ret.scheme)) {\r\n\t\tthrow new Error('[UriError]: Scheme contains illegal characters.');\r\n\t}\r\n\r\n\t// path, http://tools.ietf.org/html/rfc3986#section-3.3\r\n\t// If a URI contains an authority component, then the path component\r\n\t// must either be empty or begin with a slash (\"/\") character. If a URI\r\n\t// does not contain an authority component, then the path cannot begin\r\n\t// with two slash characters (\"//\").\r\n\tif (ret.path) {\r\n\t\tif (ret.authority) {\r\n\t\t\tif (!_singleSlashStart.test(ret.path)) {\r\n\t\t\t\tthrow new Error('[UriError]: If a URI contains an authority component, then the path component must either be empty or begin with a slash (\"/\") character');\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tif (_doubleSlashStart.test(ret.path)) {\r\n\t\t\t\tthrow new Error('[UriError]: If a URI does not contain an authority component, then the path cannot begin with two slash characters (\"//\")');\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\n// for a while we allowed uris *without* schemes and this is the migration\r\n// for them, e.g. an uri without scheme and without strict-mode warns and falls\r\n// back to the file-scheme. that should cause the least carnage and still be a\r\n// clear warning\r\nfunction _schemeFix(scheme: string, _strict: boolean): string {\r\n\tif (!scheme && !_strict) {\r\n\t\treturn 'file';\r\n\t}\r\n\treturn scheme;\r\n}\r\n\r\n// implements a bit of https://tools.ietf.org/html/rfc3986#section-5\r\nfunction _referenceResolution(scheme: string, path: string): string {\r\n\r\n\t// the slash-character is our 'default base' as we don't\r\n\t// support constructing URIs relative to other URIs. This\r\n\t// also means that we alter and potentially break paths.\r\n\t// see https://tools.ietf.org/html/rfc3986#section-5.1.4\r\n\tswitch (scheme) {\r\n\t\tcase 'https':\r\n\t\tcase 'http':\r\n\t\tcase 'file':\r\n\t\t\tif (!path) {\r\n\t\t\t\tpath = _slash;\r\n\t\t\t} else if (path[0] !== _slash) {\r\n\t\t\t\tpath = _slash + path;\r\n\t\t\t}\r\n\t\t\tbreak;\r\n\t}\r\n\treturn path;\r\n}\r\n\r\nconst _empty = '';\r\nconst _slash = '/';\r\nconst _regexp = /^(([^:/?#]+?):)?(\\/\\/([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?/;\r\n\r\n/**\r\n * Uniform Resource Identifier (URI) http://tools.ietf.org/html/rfc3986.\r\n * This class is a simple parser which creates the basic component parts\r\n * (http://tools.ietf.org/html/rfc3986#section-3) with minimal validation\r\n * and encoding.\r\n *\r\n * ```txt\r\n * foo://example.com:8042/over/there?name=ferret#nose\r\n * \\_/ \\______________/\\_________/ \\_________/ \\__/\r\n * | | | | |\r\n * scheme authority path query fragment\r\n * | _____________________|__\r\n * / \\ / \\\r\n * urn:example:animal:ferret:nose\r\n * ```\r\n */\r\nexport class URI implements UriComponents {\r\n\r\n\tstatic isUri(thing: any): thing is URI {\r\n\t\tif (thing instanceof URI) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (!thing) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn typeof (thing).authority === 'string'\r\n\t\t\t&& typeof (thing).fragment === 'string'\r\n\t\t\t&& typeof (thing).path === 'string'\r\n\t\t\t&& typeof (thing).query === 'string'\r\n\t\t\t&& typeof (thing).scheme === 'string'\r\n\t\t\t&& typeof (thing).fsPath === 'string'\r\n\t\t\t&& typeof (thing).with === 'function'\r\n\t\t\t&& typeof (thing).toString === 'function';\r\n\t}\r\n\r\n\t/**\r\n\t * scheme is the 'http' part of 'http://www.msft.com/some/path?query#fragment'.\r\n\t * The part before the first colon.\r\n\t */\r\n\treadonly scheme: string;\r\n\r\n\t/**\r\n\t * authority is the 'www.msft.com' part of 'http://www.msft.com/some/path?query#fragment'.\r\n\t * The part between the first double slashes and the next slash.\r\n\t */\r\n\treadonly authority: string;\r\n\r\n\t/**\r\n\t * path is the '/some/path' part of 'http://www.msft.com/some/path?query#fragment'.\r\n\t */\r\n\treadonly path: string;\r\n\r\n\t/**\r\n\t * query is the 'query' part of 'http://www.msft.com/some/path?query#fragment'.\r\n\t */\r\n\treadonly query: string;\r\n\r\n\t/**\r\n\t * fragment is the 'fragment' part of 'http://www.msft.com/some/path?query#fragment'.\r\n\t */\r\n\treadonly fragment: string;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tprotected constructor(scheme: string, authority?: string, path?: string, query?: string, fragment?: string, _strict?: boolean);\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tprotected constructor(components: UriComponents);\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tprotected constructor(schemeOrData: string | UriComponents, authority?: string, path?: string, query?: string, fragment?: string, _strict: boolean = false) {\r\n\r\n\t\tif (typeof schemeOrData === 'object') {\r\n\t\t\tthis.scheme = schemeOrData.scheme || _empty;\r\n\t\t\tthis.authority = schemeOrData.authority || _empty;\r\n\t\t\tthis.path = schemeOrData.path || _empty;\r\n\t\t\tthis.query = schemeOrData.query || _empty;\r\n\t\t\tthis.fragment = schemeOrData.fragment || _empty;\r\n\t\t\t// no validation because it's this URI\r\n\t\t\t// that creates uri components.\r\n\t\t\t// _validateUri(this);\r\n\t\t} else {\r\n\t\t\tthis.scheme = _schemeFix(schemeOrData, _strict);\r\n\t\t\tthis.authority = authority || _empty;\r\n\t\t\tthis.path = _referenceResolution(this.scheme, path || _empty);\r\n\t\t\tthis.query = query || _empty;\r\n\t\t\tthis.fragment = fragment || _empty;\r\n\r\n\t\t\t_validateUri(this, _strict);\r\n\t\t}\r\n\t}\r\n\r\n\t// ---- filesystem path -----------------------\r\n\r\n\t/**\r\n\t * Returns a string representing the corresponding file system path of this URI.\r\n\t * Will handle UNC paths, normalizes windows drive letters to lower-case, and uses the\r\n\t * platform specific path separator.\r\n\t *\r\n\t * * Will *not* validate the path for invalid characters and semantics.\r\n\t * * Will *not* look at the scheme of this URI.\r\n\t * * The result shall *not* be used for display purposes but for accessing a file on disk.\r\n\t *\r\n\t *\r\n\t * The *difference* to `URI#path` is the use of the platform specific separator and the handling\r\n\t * of UNC paths. See the below sample of a file-uri with an authority (UNC path).\r\n\t *\r\n\t * ```ts\r\n\t\tconst u = URI.parse('file://server/c$/folder/file.txt')\r\n\t\tu.authority === 'server'\r\n\t\tu.path === '/shares/c$/file.txt'\r\n\t\tu.fsPath === '\\\\server\\c$\\folder\\file.txt'\r\n\t```\r\n\t *\r\n\t * Using `URI#path` to read a file (using fs-apis) would not be enough because parts of the path,\r\n\t * namely the server name, would be missing. Therefore `URI#fsPath` exists - it's sugar to ease working\r\n\t * with URIs that represent files on disk (`file` scheme).\r\n\t */\r\n\tget fsPath(): string {\r\n\t\t// if (this.scheme !== 'file') {\r\n\t\t// \tconsole.warn(`[UriError] calling fsPath with scheme ${this.scheme}`);\r\n\t\t// }\r\n\t\treturn uriToFsPath(this, false);\r\n\t}\r\n\r\n\t// ---- modify to new -------------------------\r\n\r\n\twith(change: { scheme?: string; authority?: string | null; path?: string | null; query?: string | null; fragment?: string | null }): URI {\r\n\r\n\t\tif (!change) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tlet { scheme, authority, path, query, fragment } = change;\r\n\t\tif (scheme === undefined) {\r\n\t\t\tscheme = this.scheme;\r\n\t\t} else if (scheme === null) {\r\n\t\t\tscheme = _empty;\r\n\t\t}\r\n\t\tif (authority === undefined) {\r\n\t\t\tauthority = this.authority;\r\n\t\t} else if (authority === null) {\r\n\t\t\tauthority = _empty;\r\n\t\t}\r\n\t\tif (path === undefined) {\r\n\t\t\tpath = this.path;\r\n\t\t} else if (path === null) {\r\n\t\t\tpath = _empty;\r\n\t\t}\r\n\t\tif (query === undefined) {\r\n\t\t\tquery = this.query;\r\n\t\t} else if (query === null) {\r\n\t\t\tquery = _empty;\r\n\t\t}\r\n\t\tif (fragment === undefined) {\r\n\t\t\tfragment = this.fragment;\r\n\t\t} else if (fragment === null) {\r\n\t\t\tfragment = _empty;\r\n\t\t}\r\n\r\n\t\tif (scheme === this.scheme\r\n\t\t\t&& authority === this.authority\r\n\t\t\t&& path === this.path\r\n\t\t\t&& query === this.query\r\n\t\t\t&& fragment === this.fragment) {\r\n\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\treturn new Uri(scheme, authority, path, query, fragment);\r\n\t}\r\n\r\n\t// ---- parse & validate ------------------------\r\n\r\n\t/**\r\n\t * Creates a new URI from a string, e.g. `http://www.msft.com/some/path`,\r\n\t * `file:///usr/home`, or `scheme:with/path`.\r\n\t *\r\n\t * @param value A string which represents an URI (see `URI#toString`).\r\n\t */\r\n\tstatic parse(value: string, _strict: boolean = false): URI {\r\n\t\tconst match = _regexp.exec(value);\r\n\t\tif (!match) {\r\n\t\t\treturn new Uri(_empty, _empty, _empty, _empty, _empty);\r\n\t\t}\r\n\t\treturn new Uri(\r\n\t\t\tmatch[2] || _empty,\r\n\t\t\tpercentDecode(match[4] || _empty),\r\n\t\t\tpercentDecode(match[5] || _empty),\r\n\t\t\tpercentDecode(match[7] || _empty),\r\n\t\t\tpercentDecode(match[9] || _empty),\r\n\t\t\t_strict\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * Creates a new URI from a file system path, e.g. `c:\\my\\files`,\r\n\t * `/usr/home`, or `\\\\server\\share\\some\\path`.\r\n\t *\r\n\t * The *difference* between `URI#parse` and `URI#file` is that the latter treats the argument\r\n\t * as path, not as stringified-uri. E.g. `URI.file(path)` is **not the same as**\r\n\t * `URI.parse('file://' + path)` because the path might contain characters that are\r\n\t * interpreted (# and ?). See the following sample:\r\n\t * ```ts\r\n\tconst good = URI.file('/coding/c#/project1');\r\n\tgood.scheme === 'file';\r\n\tgood.path === '/coding/c#/project1';\r\n\tgood.fragment === '';\r\n\tconst bad = URI.parse('file://' + '/coding/c#/project1');\r\n\tbad.scheme === 'file';\r\n\tbad.path === '/coding/c'; // path is now broken\r\n\tbad.fragment === '/project1';\r\n\t```\r\n\t *\r\n\t * @param path A file system path (see `URI#fsPath`)\r\n\t */\r\n\tstatic file(path: string): URI {\r\n\r\n\t\tlet authority = _empty;\r\n\r\n\t\t// normalize to fwd-slashes on windows,\r\n\t\t// on other systems bwd-slashes are valid\r\n\t\t// filename character, eg /f\\oo/ba\\r.txt\r\n\t\tif (isWindows) {\r\n\t\t\tpath = path.replace(/\\\\/g, _slash);\r\n\t\t}\r\n\r\n\t\t// check for authority as used in UNC shares\r\n\t\t// or use the path as given\r\n\t\tif (path[0] === _slash && path[1] === _slash) {\r\n\t\t\tconst idx = path.indexOf(_slash, 2);\r\n\t\t\tif (idx === -1) {\r\n\t\t\t\tauthority = path.substring(2);\r\n\t\t\t\tpath = _slash;\r\n\t\t\t} else {\r\n\t\t\t\tauthority = path.substring(2, idx);\r\n\t\t\t\tpath = path.substring(idx) || _slash;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn new Uri('file', authority, path, _empty, _empty);\r\n\t}\r\n\r\n\tstatic from(components: { scheme: string; authority?: string; path?: string; query?: string; fragment?: string }): URI {\r\n\t\treturn new Uri(\r\n\t\t\tcomponents.scheme,\r\n\t\t\tcomponents.authority,\r\n\t\t\tcomponents.path,\r\n\t\t\tcomponents.query,\r\n\t\t\tcomponents.fragment,\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * Join a URI path with path fragments and normalizes the resulting path.\r\n\t *\r\n\t * @param uri The input URI.\r\n\t * @param pathFragment The path fragment to add to the URI path.\r\n\t * @returns The resulting URI.\r\n\t */\r\n\tstatic joinPath(uri: URI, ...pathFragment: string[]): URI {\r\n\t\tif (!uri.path) {\r\n\t\t\tthrow new Error(`[UriError]: cannot call joinPath on URI without path`);\r\n\t\t}\r\n\t\tlet newPath: string;\r\n\t\tif (isWindows && uri.scheme === 'file') {\r\n\t\t\tnewPath = URI.file(paths.win32.join(uriToFsPath(uri, true), ...pathFragment)).path;\r\n\t\t} else {\r\n\t\t\tnewPath = paths.posix.join(uri.path, ...pathFragment);\r\n\t\t}\r\n\t\treturn uri.with({ path: newPath });\r\n\t}\r\n\r\n\t// ---- printing/externalize ---------------------------\r\n\r\n\t/**\r\n\t * Creates a string representation for this URI. It's guaranteed that calling\r\n\t * `URI.parse` with the result of this function creates an URI which is equal\r\n\t * to this URI.\r\n\t *\r\n\t * * The result shall *not* be used for display purposes but for externalization or transport.\r\n\t * * The result will be encoded using the percentage encoding and encoding happens mostly\r\n\t * ignore the scheme-specific encoding rules.\r\n\t *\r\n\t * @param skipEncoding Do not encode the result, default is `false`\r\n\t */\r\n\ttoString(skipEncoding: boolean = false): string {\r\n\t\treturn _asFormatted(this, skipEncoding);\r\n\t}\r\n\r\n\ttoJSON(): UriComponents {\r\n\t\treturn this;\r\n\t}\r\n\r\n\tstatic revive(data: UriComponents | URI): URI;\r\n\tstatic revive(data: UriComponents | URI | undefined): URI | undefined;\r\n\tstatic revive(data: UriComponents | URI | null): URI | null;\r\n\tstatic revive(data: UriComponents | URI | undefined | null): URI | undefined | null;\r\n\tstatic revive(data: UriComponents | URI | undefined | null): URI | undefined | null {\r\n\t\tif (!data) {\r\n\t\t\treturn data;\r\n\t\t} else if (data instanceof URI) {\r\n\t\t\treturn data;\r\n\t\t} else {\r\n\t\t\tconst result = new Uri(data);\r\n\t\t\tresult._formatted = (data).external;\r\n\t\t\tresult._fsPath = (data)._sep === _pathSepMarker ? (data).fsPath : null;\r\n\t\t\treturn result;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport interface UriComponents {\r\n\tscheme: string;\r\n\tauthority: string;\r\n\tpath: string;\r\n\tquery: string;\r\n\tfragment: string;\r\n}\r\n\r\ninterface UriState extends UriComponents {\r\n\t$mid: number;\r\n\texternal: string;\r\n\tfsPath: string;\r\n\t_sep: 1 | undefined;\r\n}\r\n\r\nconst _pathSepMarker = isWindows ? 1 : undefined;\r\n\r\n// This class exists so that URI is compatibile with vscode.Uri (API).\r\nclass Uri extends URI {\r\n\r\n\t_formatted: string | null = null;\r\n\t_fsPath: string | null = null;\r\n\r\n\tget fsPath(): string {\r\n\t\tif (!this._fsPath) {\r\n\t\t\tthis._fsPath = uriToFsPath(this, false);\r\n\t\t}\r\n\t\treturn this._fsPath;\r\n\t}\r\n\r\n\ttoString(skipEncoding: boolean = false): string {\r\n\t\tif (!skipEncoding) {\r\n\t\t\tif (!this._formatted) {\r\n\t\t\t\tthis._formatted = _asFormatted(this, false);\r\n\t\t\t}\r\n\t\t\treturn this._formatted;\r\n\t\t} else {\r\n\t\t\t// we don't cache that\r\n\t\t\treturn _asFormatted(this, true);\r\n\t\t}\r\n\t}\r\n\r\n\ttoJSON(): UriComponents {\r\n\t\tconst res = {\r\n\t\t\t$mid: 1\r\n\t\t};\r\n\t\t// cached state\r\n\t\tif (this._fsPath) {\r\n\t\t\tres.fsPath = this._fsPath;\r\n\t\t\tres._sep = _pathSepMarker;\r\n\t\t}\r\n\t\tif (this._formatted) {\r\n\t\t\tres.external = this._formatted;\r\n\t\t}\r\n\t\t// uri components\r\n\t\tif (this.path) {\r\n\t\t\tres.path = this.path;\r\n\t\t}\r\n\t\tif (this.scheme) {\r\n\t\t\tres.scheme = this.scheme;\r\n\t\t}\r\n\t\tif (this.authority) {\r\n\t\t\tres.authority = this.authority;\r\n\t\t}\r\n\t\tif (this.query) {\r\n\t\t\tres.query = this.query;\r\n\t\t}\r\n\t\tif (this.fragment) {\r\n\t\t\tres.fragment = this.fragment;\r\n\t\t}\r\n\t\treturn res;\r\n\t}\r\n}\r\n\r\n// reserved characters: https://tools.ietf.org/html/rfc3986#section-2.2\r\nconst encodeTable: { [ch: number]: string } = {\r\n\t[CharCode.Colon]: '%3A', // gen-delims\r\n\t[CharCode.Slash]: '%2F',\r\n\t[CharCode.QuestionMark]: '%3F',\r\n\t[CharCode.Hash]: '%23',\r\n\t[CharCode.OpenSquareBracket]: '%5B',\r\n\t[CharCode.CloseSquareBracket]: '%5D',\r\n\t[CharCode.AtSign]: '%40',\r\n\r\n\t[CharCode.ExclamationMark]: '%21', // sub-delims\r\n\t[CharCode.DollarSign]: '%24',\r\n\t[CharCode.Ampersand]: '%26',\r\n\t[CharCode.SingleQuote]: '%27',\r\n\t[CharCode.OpenParen]: '%28',\r\n\t[CharCode.CloseParen]: '%29',\r\n\t[CharCode.Asterisk]: '%2A',\r\n\t[CharCode.Plus]: '%2B',\r\n\t[CharCode.Comma]: '%2C',\r\n\t[CharCode.Semicolon]: '%3B',\r\n\t[CharCode.Equals]: '%3D',\r\n\r\n\t[CharCode.Space]: '%20',\r\n};\r\n\r\nfunction encodeURIComponentFast(uriComponent: string, allowSlash: boolean): string {\r\n\tlet res: string | undefined = undefined;\r\n\tlet nativeEncodePos = -1;\r\n\r\n\tfor (let pos = 0; pos < uriComponent.length; pos++) {\r\n\t\tconst code = uriComponent.charCodeAt(pos);\r\n\r\n\t\t// unreserved characters: https://tools.ietf.org/html/rfc3986#section-2.3\r\n\t\tif (\r\n\t\t\t(code >= CharCode.a && code <= CharCode.z)\r\n\t\t\t|| (code >= CharCode.A && code <= CharCode.Z)\r\n\t\t\t|| (code >= CharCode.Digit0 && code <= CharCode.Digit9)\r\n\t\t\t|| code === CharCode.Dash\r\n\t\t\t|| code === CharCode.Period\r\n\t\t\t|| code === CharCode.Underline\r\n\t\t\t|| code === CharCode.Tilde\r\n\t\t\t|| (allowSlash && code === CharCode.Slash)\r\n\t\t) {\r\n\t\t\t// check if we are delaying native encode\r\n\t\t\tif (nativeEncodePos !== -1) {\r\n\t\t\t\tres += encodeURIComponent(uriComponent.substring(nativeEncodePos, pos));\r\n\t\t\t\tnativeEncodePos = -1;\r\n\t\t\t}\r\n\t\t\t// check if we write into a new string (by default we try to return the param)\r\n\t\t\tif (res !== undefined) {\r\n\t\t\t\tres += uriComponent.charAt(pos);\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\t\t\t// encoding needed, we need to allocate a new string\r\n\t\t\tif (res === undefined) {\r\n\t\t\t\tres = uriComponent.substr(0, pos);\r\n\t\t\t}\r\n\r\n\t\t\t// check with default table first\r\n\t\t\tconst escaped = encodeTable[code];\r\n\t\t\tif (escaped !== undefined) {\r\n\r\n\t\t\t\t// check if we are delaying native encode\r\n\t\t\t\tif (nativeEncodePos !== -1) {\r\n\t\t\t\t\tres += encodeURIComponent(uriComponent.substring(nativeEncodePos, pos));\r\n\t\t\t\t\tnativeEncodePos = -1;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// append escaped variant to result\r\n\t\t\t\tres += escaped;\r\n\r\n\t\t\t} else if (nativeEncodePos === -1) {\r\n\t\t\t\t// use native encode only when needed\r\n\t\t\t\tnativeEncodePos = pos;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tif (nativeEncodePos !== -1) {\r\n\t\tres += encodeURIComponent(uriComponent.substring(nativeEncodePos));\r\n\t}\r\n\r\n\treturn res !== undefined ? res : uriComponent;\r\n}\r\n\r\nfunction encodeURIComponentMinimal(path: string): string {\r\n\tlet res: string | undefined = undefined;\r\n\tfor (let pos = 0; pos < path.length; pos++) {\r\n\t\tconst code = path.charCodeAt(pos);\r\n\t\tif (code === CharCode.Hash || code === CharCode.QuestionMark) {\r\n\t\t\tif (res === undefined) {\r\n\t\t\t\tres = path.substr(0, pos);\r\n\t\t\t}\r\n\t\t\tres += encodeTable[code];\r\n\t\t} else {\r\n\t\t\tif (res !== undefined) {\r\n\t\t\t\tres += path[pos];\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn res !== undefined ? res : path;\r\n}\r\n\r\n/**\r\n * Compute `fsPath` for the given uri\r\n */\r\nexport function uriToFsPath(uri: URI, keepDriveLetterCasing: boolean): string {\r\n\r\n\tlet value: string;\r\n\tif (uri.authority && uri.path.length > 1 && uri.scheme === 'file') {\r\n\t\t// unc path: file://shares/c$/far/boo\r\n\t\tvalue = `//${uri.authority}${uri.path}`;\r\n\t} else if (\r\n\t\turi.path.charCodeAt(0) === CharCode.Slash\r\n\t\t&& (uri.path.charCodeAt(1) >= CharCode.A && uri.path.charCodeAt(1) <= CharCode.Z || uri.path.charCodeAt(1) >= CharCode.a && uri.path.charCodeAt(1) <= CharCode.z)\r\n\t\t&& uri.path.charCodeAt(2) === CharCode.Colon\r\n\t) {\r\n\t\tif (!keepDriveLetterCasing) {\r\n\t\t\t// windows drive letter: file:///c:/far/boo\r\n\t\t\tvalue = uri.path[1].toLowerCase() + uri.path.substr(2);\r\n\t\t} else {\r\n\t\t\tvalue = uri.path.substr(1);\r\n\t\t}\r\n\t} else {\r\n\t\t// other path\r\n\t\tvalue = uri.path;\r\n\t}\r\n\tif (isWindows) {\r\n\t\tvalue = value.replace(/\\//g, '\\\\');\r\n\t}\r\n\treturn value;\r\n}\r\n\r\n/**\r\n * Create the external version of a uri\r\n */\r\nfunction _asFormatted(uri: URI, skipEncoding: boolean): string {\r\n\r\n\tconst encoder = !skipEncoding\r\n\t\t? encodeURIComponentFast\r\n\t\t: encodeURIComponentMinimal;\r\n\r\n\tlet res = '';\r\n\tlet { scheme, authority, path, query, fragment } = uri;\r\n\tif (scheme) {\r\n\t\tres += scheme;\r\n\t\tres += ':';\r\n\t}\r\n\tif (authority || scheme === 'file') {\r\n\t\tres += _slash;\r\n\t\tres += _slash;\r\n\t}\r\n\tif (authority) {\r\n\t\tlet idx = authority.indexOf('@');\r\n\t\tif (idx !== -1) {\r\n\t\t\t// @\r\n\t\t\tconst userinfo = authority.substr(0, idx);\r\n\t\t\tauthority = authority.substr(idx + 1);\r\n\t\t\tidx = userinfo.indexOf(':');\r\n\t\t\tif (idx === -1) {\r\n\t\t\t\tres += encoder(userinfo, false);\r\n\t\t\t} else {\r\n\t\t\t\t// :@\r\n\t\t\t\tres += encoder(userinfo.substr(0, idx), false);\r\n\t\t\t\tres += ':';\r\n\t\t\t\tres += encoder(userinfo.substr(idx + 1), false);\r\n\t\t\t}\r\n\t\t\tres += '@';\r\n\t\t}\r\n\t\tauthority = authority.toLowerCase();\r\n\t\tidx = authority.indexOf(':');\r\n\t\tif (idx === -1) {\r\n\t\t\tres += encoder(authority, false);\r\n\t\t} else {\r\n\t\t\t// :\r\n\t\t\tres += encoder(authority.substr(0, idx), false);\r\n\t\t\tres += authority.substr(idx);\r\n\t\t}\r\n\t}\r\n\tif (path) {\r\n\t\t// lower-case windows drive letters in /C:/fff or C:/fff\r\n\t\tif (path.length >= 3 && path.charCodeAt(0) === CharCode.Slash && path.charCodeAt(2) === CharCode.Colon) {\r\n\t\t\tconst code = path.charCodeAt(1);\r\n\t\t\tif (code >= CharCode.A && code <= CharCode.Z) {\r\n\t\t\t\tpath = `/${String.fromCharCode(code + 32)}:${path.substr(3)}`; // \"/c:\".length === 3\r\n\t\t\t}\r\n\t\t} else if (path.length >= 2 && path.charCodeAt(1) === CharCode.Colon) {\r\n\t\t\tconst code = path.charCodeAt(0);\r\n\t\t\tif (code >= CharCode.A && code <= CharCode.Z) {\r\n\t\t\t\tpath = `${String.fromCharCode(code + 32)}:${path.substr(2)}`; // \"/c:\".length === 3\r\n\t\t\t}\r\n\t\t}\r\n\t\t// encode the rest of the path\r\n\t\tres += encoder(path, true);\r\n\t}\r\n\tif (query) {\r\n\t\tres += '?';\r\n\t\tres += encoder(query, false);\r\n\t}\r\n\tif (fragment) {\r\n\t\tres += '#';\r\n\t\tres += !skipEncoding ? encodeURIComponentFast(fragment, false) : fragment;\r\n\t}\r\n\treturn res;\r\n}\r\n\r\n// --- decode\r\n\r\nfunction decodeURIComponentGraceful(str: string): string {\r\n\ttry {\r\n\t\treturn decodeURIComponent(str);\r\n\t} catch {\r\n\t\tif (str.length > 3) {\r\n\t\t\treturn str.substr(0, 3) + decodeURIComponentGraceful(str.substr(3));\r\n\t\t} else {\r\n\t\t\treturn str;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nconst _rEncodedAsHex = /(%[0-9A-Za-z][0-9A-Za-z])+/g;\r\n\r\nfunction percentDecode(str: string): string {\r\n\tif (!str.match(_rEncodedAsHex)) {\r\n\t\treturn str;\r\n\t}\r\n\treturn str.replace(_rEncodedAsHex, (match) => decodeURIComponentGraceful(match));\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport { compareSubstringIgnoreCase, compare, compareSubstring, compareIgnoreCase } from 'vs/base/common/strings';\r\n\r\nexport interface IKeyIterator {\r\n\treset(key: K): this;\r\n\tnext(): this;\r\n\r\n\thasNext(): boolean;\r\n\tcmp(a: string): number;\r\n\tvalue(): string;\r\n}\r\n\r\nexport class StringIterator implements IKeyIterator {\r\n\r\n\tprivate _value: string = '';\r\n\tprivate _pos: number = 0;\r\n\r\n\treset(key: string): this {\r\n\t\tthis._value = key;\r\n\t\tthis._pos = 0;\r\n\t\treturn this;\r\n\t}\r\n\r\n\tnext(): this {\r\n\t\tthis._pos += 1;\r\n\t\treturn this;\r\n\t}\r\n\r\n\thasNext(): boolean {\r\n\t\treturn this._pos < this._value.length - 1;\r\n\t}\r\n\r\n\tcmp(a: string): number {\r\n\t\tconst aCode = a.charCodeAt(0);\r\n\t\tconst thisCode = this._value.charCodeAt(this._pos);\r\n\t\treturn aCode - thisCode;\r\n\t}\r\n\r\n\tvalue(): string {\r\n\t\treturn this._value[this._pos];\r\n\t}\r\n}\r\n\r\nexport class ConfigKeysIterator implements IKeyIterator {\r\n\r\n\tprivate _value!: string;\r\n\tprivate _from!: number;\r\n\tprivate _to!: number;\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _caseSensitive: boolean = true\r\n\t) { }\r\n\r\n\treset(key: string): this {\r\n\t\tthis._value = key;\r\n\t\tthis._from = 0;\r\n\t\tthis._to = 0;\r\n\t\treturn this.next();\r\n\t}\r\n\r\n\thasNext(): boolean {\r\n\t\treturn this._to < this._value.length;\r\n\t}\r\n\r\n\tnext(): this {\r\n\t\t// this._data = key.split(/[\\\\/]/).filter(s => !!s);\r\n\t\tthis._from = this._to;\r\n\t\tlet justSeps = true;\r\n\t\tfor (; this._to < this._value.length; this._to++) {\r\n\t\t\tconst ch = this._value.charCodeAt(this._to);\r\n\t\t\tif (ch === CharCode.Period) {\r\n\t\t\t\tif (justSeps) {\r\n\t\t\t\t\tthis._from++;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tjustSeps = false;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this;\r\n\t}\r\n\r\n\tcmp(a: string): number {\r\n\t\treturn this._caseSensitive\r\n\t\t\t? compareSubstring(a, this._value, 0, a.length, this._from, this._to)\r\n\t\t\t: compareSubstringIgnoreCase(a, this._value, 0, a.length, this._from, this._to);\r\n\t}\r\n\r\n\tvalue(): string {\r\n\t\treturn this._value.substring(this._from, this._to);\r\n\t}\r\n}\r\n\r\nexport class PathIterator implements IKeyIterator {\r\n\r\n\tprivate _value!: string;\r\n\tprivate _from!: number;\r\n\tprivate _to!: number;\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _splitOnBackslash: boolean = true,\r\n\t\tprivate readonly _caseSensitive: boolean = true\r\n\t) { }\r\n\r\n\treset(key: string): this {\r\n\t\tthis._value = key.replace(/\\\\$|\\/$/, '');\r\n\t\tthis._from = 0;\r\n\t\tthis._to = 0;\r\n\t\treturn this.next();\r\n\t}\r\n\r\n\thasNext(): boolean {\r\n\t\treturn this._to < this._value.length;\r\n\t}\r\n\r\n\tnext(): this {\r\n\t\t// this._data = key.split(/[\\\\/]/).filter(s => !!s);\r\n\t\tthis._from = this._to;\r\n\t\tlet justSeps = true;\r\n\t\tfor (; this._to < this._value.length; this._to++) {\r\n\t\t\tconst ch = this._value.charCodeAt(this._to);\r\n\t\t\tif (ch === CharCode.Slash || this._splitOnBackslash && ch === CharCode.Backslash) {\r\n\t\t\t\tif (justSeps) {\r\n\t\t\t\t\tthis._from++;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tjustSeps = false;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this;\r\n\t}\r\n\r\n\tcmp(a: string): number {\r\n\t\treturn this._caseSensitive\r\n\t\t\t? compareSubstring(a, this._value, 0, a.length, this._from, this._to)\r\n\t\t\t: compareSubstringIgnoreCase(a, this._value, 0, a.length, this._from, this._to);\r\n\t}\r\n\r\n\tvalue(): string {\r\n\t\treturn this._value.substring(this._from, this._to);\r\n\t}\r\n}\r\n\r\nconst enum UriIteratorState {\r\n\tScheme = 1, Authority = 2, Path = 3, Query = 4, Fragment = 5\r\n}\r\n\r\nexport class UriIterator implements IKeyIterator {\r\n\r\n\tprivate _pathIterator!: PathIterator;\r\n\tprivate _value!: URI;\r\n\tprivate _states: UriIteratorState[] = [];\r\n\tprivate _stateIdx: number = 0;\r\n\r\n\tconstructor(private readonly _ignorePathCasing: (uri: URI) => boolean) { }\r\n\r\n\treset(key: URI): this {\r\n\t\tthis._value = key;\r\n\t\tthis._states = [];\r\n\t\tif (this._value.scheme) {\r\n\t\t\tthis._states.push(UriIteratorState.Scheme);\r\n\t\t}\r\n\t\tif (this._value.authority) {\r\n\t\t\tthis._states.push(UriIteratorState.Authority);\r\n\t\t}\r\n\t\tif (this._value.path) {\r\n\t\t\tthis._pathIterator = new PathIterator(false, !this._ignorePathCasing(key));\r\n\t\t\tthis._pathIterator.reset(key.path);\r\n\t\t\tif (this._pathIterator.value()) {\r\n\t\t\t\tthis._states.push(UriIteratorState.Path);\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (this._value.query) {\r\n\t\t\tthis._states.push(UriIteratorState.Query);\r\n\t\t}\r\n\t\tif (this._value.fragment) {\r\n\t\t\tthis._states.push(UriIteratorState.Fragment);\r\n\t\t}\r\n\t\tthis._stateIdx = 0;\r\n\t\treturn this;\r\n\t}\r\n\r\n\tnext(): this {\r\n\t\tif (this._states[this._stateIdx] === UriIteratorState.Path && this._pathIterator.hasNext()) {\r\n\t\t\tthis._pathIterator.next();\r\n\t\t} else {\r\n\t\t\tthis._stateIdx += 1;\r\n\t\t}\r\n\t\treturn this;\r\n\t}\r\n\r\n\thasNext(): boolean {\r\n\t\treturn (this._states[this._stateIdx] === UriIteratorState.Path && this._pathIterator.hasNext())\r\n\t\t\t|| this._stateIdx < this._states.length - 1;\r\n\t}\r\n\r\n\tcmp(a: string): number {\r\n\t\tif (this._states[this._stateIdx] === UriIteratorState.Scheme) {\r\n\t\t\treturn compareIgnoreCase(a, this._value.scheme);\r\n\t\t} else if (this._states[this._stateIdx] === UriIteratorState.Authority) {\r\n\t\t\treturn compareIgnoreCase(a, this._value.authority);\r\n\t\t} else if (this._states[this._stateIdx] === UriIteratorState.Path) {\r\n\t\t\treturn this._pathIterator.cmp(a);\r\n\t\t} else if (this._states[this._stateIdx] === UriIteratorState.Query) {\r\n\t\t\treturn compare(a, this._value.query);\r\n\t\t} else if (this._states[this._stateIdx] === UriIteratorState.Fragment) {\r\n\t\t\treturn compare(a, this._value.fragment);\r\n\t\t}\r\n\t\tthrow new Error();\r\n\t}\r\n\r\n\tvalue(): string {\r\n\t\tif (this._states[this._stateIdx] === UriIteratorState.Scheme) {\r\n\t\t\treturn this._value.scheme;\r\n\t\t} else if (this._states[this._stateIdx] === UriIteratorState.Authority) {\r\n\t\t\treturn this._value.authority;\r\n\t\t} else if (this._states[this._stateIdx] === UriIteratorState.Path) {\r\n\t\t\treturn this._pathIterator.value();\r\n\t\t} else if (this._states[this._stateIdx] === UriIteratorState.Query) {\r\n\t\t\treturn this._value.query;\r\n\t\t} else if (this._states[this._stateIdx] === UriIteratorState.Fragment) {\r\n\t\t\treturn this._value.fragment;\r\n\t\t}\r\n\t\tthrow new Error();\r\n\t}\r\n}\r\n\r\nclass TernarySearchTreeNode {\r\n\tsegment!: string;\r\n\tvalue: V | undefined;\r\n\tkey!: K;\r\n\tleft: TernarySearchTreeNode | undefined;\r\n\tmid: TernarySearchTreeNode | undefined;\r\n\tright: TernarySearchTreeNode | undefined;\r\n\r\n\tisEmpty(): boolean {\r\n\t\treturn !this.left && !this.mid && !this.right && !this.value;\r\n\t}\r\n}\r\n\r\nexport class TernarySearchTree {\r\n\r\n\tstatic forUris(ignorePathCasing: (key: URI) => boolean = () => false): TernarySearchTree {\r\n\t\treturn new TernarySearchTree(new UriIterator(ignorePathCasing));\r\n\t}\r\n\r\n\tstatic forStrings(): TernarySearchTree {\r\n\t\treturn new TernarySearchTree(new StringIterator());\r\n\t}\r\n\r\n\tstatic forConfigKeys(): TernarySearchTree {\r\n\t\treturn new TernarySearchTree(new ConfigKeysIterator());\r\n\t}\r\n\r\n\tprivate _iter: IKeyIterator;\r\n\tprivate _root: TernarySearchTreeNode | undefined;\r\n\r\n\tconstructor(segments: IKeyIterator) {\r\n\t\tthis._iter = segments;\r\n\t}\r\n\r\n\tclear(): void {\r\n\t\tthis._root = undefined;\r\n\t}\r\n\r\n\tset(key: K, element: V): V | undefined {\r\n\t\tconst iter = this._iter.reset(key);\r\n\t\tlet node: TernarySearchTreeNode;\r\n\r\n\t\tif (!this._root) {\r\n\t\t\tthis._root = new TernarySearchTreeNode();\r\n\t\t\tthis._root.segment = iter.value();\r\n\t\t}\r\n\r\n\t\tnode = this._root;\r\n\t\twhile (true) {\r\n\t\t\tconst val = iter.cmp(node.segment);\r\n\t\t\tif (val > 0) {\r\n\t\t\t\t// left\r\n\t\t\t\tif (!node.left) {\r\n\t\t\t\t\tnode.left = new TernarySearchTreeNode();\r\n\t\t\t\t\tnode.left.segment = iter.value();\r\n\t\t\t\t}\r\n\t\t\t\tnode = node.left;\r\n\r\n\t\t\t} else if (val < 0) {\r\n\t\t\t\t// right\r\n\t\t\t\tif (!node.right) {\r\n\t\t\t\t\tnode.right = new TernarySearchTreeNode();\r\n\t\t\t\t\tnode.right.segment = iter.value();\r\n\t\t\t\t}\r\n\t\t\t\tnode = node.right;\r\n\r\n\t\t\t} else if (iter.hasNext()) {\r\n\t\t\t\t// mid\r\n\t\t\t\titer.next();\r\n\t\t\t\tif (!node.mid) {\r\n\t\t\t\t\tnode.mid = new TernarySearchTreeNode();\r\n\t\t\t\t\tnode.mid.segment = iter.value();\r\n\t\t\t\t}\r\n\t\t\t\tnode = node.mid;\r\n\t\t\t} else {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t\tconst oldElement = node.value;\r\n\t\tnode.value = element;\r\n\t\tnode.key = key;\r\n\t\treturn oldElement;\r\n\t}\r\n\r\n\tget(key: K): V | undefined {\r\n\t\treturn this._getNode(key)?.value;\r\n\t}\r\n\r\n\tprivate _getNode(key: K) {\r\n\t\tconst iter = this._iter.reset(key);\r\n\t\tlet node = this._root;\r\n\t\twhile (node) {\r\n\t\t\tconst val = iter.cmp(node.segment);\r\n\t\t\tif (val > 0) {\r\n\t\t\t\t// left\r\n\t\t\t\tnode = node.left;\r\n\t\t\t} else if (val < 0) {\r\n\t\t\t\t// right\r\n\t\t\t\tnode = node.right;\r\n\t\t\t} else if (iter.hasNext()) {\r\n\t\t\t\t// mid\r\n\t\t\t\titer.next();\r\n\t\t\t\tnode = node.mid;\r\n\t\t\t} else {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn node;\r\n\t}\r\n\r\n\thas(key: K): boolean {\r\n\t\tconst node = this._getNode(key);\r\n\t\treturn !(node?.value === undefined && node?.mid === undefined);\r\n\t}\r\n\r\n\tdelete(key: K): void {\r\n\t\treturn this._delete(key, false);\r\n\t}\r\n\r\n\tdeleteSuperstr(key: K): void {\r\n\t\treturn this._delete(key, true);\r\n\t}\r\n\r\n\tprivate _delete(key: K, superStr: boolean): void {\r\n\t\tconst iter = this._iter.reset(key);\r\n\t\tconst stack: [-1 | 0 | 1, TernarySearchTreeNode][] = [];\r\n\t\tlet node = this._root;\r\n\r\n\t\t// find and unset node\r\n\t\twhile (node) {\r\n\t\t\tconst val = iter.cmp(node.segment);\r\n\t\t\tif (val > 0) {\r\n\t\t\t\t// left\r\n\t\t\t\tstack.push([1, node]);\r\n\t\t\t\tnode = node.left;\r\n\t\t\t} else if (val < 0) {\r\n\t\t\t\t// right\r\n\t\t\t\tstack.push([-1, node]);\r\n\t\t\t\tnode = node.right;\r\n\t\t\t} else if (iter.hasNext()) {\r\n\t\t\t\t// mid\r\n\t\t\t\titer.next();\r\n\t\t\t\tstack.push([0, node]);\r\n\t\t\t\tnode = node.mid;\r\n\t\t\t} else {\r\n\t\t\t\tif (superStr) {\r\n\t\t\t\t\t// remove children\r\n\t\t\t\t\tnode.left = undefined;\r\n\t\t\t\t\tnode.mid = undefined;\r\n\t\t\t\t\tnode.right = undefined;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// remove element\r\n\t\t\t\t\tnode.value = undefined;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// clean up empty nodes\r\n\t\t\t\twhile (stack.length > 0 && node.isEmpty()) {\r\n\t\t\t\t\tlet [dir, parent] = stack.pop()!;\r\n\t\t\t\t\tswitch (dir) {\r\n\t\t\t\t\t\tcase 1: parent.left = undefined; break;\r\n\t\t\t\t\t\tcase 0: parent.mid = undefined; break;\r\n\t\t\t\t\t\tcase -1: parent.right = undefined; break;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tnode = parent;\r\n\t\t\t\t}\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tfindSubstr(key: K): V | undefined {\r\n\t\tconst iter = this._iter.reset(key);\r\n\t\tlet node = this._root;\r\n\t\tlet candidate: V | undefined = undefined;\r\n\t\twhile (node) {\r\n\t\t\tconst val = iter.cmp(node.segment);\r\n\t\t\tif (val > 0) {\r\n\t\t\t\t// left\r\n\t\t\t\tnode = node.left;\r\n\t\t\t} else if (val < 0) {\r\n\t\t\t\t// right\r\n\t\t\t\tnode = node.right;\r\n\t\t\t} else if (iter.hasNext()) {\r\n\t\t\t\t// mid\r\n\t\t\t\titer.next();\r\n\t\t\t\tcandidate = node.value || candidate;\r\n\t\t\t\tnode = node.mid;\r\n\t\t\t} else {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn node && node.value || candidate;\r\n\t}\r\n\r\n\tfindSuperstr(key: K): IterableIterator<[K, V]> | undefined {\r\n\t\tconst iter = this._iter.reset(key);\r\n\t\tlet node = this._root;\r\n\t\twhile (node) {\r\n\t\t\tconst val = iter.cmp(node.segment);\r\n\t\t\tif (val > 0) {\r\n\t\t\t\t// left\r\n\t\t\t\tnode = node.left;\r\n\t\t\t} else if (val < 0) {\r\n\t\t\t\t// right\r\n\t\t\t\tnode = node.right;\r\n\t\t\t} else if (iter.hasNext()) {\r\n\t\t\t\t// mid\r\n\t\t\t\titer.next();\r\n\t\t\t\tnode = node.mid;\r\n\t\t\t} else {\r\n\t\t\t\t// collect\r\n\t\t\t\tif (!node.mid) {\r\n\t\t\t\t\treturn undefined;\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn this._entries(node.mid);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tforEach(callback: (value: V, index: K) => any): void {\r\n\t\tfor (const [key, value] of this) {\r\n\t\t\tcallback(value, key);\r\n\t\t}\r\n\t}\r\n\r\n\t*[Symbol.iterator](): IterableIterator<[K, V]> {\r\n\t\tyield* this._entries(this._root);\r\n\t}\r\n\r\n\tprivate *_entries(node: TernarySearchTreeNode | undefined): IterableIterator<[K, V]> {\r\n\t\tif (node) {\r\n\t\t\t// left\r\n\t\t\tyield* this._entries(node.left);\r\n\r\n\t\t\t// node\r\n\t\t\tif (node.value) {\r\n\t\t\t\t// callback(node.value, this._iter.join(parts));\r\n\t\t\t\tyield [node.key, node.value];\r\n\t\t\t}\r\n\t\t\t// mid\r\n\t\t\tyield* this._entries(node.mid);\r\n\r\n\t\t\t// right\r\n\t\t\tyield* this._entries(node.right);\r\n\t\t}\r\n\t}\r\n}\r\n\r\ninterface ResourceMapKeyFn {\r\n\t(resource: URI): string;\r\n}\r\n\r\nexport class ResourceMap implements Map {\r\n\r\n\tprivate static readonly defaultToKey = (resource: URI) => resource.toString();\r\n\r\n\treadonly [Symbol.toStringTag] = 'ResourceMap';\r\n\r\n\tprivate readonly map: Map;\r\n\tprivate readonly toKey: ResourceMapKeyFn;\r\n\r\n\t/**\r\n\t *\r\n\t * @param toKey Custom uri identity function, e.g use an existing `IExtUri#getComparison`-util\r\n\t */\r\n\tconstructor(toKey?: ResourceMapKeyFn);\r\n\r\n\t/**\r\n\t *\r\n\t * @param other Another resource which this maps is created from\r\n\t * @param toKey Custom uri identity function, e.g use an existing `IExtUri#getComparison`-util\r\n\t */\r\n\tconstructor(other?: ResourceMap, toKey?: ResourceMapKeyFn);\r\n\r\n\tconstructor(mapOrKeyFn?: ResourceMap | ResourceMapKeyFn, toKey?: ResourceMapKeyFn) {\r\n\t\tif (mapOrKeyFn instanceof ResourceMap) {\r\n\t\t\tthis.map = new Map(mapOrKeyFn.map);\r\n\t\t\tthis.toKey = toKey ?? ResourceMap.defaultToKey;\r\n\t\t} else {\r\n\t\t\tthis.map = new Map();\r\n\t\t\tthis.toKey = mapOrKeyFn ?? ResourceMap.defaultToKey;\r\n\t\t}\r\n\t}\r\n\r\n\tset(resource: URI, value: T): this {\r\n\t\tthis.map.set(this.toKey(resource), value);\r\n\t\treturn this;\r\n\t}\r\n\r\n\tget(resource: URI): T | undefined {\r\n\t\treturn this.map.get(this.toKey(resource));\r\n\t}\r\n\r\n\thas(resource: URI): boolean {\r\n\t\treturn this.map.has(this.toKey(resource));\r\n\t}\r\n\r\n\tget size(): number {\r\n\t\treturn this.map.size;\r\n\t}\r\n\r\n\tclear(): void {\r\n\t\tthis.map.clear();\r\n\t}\r\n\r\n\tdelete(resource: URI): boolean {\r\n\t\treturn this.map.delete(this.toKey(resource));\r\n\t}\r\n\r\n\tforEach(clb: (value: T, key: URI, map: Map) => void, thisArg?: any): void {\r\n\t\tif (typeof thisArg !== 'undefined') {\r\n\t\t\tclb = clb.bind(thisArg);\r\n\t\t}\r\n\t\tfor (let [index, value] of this.map) {\r\n\t\t\tclb(value, URI.parse(index), this);\r\n\t\t}\r\n\t}\r\n\r\n\tvalues(): IterableIterator {\r\n\t\treturn this.map.values();\r\n\t}\r\n\r\n\t*keys(): IterableIterator {\r\n\t\tfor (let key of this.map.keys()) {\r\n\t\t\tyield URI.parse(key);\r\n\t\t}\r\n\t}\r\n\r\n\t*entries(): IterableIterator<[URI, T]> {\r\n\t\tfor (let tuple of this.map.entries()) {\r\n\t\t\tyield [URI.parse(tuple[0]), tuple[1]];\r\n\t\t}\r\n\t}\r\n\r\n\t*[Symbol.iterator](): IterableIterator<[URI, T]> {\r\n\t\tfor (let item of this.map) {\r\n\t\t\tyield [URI.parse(item[0]), item[1]];\r\n\t\t}\r\n\t}\r\n}\r\n\r\ninterface Item {\r\n\tprevious: Item | undefined;\r\n\tnext: Item | undefined;\r\n\tkey: K;\r\n\tvalue: V;\r\n}\r\n\r\nexport const enum Touch {\r\n\tNone = 0,\r\n\tAsOld = 1,\r\n\tAsNew = 2\r\n}\r\n\r\nexport class LinkedMap implements Map {\r\n\r\n\treadonly [Symbol.toStringTag] = 'LinkedMap';\r\n\r\n\tprivate _map: Map>;\r\n\tprivate _head: Item | undefined;\r\n\tprivate _tail: Item | undefined;\r\n\tprivate _size: number;\r\n\r\n\tprivate _state: number;\r\n\r\n\tconstructor() {\r\n\t\tthis._map = new Map>();\r\n\t\tthis._head = undefined;\r\n\t\tthis._tail = undefined;\r\n\t\tthis._size = 0;\r\n\t\tthis._state = 0;\r\n\t}\r\n\r\n\tclear(): void {\r\n\t\tthis._map.clear();\r\n\t\tthis._head = undefined;\r\n\t\tthis._tail = undefined;\r\n\t\tthis._size = 0;\r\n\t\tthis._state++;\r\n\t}\r\n\r\n\tisEmpty(): boolean {\r\n\t\treturn !this._head && !this._tail;\r\n\t}\r\n\r\n\tget size(): number {\r\n\t\treturn this._size;\r\n\t}\r\n\r\n\tget first(): V | undefined {\r\n\t\treturn this._head?.value;\r\n\t}\r\n\r\n\tget last(): V | undefined {\r\n\t\treturn this._tail?.value;\r\n\t}\r\n\r\n\thas(key: K): boolean {\r\n\t\treturn this._map.has(key);\r\n\t}\r\n\r\n\tget(key: K, touch: Touch = Touch.None): V | undefined {\r\n\t\tconst item = this._map.get(key);\r\n\t\tif (!item) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\t\tif (touch !== Touch.None) {\r\n\t\t\tthis.touch(item, touch);\r\n\t\t}\r\n\t\treturn item.value;\r\n\t}\r\n\r\n\tset(key: K, value: V, touch: Touch = Touch.None): this {\r\n\t\tlet item = this._map.get(key);\r\n\t\tif (item) {\r\n\t\t\titem.value = value;\r\n\t\t\tif (touch !== Touch.None) {\r\n\t\t\t\tthis.touch(item, touch);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\titem = { key, value, next: undefined, previous: undefined };\r\n\t\t\tswitch (touch) {\r\n\t\t\t\tcase Touch.None:\r\n\t\t\t\t\tthis.addItemLast(item);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase Touch.AsOld:\r\n\t\t\t\t\tthis.addItemFirst(item);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase Touch.AsNew:\r\n\t\t\t\t\tthis.addItemLast(item);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tdefault:\r\n\t\t\t\t\tthis.addItemLast(item);\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tthis._map.set(key, item);\r\n\t\t\tthis._size++;\r\n\t\t}\r\n\t\treturn this;\r\n\t}\r\n\r\n\tdelete(key: K): boolean {\r\n\t\treturn !!this.remove(key);\r\n\t}\r\n\r\n\tremove(key: K): V | undefined {\r\n\t\tconst item = this._map.get(key);\r\n\t\tif (!item) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\t\tthis._map.delete(key);\r\n\t\tthis.removeItem(item);\r\n\t\tthis._size--;\r\n\t\treturn item.value;\r\n\t}\r\n\r\n\tshift(): V | undefined {\r\n\t\tif (!this._head && !this._tail) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\t\tif (!this._head || !this._tail) {\r\n\t\t\tthrow new Error('Invalid list');\r\n\t\t}\r\n\t\tconst item = this._head;\r\n\t\tthis._map.delete(item.key);\r\n\t\tthis.removeItem(item);\r\n\t\tthis._size--;\r\n\t\treturn item.value;\r\n\t}\r\n\r\n\tforEach(callbackfn: (value: V, key: K, map: LinkedMap) => void, thisArg?: any): void {\r\n\t\tconst state = this._state;\r\n\t\tlet current = this._head;\r\n\t\twhile (current) {\r\n\t\t\tif (thisArg) {\r\n\t\t\t\tcallbackfn.bind(thisArg)(current.value, current.key, this);\r\n\t\t\t} else {\r\n\t\t\t\tcallbackfn(current.value, current.key, this);\r\n\t\t\t}\r\n\t\t\tif (this._state !== state) {\r\n\t\t\t\tthrow new Error(`LinkedMap got modified during iteration.`);\r\n\t\t\t}\r\n\t\t\tcurrent = current.next;\r\n\t\t}\r\n\t}\r\n\r\n\tkeys(): IterableIterator {\r\n\t\tconst map = this;\r\n\t\tconst state = this._state;\r\n\t\tlet current = this._head;\r\n\t\tconst iterator: IterableIterator = {\r\n\t\t\t[Symbol.iterator]() {\r\n\t\t\t\treturn iterator;\r\n\t\t\t},\r\n\t\t\tnext(): IteratorResult {\r\n\t\t\t\tif (map._state !== state) {\r\n\t\t\t\t\tthrow new Error(`LinkedMap got modified during iteration.`);\r\n\t\t\t\t}\r\n\t\t\t\tif (current) {\r\n\t\t\t\t\tconst result = { value: current.key, done: false };\r\n\t\t\t\t\tcurrent = current.next;\r\n\t\t\t\t\treturn result;\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn { value: undefined, done: true };\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\t\treturn iterator;\r\n\t}\r\n\r\n\tvalues(): IterableIterator {\r\n\t\tconst map = this;\r\n\t\tconst state = this._state;\r\n\t\tlet current = this._head;\r\n\t\tconst iterator: IterableIterator = {\r\n\t\t\t[Symbol.iterator]() {\r\n\t\t\t\treturn iterator;\r\n\t\t\t},\r\n\t\t\tnext(): IteratorResult {\r\n\t\t\t\tif (map._state !== state) {\r\n\t\t\t\t\tthrow new Error(`LinkedMap got modified during iteration.`);\r\n\t\t\t\t}\r\n\t\t\t\tif (current) {\r\n\t\t\t\t\tconst result = { value: current.value, done: false };\r\n\t\t\t\t\tcurrent = current.next;\r\n\t\t\t\t\treturn result;\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn { value: undefined, done: true };\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\t\treturn iterator;\r\n\t}\r\n\r\n\tentries(): IterableIterator<[K, V]> {\r\n\t\tconst map = this;\r\n\t\tconst state = this._state;\r\n\t\tlet current = this._head;\r\n\t\tconst iterator: IterableIterator<[K, V]> = {\r\n\t\t\t[Symbol.iterator]() {\r\n\t\t\t\treturn iterator;\r\n\t\t\t},\r\n\t\t\tnext(): IteratorResult<[K, V]> {\r\n\t\t\t\tif (map._state !== state) {\r\n\t\t\t\t\tthrow new Error(`LinkedMap got modified during iteration.`);\r\n\t\t\t\t}\r\n\t\t\t\tif (current) {\r\n\t\t\t\t\tconst result: IteratorResult<[K, V]> = { value: [current.key, current.value], done: false };\r\n\t\t\t\t\tcurrent = current.next;\r\n\t\t\t\t\treturn result;\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn { value: undefined, done: true };\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\t\treturn iterator;\r\n\t}\r\n\r\n\t[Symbol.iterator](): IterableIterator<[K, V]> {\r\n\t\treturn this.entries();\r\n\t}\r\n\r\n\tprotected trimOld(newSize: number) {\r\n\t\tif (newSize >= this.size) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (newSize === 0) {\r\n\t\t\tthis.clear();\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tlet current = this._head;\r\n\t\tlet currentSize = this.size;\r\n\t\twhile (current && currentSize > newSize) {\r\n\t\t\tthis._map.delete(current.key);\r\n\t\t\tcurrent = current.next;\r\n\t\t\tcurrentSize--;\r\n\t\t}\r\n\t\tthis._head = current;\r\n\t\tthis._size = currentSize;\r\n\t\tif (current) {\r\n\t\t\tcurrent.previous = undefined;\r\n\t\t}\r\n\t\tthis._state++;\r\n\t}\r\n\r\n\tprivate addItemFirst(item: Item): void {\r\n\t\t// First time Insert\r\n\t\tif (!this._head && !this._tail) {\r\n\t\t\tthis._tail = item;\r\n\t\t} else if (!this._head) {\r\n\t\t\tthrow new Error('Invalid list');\r\n\t\t} else {\r\n\t\t\titem.next = this._head;\r\n\t\t\tthis._head.previous = item;\r\n\t\t}\r\n\t\tthis._head = item;\r\n\t\tthis._state++;\r\n\t}\r\n\r\n\tprivate addItemLast(item: Item): void {\r\n\t\t// First time Insert\r\n\t\tif (!this._head && !this._tail) {\r\n\t\t\tthis._head = item;\r\n\t\t} else if (!this._tail) {\r\n\t\t\tthrow new Error('Invalid list');\r\n\t\t} else {\r\n\t\t\titem.previous = this._tail;\r\n\t\t\tthis._tail.next = item;\r\n\t\t}\r\n\t\tthis._tail = item;\r\n\t\tthis._state++;\r\n\t}\r\n\r\n\tprivate removeItem(item: Item): void {\r\n\t\tif (item === this._head && item === this._tail) {\r\n\t\t\tthis._head = undefined;\r\n\t\t\tthis._tail = undefined;\r\n\t\t}\r\n\t\telse if (item === this._head) {\r\n\t\t\t// This can only happend if size === 1 which is handle\r\n\t\t\t// by the case above.\r\n\t\t\tif (!item.next) {\r\n\t\t\t\tthrow new Error('Invalid list');\r\n\t\t\t}\r\n\t\t\titem.next.previous = undefined;\r\n\t\t\tthis._head = item.next;\r\n\t\t}\r\n\t\telse if (item === this._tail) {\r\n\t\t\t// This can only happend if size === 1 which is handle\r\n\t\t\t// by the case above.\r\n\t\t\tif (!item.previous) {\r\n\t\t\t\tthrow new Error('Invalid list');\r\n\t\t\t}\r\n\t\t\titem.previous.next = undefined;\r\n\t\t\tthis._tail = item.previous;\r\n\t\t}\r\n\t\telse {\r\n\t\t\tconst next = item.next;\r\n\t\t\tconst previous = item.previous;\r\n\t\t\tif (!next || !previous) {\r\n\t\t\t\tthrow new Error('Invalid list');\r\n\t\t\t}\r\n\t\t\tnext.previous = previous;\r\n\t\t\tprevious.next = next;\r\n\t\t}\r\n\t\titem.next = undefined;\r\n\t\titem.previous = undefined;\r\n\t\tthis._state++;\r\n\t}\r\n\r\n\tprivate touch(item: Item, touch: Touch): void {\r\n\t\tif (!this._head || !this._tail) {\r\n\t\t\tthrow new Error('Invalid list');\r\n\t\t}\r\n\t\tif ((touch !== Touch.AsOld && touch !== Touch.AsNew)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (touch === Touch.AsOld) {\r\n\t\t\tif (item === this._head) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst next = item.next;\r\n\t\t\tconst previous = item.previous;\r\n\r\n\t\t\t// Unlink the item\r\n\t\t\tif (item === this._tail) {\r\n\t\t\t\t// previous must be defined since item was not head but is tail\r\n\t\t\t\t// So there are more than on item in the map\r\n\t\t\t\tprevious!.next = undefined;\r\n\t\t\t\tthis._tail = previous;\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\t// Both next and previous are not undefined since item was neither head nor tail.\r\n\t\t\t\tnext!.previous = previous;\r\n\t\t\t\tprevious!.next = next;\r\n\t\t\t}\r\n\r\n\t\t\t// Insert the node at head\r\n\t\t\titem.previous = undefined;\r\n\t\t\titem.next = this._head;\r\n\t\t\tthis._head.previous = item;\r\n\t\t\tthis._head = item;\r\n\t\t\tthis._state++;\r\n\t\t} else if (touch === Touch.AsNew) {\r\n\t\t\tif (item === this._tail) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst next = item.next;\r\n\t\t\tconst previous = item.previous;\r\n\r\n\t\t\t// Unlink the item.\r\n\t\t\tif (item === this._head) {\r\n\t\t\t\t// next must be defined since item was not tail but is head\r\n\t\t\t\t// So there are more than on item in the map\r\n\t\t\t\tnext!.previous = undefined;\r\n\t\t\t\tthis._head = next;\r\n\t\t\t} else {\r\n\t\t\t\t// Both next and previous are not undefined since item was neither head nor tail.\r\n\t\t\t\tnext!.previous = previous;\r\n\t\t\t\tprevious!.next = next;\r\n\t\t\t}\r\n\t\t\titem.next = undefined;\r\n\t\t\titem.previous = this._tail;\r\n\t\t\tthis._tail.next = item;\r\n\t\t\tthis._tail = item;\r\n\t\t\tthis._state++;\r\n\t\t}\r\n\t}\r\n\r\n\ttoJSON(): [K, V][] {\r\n\t\tconst data: [K, V][] = [];\r\n\r\n\t\tthis.forEach((value, key) => {\r\n\t\t\tdata.push([key, value]);\r\n\t\t});\r\n\r\n\t\treturn data;\r\n\t}\r\n\r\n\tfromJSON(data: [K, V][]): void {\r\n\t\tthis.clear();\r\n\r\n\t\tfor (const [key, value] of data) {\r\n\t\t\tthis.set(key, value);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class LRUCache extends LinkedMap {\r\n\r\n\tprivate _limit: number;\r\n\tprivate _ratio: number;\r\n\r\n\tconstructor(limit: number, ratio: number = 1) {\r\n\t\tsuper();\r\n\t\tthis._limit = limit;\r\n\t\tthis._ratio = Math.min(Math.max(0, ratio), 1);\r\n\t}\r\n\r\n\tget limit(): number {\r\n\t\treturn this._limit;\r\n\t}\r\n\r\n\tset limit(limit: number) {\r\n\t\tthis._limit = limit;\r\n\t\tthis.checkTrim();\r\n\t}\r\n\r\n\tget(key: K, touch: Touch = Touch.AsNew): V | undefined {\r\n\t\treturn super.get(key, touch);\r\n\t}\r\n\r\n\tpeek(key: K): V | undefined {\r\n\t\treturn super.get(key, Touch.None);\r\n\t}\r\n\r\n\tset(key: K, value: V): this {\r\n\t\tsuper.set(key, value, Touch.AsNew);\r\n\t\tthis.checkTrim();\r\n\t\treturn this;\r\n\t}\r\n\r\n\tprivate checkTrim() {\r\n\t\tif (this.size > this._limit) {\r\n\t\t\tthis.trimOld(Math.round(this._limit * this._ratio));\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport { LRUCache } from 'vs/base/common/map';\r\nimport * as strings from 'vs/base/common/strings';\r\n\r\nexport interface IFilter {\r\n\t// Returns null if word doesn't match.\r\n\t(word: string, wordToMatchAgainst: string): IMatch[] | null;\r\n}\r\n\r\nexport interface IMatch {\r\n\tstart: number;\r\n\tend: number;\r\n}\r\n\r\n// Combined filters\r\n\r\n/**\r\n * @returns A filter which combines the provided set\r\n * of filters with an or. The *first* filters that\r\n * matches defined the return value of the returned\r\n * filter.\r\n */\r\nexport function or(...filter: IFilter[]): IFilter {\r\n\treturn function (word: string, wordToMatchAgainst: string): IMatch[] | null {\r\n\t\tfor (let i = 0, len = filter.length; i < len; i++) {\r\n\t\t\tconst match = filter[i](word, wordToMatchAgainst);\r\n\t\t\tif (match) {\r\n\t\t\t\treturn match;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn null;\r\n\t};\r\n}\r\nexport const matchesPrefix: IFilter = _matchesPrefix.bind(undefined, true);\r\n\r\nfunction _matchesPrefix(ignoreCase: boolean, word: string, wordToMatchAgainst: string): IMatch[] | null {\r\n\tif (!wordToMatchAgainst || wordToMatchAgainst.length < word.length) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\tlet matches: boolean;\r\n\tif (ignoreCase) {\r\n\t\tmatches = strings.startsWithIgnoreCase(wordToMatchAgainst, word);\r\n\t} else {\r\n\t\tmatches = wordToMatchAgainst.indexOf(word) === 0;\r\n\t}\r\n\r\n\tif (!matches) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\treturn word.length > 0 ? [{ start: 0, end: word.length }] : [];\r\n}\r\n\r\n// Contiguous Substring\r\n\r\nexport function matchesContiguousSubString(word: string, wordToMatchAgainst: string): IMatch[] | null {\r\n\tconst index = wordToMatchAgainst.toLowerCase().indexOf(word.toLowerCase());\r\n\tif (index === -1) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\treturn [{ start: index, end: index + word.length }];\r\n}\r\n\r\n// Substring\r\n\r\nexport function matchesSubString(word: string, wordToMatchAgainst: string): IMatch[] | null {\r\n\treturn _matchesSubString(word.toLowerCase(), wordToMatchAgainst.toLowerCase(), 0, 0);\r\n}\r\n\r\nfunction _matchesSubString(word: string, wordToMatchAgainst: string, i: number, j: number): IMatch[] | null {\r\n\tif (i === word.length) {\r\n\t\treturn [];\r\n\t} else if (j === wordToMatchAgainst.length) {\r\n\t\treturn null;\r\n\t} else {\r\n\t\tif (word[i] === wordToMatchAgainst[j]) {\r\n\t\t\tlet result: IMatch[] | null = null;\r\n\t\t\tif (result = _matchesSubString(word, wordToMatchAgainst, i + 1, j + 1)) {\r\n\t\t\t\treturn join({ start: j, end: j + 1 }, result);\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\treturn _matchesSubString(word, wordToMatchAgainst, i, j + 1);\r\n\t}\r\n}\r\n\r\n// CamelCase\r\n\r\nfunction isLower(code: number): boolean {\r\n\treturn CharCode.a <= code && code <= CharCode.z;\r\n}\r\n\r\nexport function isUpper(code: number): boolean {\r\n\treturn CharCode.A <= code && code <= CharCode.Z;\r\n}\r\n\r\nfunction isNumber(code: number): boolean {\r\n\treturn CharCode.Digit0 <= code && code <= CharCode.Digit9;\r\n}\r\n\r\nfunction isWhitespace(code: number): boolean {\r\n\treturn (\r\n\t\tcode === CharCode.Space\r\n\t\t|| code === CharCode.Tab\r\n\t\t|| code === CharCode.LineFeed\r\n\t\t|| code === CharCode.CarriageReturn\r\n\t);\r\n}\r\n\r\nconst wordSeparators = new Set();\r\n'`~!@#$%^&*()-=+[{]}\\\\|;:\\'\",.<>/?'\r\n\t.split('')\r\n\t.forEach(s => wordSeparators.add(s.charCodeAt(0)));\r\n\r\nfunction isWordSeparator(code: number): boolean {\r\n\treturn isWhitespace(code) || wordSeparators.has(code);\r\n}\r\n\r\nfunction charactersMatch(codeA: number, codeB: number): boolean {\r\n\treturn (codeA === codeB) || (isWordSeparator(codeA) && isWordSeparator(codeB));\r\n}\r\n\r\nfunction isAlphanumeric(code: number): boolean {\r\n\treturn isLower(code) || isUpper(code) || isNumber(code);\r\n}\r\n\r\nfunction join(head: IMatch, tail: IMatch[]): IMatch[] {\r\n\tif (tail.length === 0) {\r\n\t\ttail = [head];\r\n\t} else if (head.end === tail[0].start) {\r\n\t\ttail[0].start = head.start;\r\n\t} else {\r\n\t\ttail.unshift(head);\r\n\t}\r\n\treturn tail;\r\n}\r\n\r\nfunction nextAnchor(camelCaseWord: string, start: number): number {\r\n\tfor (let i = start; i < camelCaseWord.length; i++) {\r\n\t\tconst c = camelCaseWord.charCodeAt(i);\r\n\t\tif (isUpper(c) || isNumber(c) || (i > 0 && !isAlphanumeric(camelCaseWord.charCodeAt(i - 1)))) {\r\n\t\t\treturn i;\r\n\t\t}\r\n\t}\r\n\treturn camelCaseWord.length;\r\n}\r\n\r\nfunction _matchesCamelCase(word: string, camelCaseWord: string, i: number, j: number): IMatch[] | null {\r\n\tif (i === word.length) {\r\n\t\treturn [];\r\n\t} else if (j === camelCaseWord.length) {\r\n\t\treturn null;\r\n\t} else if (word[i] !== camelCaseWord[j].toLowerCase()) {\r\n\t\treturn null;\r\n\t} else {\r\n\t\tlet result: IMatch[] | null = null;\r\n\t\tlet nextUpperIndex = j + 1;\r\n\t\tresult = _matchesCamelCase(word, camelCaseWord, i + 1, j + 1);\r\n\t\twhile (!result && (nextUpperIndex = nextAnchor(camelCaseWord, nextUpperIndex)) < camelCaseWord.length) {\r\n\t\t\tresult = _matchesCamelCase(word, camelCaseWord, i + 1, nextUpperIndex);\r\n\t\t\tnextUpperIndex++;\r\n\t\t}\r\n\t\treturn result === null ? null : join({ start: j, end: j + 1 }, result);\r\n\t}\r\n}\r\n\r\ninterface ICamelCaseAnalysis {\r\n\tupperPercent: number;\r\n\tlowerPercent: number;\r\n\talphaPercent: number;\r\n\tnumericPercent: number;\r\n}\r\n\r\n// Heuristic to avoid computing camel case matcher for words that don't\r\n// look like camelCaseWords.\r\nfunction analyzeCamelCaseWord(word: string): ICamelCaseAnalysis {\r\n\tlet upper = 0, lower = 0, alpha = 0, numeric = 0, code = 0;\r\n\r\n\tfor (let i = 0; i < word.length; i++) {\r\n\t\tcode = word.charCodeAt(i);\r\n\r\n\t\tif (isUpper(code)) { upper++; }\r\n\t\tif (isLower(code)) { lower++; }\r\n\t\tif (isAlphanumeric(code)) { alpha++; }\r\n\t\tif (isNumber(code)) { numeric++; }\r\n\t}\r\n\r\n\tconst upperPercent = upper / word.length;\r\n\tconst lowerPercent = lower / word.length;\r\n\tconst alphaPercent = alpha / word.length;\r\n\tconst numericPercent = numeric / word.length;\r\n\r\n\treturn { upperPercent, lowerPercent, alphaPercent, numericPercent };\r\n}\r\n\r\nfunction isUpperCaseWord(analysis: ICamelCaseAnalysis): boolean {\r\n\tconst { upperPercent, lowerPercent } = analysis;\r\n\treturn lowerPercent === 0 && upperPercent > 0.6;\r\n}\r\n\r\nfunction isCamelCaseWord(analysis: ICamelCaseAnalysis): boolean {\r\n\tconst { upperPercent, lowerPercent, alphaPercent, numericPercent } = analysis;\r\n\treturn lowerPercent > 0.2 && upperPercent < 0.8 && alphaPercent > 0.6 && numericPercent < 0.2;\r\n}\r\n\r\n// Heuristic to avoid computing camel case matcher for words that don't\r\n// look like camel case patterns.\r\nfunction isCamelCasePattern(word: string): boolean {\r\n\tlet upper = 0, lower = 0, code = 0, whitespace = 0;\r\n\r\n\tfor (let i = 0; i < word.length; i++) {\r\n\t\tcode = word.charCodeAt(i);\r\n\r\n\t\tif (isUpper(code)) { upper++; }\r\n\t\tif (isLower(code)) { lower++; }\r\n\t\tif (isWhitespace(code)) { whitespace++; }\r\n\t}\r\n\r\n\tif ((upper === 0 || lower === 0) && whitespace === 0) {\r\n\t\treturn word.length <= 30;\r\n\t} else {\r\n\t\treturn upper <= 5;\r\n\t}\r\n}\r\n\r\nexport function matchesCamelCase(word: string, camelCaseWord: string): IMatch[] | null {\r\n\tif (!camelCaseWord) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\tcamelCaseWord = camelCaseWord.trim();\r\n\r\n\tif (camelCaseWord.length === 0) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\tif (!isCamelCasePattern(word)) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\tif (camelCaseWord.length > 60) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\tconst analysis = analyzeCamelCaseWord(camelCaseWord);\r\n\r\n\tif (!isCamelCaseWord(analysis)) {\r\n\t\tif (!isUpperCaseWord(analysis)) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tcamelCaseWord = camelCaseWord.toLowerCase();\r\n\t}\r\n\r\n\tlet result: IMatch[] | null = null;\r\n\tlet i = 0;\r\n\r\n\tword = word.toLowerCase();\r\n\twhile (i < camelCaseWord.length && (result = _matchesCamelCase(word, camelCaseWord, 0, i)) === null) {\r\n\t\ti = nextAnchor(camelCaseWord, i + 1);\r\n\t}\r\n\r\n\treturn result;\r\n}\r\n\r\n// Matches beginning of words supporting non-ASCII languages\r\n// If `contiguous` is true then matches word with beginnings of the words in the target. E.g. \"pul\" will match \"Git: Pull\"\r\n// Otherwise also matches sub string of the word with beginnings of the words in the target. E.g. \"gp\" or \"g p\" will match \"Git: Pull\"\r\n// Useful in cases where the target is words (e.g. command labels)\r\n\r\nexport function matchesWords(word: string, target: string, contiguous: boolean = false): IMatch[] | null {\r\n\tif (!target || target.length === 0) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\tlet result: IMatch[] | null = null;\r\n\tlet i = 0;\r\n\r\n\tword = word.toLowerCase();\r\n\ttarget = target.toLowerCase();\r\n\twhile (i < target.length && (result = _matchesWords(word, target, 0, i, contiguous)) === null) {\r\n\t\ti = nextWord(target, i + 1);\r\n\t}\r\n\r\n\treturn result;\r\n}\r\n\r\nfunction _matchesWords(word: string, target: string, i: number, j: number, contiguous: boolean): IMatch[] | null {\r\n\tif (i === word.length) {\r\n\t\treturn [];\r\n\t} else if (j === target.length) {\r\n\t\treturn null;\r\n\t} else if (!charactersMatch(word.charCodeAt(i), target.charCodeAt(j))) {\r\n\t\treturn null;\r\n\t} else {\r\n\t\tlet result: IMatch[] | null = null;\r\n\t\tlet nextWordIndex = j + 1;\r\n\t\tresult = _matchesWords(word, target, i + 1, j + 1, contiguous);\r\n\t\tif (!contiguous) {\r\n\t\t\twhile (!result && (nextWordIndex = nextWord(target, nextWordIndex)) < target.length) {\r\n\t\t\t\tresult = _matchesWords(word, target, i + 1, nextWordIndex, contiguous);\r\n\t\t\t\tnextWordIndex++;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn result === null ? null : join({ start: j, end: j + 1 }, result);\r\n\t}\r\n}\r\n\r\nfunction nextWord(word: string, start: number): number {\r\n\tfor (let i = start; i < word.length; i++) {\r\n\t\tif (isWordSeparator(word.charCodeAt(i)) ||\r\n\t\t\t(i > 0 && isWordSeparator(word.charCodeAt(i - 1)))) {\r\n\t\t\treturn i;\r\n\t\t}\r\n\t}\r\n\treturn word.length;\r\n}\r\n\r\n// Fuzzy\r\n\r\nconst fuzzyContiguousFilter = or(matchesPrefix, matchesCamelCase, matchesContiguousSubString);\r\nconst fuzzySeparateFilter = or(matchesPrefix, matchesCamelCase, matchesSubString);\r\nconst fuzzyRegExpCache = new LRUCache(10000); // bounded to 10000 elements\r\n\r\nexport function matchesFuzzy(word: string, wordToMatchAgainst: string, enableSeparateSubstringMatching = false): IMatch[] | null {\r\n\tif (typeof word !== 'string' || typeof wordToMatchAgainst !== 'string') {\r\n\t\treturn null; // return early for invalid input\r\n\t}\r\n\r\n\t// Form RegExp for wildcard matches\r\n\tlet regexp = fuzzyRegExpCache.get(word);\r\n\tif (!regexp) {\r\n\t\tregexp = new RegExp(strings.convertSimple2RegExpPattern(word), 'i');\r\n\t\tfuzzyRegExpCache.set(word, regexp);\r\n\t}\r\n\r\n\t// RegExp Filter\r\n\tconst match = regexp.exec(wordToMatchAgainst);\r\n\tif (match) {\r\n\t\treturn [{ start: match.index, end: match.index + match[0].length }];\r\n\t}\r\n\r\n\t// Default Filter\r\n\treturn enableSeparateSubstringMatching ? fuzzySeparateFilter(word, wordToMatchAgainst) : fuzzyContiguousFilter(word, wordToMatchAgainst);\r\n}\r\n\r\nexport function anyScore(pattern: string, lowPattern: string, _patternPos: number, word: string, lowWord: string, _wordPos: number): FuzzyScore {\r\n\tconst result = fuzzyScore(pattern, lowPattern, 0, word, lowWord, 0, true);\r\n\tif (result) {\r\n\t\treturn result;\r\n\t}\r\n\tlet matches: number[] = [];\r\n\tlet score = 0;\r\n\tlet idx = _wordPos;\r\n\tfor (let patternPos = 0; patternPos < lowPattern.length && patternPos < _maxLen; ++patternPos) {\r\n\t\tconst wordPos = lowWord.indexOf(lowPattern.charAt(patternPos), idx);\r\n\t\tif (wordPos >= 0) {\r\n\t\t\tscore += 1;\r\n\t\t\tmatches.unshift(wordPos);\r\n\t\t\tidx = wordPos + 1;\r\n\t\t} else if (matches.length > 0) {\r\n\t\t\t// once we have started matching things\r\n\t\t\t// we need to match the remaining pattern\r\n\t\t\t// characters\r\n\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n\treturn [score, _wordPos, ...matches];\r\n}\r\n\r\n//#region --- fuzzyScore ---\r\n\r\nexport function createMatches(score: undefined | FuzzyScore): IMatch[] {\r\n\tif (typeof score === 'undefined') {\r\n\t\treturn [];\r\n\t}\r\n\tconst res: IMatch[] = [];\r\n\tconst wordPos = score[1];\r\n\tfor (let i = score.length - 1; i > 1; i--) {\r\n\t\tconst pos = score[i] + wordPos;\r\n\t\tconst last = res[res.length - 1];\r\n\t\tif (last && last.end === pos) {\r\n\t\t\tlast.end = pos + 1;\r\n\t\t} else {\r\n\t\t\tres.push({ start: pos, end: pos + 1 });\r\n\t\t}\r\n\t}\r\n\treturn res;\r\n}\r\n\r\nconst _maxLen = 128;\r\n\r\nfunction initTable() {\r\n\tconst table: number[][] = [];\r\n\tconst row: number[] = [];\r\n\tfor (let i = 0; i <= _maxLen; i++) {\r\n\t\trow[i] = 0;\r\n\t}\r\n\tfor (let i = 0; i <= _maxLen; i++) {\r\n\t\ttable.push(row.slice(0));\r\n\t}\r\n\treturn table;\r\n}\r\n\r\nfunction initArr(maxLen: number) {\r\n\tconst row: number[] = [];\r\n\tfor (let i = 0; i <= maxLen; i++) {\r\n\t\trow[i] = 0;\r\n\t}\r\n\treturn row;\r\n}\r\n\r\nconst _minWordMatchPos = initArr(2 * _maxLen); // min word position for a certain pattern position\r\nconst _maxWordMatchPos = initArr(2 * _maxLen); // max word position for a certain pattern position\r\nconst _diag = initTable(); // the length of a contiguous diagonal match\r\nconst _table = initTable();\r\nconst _arrows = initTable();\r\nconst _debug = false;\r\n\r\nfunction printTable(table: number[][], pattern: string, patternLen: number, word: string, wordLen: number): string {\r\n\tfunction pad(s: string, n: number, pad = ' ') {\r\n\t\twhile (s.length < n) {\r\n\t\t\ts = pad + s;\r\n\t\t}\r\n\t\treturn s;\r\n\t}\r\n\tlet ret = ` | |${word.split('').map(c => pad(c, 3)).join('|')}\\n`;\r\n\r\n\tfor (let i = 0; i <= patternLen; i++) {\r\n\t\tif (i === 0) {\r\n\t\t\tret += ' |';\r\n\t\t} else {\r\n\t\t\tret += `${pattern[i - 1]}|`;\r\n\t\t}\r\n\t\tret += table[i].slice(0, wordLen + 1).map(n => pad(n.toString(), 3)).join('|') + '\\n';\r\n\t}\r\n\treturn ret;\r\n}\r\n\r\nfunction printTables(pattern: string, patternStart: number, word: string, wordStart: number): void {\r\n\tpattern = pattern.substr(patternStart);\r\n\tword = word.substr(wordStart);\r\n\tconsole.log(printTable(_table, pattern, pattern.length, word, word.length));\r\n\tconsole.log(printTable(_arrows, pattern, pattern.length, word, word.length));\r\n\tconsole.log(printTable(_diag, pattern, pattern.length, word, word.length));\r\n}\r\n\r\nfunction isSeparatorAtPos(value: string, index: number): boolean {\r\n\tif (index < 0 || index >= value.length) {\r\n\t\treturn false;\r\n\t}\r\n\tconst code = value.codePointAt(index);\r\n\tswitch (code) {\r\n\t\tcase CharCode.Underline:\r\n\t\tcase CharCode.Dash:\r\n\t\tcase CharCode.Period:\r\n\t\tcase CharCode.Space:\r\n\t\tcase CharCode.Slash:\r\n\t\tcase CharCode.Backslash:\r\n\t\tcase CharCode.SingleQuote:\r\n\t\tcase CharCode.DoubleQuote:\r\n\t\tcase CharCode.Colon:\r\n\t\tcase CharCode.DollarSign:\r\n\t\tcase CharCode.LessThan:\r\n\t\tcase CharCode.OpenParen:\r\n\t\tcase CharCode.OpenSquareBracket:\r\n\t\t\treturn true;\r\n\t\tcase undefined:\r\n\t\t\treturn false;\r\n\t\tdefault:\r\n\t\t\tif (strings.isEmojiImprecise(code)) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t\treturn false;\r\n\t}\r\n}\r\n\r\nfunction isWhitespaceAtPos(value: string, index: number): boolean {\r\n\tif (index < 0 || index >= value.length) {\r\n\t\treturn false;\r\n\t}\r\n\tconst code = value.charCodeAt(index);\r\n\tswitch (code) {\r\n\t\tcase CharCode.Space:\r\n\t\tcase CharCode.Tab:\r\n\t\t\treturn true;\r\n\t\tdefault:\r\n\t\t\treturn false;\r\n\t}\r\n}\r\n\r\nfunction isUpperCaseAtPos(pos: number, word: string, wordLow: string): boolean {\r\n\treturn word[pos] !== wordLow[pos];\r\n}\r\n\r\nexport function isPatternInWord(patternLow: string, patternPos: number, patternLen: number, wordLow: string, wordPos: number, wordLen: number, fillMinWordPosArr = false): boolean {\r\n\twhile (patternPos < patternLen && wordPos < wordLen) {\r\n\t\tif (patternLow[patternPos] === wordLow[wordPos]) {\r\n\t\t\tif (fillMinWordPosArr) {\r\n\t\t\t\t// Remember the min word position for each pattern position\r\n\t\t\t\t_minWordMatchPos[patternPos] = wordPos;\r\n\t\t\t}\r\n\t\t\tpatternPos += 1;\r\n\t\t}\r\n\t\twordPos += 1;\r\n\t}\r\n\treturn patternPos === patternLen; // pattern must be exhausted\r\n}\r\n\r\nconst enum Arrow { Diag = 1, Left = 2, LeftLeft = 3 }\r\n\r\n/**\r\n * An array representating a fuzzy match.\r\n *\r\n * 0. the score\r\n * 1. the offset at which matching started\r\n * 2. ``\r\n * 3. ``\r\n * 4. `` etc\r\n */\r\nexport type FuzzyScore = [score: number, wordStart: number, ...matches: number[]];// [number, number, number];\r\n\r\nexport namespace FuzzyScore {\r\n\t/**\r\n\t * No matches and value `-100`\r\n\t */\r\n\texport const Default: FuzzyScore = ([-100, 0]);\r\n\r\n\texport function isDefault(score?: FuzzyScore): score is [-100, 0, 0] {\r\n\t\treturn !score || (score[0] === -100 && score[1] === 0 && score[2] === 0);\r\n\t}\r\n}\r\n\r\nexport interface FuzzyScorer {\r\n\t(pattern: string, lowPattern: string, patternPos: number, word: string, lowWord: string, wordPos: number, firstMatchCanBeWeak: boolean): FuzzyScore | undefined;\r\n}\r\n\r\nexport function fuzzyScore(pattern: string, patternLow: string, patternStart: number, word: string, wordLow: string, wordStart: number, firstMatchCanBeWeak: boolean): FuzzyScore | undefined {\r\n\r\n\tconst patternLen = pattern.length > _maxLen ? _maxLen : pattern.length;\r\n\tconst wordLen = word.length > _maxLen ? _maxLen : word.length;\r\n\r\n\tif (patternStart >= patternLen || wordStart >= wordLen || (patternLen - patternStart) > (wordLen - wordStart)) {\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\t// Run a simple check if the characters of pattern occur\r\n\t// (in order) at all in word. If that isn't the case we\r\n\t// stop because no match will be possible\r\n\tif (!isPatternInWord(patternLow, patternStart, patternLen, wordLow, wordStart, wordLen, true)) {\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\t// Find the max matching word position for each pattern position\r\n\t// NOTE: the min matching word position was filled in above, in the `isPatternInWord` call\r\n\t_fillInMaxWordMatchPos(patternLen, wordLen, patternStart, wordStart, patternLow, wordLow);\r\n\r\n\tlet row: number = 1;\r\n\tlet column: number = 1;\r\n\tlet patternPos = patternStart;\r\n\tlet wordPos = wordStart;\r\n\r\n\tconst hasStrongFirstMatch = [false];\r\n\r\n\t// There will be a match, fill in tables\r\n\tfor (row = 1, patternPos = patternStart; patternPos < patternLen; row++, patternPos++) {\r\n\r\n\t\t// Reduce search space to possible matching word positions and to possible access from next row\r\n\t\tconst minWordMatchPos = _minWordMatchPos[patternPos];\r\n\t\tconst maxWordMatchPos = _maxWordMatchPos[patternPos];\r\n\t\tconst nextMaxWordMatchPos = (patternPos + 1 < patternLen ? _maxWordMatchPos[patternPos + 1] : wordLen);\r\n\r\n\t\tfor (column = minWordMatchPos - wordStart + 1, wordPos = minWordMatchPos; wordPos < nextMaxWordMatchPos; column++, wordPos++) {\r\n\r\n\t\t\tlet score = Number.MIN_SAFE_INTEGER;\r\n\t\t\tlet canComeDiag = false;\r\n\r\n\t\t\tif (wordPos <= maxWordMatchPos) {\r\n\t\t\t\tscore = _doScore(\r\n\t\t\t\t\tpattern, patternLow, patternPos, patternStart,\r\n\t\t\t\t\tword, wordLow, wordPos, wordLen, wordStart,\r\n\t\t\t\t\t_diag[row - 1][column - 1] === 0,\r\n\t\t\t\t\thasStrongFirstMatch\r\n\t\t\t\t);\r\n\t\t\t}\r\n\r\n\t\t\tlet diagScore = 0;\r\n\t\t\tif (score !== Number.MAX_SAFE_INTEGER) {\r\n\t\t\t\tcanComeDiag = true;\r\n\t\t\t\tdiagScore = score + _table[row - 1][column - 1];\r\n\t\t\t}\r\n\r\n\t\t\tconst canComeLeft = wordPos > minWordMatchPos;\r\n\t\t\tconst leftScore = canComeLeft ? _table[row][column - 1] + (_diag[row][column - 1] > 0 ? -5 : 0) : 0; // penalty for a gap start\r\n\r\n\t\t\tconst canComeLeftLeft = wordPos > minWordMatchPos + 1 && _diag[row][column - 1] > 0;\r\n\t\t\tconst leftLeftScore = canComeLeftLeft ? _table[row][column - 2] + (_diag[row][column - 2] > 0 ? -5 : 0) : 0; // penalty for a gap start\r\n\r\n\t\t\tif (canComeLeftLeft && (!canComeLeft || leftLeftScore >= leftScore) && (!canComeDiag || leftLeftScore >= diagScore)) {\r\n\t\t\t\t// always prefer choosing left left to jump over a diagonal because that means a match is earlier in the word\r\n\t\t\t\t_table[row][column] = leftLeftScore;\r\n\t\t\t\t_arrows[row][column] = Arrow.LeftLeft;\r\n\t\t\t\t_diag[row][column] = 0;\r\n\t\t\t} else if (canComeLeft && (!canComeDiag || leftScore >= diagScore)) {\r\n\t\t\t\t// always prefer choosing left since that means a match is earlier in the word\r\n\t\t\t\t_table[row][column] = leftScore;\r\n\t\t\t\t_arrows[row][column] = Arrow.Left;\r\n\t\t\t\t_diag[row][column] = 0;\r\n\t\t\t} else if (canComeDiag) {\r\n\t\t\t\t_table[row][column] = diagScore;\r\n\t\t\t\t_arrows[row][column] = Arrow.Diag;\r\n\t\t\t\t_diag[row][column] = _diag[row - 1][column - 1] + 1;\r\n\t\t\t} else {\r\n\t\t\t\tthrow new Error(`not possible`);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tif (_debug) {\r\n\t\tprintTables(pattern, patternStart, word, wordStart);\r\n\t}\r\n\r\n\tif (!hasStrongFirstMatch[0] && !firstMatchCanBeWeak) {\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\trow--;\r\n\tcolumn--;\r\n\r\n\tconst result: FuzzyScore = [_table[row][column], wordStart];\r\n\r\n\tlet backwardsDiagLength = 0;\r\n\tlet maxMatchColumn = 0;\r\n\r\n\twhile (row >= 1) {\r\n\t\t// Find the column where we go diagonally up\r\n\t\tlet diagColumn = column;\r\n\t\tdo {\r\n\t\t\tconst arrow = _arrows[row][diagColumn];\r\n\t\t\tif (arrow === Arrow.LeftLeft) {\r\n\t\t\t\tdiagColumn = diagColumn - 2;\r\n\t\t\t} else if (arrow === Arrow.Left) {\r\n\t\t\t\tdiagColumn = diagColumn - 1;\r\n\t\t\t} else {\r\n\t\t\t\t// found the diagonal\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t} while (diagColumn >= 1);\r\n\r\n\t\t// Overturn the \"forwards\" decision if keeping the \"backwards\" diagonal would give a better match\r\n\t\tif (\r\n\t\t\tbackwardsDiagLength > 1 // only if we would have a contiguous match of 3 characters\r\n\t\t\t&& patternLow[patternStart + row - 1] === wordLow[wordStart + column - 1] // only if we can do a contiguous match diagonally\r\n\t\t\t&& !isUpperCaseAtPos(diagColumn + wordStart - 1, word, wordLow) // only if the forwards chose diagonal is not an uppercase\r\n\t\t\t&& backwardsDiagLength + 1 > _diag[row][diagColumn] // only if our contiguous match would be longer than the \"forwards\" contiguous match\r\n\t\t) {\r\n\t\t\tdiagColumn = column;\r\n\t\t}\r\n\r\n\t\tif (diagColumn === column) {\r\n\t\t\t// this is a contiguous match\r\n\t\t\tbackwardsDiagLength++;\r\n\t\t} else {\r\n\t\t\tbackwardsDiagLength = 1;\r\n\t\t}\r\n\r\n\t\tif (!maxMatchColumn) {\r\n\t\t\t// remember the last matched column\r\n\t\t\tmaxMatchColumn = diagColumn;\r\n\t\t}\r\n\r\n\t\trow--;\r\n\t\tcolumn = diagColumn - 1;\r\n\t\tresult.push(column);\r\n\t}\r\n\r\n\tif (wordLen === patternLen) {\r\n\t\t// the word matches the pattern with all characters!\r\n\t\t// giving the score a total match boost (to come up ahead other words)\r\n\t\tresult[0] += 2;\r\n\t}\r\n\r\n\t// Add 1 penalty for each skipped character in the word\r\n\tconst skippedCharsCount = maxMatchColumn - patternLen;\r\n\tresult[0] -= skippedCharsCount;\r\n\r\n\treturn result;\r\n}\r\n\r\nfunction _fillInMaxWordMatchPos(patternLen: number, wordLen: number, patternStart: number, wordStart: number, patternLow: string, wordLow: string) {\r\n\tlet patternPos = patternLen - 1;\r\n\tlet wordPos = wordLen - 1;\r\n\twhile (patternPos >= patternStart && wordPos >= wordStart) {\r\n\t\tif (patternLow[patternPos] === wordLow[wordPos]) {\r\n\t\t\t_maxWordMatchPos[patternPos] = wordPos;\r\n\t\t\tpatternPos--;\r\n\t\t}\r\n\t\twordPos--;\r\n\t}\r\n}\r\n\r\nfunction _doScore(\r\n\tpattern: string, patternLow: string, patternPos: number, patternStart: number,\r\n\tword: string, wordLow: string, wordPos: number, wordLen: number, wordStart: number,\r\n\tnewMatchStart: boolean,\r\n\toutFirstMatchStrong: boolean[],\r\n): number {\r\n\tif (patternLow[patternPos] !== wordLow[wordPos]) {\r\n\t\treturn Number.MIN_SAFE_INTEGER;\r\n\t}\r\n\r\n\tlet score = 1;\r\n\tlet isGapLocation = false;\r\n\tif (wordPos === (patternPos - patternStart)) {\r\n\t\t// common prefix: `foobar <-> foobaz`\r\n\t\t// ^^^^^\r\n\t\tscore = pattern[patternPos] === word[wordPos] ? 7 : 5;\r\n\r\n\t} else if (isUpperCaseAtPos(wordPos, word, wordLow) && (wordPos === 0 || !isUpperCaseAtPos(wordPos - 1, word, wordLow))) {\r\n\t\t// hitting upper-case: `foo <-> forOthers`\r\n\t\t// ^^ ^\r\n\t\tscore = pattern[patternPos] === word[wordPos] ? 7 : 5;\r\n\t\tisGapLocation = true;\r\n\r\n\t} else if (isSeparatorAtPos(wordLow, wordPos) && (wordPos === 0 || !isSeparatorAtPos(wordLow, wordPos - 1))) {\r\n\t\t// hitting a separator: `. <-> foo.bar`\r\n\t\t// ^\r\n\t\tscore = 5;\r\n\r\n\t} else if (isSeparatorAtPos(wordLow, wordPos - 1) || isWhitespaceAtPos(wordLow, wordPos - 1)) {\r\n\t\t// post separator: `foo <-> bar_foo`\r\n\t\t// ^^^\r\n\t\tscore = 5;\r\n\t\tisGapLocation = true;\r\n\t}\r\n\r\n\tif (score > 1 && patternPos === patternStart) {\r\n\t\toutFirstMatchStrong[0] = true;\r\n\t}\r\n\r\n\tif (!isGapLocation) {\r\n\t\tisGapLocation = isUpperCaseAtPos(wordPos, word, wordLow) || isSeparatorAtPos(wordLow, wordPos - 1) || isWhitespaceAtPos(wordLow, wordPos - 1);\r\n\t}\r\n\r\n\t//\r\n\tif (patternPos === patternStart) { // first character in pattern\r\n\t\tif (wordPos > wordStart) {\r\n\t\t\t// the first pattern character would match a word character that is not at the word start\r\n\t\t\t// so introduce a penalty to account for the gap preceding this match\r\n\t\t\tscore -= isGapLocation ? 3 : 5;\r\n\t\t}\r\n\t} else {\r\n\t\tif (newMatchStart) {\r\n\t\t\t// this would be the beginning of a new match (i.e. there would be a gap before this location)\r\n\t\t\tscore += isGapLocation ? 2 : 0;\r\n\t\t} else {\r\n\t\t\t// this is part of a contiguous match, so give it a slight bonus, but do so only if it would not be a prefered gap location\r\n\t\t\tscore += isGapLocation ? 0 : 1;\r\n\t\t}\r\n\t}\r\n\r\n\tif (wordPos + 1 === wordLen) {\r\n\t\t// we always penalize gaps, but this gives unfair advantages to a match that would match the last character in the word\r\n\t\t// so pretend there is a gap after the last character in the word to normalize things\r\n\t\tscore -= isGapLocation ? 3 : 5;\r\n\t}\r\n\r\n\treturn score;\r\n}\r\n\r\n//#endregion\r\n\r\n\r\n//#region --- graceful ---\r\n\r\nexport function fuzzyScoreGracefulAggressive(pattern: string, lowPattern: string, patternPos: number, word: string, lowWord: string, wordPos: number, firstMatchCanBeWeak: boolean): FuzzyScore | undefined {\r\n\treturn fuzzyScoreWithPermutations(pattern, lowPattern, patternPos, word, lowWord, wordPos, true, firstMatchCanBeWeak);\r\n}\r\n\r\nfunction fuzzyScoreWithPermutations(pattern: string, lowPattern: string, patternPos: number, word: string, lowWord: string, wordPos: number, aggressive: boolean, firstMatchCanBeWeak: boolean): FuzzyScore | undefined {\r\n\tlet top = fuzzyScore(pattern, lowPattern, patternPos, word, lowWord, wordPos, firstMatchCanBeWeak);\r\n\r\n\tif (top && !aggressive) {\r\n\t\t// when using the original pattern yield a result we`\r\n\t\t// return it unless we are aggressive and try to find\r\n\t\t// a better alignment, e.g. `cno` -> `^co^ns^ole` or `^c^o^nsole`.\r\n\t\treturn top;\r\n\t}\r\n\r\n\tif (pattern.length >= 3) {\r\n\t\t// When the pattern is long enough then try a few (max 7)\r\n\t\t// permutations of the pattern to find a better match. The\r\n\t\t// permutations only swap neighbouring characters, e.g\r\n\t\t// `cnoso` becomes `conso`, `cnsoo`, `cnoos`.\r\n\t\tconst tries = Math.min(7, pattern.length - 1);\r\n\t\tfor (let movingPatternPos = patternPos + 1; movingPatternPos < tries; movingPatternPos++) {\r\n\t\t\tconst newPattern = nextTypoPermutation(pattern, movingPatternPos);\r\n\t\t\tif (newPattern) {\r\n\t\t\t\tconst candidate = fuzzyScore(newPattern, newPattern.toLowerCase(), patternPos, word, lowWord, wordPos, firstMatchCanBeWeak);\r\n\t\t\t\tif (candidate) {\r\n\t\t\t\t\tcandidate[0] -= 3; // permutation penalty\r\n\t\t\t\t\tif (!top || candidate[0] > top[0]) {\r\n\t\t\t\t\t\ttop = candidate;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\treturn top;\r\n}\r\n\r\nfunction nextTypoPermutation(pattern: string, patternPos: number): string | undefined {\r\n\r\n\tif (patternPos + 1 >= pattern.length) {\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tconst swap1 = pattern[patternPos];\r\n\tconst swap2 = pattern[patternPos + 1];\r\n\r\n\tif (swap1 === swap2) {\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\treturn pattern.slice(0, patternPos)\r\n\t\t+ swap2\r\n\t\t+ swap1\r\n\t\t+ pattern.slice(patternPos + 2);\r\n}\r\n\r\n//#endregion\r\n","\r\nimport { IMatch, fuzzyScore, createMatches as createFuzzyMatches } from 'vs/base/common/filters';\r\nimport { sep } from 'vs/base/common/path';\r\nimport { isWindows } from 'vs/base/common/platform';\r\nimport { stripWildcards } from 'vs/base/common/strings';\r\n\r\n// function printMatrix(query: string, target: string, matches: number[], scores: number[]): void {\r\n// \tconsole.log('\\t' + target.split('').join('\\t'));\r\n// \tfor (let queryIndex = 0; queryIndex < query.length; queryIndex++) {\r\n// \t\tlet line = query[queryIndex] + '\\t';\r\n// \t\tfor (let targetIndex = 0; targetIndex < target.length; targetIndex++) {\r\n// \t\t\tconst currentIndex = queryIndex * target.length + targetIndex;\r\n// \t\t\tline = line + 'M' + matches[currentIndex] + '/' + 'S' + scores[currentIndex] + '\\t';\r\n// \t\t}\r\n\r\n// \t\tconsole.log(line);\r\n// \t}\r\n// }\r\n\r\n//#endregion\r\n\r\n\r\n//#region Alternate fuzzy scorer implementation that is e.g. used for symbols\r\n\r\nexport type FuzzyScore2 = [number | undefined /* score */, IMatch[]];\r\n\r\nconst NO_SCORE2: FuzzyScore2 = [undefined, []];\r\n\r\nexport function scoreFuzzy2(target: string, query: IPreparedQuery | IPreparedQueryPiece, patternStart = 0, wordStart = 0): FuzzyScore2 {\r\n\r\n\t// Score: multiple inputs\r\n\tconst preparedQuery = query as IPreparedQuery;\r\n\tif (preparedQuery.values && preparedQuery.values.length > 1) {\r\n\t\treturn doScoreFuzzy2Multiple(target, preparedQuery.values, patternStart, wordStart);\r\n\t}\r\n\r\n\t// Score: single input\r\n\treturn doScoreFuzzy2Single(target, query, patternStart, wordStart);\r\n}\r\n\r\nfunction doScoreFuzzy2Multiple(target: string, query: IPreparedQueryPiece[], patternStart: number, wordStart: number): FuzzyScore2 {\r\n\tlet totalScore = 0;\r\n\tconst totalMatches: IMatch[] = [];\r\n\r\n\tfor (const queryPiece of query) {\r\n\t\tconst [score, matches] = doScoreFuzzy2Single(target, queryPiece, patternStart, wordStart);\r\n\t\tif (typeof score !== 'number') {\r\n\t\t\t// if a single query value does not match, return with\r\n\t\t\t// no score entirely, we require all queries to match\r\n\t\t\treturn NO_SCORE2;\r\n\t\t}\r\n\r\n\t\ttotalScore += score;\r\n\t\ttotalMatches.push(...matches);\r\n\t}\r\n\r\n\t// if we have a score, ensure that the positions are\r\n\t// sorted in ascending order and distinct\r\n\treturn [totalScore, normalizeMatches(totalMatches)];\r\n}\r\n\r\nfunction doScoreFuzzy2Single(target: string, query: IPreparedQueryPiece, patternStart: number, wordStart: number): FuzzyScore2 {\r\n\tconst score = fuzzyScore(query.original, query.originalLowercase, patternStart, target, target.toLowerCase(), wordStart, true);\r\n\tif (!score) {\r\n\t\treturn NO_SCORE2;\r\n\t}\r\n\r\n\treturn [score[0], createFuzzyMatches(score)];\r\n}\r\n\r\nfunction normalizeMatches(matches: IMatch[]): IMatch[] {\r\n\r\n\t// sort matches by start to be able to normalize\r\n\tconst sortedMatches = matches.sort((matchA, matchB) => {\r\n\t\treturn matchA.start - matchB.start;\r\n\t});\r\n\r\n\t// merge matches that overlap\r\n\tconst normalizedMatches: IMatch[] = [];\r\n\tlet currentMatch: IMatch | undefined = undefined;\r\n\tfor (const match of sortedMatches) {\r\n\r\n\t\t// if we have no current match or the matches\r\n\t\t// do not overlap, we take it as is and remember\r\n\t\t// it for future merging\r\n\t\tif (!currentMatch || !matchOverlaps(currentMatch, match)) {\r\n\t\t\tcurrentMatch = match;\r\n\t\t\tnormalizedMatches.push(match);\r\n\t\t}\r\n\r\n\t\t// otherwise we merge the matches\r\n\t\telse {\r\n\t\t\tcurrentMatch.start = Math.min(currentMatch.start, match.start);\r\n\t\t\tcurrentMatch.end = Math.max(currentMatch.end, match.end);\r\n\t\t}\r\n\t}\r\n\r\n\treturn normalizedMatches;\r\n}\r\n\r\nfunction matchOverlaps(matchA: IMatch, matchB: IMatch): boolean {\r\n\tif (matchA.end < matchB.start) {\r\n\t\treturn false;\t// A ends before B starts\r\n\t}\r\n\r\n\tif (matchB.end < matchA.start) {\r\n\t\treturn false; // B ends before A starts\r\n\t}\r\n\r\n\treturn true;\r\n}\r\n\r\n//#endregion\r\n\r\n\r\n//#region Query Normalizer\r\n\r\nexport interface IPreparedQueryPiece {\r\n\r\n\t/**\r\n\t * The original query as provided as input.\r\n\t */\r\n\toriginal: string;\r\n\toriginalLowercase: string;\r\n\r\n\t/**\r\n\t * Original normalized to platform separators:\r\n\t * - Windows: \\\r\n\t * - Posix: /\r\n\t */\r\n\tpathNormalized: string;\r\n\r\n\t/**\r\n\t * In addition to the normalized path, will have\r\n\t * whitespace and wildcards removed.\r\n\t */\r\n\tnormalized: string;\r\n\tnormalizedLowercase: string;\r\n}\r\n\r\nexport interface IPreparedQuery extends IPreparedQueryPiece {\r\n\r\n\t/**\r\n\t * Query split by spaces into pieces.\r\n\t */\r\n\tvalues: IPreparedQueryPiece[] | undefined;\r\n\r\n\t/**\r\n\t * Whether the query contains path separator(s) or not.\r\n\t */\r\n\tcontainsPathSeparator: boolean;\r\n}\r\n\r\n/**\r\n * Helper function to prepare a search value for scoring by removing unwanted characters\r\n * and allowing to score on multiple pieces separated by whitespace character.\r\n */\r\nconst MULTIPLE_QUERY_VALUES_SEPARATOR = ' ';\r\nexport function prepareQuery(original: string): IPreparedQuery {\r\n\tif (typeof original !== 'string') {\r\n\t\toriginal = '';\r\n\t}\r\n\r\n\tconst originalLowercase = original.toLowerCase();\r\n\tconst { pathNormalized, normalized, normalizedLowercase } = normalizeQuery(original);\r\n\tconst containsPathSeparator = pathNormalized.indexOf(sep) >= 0;\r\n\r\n\tlet values: IPreparedQueryPiece[] | undefined = undefined;\r\n\r\n\tconst originalSplit = original.split(MULTIPLE_QUERY_VALUES_SEPARATOR);\r\n\tif (originalSplit.length > 1) {\r\n\t\tfor (const originalPiece of originalSplit) {\r\n\t\t\tconst {\r\n\t\t\t\tpathNormalized: pathNormalizedPiece,\r\n\t\t\t\tnormalized: normalizedPiece,\r\n\t\t\t\tnormalizedLowercase: normalizedLowercasePiece\r\n\t\t\t} = normalizeQuery(originalPiece);\r\n\r\n\t\t\tif (normalizedPiece) {\r\n\t\t\t\tif (!values) {\r\n\t\t\t\t\tvalues = [];\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvalues.push({\r\n\t\t\t\t\toriginal: originalPiece,\r\n\t\t\t\t\toriginalLowercase: originalPiece.toLowerCase(),\r\n\t\t\t\t\tpathNormalized: pathNormalizedPiece,\r\n\t\t\t\t\tnormalized: normalizedPiece,\r\n\t\t\t\t\tnormalizedLowercase: normalizedLowercasePiece\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\treturn { original, originalLowercase, pathNormalized, normalized, normalizedLowercase, values, containsPathSeparator };\r\n}\r\n\r\nfunction normalizeQuery(original: string): { pathNormalized: string, normalized: string, normalizedLowercase: string } {\r\n\tlet pathNormalized: string;\r\n\tif (isWindows) {\r\n\t\tpathNormalized = original.replace(/\\//g, sep); // Help Windows users to search for paths when using slash\r\n\t} else {\r\n\t\tpathNormalized = original.replace(/\\\\/g, sep); // Help macOS/Linux users to search for paths when using backslash\r\n\t}\r\n\r\n\tconst normalized = stripWildcards(pathNormalized).replace(/\\s/g, '');\r\n\r\n\treturn {\r\n\t\tpathNormalized,\r\n\t\tnormalized,\r\n\t\tnormalizedLowercase: normalized.toLowerCase()\r\n\t};\r\n}\r\n\r\nexport function pieceToQuery(piece: IPreparedQueryPiece): IPreparedQuery;\r\nexport function pieceToQuery(pieces: IPreparedQueryPiece[]): IPreparedQuery;\r\nexport function pieceToQuery(arg1: IPreparedQueryPiece | IPreparedQueryPiece[]): IPreparedQuery {\r\n\tif (Array.isArray(arg1)) {\r\n\t\treturn prepareQuery(arg1.map(piece => piece.original).join(MULTIPLE_QUERY_VALUES_SEPARATOR));\r\n\t}\r\n\r\n\treturn prepareQuery(arg1.original);\r\n}\r\n\r\n//#endregion\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as strings from 'vs/base/common/strings';\r\nimport * as extpath from 'vs/base/common/extpath';\r\nimport * as paths from 'vs/base/common/path';\r\nimport { LRUCache } from 'vs/base/common/map';\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport { isThenable } from 'vs/base/common/async';\r\n\r\nexport interface IExpression {\r\n\t[pattern: string]: boolean | SiblingClause;\r\n}\r\n\r\nexport interface IRelativePattern {\r\n\tbase: string;\r\n\tpattern: string;\r\n}\r\n\r\nexport interface SiblingClause {\r\n\twhen: string;\r\n}\r\n\r\nconst GLOBSTAR = '**';\r\nconst GLOB_SPLIT = '/';\r\nconst PATH_REGEX = '[/\\\\\\\\]';\t\t// any slash or backslash\r\nconst NO_PATH_REGEX = '[^/\\\\\\\\]';\t// any non-slash and non-backslash\r\nconst ALL_FORWARD_SLASHES = /\\//g;\r\n\r\nfunction starsToRegExp(starCount: number): string {\r\n\tswitch (starCount) {\r\n\t\tcase 0:\r\n\t\t\treturn '';\r\n\t\tcase 1:\r\n\t\t\treturn `${NO_PATH_REGEX}*?`; // 1 star matches any number of characters except path separator (/ and \\) - non greedy (?)\r\n\t\tdefault:\r\n\t\t\t// Matches: (Path Sep OR Path Val followed by Path Sep OR Path Sep followed by Path Val) 0-many times\r\n\t\t\t// Group is non capturing because we don't need to capture at all (?:...)\r\n\t\t\t// Overall we use non-greedy matching because it could be that we match too much\r\n\t\t\treturn `(?:${PATH_REGEX}|${NO_PATH_REGEX}+${PATH_REGEX}|${PATH_REGEX}${NO_PATH_REGEX}+)*?`;\r\n\t}\r\n}\r\n\r\nexport function splitGlobAware(pattern: string, splitChar: string): string[] {\r\n\tif (!pattern) {\r\n\t\treturn [];\r\n\t}\r\n\r\n\tconst segments: string[] = [];\r\n\r\n\tlet inBraces = false;\r\n\tlet inBrackets = false;\r\n\r\n\tlet curVal = '';\r\n\tfor (const char of pattern) {\r\n\t\tswitch (char) {\r\n\t\t\tcase splitChar:\r\n\t\t\t\tif (!inBraces && !inBrackets) {\r\n\t\t\t\t\tsegments.push(curVal);\r\n\t\t\t\t\tcurVal = '';\r\n\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\tbreak;\r\n\t\t\tcase '{':\r\n\t\t\t\tinBraces = true;\r\n\t\t\t\tbreak;\r\n\t\t\tcase '}':\r\n\t\t\t\tinBraces = false;\r\n\t\t\t\tbreak;\r\n\t\t\tcase '[':\r\n\t\t\t\tinBrackets = true;\r\n\t\t\t\tbreak;\r\n\t\t\tcase ']':\r\n\t\t\t\tinBrackets = false;\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcurVal += char;\r\n\t}\r\n\r\n\t// Tail\r\n\tif (curVal) {\r\n\t\tsegments.push(curVal);\r\n\t}\r\n\r\n\treturn segments;\r\n}\r\n\r\nfunction parseRegExp(pattern: string): string {\r\n\tif (!pattern) {\r\n\t\treturn '';\r\n\t}\r\n\r\n\tlet regEx = '';\r\n\r\n\t// Split up into segments for each slash found\r\n\tconst segments = splitGlobAware(pattern, GLOB_SPLIT);\r\n\r\n\t// Special case where we only have globstars\r\n\tif (segments.every(s => s === GLOBSTAR)) {\r\n\t\tregEx = '.*';\r\n\t}\r\n\r\n\t// Build regex over segments\r\n\telse {\r\n\t\tlet previousSegmentWasGlobStar = false;\r\n\t\tsegments.forEach((segment, index) => {\r\n\r\n\t\t\t// Globstar is special\r\n\t\t\tif (segment === GLOBSTAR) {\r\n\r\n\t\t\t\t// if we have more than one globstar after another, just ignore it\r\n\t\t\t\tif (!previousSegmentWasGlobStar) {\r\n\t\t\t\t\tregEx += starsToRegExp(2);\r\n\t\t\t\t\tpreviousSegmentWasGlobStar = true;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\t// States\r\n\t\t\tlet inBraces = false;\r\n\t\t\tlet braceVal = '';\r\n\r\n\t\t\tlet inBrackets = false;\r\n\t\t\tlet bracketVal = '';\r\n\r\n\t\t\tfor (const char of segment) {\r\n\t\t\t\t// Support brace expansion\r\n\t\t\t\tif (char !== '}' && inBraces) {\r\n\t\t\t\t\tbraceVal += char;\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Support brackets\r\n\t\t\t\tif (inBrackets && (char !== ']' || !bracketVal) /* ] is literally only allowed as first character in brackets to match it */) {\r\n\t\t\t\t\tlet res: string;\r\n\r\n\t\t\t\t\t// range operator\r\n\t\t\t\t\tif (char === '-') {\r\n\t\t\t\t\t\tres = char;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t// negation operator (only valid on first index in bracket)\r\n\t\t\t\t\telse if ((char === '^' || char === '!') && !bracketVal) {\r\n\t\t\t\t\t\tres = '^';\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t// glob split matching is not allowed within character ranges\r\n\t\t\t\t\t// see http://man7.org/linux/man-pages/man7/glob.7.html\r\n\t\t\t\t\telse if (char === GLOB_SPLIT) {\r\n\t\t\t\t\t\tres = '';\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t// anything else gets escaped\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tres = strings.escapeRegExpCharacters(char);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tbracketVal += res;\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tswitch (char) {\r\n\t\t\t\t\tcase '{':\r\n\t\t\t\t\t\tinBraces = true;\r\n\t\t\t\t\t\tcontinue;\r\n\r\n\t\t\t\t\tcase '[':\r\n\t\t\t\t\t\tinBrackets = true;\r\n\t\t\t\t\t\tcontinue;\r\n\r\n\t\t\t\t\tcase '}':\r\n\t\t\t\t\t\tconst choices = splitGlobAware(braceVal, ',');\r\n\r\n\t\t\t\t\t\t// Converts {foo,bar} => [foo|bar]\r\n\t\t\t\t\t\tconst braceRegExp = `(?:${choices.map(c => parseRegExp(c)).join('|')})`;\r\n\r\n\t\t\t\t\t\tregEx += braceRegExp;\r\n\r\n\t\t\t\t\t\tinBraces = false;\r\n\t\t\t\t\t\tbraceVal = '';\r\n\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\tcase ']':\r\n\t\t\t\t\t\tregEx += ('[' + bracketVal + ']');\r\n\r\n\t\t\t\t\t\tinBrackets = false;\r\n\t\t\t\t\t\tbracketVal = '';\r\n\r\n\t\t\t\t\t\tbreak;\r\n\r\n\r\n\t\t\t\t\tcase '?':\r\n\t\t\t\t\t\tregEx += NO_PATH_REGEX; // 1 ? matches any single character except path separator (/ and \\)\r\n\t\t\t\t\t\tcontinue;\r\n\r\n\t\t\t\t\tcase '*':\r\n\t\t\t\t\t\tregEx += starsToRegExp(1);\r\n\t\t\t\t\t\tcontinue;\r\n\r\n\t\t\t\t\tdefault:\r\n\t\t\t\t\t\tregEx += strings.escapeRegExpCharacters(char);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// Tail: Add the slash we had split on if there is more to come and the remaining pattern is not a globstar\r\n\t\t\t// For example if pattern: some/**/*.js we want the \"/\" after some to be included in the RegEx to prevent\r\n\t\t\t// a folder called \"something\" to match as well.\r\n\t\t\t// However, if pattern: some/**, we tolerate that we also match on \"something\" because our globstar behaviour\r\n\t\t\t// is to match 0-N segments.\r\n\t\t\tif (index < segments.length - 1 && (segments[index + 1] !== GLOBSTAR || index + 2 < segments.length)) {\r\n\t\t\t\tregEx += PATH_REGEX;\r\n\t\t\t}\r\n\r\n\t\t\t// reset state\r\n\t\t\tpreviousSegmentWasGlobStar = false;\r\n\t\t});\r\n\t}\r\n\r\n\treturn regEx;\r\n}\r\n\r\n// regexes to check for trival glob patterns that just check for String#endsWith\r\nconst T1 = /^\\*\\*\\/\\*\\.[\\w\\.-]+$/; \t\t\t\t\t\t \t\t\t// **/*.something\r\nconst T2 = /^\\*\\*\\/([\\w\\.-]+)\\/?$/; \t\t\t\t\t\t\t \t\t\t// **/something\r\nconst T3 = /^{\\*\\*\\/[\\*\\.]?[\\w\\.-]+\\/?(,\\*\\*\\/[\\*\\.]?[\\w\\.-]+\\/?)*}$/; \t// {**/*.something,**/*.else} or {**/package.json,**/project.json}\r\nconst T3_2 = /^{\\*\\*\\/[\\*\\.]?[\\w\\.-]+(\\/(\\*\\*)?)?(,\\*\\*\\/[\\*\\.]?[\\w\\.-]+(\\/(\\*\\*)?)?)*}$/; \t// Like T3, with optional trailing /**\r\nconst T4 = /^\\*\\*((\\/[\\w\\.-]+)+)\\/?$/; \t\t\t\t\t\t \t\t\t// **/something/else\r\nconst T5 = /^([\\w\\.-]+(\\/[\\w\\.-]+)*)\\/?$/; \t\t\t\t\t\t \t\t// something/else\r\n\r\nexport type ParsedPattern = (path: string, basename?: string) => boolean;\r\n\r\n// The ParsedExpression returns a Promise iff hasSibling returns a Promise.\r\nexport type ParsedExpression = (path: string, basename?: string, hasSibling?: (name: string) => boolean | Promise) => string | null | Promise /* the matching pattern */;\r\n\r\nexport interface IGlobOptions {\r\n\t/**\r\n\t * Simplify patterns for use as exclusion filters during tree traversal to skip entire subtrees. Cannot be used outside of a tree traversal.\r\n\t */\r\n\ttrimForExclusions?: boolean;\r\n}\r\n\r\ninterface ParsedStringPattern {\r\n\t(path: string, basename?: string): string | null | Promise /* the matching pattern */;\r\n\tbasenames?: string[];\r\n\tpatterns?: string[];\r\n\tallBasenames?: string[];\r\n\tallPaths?: string[];\r\n}\r\ninterface ParsedExpressionPattern {\r\n\t(path: string, basename?: string, name?: string, hasSibling?: (name: string) => boolean | Promise): string | null | Promise /* the matching pattern */;\r\n\trequiresSiblings?: boolean;\r\n\tallPaths?: string[];\r\n}\r\n\r\nconst CACHE = new LRUCache(10000); // bounded to 10000 elements\r\n\r\nconst FALSE = function () {\r\n\treturn false;\r\n};\r\n\r\nconst NULL = function (): string | null {\r\n\treturn null;\r\n};\r\n\r\nfunction parsePattern(arg1: string | IRelativePattern, options: IGlobOptions): ParsedStringPattern {\r\n\tif (!arg1) {\r\n\t\treturn NULL;\r\n\t}\r\n\r\n\t// Handle IRelativePattern\r\n\tlet pattern: string;\r\n\tif (typeof arg1 !== 'string') {\r\n\t\tpattern = arg1.pattern;\r\n\t} else {\r\n\t\tpattern = arg1;\r\n\t}\r\n\r\n\t// Whitespace trimming\r\n\tpattern = pattern.trim();\r\n\r\n\t// Check cache\r\n\tconst patternKey = `${pattern}_${!!options.trimForExclusions}`;\r\n\tlet parsedPattern = CACHE.get(patternKey);\r\n\tif (parsedPattern) {\r\n\t\treturn wrapRelativePattern(parsedPattern, arg1);\r\n\t}\r\n\r\n\t// Check for Trivias\r\n\tlet match: RegExpExecArray | null;\r\n\tif (T1.test(pattern)) { // common pattern: **/*.txt just need endsWith check\r\n\t\tconst base = pattern.substr(4); // '**/*'.length === 4\r\n\t\tparsedPattern = function (path, basename) {\r\n\t\t\treturn typeof path === 'string' && path.endsWith(base) ? pattern : null;\r\n\t\t};\r\n\t} else if (match = T2.exec(trimForExclusions(pattern, options))) { // common pattern: **/some.txt just need basename check\r\n\t\tparsedPattern = trivia2(match[1], pattern);\r\n\t} else if ((options.trimForExclusions ? T3_2 : T3).test(pattern)) { // repetition of common patterns (see above) {**/*.txt,**/*.png}\r\n\t\tparsedPattern = trivia3(pattern, options);\r\n\t} else if (match = T4.exec(trimForExclusions(pattern, options))) { // common pattern: **/something/else just need endsWith check\r\n\t\tparsedPattern = trivia4and5(match[1].substr(1), pattern, true);\r\n\t} else if (match = T5.exec(trimForExclusions(pattern, options))) { // common pattern: something/else just need equals check\r\n\t\tparsedPattern = trivia4and5(match[1], pattern, false);\r\n\t}\r\n\r\n\t// Otherwise convert to pattern\r\n\telse {\r\n\t\tparsedPattern = toRegExp(pattern);\r\n\t}\r\n\r\n\t// Cache\r\n\tCACHE.set(patternKey, parsedPattern);\r\n\r\n\treturn wrapRelativePattern(parsedPattern, arg1);\r\n}\r\n\r\nfunction wrapRelativePattern(parsedPattern: ParsedStringPattern, arg2: string | IRelativePattern): ParsedStringPattern {\r\n\tif (typeof arg2 === 'string') {\r\n\t\treturn parsedPattern;\r\n\t}\r\n\r\n\treturn function (path, basename) {\r\n\t\tif (!extpath.isEqualOrParent(path, arg2.base)) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn parsedPattern(paths.relative(arg2.base, path), basename);\r\n\t};\r\n}\r\n\r\nfunction trimForExclusions(pattern: string, options: IGlobOptions): string {\r\n\treturn options.trimForExclusions && pattern.endsWith('/**') ? pattern.substr(0, pattern.length - 2) : pattern; // dropping **, tailing / is dropped later\r\n}\r\n\r\n// common pattern: **/some.txt just need basename check\r\nfunction trivia2(base: string, originalPattern: string): ParsedStringPattern {\r\n\tconst slashBase = `/${base}`;\r\n\tconst backslashBase = `\\\\${base}`;\r\n\tconst parsedPattern: ParsedStringPattern = function (path, basename) {\r\n\t\tif (typeof path !== 'string') {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tif (basename) {\r\n\t\t\treturn basename === base ? originalPattern : null;\r\n\t\t}\r\n\t\treturn path === base || path.endsWith(slashBase) || path.endsWith(backslashBase) ? originalPattern : null;\r\n\t};\r\n\tconst basenames = [base];\r\n\tparsedPattern.basenames = basenames;\r\n\tparsedPattern.patterns = [originalPattern];\r\n\tparsedPattern.allBasenames = basenames;\r\n\treturn parsedPattern;\r\n}\r\n\r\n// repetition of common patterns (see above) {**/*.txt,**/*.png}\r\nfunction trivia3(pattern: string, options: IGlobOptions): ParsedStringPattern {\r\n\tconst parsedPatterns = aggregateBasenameMatches(pattern.slice(1, -1).split(',')\r\n\t\t.map(pattern => parsePattern(pattern, options))\r\n\t\t.filter(pattern => pattern !== NULL), pattern);\r\n\tconst n = parsedPatterns.length;\r\n\tif (!n) {\r\n\t\treturn NULL;\r\n\t}\r\n\tif (n === 1) {\r\n\t\treturn parsedPatterns[0];\r\n\t}\r\n\tconst parsedPattern: ParsedStringPattern = function (path: string, basename?: string) {\r\n\t\tfor (let i = 0, n = parsedPatterns.length; i < n; i++) {\r\n\t\t\tif ((parsedPatterns[i])(path, basename)) {\r\n\t\t\t\treturn pattern;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn null;\r\n\t};\r\n\tconst withBasenames = parsedPatterns.find(pattern => !!(pattern).allBasenames);\r\n\tif (withBasenames) {\r\n\t\tparsedPattern.allBasenames = (withBasenames).allBasenames;\r\n\t}\r\n\tconst allPaths = parsedPatterns.reduce((all, current) => current.allPaths ? all.concat(current.allPaths) : all, []);\r\n\tif (allPaths.length) {\r\n\t\tparsedPattern.allPaths = allPaths;\r\n\t}\r\n\treturn parsedPattern;\r\n}\r\n\r\n// common patterns: **/something/else just need endsWith check, something/else just needs and equals check\r\nfunction trivia4and5(targetPath: string, pattern: string, matchPathEnds: boolean): ParsedStringPattern {\r\n\tconst usingPosixSep = paths.sep === paths.posix.sep;\r\n\tconst nativePath = usingPosixSep ? targetPath : targetPath.replace(ALL_FORWARD_SLASHES, paths.sep);\r\n\tconst nativePathEnd = paths.sep + nativePath;\r\n\tconst targetPathEnd = paths.posix.sep + targetPath;\r\n\r\n\tconst parsedPattern: ParsedStringPattern = matchPathEnds ? function (testPath, basename) {\r\n\t\treturn typeof testPath === 'string' &&\r\n\t\t\t((testPath === nativePath || testPath.endsWith(nativePathEnd))\r\n\t\t\t\t|| !usingPosixSep && (testPath === targetPath || testPath.endsWith(targetPathEnd)))\r\n\t\t\t? pattern : null;\r\n\t} : function (testPath, basename) {\r\n\t\treturn typeof testPath === 'string' &&\r\n\t\t\t(testPath === nativePath\r\n\t\t\t\t|| (!usingPosixSep && testPath === targetPath))\r\n\t\t\t? pattern : null;\r\n\t};\r\n\tparsedPattern.allPaths = [(matchPathEnds ? '*/' : './') + targetPath];\r\n\treturn parsedPattern;\r\n}\r\n\r\nfunction toRegExp(pattern: string): ParsedStringPattern {\r\n\ttry {\r\n\t\tconst regExp = new RegExp(`^${parseRegExp(pattern)}$`);\r\n\t\treturn function (path: string) {\r\n\t\t\tregExp.lastIndex = 0; // reset RegExp to its initial state to reuse it!\r\n\t\t\treturn typeof path === 'string' && regExp.test(path) ? pattern : null;\r\n\t\t};\r\n\t} catch (error) {\r\n\t\treturn NULL;\r\n\t}\r\n}\r\n\r\n/**\r\n * Simplified glob matching. Supports a subset of glob patterns:\r\n * - * matches anything inside a path segment\r\n * - ? matches 1 character inside a path segment\r\n * - ** matches anything including an empty path segment\r\n * - simple brace expansion ({js,ts} => js or ts)\r\n * - character ranges (using [...])\r\n */\r\nexport function match(pattern: string | IRelativePattern, path: string): boolean;\r\nexport function match(expression: IExpression, path: string, hasSibling?: (name: string) => boolean): string /* the matching pattern */;\r\nexport function match(arg1: string | IExpression | IRelativePattern, path: string, hasSibling?: (name: string) => boolean): boolean | string | null | Promise {\r\n\tif (!arg1 || typeof path !== 'string') {\r\n\t\treturn false;\r\n\t}\r\n\r\n\treturn parse(arg1)(path, undefined, hasSibling);\r\n}\r\n\r\n/**\r\n * Simplified glob matching. Supports a subset of glob patterns:\r\n * - * matches anything inside a path segment\r\n * - ? matches 1 character inside a path segment\r\n * - ** matches anything including an empty path segment\r\n * - simple brace expansion ({js,ts} => js or ts)\r\n * - character ranges (using [...])\r\n */\r\nexport function parse(pattern: string | IRelativePattern, options?: IGlobOptions): ParsedPattern;\r\nexport function parse(expression: IExpression, options?: IGlobOptions): ParsedExpression;\r\nexport function parse(arg1: string | IExpression | IRelativePattern, options: IGlobOptions = {}): ParsedPattern | ParsedExpression {\r\n\tif (!arg1) {\r\n\t\treturn FALSE;\r\n\t}\r\n\r\n\t// Glob with String\r\n\tif (typeof arg1 === 'string' || isRelativePattern(arg1)) {\r\n\t\tconst parsedPattern = parsePattern(arg1, options);\r\n\t\tif (parsedPattern === NULL) {\r\n\t\t\treturn FALSE;\r\n\t\t}\r\n\t\tconst resultPattern: ParsedPattern & { allBasenames?: string[]; allPaths?: string[]; } = function (path: string, basename?: string) {\r\n\t\t\treturn !!parsedPattern(path, basename);\r\n\t\t};\r\n\t\tif (parsedPattern.allBasenames) {\r\n\t\t\tresultPattern.allBasenames = parsedPattern.allBasenames;\r\n\t\t}\r\n\t\tif (parsedPattern.allPaths) {\r\n\t\t\tresultPattern.allPaths = parsedPattern.allPaths;\r\n\t\t}\r\n\t\treturn resultPattern;\r\n\t}\r\n\r\n\t// Glob with Expression\r\n\treturn parsedExpression(arg1, options);\r\n}\r\n\r\nexport function isRelativePattern(obj: unknown): obj is IRelativePattern {\r\n\tconst rp = obj as IRelativePattern;\r\n\r\n\treturn rp && typeof rp.base === 'string' && typeof rp.pattern === 'string';\r\n}\r\n\r\nfunction parsedExpression(expression: IExpression, options: IGlobOptions): ParsedExpression {\r\n\tconst parsedPatterns = aggregateBasenameMatches(Object.getOwnPropertyNames(expression)\r\n\t\t.map(pattern => parseExpressionPattern(pattern, expression[pattern], options))\r\n\t\t.filter(pattern => pattern !== NULL));\r\n\r\n\tconst n = parsedPatterns.length;\r\n\tif (!n) {\r\n\t\treturn NULL;\r\n\t}\r\n\r\n\tif (!parsedPatterns.some(parsedPattern => !!(parsedPattern).requiresSiblings)) {\r\n\t\tif (n === 1) {\r\n\t\t\treturn parsedPatterns[0];\r\n\t\t}\r\n\r\n\t\tconst resultExpression: ParsedStringPattern = function (path: string, basename?: string) {\r\n\t\t\tfor (let i = 0, n = parsedPatterns.length; i < n; i++) {\r\n\t\t\t\t// Pattern matches path\r\n\t\t\t\tconst result = (parsedPatterns[i])(path, basename);\r\n\t\t\t\tif (result) {\r\n\t\t\t\t\treturn result;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn null;\r\n\t\t};\r\n\r\n\t\tconst withBasenames = parsedPatterns.find(pattern => !!(pattern).allBasenames);\r\n\t\tif (withBasenames) {\r\n\t\t\tresultExpression.allBasenames = (withBasenames).allBasenames;\r\n\t\t}\r\n\r\n\t\tconst allPaths = parsedPatterns.reduce((all, current) => current.allPaths ? all.concat(current.allPaths) : all, []);\r\n\t\tif (allPaths.length) {\r\n\t\t\tresultExpression.allPaths = allPaths;\r\n\t\t}\r\n\r\n\t\treturn resultExpression;\r\n\t}\r\n\r\n\tconst resultExpression: ParsedStringPattern = function (path: string, basename?: string, hasSibling?: (name: string) => boolean | Promise) {\r\n\t\tlet name: string | undefined = undefined;\r\n\r\n\t\tfor (let i = 0, n = parsedPatterns.length; i < n; i++) {\r\n\t\t\t// Pattern matches path\r\n\t\t\tconst parsedPattern = (parsedPatterns[i]);\r\n\t\t\tif (parsedPattern.requiresSiblings && hasSibling) {\r\n\t\t\t\tif (!basename) {\r\n\t\t\t\t\tbasename = paths.basename(path);\r\n\t\t\t\t}\r\n\t\t\t\tif (!name) {\r\n\t\t\t\t\tname = basename.substr(0, basename.length - paths.extname(path).length);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tconst result = parsedPattern(path, basename, name, hasSibling);\r\n\t\t\tif (result) {\r\n\t\t\t\treturn result;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t};\r\n\r\n\tconst withBasenames = parsedPatterns.find(pattern => !!(pattern).allBasenames);\r\n\tif (withBasenames) {\r\n\t\tresultExpression.allBasenames = (withBasenames).allBasenames;\r\n\t}\r\n\r\n\tconst allPaths = parsedPatterns.reduce((all, current) => current.allPaths ? all.concat(current.allPaths) : all, []);\r\n\tif (allPaths.length) {\r\n\t\tresultExpression.allPaths = allPaths;\r\n\t}\r\n\r\n\treturn resultExpression;\r\n}\r\n\r\nfunction parseExpressionPattern(pattern: string, value: boolean | SiblingClause, options: IGlobOptions): (ParsedStringPattern | ParsedExpressionPattern) {\r\n\tif (value === false) {\r\n\t\treturn NULL; // pattern is disabled\r\n\t}\r\n\r\n\tconst parsedPattern = parsePattern(pattern, options);\r\n\tif (parsedPattern === NULL) {\r\n\t\treturn NULL;\r\n\t}\r\n\r\n\t// Expression Pattern is \r\n\tif (typeof value === 'boolean') {\r\n\t\treturn parsedPattern;\r\n\t}\r\n\r\n\t// Expression Pattern is \r\n\tif (value) {\r\n\t\tconst when = (value).when;\r\n\t\tif (typeof when === 'string') {\r\n\t\t\tconst result: ParsedExpressionPattern = (path: string, basename?: string, name?: string, hasSibling?: (name: string) => boolean | Promise) => {\r\n\t\t\t\tif (!hasSibling || !parsedPattern(path, basename)) {\r\n\t\t\t\t\treturn null;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst clausePattern = when.replace('$(basename)', name!);\r\n\t\t\t\tconst matched = hasSibling(clausePattern);\r\n\t\t\t\treturn isThenable(matched) ?\r\n\t\t\t\t\tmatched.then(m => m ? pattern : null) :\r\n\t\t\t\t\tmatched ? pattern : null;\r\n\t\t\t};\r\n\t\t\tresult.requiresSiblings = true;\r\n\t\t\treturn result;\r\n\t\t}\r\n\t}\r\n\r\n\t// Expression is Anything\r\n\treturn parsedPattern;\r\n}\r\n\r\nfunction aggregateBasenameMatches(parsedPatterns: Array, result?: string): Array {\r\n\tconst basenamePatterns = parsedPatterns.filter(parsedPattern => !!(parsedPattern).basenames);\r\n\tif (basenamePatterns.length < 2) {\r\n\t\treturn parsedPatterns;\r\n\t}\r\n\r\n\tconst basenames = basenamePatterns.reduce((all, current) => {\r\n\t\tconst basenames = (current).basenames;\r\n\t\treturn basenames ? all.concat(basenames) : all;\r\n\t}, []);\r\n\tlet patterns: string[];\r\n\tif (result) {\r\n\t\tpatterns = [];\r\n\t\tfor (let i = 0, n = basenames.length; i < n; i++) {\r\n\t\t\tpatterns.push(result);\r\n\t\t}\r\n\t} else {\r\n\t\tpatterns = basenamePatterns.reduce((all, current) => {\r\n\t\t\tconst patterns = (current).patterns;\r\n\t\t\treturn patterns ? all.concat(patterns) : all;\r\n\t\t}, []);\r\n\t}\r\n\tconst aggregate: ParsedStringPattern = function (path, basename) {\r\n\t\tif (typeof path !== 'string') {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tif (!basename) {\r\n\t\t\tlet i: number;\r\n\t\t\tfor (i = path.length; i > 0; i--) {\r\n\t\t\t\tconst ch = path.charCodeAt(i - 1);\r\n\t\t\t\tif (ch === CharCode.Slash || ch === CharCode.Backslash) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tbasename = path.substr(i);\r\n\t\t}\r\n\t\tconst index = basenames.indexOf(basename);\r\n\t\treturn index !== -1 ? patterns[index] : null;\r\n\t};\r\n\taggregate.basenames = basenames;\r\n\taggregate.patterns = patterns;\r\n\taggregate.allBasenames = basenames;\r\n\r\n\tconst aggregatedPatterns = parsedPatterns.filter(parsedPattern => !(parsedPattern).basenames);\r\n\taggregatedPatterns.push(aggregate);\r\n\treturn aggregatedPatterns;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { matchesFuzzy, IMatch } from 'vs/base/common/filters';\r\nimport { ltrim } from 'vs/base/common/strings';\r\n\r\nexport const iconStartMarker = '$(';\r\n\r\nconst escapeIconsRegex = /(\\\\)?\\$\\([a-z0-9\\-]+?(?:~[a-z0-9\\-]*?)?\\)/gi;\r\nexport function escapeIcons(text: string): string {\r\n\treturn text.replace(escapeIconsRegex, (match, escaped) => escaped ? match : `\\\\${match}`);\r\n}\r\n\r\nconst markdownEscapedIconsRegex = /\\\\\\$\\([a-z0-9\\-]+?(?:~[a-z0-9\\-]*?)?\\)/gi;\r\nexport function markdownEscapeEscapedIcons(text: string): string {\r\n\t// Need to add an extra \\ for escaping in markdown\r\n\treturn text.replace(markdownEscapedIconsRegex, match => `\\\\${match}`);\r\n}\r\n\r\nconst stripIconsRegex = /(\\s)?(\\\\)?\\$\\([a-z0-9\\-]+?(?:~[a-z0-9\\-]*?)?\\)(\\s)?/gi;\r\nexport function stripIcons(text: string): string {\r\n\tif (text.indexOf(iconStartMarker) === -1) {\r\n\t\treturn text;\r\n\t}\r\n\r\n\treturn text.replace(stripIconsRegex, (match, preWhitespace, escaped, postWhitespace) => escaped ? match : preWhitespace || postWhitespace || '');\r\n}\r\n\r\n\r\nexport interface IParsedLabelWithIcons {\r\n\treadonly text: string;\r\n\treadonly iconOffsets?: readonly number[];\r\n}\r\n\r\nexport function parseLabelWithIcons(text: string): IParsedLabelWithIcons {\r\n\tconst firstIconIndex = text.indexOf(iconStartMarker);\r\n\tif (firstIconIndex === -1) {\r\n\t\treturn { text }; // return early if the word does not include an icon\r\n\t}\r\n\r\n\treturn doParseLabelWithIcons(text, firstIconIndex);\r\n}\r\n\r\nfunction doParseLabelWithIcons(text: string, firstIconIndex: number): IParsedLabelWithIcons {\r\n\tconst iconOffsets: number[] = [];\r\n\tlet textWithoutIcons: string = '';\r\n\r\n\tfunction appendChars(chars: string) {\r\n\t\tif (chars) {\r\n\t\t\ttextWithoutIcons += chars;\r\n\r\n\t\t\tfor (const _ of chars) {\r\n\t\t\t\ticonOffsets.push(iconsOffset); // make sure to fill in icon offsets\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tlet currentIconStart = -1;\r\n\tlet currentIconValue: string = '';\r\n\tlet iconsOffset = 0;\r\n\r\n\tlet char: string;\r\n\tlet nextChar: string;\r\n\r\n\tlet offset = firstIconIndex;\r\n\tconst length = text.length;\r\n\r\n\t// Append all characters until the first icon\r\n\tappendChars(text.substr(0, firstIconIndex));\r\n\r\n\t// example: $(file-symlink-file) my cool $(other-icon) entry\r\n\twhile (offset < length) {\r\n\t\tchar = text[offset];\r\n\t\tnextChar = text[offset + 1];\r\n\r\n\t\t// beginning of icon: some value $( <--\r\n\t\tif (char === iconStartMarker[0] && nextChar === iconStartMarker[1]) {\r\n\t\t\tcurrentIconStart = offset;\r\n\r\n\t\t\t// if we had a previous potential icon value without\r\n\t\t\t// the closing ')', it was actually not an icon and\r\n\t\t\t// so we have to add it to the actual value\r\n\t\t\tappendChars(currentIconValue);\r\n\r\n\t\t\tcurrentIconValue = iconStartMarker;\r\n\r\n\t\t\toffset++; // jump over '('\r\n\t\t}\r\n\r\n\t\t// end of icon: some value $(some-icon) <--\r\n\t\telse if (char === ')' && currentIconStart !== -1) {\r\n\t\t\tconst currentIconLength = offset - currentIconStart + 1; // +1 to include the closing ')'\r\n\t\t\ticonsOffset += currentIconLength;\r\n\t\t\tcurrentIconStart = -1;\r\n\t\t\tcurrentIconValue = '';\r\n\t\t}\r\n\r\n\t\t// within icon\r\n\t\telse if (currentIconStart !== -1) {\r\n\t\t\t// Make sure this is a real icon name\r\n\t\t\tif (/^[a-z0-9\\-]$/i.test(char)) {\r\n\t\t\t\tcurrentIconValue += char;\r\n\t\t\t} else {\r\n\t\t\t\t// This is not a real icon, treat it as text\r\n\t\t\t\tappendChars(currentIconValue);\r\n\r\n\t\t\t\tcurrentIconStart = -1;\r\n\t\t\t\tcurrentIconValue = '';\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// any value outside of icon\r\n\t\telse {\r\n\t\t\tappendChars(char);\r\n\t\t}\r\n\r\n\t\toffset++;\r\n\t}\r\n\r\n\t// if we had a previous potential icon value without\r\n\t// the closing ')', it was actually not an icon and\r\n\t// so we have to add it to the actual value\r\n\tappendChars(currentIconValue);\r\n\r\n\treturn { text: textWithoutIcons, iconOffsets };\r\n}\r\n\r\nexport function matchesFuzzyIconAware(query: string, target: IParsedLabelWithIcons, enableSeparateSubstringMatching = false): IMatch[] | null {\r\n\tconst { text, iconOffsets } = target;\r\n\r\n\t// Return early if there are no icon markers in the word to match against\r\n\tif (!iconOffsets || iconOffsets.length === 0) {\r\n\t\treturn matchesFuzzy(query, text, enableSeparateSubstringMatching);\r\n\t}\r\n\r\n\t// Trim the word to match against because it could have leading\r\n\t// whitespace now if the word started with an icon\r\n\tconst wordToMatchAgainstWithoutIconsTrimmed = ltrim(text, ' ');\r\n\tconst leadingWhitespaceOffset = text.length - wordToMatchAgainstWithoutIconsTrimmed.length;\r\n\r\n\t// match on value without icon\r\n\tconst matches = matchesFuzzy(query, wordToMatchAgainstWithoutIconsTrimmed, enableSeparateSubstringMatching);\r\n\r\n\t// Map matches back to offsets with icon and trimming\r\n\tif (matches) {\r\n\t\tfor (const match of matches) {\r\n\t\t\tconst iconOffset = iconOffsets[match.start + leadingWhitespaceOffset] /* icon offsets at index */ + leadingWhitespaceOffset /* overall leading whitespace offset */;\r\n\t\t\tmatch.start += iconOffset;\r\n\t\t\tmatch.end += iconOffset;\r\n\t\t}\r\n\t}\r\n\r\n\treturn matches;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { equals } from 'vs/base/common/arrays';\r\nimport { UriComponents } from 'vs/base/common/uri';\r\nimport { escapeIcons } from 'vs/base/common/iconLabels';\r\nimport { illegalArgument } from 'vs/base/common/errors';\r\n\r\nexport interface IMarkdownString {\r\n\treadonly value: string;\r\n\treadonly isTrusted?: boolean;\r\n\treadonly supportThemeIcons?: boolean;\r\n\turis?: { [href: string]: UriComponents };\r\n}\r\n\r\nexport const enum MarkdownStringTextNewlineStyle {\r\n\tParagraph = 0,\r\n\tBreak = 1,\r\n}\r\n\r\nexport class MarkdownString implements IMarkdownString {\r\n\r\n\tpublic value: string;\r\n\tpublic isTrusted?: boolean;\r\n\tpublic supportThemeIcons?: boolean;\r\n\r\n\tconstructor(\r\n\t\tvalue: string = '',\r\n\t\tisTrustedOrOptions: boolean | { isTrusted?: boolean, supportThemeIcons?: boolean } = false,\r\n\t) {\r\n\t\tthis.value = value;\r\n\t\tif (typeof this.value !== 'string') {\r\n\t\t\tthrow illegalArgument('value');\r\n\t\t}\r\n\r\n\t\tif (typeof isTrustedOrOptions === 'boolean') {\r\n\t\t\tthis.isTrusted = isTrustedOrOptions;\r\n\t\t\tthis.supportThemeIcons = false;\r\n\t\t}\r\n\t\telse {\r\n\t\t\tthis.isTrusted = isTrustedOrOptions.isTrusted ?? undefined;\r\n\t\t\tthis.supportThemeIcons = isTrustedOrOptions.supportThemeIcons ?? false;\r\n\t\t}\r\n\t}\r\n\r\n\tappendText(value: string, newlineStyle: MarkdownStringTextNewlineStyle = MarkdownStringTextNewlineStyle.Paragraph): MarkdownString {\r\n\t\tthis.value += escapeMarkdownSyntaxTokens(this.supportThemeIcons ? escapeIcons(value) : value)\r\n\t\t\t.replace(/([ \\t]+)/g, (_match, g1) => ' '.repeat(g1.length))\r\n\t\t\t.replace(/^>/gm, '\\\\>')\r\n\t\t\t.replace(/\\n/g, newlineStyle === MarkdownStringTextNewlineStyle.Break ? '\\\\\\n' : '\\n\\n');\r\n\r\n\t\treturn this;\r\n\t}\r\n\r\n\tappendMarkdown(value: string): MarkdownString {\r\n\t\tthis.value += value;\r\n\t\treturn this;\r\n\t}\r\n\r\n\tappendCodeblock(langId: string, code: string): MarkdownString {\r\n\t\tthis.value += '\\n```';\r\n\t\tthis.value += langId;\r\n\t\tthis.value += '\\n';\r\n\t\tthis.value += code;\r\n\t\tthis.value += '\\n```\\n';\r\n\t\treturn this;\r\n\t}\r\n}\r\n\r\nexport function isEmptyMarkdownString(oneOrMany: IMarkdownString | IMarkdownString[] | null | undefined): boolean {\r\n\tif (isMarkdownString(oneOrMany)) {\r\n\t\treturn !oneOrMany.value;\r\n\t} else if (Array.isArray(oneOrMany)) {\r\n\t\treturn oneOrMany.every(isEmptyMarkdownString);\r\n\t} else {\r\n\t\treturn true;\r\n\t}\r\n}\r\n\r\nexport function isMarkdownString(thing: any): thing is IMarkdownString {\r\n\tif (thing instanceof MarkdownString) {\r\n\t\treturn true;\r\n\t} else if (thing && typeof thing === 'object') {\r\n\t\treturn typeof (thing).value === 'string'\r\n\t\t\t&& (typeof (thing).isTrusted === 'boolean' || (thing).isTrusted === undefined)\r\n\t\t\t&& (typeof (thing).supportThemeIcons === 'boolean' || (thing).supportThemeIcons === undefined);\r\n\t}\r\n\treturn false;\r\n}\r\n\r\nexport function markedStringsEquals(a: IMarkdownString | IMarkdownString[], b: IMarkdownString | IMarkdownString[]): boolean {\r\n\tif (!a && !b) {\r\n\t\treturn true;\r\n\t} else if (!a || !b) {\r\n\t\treturn false;\r\n\t} else if (Array.isArray(a) && Array.isArray(b)) {\r\n\t\treturn equals(a, b, markdownStringEqual);\r\n\t} else if (isMarkdownString(a) && isMarkdownString(b)) {\r\n\t\treturn markdownStringEqual(a, b);\r\n\t} else {\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\nfunction markdownStringEqual(a: IMarkdownString, b: IMarkdownString): boolean {\r\n\tif (a === b) {\r\n\t\treturn true;\r\n\t} else if (!a || !b) {\r\n\t\treturn false;\r\n\t} else {\r\n\t\treturn a.value === b.value && a.isTrusted === b.isTrusted && a.supportThemeIcons === b.supportThemeIcons;\r\n\t}\r\n}\r\n\r\nexport function escapeMarkdownSyntaxTokens(text: string): string {\r\n\t// escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash\r\n\treturn text.replace(/[\\\\`*_{}[\\]()#+\\-.!]/g, '\\\\$&');\r\n}\r\n\r\nexport function removeMarkdownEscapes(text: string): string {\r\n\tif (!text) {\r\n\t\treturn text;\r\n\t}\r\n\treturn text.replace(/\\\\([\\\\`*_{}[\\]()#+\\-.!])/g, '$1');\r\n}\r\n\r\nexport function parseHrefAndDimensions(href: string): { href: string, dimensions: string[] } {\r\n\tconst dimensions: string[] = [];\r\n\tconst splitted = href.split('|').map(s => s.trim());\r\n\thref = splitted[0];\r\n\tconst parameters = splitted[1];\r\n\tif (parameters) {\r\n\t\tconst heightFromParams = /height=(\\d+)/.exec(parameters);\r\n\t\tconst widthFromParams = /width=(\\d+)/.exec(parameters);\r\n\t\tconst height = heightFromParams ? heightFromParams[1] : '';\r\n\t\tconst width = widthFromParams ? widthFromParams[1] : '';\r\n\t\tconst widthIsFinite = isFinite(parseInt(width));\r\n\t\tconst heightIsFinite = isFinite(parseInt(height));\r\n\t\tif (widthIsFinite) {\r\n\t\t\tdimensions.push(`width=\"${width}\"`);\r\n\t\t}\r\n\t\tif (heightIsFinite) {\r\n\t\t\tdimensions.push(`height=\"${height}\"`);\r\n\t\t}\r\n\t}\r\n\treturn { href, dimensions };\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { VSBuffer } from 'vs/base/common/buffer';\r\nimport { URI, UriComponents } from 'vs/base/common/uri';\r\n\r\nexport function parse(text: string): any {\r\n\tlet data = JSON.parse(text);\r\n\tdata = revive(data);\r\n\treturn data;\r\n}\r\n\r\nexport interface MarshalledObject {\r\n\t$mid: number;\r\n}\r\n\r\n\r\ntype Deserialize = T extends UriComponents ? URI\r\n\t: T extends object\r\n\t? Revived\r\n\t: T;\r\n\r\nexport type Revived = { [K in keyof T]: Deserialize };\r\n\r\nexport function revive(obj: any, depth = 0): Revived {\r\n\tif (!obj || depth > 200) {\r\n\t\treturn obj;\r\n\t}\r\n\r\n\tif (typeof obj === 'object') {\r\n\r\n\t\tswitch ((obj).$mid) {\r\n\t\t\tcase 1: return URI.revive(obj);\r\n\t\t\tcase 2: return new RegExp(obj.source, obj.flags);\r\n\t\t}\r\n\r\n\t\tif (\r\n\t\t\tobj instanceof VSBuffer\r\n\t\t\t|| obj instanceof Uint8Array\r\n\t\t) {\r\n\t\t\treturn obj;\r\n\t\t}\r\n\r\n\t\tif (Array.isArray(obj)) {\r\n\t\t\tfor (let i = 0; i < obj.length; ++i) {\r\n\t\t\t\tobj[i] = revive(obj[i], depth + 1);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\t// walk object\r\n\t\t\tfor (const key in obj) {\r\n\t\t\t\tif (Object.hasOwnProperty.call(obj, key)) {\r\n\t\t\t\t\tobj[key] = revive(obj[key], depth + 1);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\treturn obj;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { URI } from 'vs/base/common/uri';\r\nimport * as platform from 'vs/base/common/platform';\r\n\r\nexport namespace Schemas {\r\n\r\n\t/**\r\n\t * A schema that is used for models that exist in memory\r\n\t * only and that have no correspondence on a server or such.\r\n\t */\r\n\texport const inMemory = 'inmemory';\r\n\r\n\t/**\r\n\t * A schema that is used for setting files\r\n\t */\r\n\texport const vscode = 'vscode';\r\n\r\n\t/**\r\n\t * A schema that is used for internal private files\r\n\t */\r\n\texport const internal = 'private';\r\n\r\n\t/**\r\n\t * A walk-through document.\r\n\t */\r\n\texport const walkThrough = 'walkThrough';\r\n\r\n\t/**\r\n\t * An embedded code snippet.\r\n\t */\r\n\texport const walkThroughSnippet = 'walkThroughSnippet';\r\n\r\n\texport const http = 'http';\r\n\r\n\texport const https = 'https';\r\n\r\n\texport const file = 'file';\r\n\r\n\texport const mailto = 'mailto';\r\n\r\n\texport const untitled = 'untitled';\r\n\r\n\texport const data = 'data';\r\n\r\n\texport const command = 'command';\r\n\r\n\texport const vscodeRemote = 'vscode-remote';\r\n\r\n\texport const vscodeRemoteResource = 'vscode-remote-resource';\r\n\r\n\texport const userData = 'vscode-userdata';\r\n\r\n\texport const vscodeCustomEditor = 'vscode-custom-editor';\r\n\r\n\texport const vscodeNotebook = 'vscode-notebook';\r\n\r\n\texport const vscodeNotebookCell = 'vscode-notebook-cell';\r\n\r\n\texport const vscodeNotebookCellMetadata = 'vscode-notebook-cell-metadata';\r\n\r\n\texport const vscodeSettings = 'vscode-settings';\r\n\r\n\texport const webviewPanel = 'webview-panel';\r\n\r\n\t/**\r\n\t * Scheme used for loading the wrapper html and script in webviews.\r\n\t */\r\n\texport const vscodeWebview = 'vscode-webview';\r\n\r\n\t/**\r\n\t * Scheme used for loading resources inside of webviews.\r\n\t */\r\n\texport const vscodeWebviewResource = 'vscode-webview-resource';\r\n\r\n\t/**\r\n\t * Scheme used for extension pages\r\n\t */\r\n\texport const extension = 'extension';\r\n\r\n\t/**\r\n\t * Scheme used as a replacement of `file` scheme to load\r\n\t * files with our custom protocol handler (desktop only).\r\n\t */\r\n\texport const vscodeFileResource = 'vscode-file';\r\n}\r\n\r\nclass RemoteAuthoritiesImpl {\r\n\tprivate readonly _hosts: { [authority: string]: string | undefined; } = Object.create(null);\r\n\tprivate readonly _ports: { [authority: string]: number | undefined; } = Object.create(null);\r\n\tprivate readonly _connectionTokens: { [authority: string]: string | undefined; } = Object.create(null);\r\n\tprivate _preferredWebSchema: 'http' | 'https' = 'http';\r\n\tprivate _delegate: ((uri: URI) => URI) | null = null;\r\n\r\n\tsetPreferredWebSchema(schema: 'http' | 'https') {\r\n\t\tthis._preferredWebSchema = schema;\r\n\t}\r\n\r\n\trewrite(uri: URI): URI {\r\n\t\tif (this._delegate) {\r\n\t\t\treturn this._delegate(uri);\r\n\t\t}\r\n\t\tconst authority = uri.authority;\r\n\t\tlet host = this._hosts[authority];\r\n\t\tif (host && host.indexOf(':') !== -1) {\r\n\t\t\thost = `[${host}]`;\r\n\t\t}\r\n\t\tconst port = this._ports[authority];\r\n\t\tconst connectionToken = this._connectionTokens[authority];\r\n\t\tlet query = `path=${encodeURIComponent(uri.path)}`;\r\n\t\tif (typeof connectionToken === 'string') {\r\n\t\t\tquery += `&tkn=${encodeURIComponent(connectionToken)}`;\r\n\t\t}\r\n\t\treturn URI.from({\r\n\t\t\tscheme: platform.isWeb ? this._preferredWebSchema : Schemas.vscodeRemoteResource,\r\n\t\t\tauthority: `${host}:${port}`,\r\n\t\t\tpath: `/vscode-remote-resource`,\r\n\t\t\tquery\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport const RemoteAuthorities = new RemoteAuthoritiesImpl();\r\n\r\nclass FileAccessImpl {\r\n\r\n\tprivate readonly FALLBACK_AUTHORITY = 'vscode-app';\r\n\r\n\t/**\r\n\t * Returns a URI to use in contexts where the browser is responsible\r\n\t * for loading (e.g. fetch()) or when used within the DOM.\r\n\t *\r\n\t * **Note:** use `dom.ts#asCSSUrl` whenever the URL is to be used in CSS context.\r\n\t */\r\n\tasBrowserUri(uri: URI): URI;\r\n\tasBrowserUri(moduleId: string, moduleIdToUrl: { toUrl(moduleId: string): string }, __forceCodeFileUri?: boolean): URI;\r\n\tasBrowserUri(uriOrModule: URI | string, moduleIdToUrl?: { toUrl(moduleId: string): string }, __forceCodeFileUri?: boolean): URI {\r\n\t\tconst uri = this.toUri(uriOrModule, moduleIdToUrl);\r\n\r\n\t\t// Handle remote URIs via `RemoteAuthorities`\r\n\t\tif (uri.scheme === Schemas.vscodeRemote) {\r\n\t\t\treturn RemoteAuthorities.rewrite(uri);\r\n\t\t}\r\n\r\n\t\t// Only convert the URI if we are in a native context and it has `file:` scheme\r\n\t\t// and we have explicitly enabled the conversion (sandbox, or ENABLE_VSCODE_BROWSER_CODE_LOADING)\r\n\t\tif (platform.isNative && (__forceCodeFileUri || platform.isPreferringBrowserCodeLoad) && uri.scheme === Schemas.file) {\r\n\t\t\treturn uri.with({\r\n\t\t\t\tscheme: Schemas.vscodeFileResource,\r\n\t\t\t\t// We need to provide an authority here so that it can serve\r\n\t\t\t\t// as origin for network and loading matters in chromium.\r\n\t\t\t\t// If the URI is not coming with an authority already, we\r\n\t\t\t\t// add our own\r\n\t\t\t\tauthority: uri.authority || this.FALLBACK_AUTHORITY,\r\n\t\t\t\tquery: null,\r\n\t\t\t\tfragment: null\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\treturn uri;\r\n\t}\r\n\r\n\tprivate toUri(uriOrModule: URI | string, moduleIdToUrl?: { toUrl(moduleId: string): string }): URI {\r\n\t\tif (URI.isUri(uriOrModule)) {\r\n\t\t\treturn uriOrModule;\r\n\t\t}\r\n\r\n\t\treturn URI.parse(moduleIdToUrl!.toUrl(uriOrModule));\r\n\t}\r\n}\r\n\r\nexport const FileAccess = new FileAccessImpl();\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as browser from 'vs/base/browser/browser';\r\nimport { domEvent } from 'vs/base/browser/event';\r\nimport { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { IMouseEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent';\r\nimport { TimeoutTimer } from 'vs/base/common/async';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { FileAccess, RemoteAuthorities } from 'vs/base/common/network';\r\nimport { BrowserFeatures } from 'vs/base/browser/canIUse';\r\nimport { KeyCode } from 'vs/base/common/keyCodes';\r\n\r\nexport function clearNode(node: HTMLElement): void {\r\n\twhile (node.firstChild) {\r\n\t\tnode.firstChild.remove();\r\n\t}\r\n}\r\n\r\n/**\r\n * @deprecated Use node.isConnected directly\r\n */\r\nexport function isInDOM(node: Node | null): boolean {\r\n\treturn node?.isConnected ?? false;\r\n}\r\n\r\nclass DomListener implements IDisposable {\r\n\r\n\tprivate _handler: (e: any) => void;\r\n\tprivate _node: EventTarget;\r\n\tprivate readonly _type: string;\r\n\tprivate readonly _options: boolean | AddEventListenerOptions;\r\n\r\n\tconstructor(node: EventTarget, type: string, handler: (e: any) => void, options?: boolean | AddEventListenerOptions) {\r\n\t\tthis._node = node;\r\n\t\tthis._type = type;\r\n\t\tthis._handler = handler;\r\n\t\tthis._options = (options || false);\r\n\t\tthis._node.addEventListener(this._type, this._handler, this._options);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tif (!this._handler) {\r\n\t\t\t// Already disposed\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._node.removeEventListener(this._type, this._handler, this._options);\r\n\r\n\t\t// Prevent leakers from holding on to the dom or handler func\r\n\t\tthis._node = null!;\r\n\t\tthis._handler = null!;\r\n\t}\r\n}\r\n\r\nexport function addDisposableListener(node: EventTarget, type: K, handler: (event: GlobalEventHandlersEventMap[K]) => void, useCapture?: boolean): IDisposable;\r\nexport function addDisposableListener(node: EventTarget, type: string, handler: (event: any) => void, useCapture?: boolean): IDisposable;\r\nexport function addDisposableListener(node: EventTarget, type: string, handler: (event: any) => void, options: AddEventListenerOptions): IDisposable;\r\nexport function addDisposableListener(node: EventTarget, type: string, handler: (event: any) => void, useCaptureOrOptions?: boolean | AddEventListenerOptions): IDisposable {\r\n\treturn new DomListener(node, type, handler, useCaptureOrOptions);\r\n}\r\n\r\nexport interface IAddStandardDisposableListenerSignature {\r\n\t(node: HTMLElement, type: 'click', handler: (event: IMouseEvent) => void, useCapture?: boolean): IDisposable;\r\n\t(node: HTMLElement, type: 'mousedown', handler: (event: IMouseEvent) => void, useCapture?: boolean): IDisposable;\r\n\t(node: HTMLElement, type: 'keydown', handler: (event: IKeyboardEvent) => void, useCapture?: boolean): IDisposable;\r\n\t(node: HTMLElement, type: 'keypress', handler: (event: IKeyboardEvent) => void, useCapture?: boolean): IDisposable;\r\n\t(node: HTMLElement, type: 'keyup', handler: (event: IKeyboardEvent) => void, useCapture?: boolean): IDisposable;\r\n\t(node: HTMLElement, type: string, handler: (event: any) => void, useCapture?: boolean): IDisposable;\r\n}\r\nfunction _wrapAsStandardMouseEvent(handler: (e: IMouseEvent) => void): (e: MouseEvent) => void {\r\n\treturn function (e: MouseEvent) {\r\n\t\treturn handler(new StandardMouseEvent(e));\r\n\t};\r\n}\r\nfunction _wrapAsStandardKeyboardEvent(handler: (e: IKeyboardEvent) => void): (e: KeyboardEvent) => void {\r\n\treturn function (e: KeyboardEvent) {\r\n\t\treturn handler(new StandardKeyboardEvent(e));\r\n\t};\r\n}\r\nexport let addStandardDisposableListener: IAddStandardDisposableListenerSignature = function addStandardDisposableListener(node: HTMLElement, type: string, handler: (event: any) => void, useCapture?: boolean): IDisposable {\r\n\tlet wrapHandler = handler;\r\n\r\n\tif (type === 'click' || type === 'mousedown') {\r\n\t\twrapHandler = _wrapAsStandardMouseEvent(handler);\r\n\t} else if (type === 'keydown' || type === 'keypress' || type === 'keyup') {\r\n\t\twrapHandler = _wrapAsStandardKeyboardEvent(handler);\r\n\t}\r\n\r\n\treturn addDisposableListener(node, type, wrapHandler, useCapture);\r\n};\r\n\r\nexport let addStandardDisposableGenericMouseDownListner = function addStandardDisposableListener(node: HTMLElement, handler: (event: any) => void, useCapture?: boolean): IDisposable {\r\n\tlet wrapHandler = _wrapAsStandardMouseEvent(handler);\r\n\r\n\treturn addDisposableGenericMouseDownListner(node, wrapHandler, useCapture);\r\n};\r\nexport function addDisposableGenericMouseDownListner(node: EventTarget, handler: (event: any) => void, useCapture?: boolean): IDisposable {\r\n\treturn addDisposableListener(node, platform.isIOS && BrowserFeatures.pointerEvents ? EventType.POINTER_DOWN : EventType.MOUSE_DOWN, handler, useCapture);\r\n}\r\n\r\nexport function addDisposableGenericMouseUpListner(node: EventTarget, handler: (event: any) => void, useCapture?: boolean): IDisposable {\r\n\treturn addDisposableListener(node, platform.isIOS && BrowserFeatures.pointerEvents ? EventType.POINTER_UP : EventType.MOUSE_UP, handler, useCapture);\r\n}\r\nexport function addDisposableNonBubblingMouseOutListener(node: Element, handler: (event: MouseEvent) => void): IDisposable {\r\n\treturn addDisposableListener(node, 'mouseout', (e: MouseEvent) => {\r\n\t\t// Mouse out bubbles, so this is an attempt to ignore faux mouse outs coming from children elements\r\n\t\tlet toElement: Node | null = (e.relatedTarget);\r\n\t\twhile (toElement && toElement !== node) {\r\n\t\t\ttoElement = toElement.parentNode;\r\n\t\t}\r\n\t\tif (toElement === node) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\thandler(e);\r\n\t});\r\n}\r\n\r\nexport function addDisposableNonBubblingPointerOutListener(node: Element, handler: (event: MouseEvent) => void): IDisposable {\r\n\treturn addDisposableListener(node, 'pointerout', (e: MouseEvent) => {\r\n\t\t// Mouse out bubbles, so this is an attempt to ignore faux mouse outs coming from children elements\r\n\t\tlet toElement: Node | null = (e.relatedTarget);\r\n\t\twhile (toElement && toElement !== node) {\r\n\t\t\ttoElement = toElement.parentNode;\r\n\t\t}\r\n\t\tif (toElement === node) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\thandler(e);\r\n\t});\r\n}\r\n\r\ninterface IRequestAnimationFrame {\r\n\t(callback: (time: number) => void): number;\r\n}\r\nlet _animationFrame: IRequestAnimationFrame | null = null;\r\nfunction doRequestAnimationFrame(callback: (time: number) => void): number {\r\n\tif (!_animationFrame) {\r\n\t\tconst emulatedRequestAnimationFrame = (callback: (time: number) => void): any => {\r\n\t\t\treturn setTimeout(() => callback(new Date().getTime()), 0);\r\n\t\t};\r\n\t\t_animationFrame = (\r\n\t\t\tself.requestAnimationFrame\r\n\t\t\t|| (self).msRequestAnimationFrame\r\n\t\t\t|| (self).webkitRequestAnimationFrame\r\n\t\t\t|| (self).mozRequestAnimationFrame\r\n\t\t\t|| (self).oRequestAnimationFrame\r\n\t\t\t|| emulatedRequestAnimationFrame\r\n\t\t);\r\n\t}\r\n\treturn _animationFrame.call(self, callback);\r\n}\r\n\r\n/**\r\n * Schedule a callback to be run at the next animation frame.\r\n * This allows multiple parties to register callbacks that should run at the next animation frame.\r\n * If currently in an animation frame, `runner` will be executed immediately.\r\n * @return token that can be used to cancel the scheduled runner (only if `runner` was not executed immediately).\r\n */\r\nexport let runAtThisOrScheduleAtNextAnimationFrame: (runner: () => void, priority?: number) => IDisposable;\r\n/**\r\n * Schedule a callback to be run at the next animation frame.\r\n * This allows multiple parties to register callbacks that should run at the next animation frame.\r\n * If currently in an animation frame, `runner` will be executed at the next animation frame.\r\n * @return token that can be used to cancel the scheduled runner.\r\n */\r\nexport let scheduleAtNextAnimationFrame: (runner: () => void, priority?: number) => IDisposable;\r\n\r\nclass AnimationFrameQueueItem implements IDisposable {\r\n\r\n\tprivate _runner: () => void;\r\n\tpublic priority: number;\r\n\tprivate _canceled: boolean;\r\n\r\n\tconstructor(runner: () => void, priority: number = 0) {\r\n\t\tthis._runner = runner;\r\n\t\tthis.priority = priority;\r\n\t\tthis._canceled = false;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._canceled = true;\r\n\t}\r\n\r\n\tpublic execute(): void {\r\n\t\tif (this._canceled) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\tthis._runner();\r\n\t\t} catch (e) {\r\n\t\t\tonUnexpectedError(e);\r\n\t\t}\r\n\t}\r\n\r\n\t// Sort by priority (largest to lowest)\r\n\tpublic static sort(a: AnimationFrameQueueItem, b: AnimationFrameQueueItem): number {\r\n\t\treturn b.priority - a.priority;\r\n\t}\r\n}\r\n\r\n(function () {\r\n\t/**\r\n\t * The runners scheduled at the next animation frame\r\n\t */\r\n\tlet NEXT_QUEUE: AnimationFrameQueueItem[] = [];\r\n\t/**\r\n\t * The runners scheduled at the current animation frame\r\n\t */\r\n\tlet CURRENT_QUEUE: AnimationFrameQueueItem[] | null = null;\r\n\t/**\r\n\t * A flag to keep track if the native requestAnimationFrame was already called\r\n\t */\r\n\tlet animFrameRequested = false;\r\n\t/**\r\n\t * A flag to indicate if currently handling a native requestAnimationFrame callback\r\n\t */\r\n\tlet inAnimationFrameRunner = false;\r\n\r\n\tlet animationFrameRunner = () => {\r\n\t\tanimFrameRequested = false;\r\n\r\n\t\tCURRENT_QUEUE = NEXT_QUEUE;\r\n\t\tNEXT_QUEUE = [];\r\n\r\n\t\tinAnimationFrameRunner = true;\r\n\t\twhile (CURRENT_QUEUE.length > 0) {\r\n\t\t\tCURRENT_QUEUE.sort(AnimationFrameQueueItem.sort);\r\n\t\t\tlet top = CURRENT_QUEUE.shift()!;\r\n\t\t\ttop.execute();\r\n\t\t}\r\n\t\tinAnimationFrameRunner = false;\r\n\t};\r\n\r\n\tscheduleAtNextAnimationFrame = (runner: () => void, priority: number = 0) => {\r\n\t\tlet item = new AnimationFrameQueueItem(runner, priority);\r\n\t\tNEXT_QUEUE.push(item);\r\n\r\n\t\tif (!animFrameRequested) {\r\n\t\t\tanimFrameRequested = true;\r\n\t\t\tdoRequestAnimationFrame(animationFrameRunner);\r\n\t\t}\r\n\r\n\t\treturn item;\r\n\t};\r\n\r\n\trunAtThisOrScheduleAtNextAnimationFrame = (runner: () => void, priority?: number) => {\r\n\t\tif (inAnimationFrameRunner) {\r\n\t\t\tlet item = new AnimationFrameQueueItem(runner, priority);\r\n\t\t\tCURRENT_QUEUE!.push(item);\r\n\t\t\treturn item;\r\n\t\t} else {\r\n\t\t\treturn scheduleAtNextAnimationFrame(runner, priority);\r\n\t\t}\r\n\t};\r\n})();\r\n\r\n/**\r\n * Add a throttled listener. `handler` is fired at most every 16ms or with the next animation frame (if browser supports it).\r\n */\r\nexport interface IEventMerger {\r\n\t(lastEvent: R | null, currentEvent: E): R;\r\n}\r\n\r\nexport interface DOMEvent {\r\n}\r\n\r\nconst MINIMUM_TIME_MS = 16;\r\nconst DEFAULT_EVENT_MERGER: IEventMerger = function (lastEvent: DOMEvent | null, currentEvent: DOMEvent) {\r\n\treturn currentEvent;\r\n};\r\n\r\nclass TimeoutThrottledDomListener extends Disposable {\r\n\r\n\tconstructor(node: any, type: string, handler: (event: R) => void, eventMerger: IEventMerger = DEFAULT_EVENT_MERGER, minimumTimeMs: number = MINIMUM_TIME_MS) {\r\n\t\tsuper();\r\n\r\n\t\tlet lastEvent: R | null = null;\r\n\t\tlet lastHandlerTime = 0;\r\n\t\tlet timeout = this._register(new TimeoutTimer());\r\n\r\n\t\tlet invokeHandler = () => {\r\n\t\t\tlastHandlerTime = (new Date()).getTime();\r\n\t\t\thandler(lastEvent);\r\n\t\t\tlastEvent = null;\r\n\t\t};\r\n\r\n\t\tthis._register(addDisposableListener(node, type, (e) => {\r\n\r\n\t\t\tlastEvent = eventMerger(lastEvent, e);\r\n\t\t\tlet elapsedTime = (new Date()).getTime() - lastHandlerTime;\r\n\r\n\t\t\tif (elapsedTime >= minimumTimeMs) {\r\n\t\t\t\ttimeout.cancel();\r\n\t\t\t\tinvokeHandler();\r\n\t\t\t} else {\r\n\t\t\t\ttimeout.setIfNotSet(invokeHandler, minimumTimeMs - elapsedTime);\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n}\r\n\r\nexport function addDisposableThrottledListener(node: any, type: string, handler: (event: R) => void, eventMerger?: IEventMerger, minimumTimeMs?: number): IDisposable {\r\n\treturn new TimeoutThrottledDomListener(node, type, handler, eventMerger, minimumTimeMs);\r\n}\r\n\r\nexport function getComputedStyle(el: HTMLElement): CSSStyleDeclaration {\r\n\treturn document.defaultView!.getComputedStyle(el, null);\r\n}\r\n\r\nexport function getClientArea(element: HTMLElement): Dimension {\r\n\r\n\t// Try with DOM clientWidth / clientHeight\r\n\tif (element !== document.body) {\r\n\t\treturn new Dimension(element.clientWidth, element.clientHeight);\r\n\t}\r\n\r\n\t// If visual view port exits and it's on mobile, it should be used instead of window innerWidth / innerHeight, or document.body.clientWidth / document.body.clientHeight\r\n\tif (platform.isIOS && window.visualViewport) {\r\n\t\tconst width = window.visualViewport.width;\r\n\t\tconst height = window.visualViewport.height - (\r\n\t\t\tbrowser.isStandalone\r\n\t\t\t\t// in PWA mode, the visual viewport always includes the safe-area-inset-bottom (which is for the home indicator)\r\n\t\t\t\t// even when you are using the onscreen monitor, the visual viewport will include the area between system statusbar and the onscreen keyboard\r\n\t\t\t\t// plus the area between onscreen keyboard and the bottom bezel, which is 20px on iOS.\r\n\t\t\t\t? (20 + 4) // + 4px for body margin\r\n\t\t\t\t: 0\r\n\t\t);\r\n\t\treturn new Dimension(width, height);\r\n\t}\r\n\r\n\t// Try innerWidth / innerHeight\r\n\tif (window.innerWidth && window.innerHeight) {\r\n\t\treturn new Dimension(window.innerWidth, window.innerHeight);\r\n\t}\r\n\r\n\t// Try with document.body.clientWidth / document.body.clientHeight\r\n\tif (document.body && document.body.clientWidth && document.body.clientHeight) {\r\n\t\treturn new Dimension(document.body.clientWidth, document.body.clientHeight);\r\n\t}\r\n\r\n\t// Try with document.documentElement.clientWidth / document.documentElement.clientHeight\r\n\tif (document.documentElement && document.documentElement.clientWidth && document.documentElement.clientHeight) {\r\n\t\treturn new Dimension(document.documentElement.clientWidth, document.documentElement.clientHeight);\r\n\t}\r\n\r\n\tthrow new Error('Unable to figure out browser width and height');\r\n}\r\n\r\nclass SizeUtils {\r\n\t// Adapted from WinJS\r\n\t// Converts a CSS positioning string for the specified element to pixels.\r\n\tprivate static convertToPixels(element: HTMLElement, value: string): number {\r\n\t\treturn parseFloat(value) || 0;\r\n\t}\r\n\r\n\tprivate static getDimension(element: HTMLElement, cssPropertyName: string, jsPropertyName: string): number {\r\n\t\tlet computedStyle: CSSStyleDeclaration = getComputedStyle(element);\r\n\t\tlet value = '0';\r\n\t\tif (computedStyle) {\r\n\t\t\tif (computedStyle.getPropertyValue) {\r\n\t\t\t\tvalue = computedStyle.getPropertyValue(cssPropertyName);\r\n\t\t\t} else {\r\n\t\t\t\t// IE8\r\n\t\t\t\tvalue = (computedStyle).getAttribute(jsPropertyName);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn SizeUtils.convertToPixels(element, value);\r\n\t}\r\n\r\n\tstatic getBorderLeftWidth(element: HTMLElement): number {\r\n\t\treturn SizeUtils.getDimension(element, 'border-left-width', 'borderLeftWidth');\r\n\t}\r\n\tstatic getBorderRightWidth(element: HTMLElement): number {\r\n\t\treturn SizeUtils.getDimension(element, 'border-right-width', 'borderRightWidth');\r\n\t}\r\n\tstatic getBorderTopWidth(element: HTMLElement): number {\r\n\t\treturn SizeUtils.getDimension(element, 'border-top-width', 'borderTopWidth');\r\n\t}\r\n\tstatic getBorderBottomWidth(element: HTMLElement): number {\r\n\t\treturn SizeUtils.getDimension(element, 'border-bottom-width', 'borderBottomWidth');\r\n\t}\r\n\r\n\tstatic getPaddingLeft(element: HTMLElement): number {\r\n\t\treturn SizeUtils.getDimension(element, 'padding-left', 'paddingLeft');\r\n\t}\r\n\tstatic getPaddingRight(element: HTMLElement): number {\r\n\t\treturn SizeUtils.getDimension(element, 'padding-right', 'paddingRight');\r\n\t}\r\n\tstatic getPaddingTop(element: HTMLElement): number {\r\n\t\treturn SizeUtils.getDimension(element, 'padding-top', 'paddingTop');\r\n\t}\r\n\tstatic getPaddingBottom(element: HTMLElement): number {\r\n\t\treturn SizeUtils.getDimension(element, 'padding-bottom', 'paddingBottom');\r\n\t}\r\n\r\n\tstatic getMarginLeft(element: HTMLElement): number {\r\n\t\treturn SizeUtils.getDimension(element, 'margin-left', 'marginLeft');\r\n\t}\r\n\tstatic getMarginTop(element: HTMLElement): number {\r\n\t\treturn SizeUtils.getDimension(element, 'margin-top', 'marginTop');\r\n\t}\r\n\tstatic getMarginRight(element: HTMLElement): number {\r\n\t\treturn SizeUtils.getDimension(element, 'margin-right', 'marginRight');\r\n\t}\r\n\tstatic getMarginBottom(element: HTMLElement): number {\r\n\t\treturn SizeUtils.getDimension(element, 'margin-bottom', 'marginBottom');\r\n\t}\r\n}\r\n\r\n// ----------------------------------------------------------------------------------------\r\n// Position & Dimension\r\n\r\nexport interface IDimension {\r\n\treadonly width: number;\r\n\treadonly height: number;\r\n}\r\n\r\nexport class Dimension implements IDimension {\r\n\r\n\tconstructor(\r\n\t\tpublic readonly width: number,\r\n\t\tpublic readonly height: number,\r\n\t) { }\r\n\r\n\twith(width: number = this.width, height: number = this.height): Dimension {\r\n\t\tif (width !== this.width || height !== this.height) {\r\n\t\t\treturn new Dimension(width, height);\r\n\t\t} else {\r\n\t\t\treturn this;\r\n\t\t}\r\n\t}\r\n\r\n\tstatic is(obj: unknown): obj is IDimension {\r\n\t\treturn typeof obj === 'object' && typeof (obj).height === 'number' && typeof (obj).width === 'number';\r\n\t}\r\n\r\n\tstatic lift(obj: IDimension): Dimension {\r\n\t\tif (obj instanceof Dimension) {\r\n\t\t\treturn obj;\r\n\t\t} else {\r\n\t\t\treturn new Dimension(obj.width, obj.height);\r\n\t\t}\r\n\t}\r\n\r\n\tstatic equals(a: Dimension | undefined, b: Dimension | undefined): boolean {\r\n\t\tif (a === b) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (!a || !b) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn a.width === b.width && a.height === b.height;\r\n\t}\r\n}\r\n\r\nexport function getTopLeftOffset(element: HTMLElement): { left: number; top: number; } {\r\n\t// Adapted from WinJS.Utilities.getPosition\r\n\t// and added borders to the mix\r\n\r\n\tlet offsetParent = element.offsetParent;\r\n\tlet top = element.offsetTop;\r\n\tlet left = element.offsetLeft;\r\n\r\n\twhile (\r\n\t\t(element = element.parentNode) !== null\r\n\t\t&& element !== document.body\r\n\t\t&& element !== document.documentElement\r\n\t) {\r\n\t\ttop -= element.scrollTop;\r\n\t\tconst c = isShadowRoot(element) ? null : getComputedStyle(element);\r\n\t\tif (c) {\r\n\t\t\tleft -= c.direction !== 'rtl' ? element.scrollLeft : -element.scrollLeft;\r\n\t\t}\r\n\r\n\t\tif (element === offsetParent) {\r\n\t\t\tleft += SizeUtils.getBorderLeftWidth(element);\r\n\t\t\ttop += SizeUtils.getBorderTopWidth(element);\r\n\t\t\ttop += element.offsetTop;\r\n\t\t\tleft += element.offsetLeft;\r\n\t\t\toffsetParent = element.offsetParent;\r\n\t\t}\r\n\t}\r\n\r\n\treturn {\r\n\t\tleft: left,\r\n\t\ttop: top\r\n\t};\r\n}\r\n\r\nexport interface IDomNodePagePosition {\r\n\tleft: number;\r\n\ttop: number;\r\n\twidth: number;\r\n\theight: number;\r\n}\r\n\r\nexport function size(element: HTMLElement, width: number | null, height: number | null): void {\r\n\tif (typeof width === 'number') {\r\n\t\telement.style.width = `${width}px`;\r\n\t}\r\n\r\n\tif (typeof height === 'number') {\r\n\t\telement.style.height = `${height}px`;\r\n\t}\r\n}\r\n\r\n/**\r\n * Returns the position of a dom node relative to the entire page.\r\n */\r\nexport function getDomNodePagePosition(domNode: HTMLElement): IDomNodePagePosition {\r\n\tlet bb = domNode.getBoundingClientRect();\r\n\treturn {\r\n\t\tleft: bb.left + StandardWindow.scrollX,\r\n\t\ttop: bb.top + StandardWindow.scrollY,\r\n\t\twidth: bb.width,\r\n\t\theight: bb.height\r\n\t};\r\n}\r\n\r\nexport interface IStandardWindow {\r\n\treadonly scrollX: number;\r\n\treadonly scrollY: number;\r\n}\r\n\r\nexport const StandardWindow: IStandardWindow = new class implements IStandardWindow {\r\n\tget scrollX(): number {\r\n\t\tif (typeof window.scrollX === 'number') {\r\n\t\t\t// modern browsers\r\n\t\t\treturn window.scrollX;\r\n\t\t} else {\r\n\t\t\treturn document.body.scrollLeft + document.documentElement!.scrollLeft;\r\n\t\t}\r\n\t}\r\n\r\n\tget scrollY(): number {\r\n\t\tif (typeof window.scrollY === 'number') {\r\n\t\t\t// modern browsers\r\n\t\t\treturn window.scrollY;\r\n\t\t} else {\r\n\t\t\treturn document.body.scrollTop + document.documentElement!.scrollTop;\r\n\t\t}\r\n\t}\r\n};\r\n\r\n// Adapted from WinJS\r\n// Gets the width of the element, including margins.\r\nexport function getTotalWidth(element: HTMLElement): number {\r\n\tlet margin = SizeUtils.getMarginLeft(element) + SizeUtils.getMarginRight(element);\r\n\treturn element.offsetWidth + margin;\r\n}\r\n\r\nexport function getContentWidth(element: HTMLElement): number {\r\n\tlet border = SizeUtils.getBorderLeftWidth(element) + SizeUtils.getBorderRightWidth(element);\r\n\tlet padding = SizeUtils.getPaddingLeft(element) + SizeUtils.getPaddingRight(element);\r\n\treturn element.offsetWidth - border - padding;\r\n}\r\n\r\n// Adapted from WinJS\r\n// Gets the height of the content of the specified element. The content height does not include borders or padding.\r\nexport function getContentHeight(element: HTMLElement): number {\r\n\tlet border = SizeUtils.getBorderTopWidth(element) + SizeUtils.getBorderBottomWidth(element);\r\n\tlet padding = SizeUtils.getPaddingTop(element) + SizeUtils.getPaddingBottom(element);\r\n\treturn element.offsetHeight - border - padding;\r\n}\r\n\r\n// Adapted from WinJS\r\n// Gets the height of the element, including its margins.\r\nexport function getTotalHeight(element: HTMLElement): number {\r\n\tlet margin = SizeUtils.getMarginTop(element) + SizeUtils.getMarginBottom(element);\r\n\treturn element.offsetHeight + margin;\r\n}\r\n\r\n// ----------------------------------------------------------------------------------------\r\n\r\nexport function isAncestor(testChild: Node | null, testAncestor: Node | null): boolean {\r\n\twhile (testChild) {\r\n\t\tif (testChild === testAncestor) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\ttestChild = testChild.parentNode;\r\n\t}\r\n\r\n\treturn false;\r\n}\r\n\r\nexport function findParentWithClass(node: HTMLElement, clazz: string, stopAtClazzOrNode?: string | HTMLElement): HTMLElement | null {\r\n\twhile (node && node.nodeType === node.ELEMENT_NODE) {\r\n\t\tif (node.classList.contains(clazz)) {\r\n\t\t\treturn node;\r\n\t\t}\r\n\r\n\t\tif (stopAtClazzOrNode) {\r\n\t\t\tif (typeof stopAtClazzOrNode === 'string') {\r\n\t\t\t\tif (node.classList.contains(stopAtClazzOrNode)) {\r\n\t\t\t\t\treturn null;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tif (node === stopAtClazzOrNode) {\r\n\t\t\t\t\treturn null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tnode = node.parentNode;\r\n\t}\r\n\r\n\treturn null;\r\n}\r\n\r\nexport function hasParentWithClass(node: HTMLElement, clazz: string, stopAtClazzOrNode?: string | HTMLElement): boolean {\r\n\treturn !!findParentWithClass(node, clazz, stopAtClazzOrNode);\r\n}\r\n\r\nexport function isShadowRoot(node: Node): node is ShadowRoot {\r\n\treturn (\r\n\t\tnode && !!(node).host && !!(node).mode\r\n\t);\r\n}\r\n\r\nexport function isInShadowDOM(domNode: Node): boolean {\r\n\treturn !!getShadowRoot(domNode);\r\n}\r\n\r\nexport function getShadowRoot(domNode: Node): ShadowRoot | null {\r\n\twhile (domNode.parentNode) {\r\n\t\tif (domNode === document.body) {\r\n\t\t\t// reached the body\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tdomNode = domNode.parentNode;\r\n\t}\r\n\treturn isShadowRoot(domNode) ? domNode : null;\r\n}\r\n\r\nexport function getActiveElement(): Element | null {\r\n\tlet result = document.activeElement;\r\n\r\n\twhile (result?.shadowRoot) {\r\n\t\tresult = result.shadowRoot.activeElement;\r\n\t}\r\n\r\n\treturn result;\r\n}\r\n\r\nexport function createStyleSheet(container: HTMLElement = document.getElementsByTagName('head')[0]): HTMLStyleElement {\r\n\tlet style = document.createElement('style');\r\n\tstyle.type = 'text/css';\r\n\tstyle.media = 'screen';\r\n\tcontainer.appendChild(style);\r\n\treturn style;\r\n}\r\n\r\nlet _sharedStyleSheet: HTMLStyleElement | null = null;\r\nfunction getSharedStyleSheet(): HTMLStyleElement {\r\n\tif (!_sharedStyleSheet) {\r\n\t\t_sharedStyleSheet = createStyleSheet();\r\n\t}\r\n\treturn _sharedStyleSheet;\r\n}\r\n\r\nfunction getDynamicStyleSheetRules(style: any) {\r\n\tif (style?.sheet?.rules) {\r\n\t\t// Chrome, IE\r\n\t\treturn style.sheet.rules;\r\n\t}\r\n\tif (style?.sheet?.cssRules) {\r\n\t\t// FF\r\n\t\treturn style.sheet.cssRules;\r\n\t}\r\n\treturn [];\r\n}\r\n\r\nexport function createCSSRule(selector: string, cssText: string, style: HTMLStyleElement = getSharedStyleSheet()): void {\r\n\tif (!style || !cssText) {\r\n\t\treturn;\r\n\t}\r\n\r\n\t(style.sheet).insertRule(selector + '{' + cssText + '}', 0);\r\n}\r\n\r\nexport function removeCSSRulesContainingSelector(ruleName: string, style: HTMLStyleElement = getSharedStyleSheet()): void {\r\n\tif (!style) {\r\n\t\treturn;\r\n\t}\r\n\r\n\tlet rules = getDynamicStyleSheetRules(style);\r\n\tlet toDelete: number[] = [];\r\n\tfor (let i = 0; i < rules.length; i++) {\r\n\t\tlet rule = rules[i];\r\n\t\tif (rule.selectorText.indexOf(ruleName) !== -1) {\r\n\t\t\ttoDelete.push(i);\r\n\t\t}\r\n\t}\r\n\r\n\tfor (let i = toDelete.length - 1; i >= 0; i--) {\r\n\t\t(style.sheet).deleteRule(toDelete[i]);\r\n\t}\r\n}\r\n\r\nexport function isHTMLElement(o: any): o is HTMLElement {\r\n\tif (typeof HTMLElement === 'object') {\r\n\t\treturn o instanceof HTMLElement;\r\n\t}\r\n\treturn o && typeof o === 'object' && o.nodeType === 1 && typeof o.nodeName === 'string';\r\n}\r\n\r\nexport const EventType = {\r\n\t// Mouse\r\n\tCLICK: 'click',\r\n\tAUXCLICK: 'auxclick',\r\n\tDBLCLICK: 'dblclick',\r\n\tMOUSE_UP: 'mouseup',\r\n\tMOUSE_DOWN: 'mousedown',\r\n\tMOUSE_OVER: 'mouseover',\r\n\tMOUSE_MOVE: 'mousemove',\r\n\tMOUSE_OUT: 'mouseout',\r\n\tMOUSE_ENTER: 'mouseenter',\r\n\tMOUSE_LEAVE: 'mouseleave',\r\n\tMOUSE_WHEEL: browser.isEdgeLegacy ? 'mousewheel' : 'wheel',\r\n\tPOINTER_UP: 'pointerup',\r\n\tPOINTER_DOWN: 'pointerdown',\r\n\tPOINTER_MOVE: 'pointermove',\r\n\tCONTEXT_MENU: 'contextmenu',\r\n\tWHEEL: 'wheel',\r\n\t// Keyboard\r\n\tKEY_DOWN: 'keydown',\r\n\tKEY_PRESS: 'keypress',\r\n\tKEY_UP: 'keyup',\r\n\t// HTML Document\r\n\tLOAD: 'load',\r\n\tBEFORE_UNLOAD: 'beforeunload',\r\n\tUNLOAD: 'unload',\r\n\tABORT: 'abort',\r\n\tERROR: 'error',\r\n\tRESIZE: 'resize',\r\n\tSCROLL: 'scroll',\r\n\tFULLSCREEN_CHANGE: 'fullscreenchange',\r\n\tWK_FULLSCREEN_CHANGE: 'webkitfullscreenchange',\r\n\t// Form\r\n\tSELECT: 'select',\r\n\tCHANGE: 'change',\r\n\tSUBMIT: 'submit',\r\n\tRESET: 'reset',\r\n\tFOCUS: 'focus',\r\n\tFOCUS_IN: 'focusin',\r\n\tFOCUS_OUT: 'focusout',\r\n\tBLUR: 'blur',\r\n\tINPUT: 'input',\r\n\t// Local Storage\r\n\tSTORAGE: 'storage',\r\n\t// Drag\r\n\tDRAG_START: 'dragstart',\r\n\tDRAG: 'drag',\r\n\tDRAG_ENTER: 'dragenter',\r\n\tDRAG_LEAVE: 'dragleave',\r\n\tDRAG_OVER: 'dragover',\r\n\tDROP: 'drop',\r\n\tDRAG_END: 'dragend',\r\n\t// Animation\r\n\tANIMATION_START: browser.isWebKit ? 'webkitAnimationStart' : 'animationstart',\r\n\tANIMATION_END: browser.isWebKit ? 'webkitAnimationEnd' : 'animationend',\r\n\tANIMATION_ITERATION: browser.isWebKit ? 'webkitAnimationIteration' : 'animationiteration'\r\n} as const;\r\n\r\nexport interface EventLike {\r\n\tpreventDefault(): void;\r\n\tstopPropagation(): void;\r\n}\r\n\r\nexport const EventHelper = {\r\n\tstop: function (e: EventLike, cancelBubble?: boolean) {\r\n\t\tif (e.preventDefault) {\r\n\t\t\te.preventDefault();\r\n\t\t} else {\r\n\t\t\t// IE8\r\n\t\t\t(e).returnValue = false;\r\n\t\t}\r\n\r\n\t\tif (cancelBubble) {\r\n\t\t\tif (e.stopPropagation) {\r\n\t\t\t\te.stopPropagation();\r\n\t\t\t} else {\r\n\t\t\t\t// IE8\r\n\t\t\t\t(e).cancelBubble = true;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n};\r\n\r\nexport interface IFocusTracker extends Disposable {\r\n\tonDidFocus: Event;\r\n\tonDidBlur: Event;\r\n}\r\n\r\nexport function saveParentsScrollTop(node: Element): number[] {\r\n\tlet r: number[] = [];\r\n\tfor (let i = 0; node && node.nodeType === node.ELEMENT_NODE; i++) {\r\n\t\tr[i] = node.scrollTop;\r\n\t\tnode = node.parentNode;\r\n\t}\r\n\treturn r;\r\n}\r\n\r\nexport function restoreParentsScrollTop(node: Element, state: number[]): void {\r\n\tfor (let i = 0; node && node.nodeType === node.ELEMENT_NODE; i++) {\r\n\t\tif (node.scrollTop !== state[i]) {\r\n\t\t\tnode.scrollTop = state[i];\r\n\t\t}\r\n\t\tnode = node.parentNode;\r\n\t}\r\n}\r\n\r\nclass FocusTracker extends Disposable implements IFocusTracker {\r\n\r\n\tprivate readonly _onDidFocus = this._register(new Emitter());\r\n\tpublic readonly onDidFocus: Event = this._onDidFocus.event;\r\n\r\n\tprivate readonly _onDidBlur = this._register(new Emitter());\r\n\tpublic readonly onDidBlur: Event = this._onDidBlur.event;\r\n\r\n\tprivate _refreshStateHandler: () => void;\r\n\r\n\tconstructor(element: HTMLElement | Window) {\r\n\t\tsuper();\r\n\t\tlet hasFocus = isAncestor(document.activeElement, element);\r\n\t\tlet loosingFocus = false;\r\n\r\n\t\tconst onFocus = () => {\r\n\t\t\tloosingFocus = false;\r\n\t\t\tif (!hasFocus) {\r\n\t\t\t\thasFocus = true;\r\n\t\t\t\tthis._onDidFocus.fire();\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tconst onBlur = () => {\r\n\t\t\tif (hasFocus) {\r\n\t\t\t\tloosingFocus = true;\r\n\t\t\t\twindow.setTimeout(() => {\r\n\t\t\t\t\tif (loosingFocus) {\r\n\t\t\t\t\t\tloosingFocus = false;\r\n\t\t\t\t\t\thasFocus = false;\r\n\t\t\t\t\t\tthis._onDidBlur.fire();\r\n\t\t\t\t\t}\r\n\t\t\t\t}, 0);\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tthis._refreshStateHandler = () => {\r\n\t\t\tlet currentNodeHasFocus = isAncestor(document.activeElement, element);\r\n\t\t\tif (currentNodeHasFocus !== hasFocus) {\r\n\t\t\t\tif (hasFocus) {\r\n\t\t\t\t\tonBlur();\r\n\t\t\t\t} else {\r\n\t\t\t\t\tonFocus();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tthis._register(domEvent(element, EventType.FOCUS, true)(onFocus));\r\n\t\tthis._register(domEvent(element, EventType.BLUR, true)(onBlur));\r\n\t}\r\n}\r\n\r\nexport function trackFocus(element: HTMLElement | Window): IFocusTracker {\r\n\treturn new FocusTracker(element);\r\n}\r\n\r\nexport function append(parent: HTMLElement, child: T): T;\r\nexport function append(parent: HTMLElement, ...children: (T | string)[]): void;\r\nexport function append(parent: HTMLElement, ...children: (T | string)[]): T | void {\r\n\tparent.append(...children);\r\n\tif (children.length === 1 && typeof children[0] !== 'string') {\r\n\t\treturn children[0];\r\n\t}\r\n}\r\n\r\n/**\r\n * Removes all children from `parent` and appends `children`\r\n */\r\nexport function reset(parent: HTMLElement, ...children: Array): void {\r\n\tparent.innerText = '';\r\n\tappend(parent, ...children);\r\n}\r\n\r\nconst SELECTOR_REGEX = /([\\w\\-]+)?(#([\\w\\-]+))?((\\.([\\w\\-]+))*)/;\r\n\r\nexport enum Namespace {\r\n\tHTML = 'http://www.w3.org/1999/xhtml',\r\n\tSVG = 'http://www.w3.org/2000/svg'\r\n}\r\n\r\nfunction _$(namespace: Namespace, description: string, attrs?: { [key: string]: any; }, ...children: Array): T {\r\n\tlet match = SELECTOR_REGEX.exec(description);\r\n\r\n\tif (!match) {\r\n\t\tthrow new Error('Bad use of emmet');\r\n\t}\r\n\r\n\tattrs = { ...(attrs || {}) };\r\n\r\n\tlet tagName = match[1] || 'div';\r\n\tlet result: T;\r\n\r\n\tif (namespace !== Namespace.HTML) {\r\n\t\tresult = document.createElementNS(namespace as string, tagName) as T;\r\n\t} else {\r\n\t\tresult = document.createElement(tagName) as unknown as T;\r\n\t}\r\n\r\n\tif (match[3]) {\r\n\t\tresult.id = match[3];\r\n\t}\r\n\tif (match[4]) {\r\n\t\tresult.className = match[4].replace(/\\./g, ' ').trim();\r\n\t}\r\n\r\n\tObject.keys(attrs).forEach(name => {\r\n\t\tconst value = attrs![name];\r\n\r\n\t\tif (typeof value === 'undefined') {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (/^on\\w+$/.test(name)) {\r\n\t\t\t(result)[name] = value;\r\n\t\t} else if (name === 'selected') {\r\n\t\t\tif (value) {\r\n\t\t\t\tresult.setAttribute(name, 'true');\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\t\t\tresult.setAttribute(name, value);\r\n\t\t}\r\n\t});\r\n\r\n\tresult.append(...children);\r\n\r\n\treturn result as T;\r\n}\r\n\r\nexport function $(description: string, attrs?: { [key: string]: any; }, ...children: Array): T {\r\n\treturn _$(Namespace.HTML, description, attrs, ...children);\r\n}\r\n\r\n$.SVG = function (description: string, attrs?: { [key: string]: any; }, ...children: Array): T {\r\n\treturn _$(Namespace.SVG, description, attrs, ...children);\r\n};\r\n\r\nexport function show(...elements: HTMLElement[]): void {\r\n\tfor (let element of elements) {\r\n\t\telement.style.display = '';\r\n\t\telement.removeAttribute('aria-hidden');\r\n\t}\r\n}\r\n\r\nexport function hide(...elements: HTMLElement[]): void {\r\n\tfor (let element of elements) {\r\n\t\telement.style.display = 'none';\r\n\t\telement.setAttribute('aria-hidden', 'true');\r\n\t}\r\n}\r\n\r\nfunction findParentWithAttribute(node: Node | null, attribute: string): HTMLElement | null {\r\n\twhile (node && node.nodeType === node.ELEMENT_NODE) {\r\n\t\tif (node instanceof HTMLElement && node.hasAttribute(attribute)) {\r\n\t\t\treturn node;\r\n\t\t}\r\n\r\n\t\tnode = node.parentNode;\r\n\t}\r\n\r\n\treturn null;\r\n}\r\n\r\nexport function removeTabIndexAndUpdateFocus(node: HTMLElement): void {\r\n\tif (!node || !node.hasAttribute('tabIndex')) {\r\n\t\treturn;\r\n\t}\r\n\r\n\t// If we are the currently focused element and tabIndex is removed,\r\n\t// standard DOM behavior is to move focus to the element. We\r\n\t// typically never want that, rather put focus to the closest element\r\n\t// in the hierarchy of the parent DOM nodes.\r\n\tif (document.activeElement === node) {\r\n\t\tlet parentFocusable = findParentWithAttribute(node.parentElement, 'tabIndex');\r\n\t\tif (parentFocusable) {\r\n\t\t\tparentFocusable.focus();\r\n\t\t}\r\n\t}\r\n\r\n\tnode.removeAttribute('tabindex');\r\n}\r\n\r\nexport function getElementsByTagName(tag: string): HTMLElement[] {\r\n\treturn Array.prototype.slice.call(document.getElementsByTagName(tag), 0);\r\n}\r\n\r\n/**\r\n * Find a value usable for a dom node size such that the likelihood that it would be\r\n * displayed with constant screen pixels size is as high as possible.\r\n *\r\n * e.g. We would desire for the cursors to be 2px (CSS px) wide. Under a devicePixelRatio\r\n * of 1.25, the cursor will be 2.5 screen pixels wide. Depending on how the dom node aligns/\"snaps\"\r\n * with the screen pixels, it will sometimes be rendered with 2 screen pixels, and sometimes with 3 screen pixels.\r\n */\r\nexport function computeScreenAwareSize(cssPx: number): number {\r\n\tconst screenPx = window.devicePixelRatio * cssPx;\r\n\treturn Math.max(1, Math.floor(screenPx)) / window.devicePixelRatio;\r\n}\r\n\r\n/**\r\n * See https://github.com/microsoft/monaco-editor/issues/601\r\n * To protect against malicious code in the linked site, particularly phishing attempts,\r\n * the window.opener should be set to null to prevent the linked site from having access\r\n * to change the location of the current page.\r\n * See https://mathiasbynens.github.io/rel-noopener/\r\n */\r\nexport function windowOpenNoOpener(url: string): void {\r\n\tif (browser.isElectron || browser.isEdgeLegacyWebView) {\r\n\t\t// In VSCode, window.open() always returns null...\r\n\t\t// The same is true for a WebView (see https://github.com/microsoft/monaco-editor/issues/628)\r\n\t\t// Also call directly window.open in sandboxed Electron (see https://github.com/microsoft/monaco-editor/issues/2220)\r\n\t\twindow.open(url);\r\n\t} else {\r\n\t\tlet newTab = window.open();\r\n\t\tif (newTab) {\r\n\t\t\t(newTab as any).opener = null;\r\n\t\t\tnewTab.location.href = url;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport function animate(fn: () => void): IDisposable {\r\n\tconst step = () => {\r\n\t\tfn();\r\n\t\tstepDisposable = scheduleAtNextAnimationFrame(step);\r\n\t};\r\n\r\n\tlet stepDisposable = scheduleAtNextAnimationFrame(step);\r\n\treturn toDisposable(() => stepDisposable.dispose());\r\n}\r\n\r\nRemoteAuthorities.setPreferredWebSchema(/^https:/.test(window.location.href) ? 'https' : 'http');\r\n\r\n/**\r\n * returns url('...')\r\n */\r\nexport function asCSSUrl(uri: URI): string {\r\n\tif (!uri) {\r\n\t\treturn `url('')`;\r\n\t}\r\n\treturn `url('${FileAccess.asBrowserUri(uri).toString(true).replace(/'/g, '%27')}')`;\r\n}\r\n\r\ntype ModifierKey = 'alt' | 'ctrl' | 'shift' | 'meta';\r\n\r\nexport interface IModifierKeyStatus {\r\n\taltKey: boolean;\r\n\tshiftKey: boolean;\r\n\tctrlKey: boolean;\r\n\tmetaKey: boolean;\r\n\tlastKeyPressed?: ModifierKey;\r\n\tlastKeyReleased?: ModifierKey;\r\n\tevent?: KeyboardEvent;\r\n}\r\n\r\nexport class ModifierKeyEmitter extends Emitter {\r\n\r\n\tprivate readonly _subscriptions = new DisposableStore();\r\n\tprivate _keyStatus: IModifierKeyStatus;\r\n\tprivate static instance: ModifierKeyEmitter;\r\n\r\n\tprivate constructor() {\r\n\t\tsuper();\r\n\r\n\t\tthis._keyStatus = {\r\n\t\t\taltKey: false,\r\n\t\t\tshiftKey: false,\r\n\t\t\tctrlKey: false,\r\n\t\t\tmetaKey: false\r\n\t\t};\r\n\r\n\t\tthis._subscriptions.add(domEvent(document.body, 'keydown', true)(e => {\r\n\t\t\t// if keydown event is repeated, ignore it #112347\r\n\t\t\tif (e.repeat) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst event = new StandardKeyboardEvent(e);\r\n\r\n\t\t\tif (e.altKey && !this._keyStatus.altKey) {\r\n\t\t\t\tthis._keyStatus.lastKeyPressed = 'alt';\r\n\t\t\t} else if (e.ctrlKey && !this._keyStatus.ctrlKey) {\r\n\t\t\t\tthis._keyStatus.lastKeyPressed = 'ctrl';\r\n\t\t\t} else if (e.metaKey && !this._keyStatus.metaKey) {\r\n\t\t\t\tthis._keyStatus.lastKeyPressed = 'meta';\r\n\t\t\t} else if (e.shiftKey && !this._keyStatus.shiftKey) {\r\n\t\t\t\tthis._keyStatus.lastKeyPressed = 'shift';\r\n\t\t\t} else if (event.keyCode !== KeyCode.Alt) {\r\n\t\t\t\tthis._keyStatus.lastKeyPressed = undefined;\r\n\t\t\t} else {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tthis._keyStatus.altKey = e.altKey;\r\n\t\t\tthis._keyStatus.ctrlKey = e.ctrlKey;\r\n\t\t\tthis._keyStatus.metaKey = e.metaKey;\r\n\t\t\tthis._keyStatus.shiftKey = e.shiftKey;\r\n\r\n\t\t\tif (this._keyStatus.lastKeyPressed) {\r\n\t\t\t\tthis._keyStatus.event = e;\r\n\t\t\t\tthis.fire(this._keyStatus);\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._subscriptions.add(domEvent(document.body, 'keyup', true)(e => {\r\n\t\t\tif (!e.altKey && this._keyStatus.altKey) {\r\n\t\t\t\tthis._keyStatus.lastKeyReleased = 'alt';\r\n\t\t\t} else if (!e.ctrlKey && this._keyStatus.ctrlKey) {\r\n\t\t\t\tthis._keyStatus.lastKeyReleased = 'ctrl';\r\n\t\t\t} else if (!e.metaKey && this._keyStatus.metaKey) {\r\n\t\t\t\tthis._keyStatus.lastKeyReleased = 'meta';\r\n\t\t\t} else if (!e.shiftKey && this._keyStatus.shiftKey) {\r\n\t\t\t\tthis._keyStatus.lastKeyReleased = 'shift';\r\n\t\t\t} else {\r\n\t\t\t\tthis._keyStatus.lastKeyReleased = undefined;\r\n\t\t\t}\r\n\r\n\t\t\tif (this._keyStatus.lastKeyPressed !== this._keyStatus.lastKeyReleased) {\r\n\t\t\t\tthis._keyStatus.lastKeyPressed = undefined;\r\n\t\t\t}\r\n\r\n\t\t\tthis._keyStatus.altKey = e.altKey;\r\n\t\t\tthis._keyStatus.ctrlKey = e.ctrlKey;\r\n\t\t\tthis._keyStatus.metaKey = e.metaKey;\r\n\t\t\tthis._keyStatus.shiftKey = e.shiftKey;\r\n\r\n\t\t\tif (this._keyStatus.lastKeyReleased) {\r\n\t\t\t\tthis._keyStatus.event = e;\r\n\t\t\t\tthis.fire(this._keyStatus);\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._subscriptions.add(domEvent(document.body, 'mousedown', true)(e => {\r\n\t\t\tthis._keyStatus.lastKeyPressed = undefined;\r\n\t\t}));\r\n\r\n\t\tthis._subscriptions.add(domEvent(document.body, 'mouseup', true)(e => {\r\n\t\t\tthis._keyStatus.lastKeyPressed = undefined;\r\n\t\t}));\r\n\r\n\t\tthis._subscriptions.add(domEvent(document.body, 'mousemove', true)(e => {\r\n\t\t\tif (e.buttons) {\r\n\t\t\t\tthis._keyStatus.lastKeyPressed = undefined;\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._subscriptions.add(domEvent(window, 'blur')(e => {\r\n\t\t\tthis.resetKeyStatus();\r\n\t\t}));\r\n\t}\r\n\r\n\tget keyStatus(): IModifierKeyStatus {\r\n\t\treturn this._keyStatus;\r\n\t}\r\n\r\n\t/**\r\n\t * Allows to explicitly reset the key status based on more knowledge (#109062)\r\n\t */\r\n\tresetKeyStatus(): void {\r\n\t\tthis.doResetKeyStatus();\r\n\t\tthis.fire(this._keyStatus);\r\n\t}\r\n\r\n\tprivate doResetKeyStatus(): void {\r\n\t\tthis._keyStatus = {\r\n\t\t\taltKey: false,\r\n\t\t\tshiftKey: false,\r\n\t\t\tctrlKey: false,\r\n\t\t\tmetaKey: false\r\n\t\t};\r\n\t}\r\n\r\n\tstatic getInstance() {\r\n\t\tif (!ModifierKeyEmitter.instance) {\r\n\t\t\tModifierKeyEmitter.instance = new ModifierKeyEmitter();\r\n\t\t}\r\n\r\n\t\treturn ModifierKeyEmitter.instance;\r\n\t}\r\n\r\n\tdispose() {\r\n\t\tsuper.dispose();\r\n\t\tthis._subscriptions.dispose();\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as DOM from 'vs/base/browser/dom';\r\nimport { IMouseEvent } from 'vs/base/browser/mouseEvent';\r\nimport { DisposableStore } from 'vs/base/common/lifecycle';\r\n\r\nexport interface IContentActionHandler {\r\n\tcallback: (content: string, event?: IMouseEvent) => void;\r\n\treadonly disposeables: DisposableStore;\r\n}\r\n\r\nexport interface FormattedTextRenderOptions {\r\n\treadonly className?: string;\r\n\treadonly inline?: boolean;\r\n\treadonly actionHandler?: IContentActionHandler;\r\n}\r\n\r\nexport function renderText(text: string, options: FormattedTextRenderOptions = {}): HTMLElement {\r\n\tconst element = createElement(options);\r\n\telement.textContent = text;\r\n\treturn element;\r\n}\r\n\r\nexport function renderFormattedText(formattedText: string, options: FormattedTextRenderOptions = {}): HTMLElement {\r\n\tconst element = createElement(options);\r\n\t_renderFormattedText(element, parseFormattedText(formattedText), options.actionHandler);\r\n\treturn element;\r\n}\r\n\r\nexport function createElement(options: FormattedTextRenderOptions): HTMLElement {\r\n\tconst tagName = options.inline ? 'span' : 'div';\r\n\tconst element = document.createElement(tagName);\r\n\tif (options.className) {\r\n\t\telement.className = options.className;\r\n\t}\r\n\treturn element;\r\n}\r\n\r\nclass StringStream {\r\n\tprivate source: string;\r\n\tprivate index: number;\r\n\r\n\tconstructor(source: string) {\r\n\t\tthis.source = source;\r\n\t\tthis.index = 0;\r\n\t}\r\n\r\n\tpublic eos(): boolean {\r\n\t\treturn this.index >= this.source.length;\r\n\t}\r\n\r\n\tpublic next(): string {\r\n\t\tconst next = this.peek();\r\n\t\tthis.advance();\r\n\t\treturn next;\r\n\t}\r\n\r\n\tpublic peek(): string {\r\n\t\treturn this.source[this.index];\r\n\t}\r\n\r\n\tpublic advance(): void {\r\n\t\tthis.index++;\r\n\t}\r\n}\r\n\r\nconst enum FormatType {\r\n\tInvalid,\r\n\tRoot,\r\n\tText,\r\n\tBold,\r\n\tItalics,\r\n\tAction,\r\n\tActionClose,\r\n\tNewLine\r\n}\r\n\r\ninterface IFormatParseTree {\r\n\ttype: FormatType;\r\n\tcontent?: string;\r\n\tindex?: number;\r\n\tchildren?: IFormatParseTree[];\r\n}\r\n\r\nfunction _renderFormattedText(element: Node, treeNode: IFormatParseTree, actionHandler?: IContentActionHandler) {\r\n\tlet child: Node | undefined;\r\n\r\n\tif (treeNode.type === FormatType.Text) {\r\n\t\tchild = document.createTextNode(treeNode.content || '');\r\n\t} else if (treeNode.type === FormatType.Bold) {\r\n\t\tchild = document.createElement('b');\r\n\t} else if (treeNode.type === FormatType.Italics) {\r\n\t\tchild = document.createElement('i');\r\n\t} else if (treeNode.type === FormatType.Action && actionHandler) {\r\n\t\tconst a = document.createElement('a');\r\n\t\ta.href = '#';\r\n\t\tactionHandler.disposeables.add(DOM.addStandardDisposableListener(a, 'click', (event) => {\r\n\t\t\tactionHandler.callback(String(treeNode.index), event);\r\n\t\t}));\r\n\r\n\t\tchild = a;\r\n\t} else if (treeNode.type === FormatType.NewLine) {\r\n\t\tchild = document.createElement('br');\r\n\t} else if (treeNode.type === FormatType.Root) {\r\n\t\tchild = element;\r\n\t}\r\n\r\n\tif (child && element !== child) {\r\n\t\telement.appendChild(child);\r\n\t}\r\n\r\n\tif (child && Array.isArray(treeNode.children)) {\r\n\t\ttreeNode.children.forEach((nodeChild) => {\r\n\t\t\t_renderFormattedText(child!, nodeChild, actionHandler);\r\n\t\t});\r\n\t}\r\n}\r\n\r\nfunction parseFormattedText(content: string): IFormatParseTree {\r\n\r\n\tconst root: IFormatParseTree = {\r\n\t\ttype: FormatType.Root,\r\n\t\tchildren: []\r\n\t};\r\n\r\n\tlet actionViewItemIndex = 0;\r\n\tlet current = root;\r\n\tconst stack: IFormatParseTree[] = [];\r\n\tconst stream = new StringStream(content);\r\n\r\n\twhile (!stream.eos()) {\r\n\t\tlet next = stream.next();\r\n\r\n\t\tconst isEscapedFormatType = (next === '\\\\' && formatTagType(stream.peek()) !== FormatType.Invalid);\r\n\t\tif (isEscapedFormatType) {\r\n\t\t\tnext = stream.next(); // unread the backslash if it escapes a format tag type\r\n\t\t}\r\n\r\n\t\tif (!isEscapedFormatType && isFormatTag(next) && next === stream.peek()) {\r\n\t\t\tstream.advance();\r\n\r\n\t\t\tif (current.type === FormatType.Text) {\r\n\t\t\t\tcurrent = stack.pop()!;\r\n\t\t\t}\r\n\r\n\t\t\tconst type = formatTagType(next);\r\n\t\t\tif (current.type === type || (current.type === FormatType.Action && type === FormatType.ActionClose)) {\r\n\t\t\t\tcurrent = stack.pop()!;\r\n\t\t\t} else {\r\n\t\t\t\tconst newCurrent: IFormatParseTree = {\r\n\t\t\t\t\ttype: type,\r\n\t\t\t\t\tchildren: []\r\n\t\t\t\t};\r\n\r\n\t\t\t\tif (type === FormatType.Action) {\r\n\t\t\t\t\tnewCurrent.index = actionViewItemIndex;\r\n\t\t\t\t\tactionViewItemIndex++;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tcurrent.children!.push(newCurrent);\r\n\t\t\t\tstack.push(current);\r\n\t\t\t\tcurrent = newCurrent;\r\n\t\t\t}\r\n\t\t} else if (next === '\\n') {\r\n\t\t\tif (current.type === FormatType.Text) {\r\n\t\t\t\tcurrent = stack.pop()!;\r\n\t\t\t}\r\n\r\n\t\t\tcurrent.children!.push({\r\n\t\t\t\ttype: FormatType.NewLine\r\n\t\t\t});\r\n\r\n\t\t} else {\r\n\t\t\tif (current.type !== FormatType.Text) {\r\n\t\t\t\tconst textCurrent: IFormatParseTree = {\r\n\t\t\t\t\ttype: FormatType.Text,\r\n\t\t\t\t\tcontent: next\r\n\t\t\t\t};\r\n\t\t\t\tcurrent.children!.push(textCurrent);\r\n\t\t\t\tstack.push(current);\r\n\t\t\t\tcurrent = textCurrent;\r\n\r\n\t\t\t} else {\r\n\t\t\t\tcurrent.content += next;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tif (current.type === FormatType.Text) {\r\n\t\tcurrent = stack.pop()!;\r\n\t}\r\n\r\n\tif (stack.length) {\r\n\t\t// incorrectly formatted string literal\r\n\t}\r\n\r\n\treturn root;\r\n}\r\n\r\nfunction isFormatTag(char: string): boolean {\r\n\treturn formatTagType(char) !== FormatType.Invalid;\r\n}\r\n\r\nfunction formatTagType(char: string): FormatType {\r\n\tswitch (char) {\r\n\t\tcase '*':\r\n\t\t\treturn FormatType.Bold;\r\n\t\tcase '_':\r\n\t\t\treturn FormatType.Italics;\r\n\t\tcase '[':\r\n\t\t\treturn FormatType.Action;\r\n\t\tcase ']':\r\n\t\t\treturn FormatType.ActionClose;\r\n\t\tdefault:\r\n\t\t\treturn FormatType.Invalid;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { IframeUtils } from 'vs/base/browser/iframe';\r\nimport { StandardMouseEvent } from 'vs/base/browser/mouseEvent';\r\nimport { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';\r\n\r\nexport interface IStandardMouseMoveEventData {\r\n\tleftButton: boolean;\r\n\tbuttons: number;\r\n\tposx: number;\r\n\tposy: number;\r\n}\r\n\r\nexport interface IEventMerger {\r\n\t(lastEvent: R | null, currentEvent: MouseEvent): R;\r\n}\r\n\r\nexport interface IMouseMoveCallback {\r\n\t(mouseMoveData: R): void;\r\n}\r\n\r\nexport interface IOnStopCallback {\r\n\t(browserEvent?: MouseEvent | KeyboardEvent): void;\r\n}\r\n\r\nexport function standardMouseMoveMerger(lastEvent: IStandardMouseMoveEventData | null, currentEvent: MouseEvent): IStandardMouseMoveEventData {\r\n\tlet ev = new StandardMouseEvent(currentEvent);\r\n\tev.preventDefault();\r\n\treturn {\r\n\t\tleftButton: ev.leftButton,\r\n\t\tbuttons: ev.buttons,\r\n\t\tposx: ev.posx,\r\n\t\tposy: ev.posy\r\n\t};\r\n}\r\n\r\nexport class GlobalMouseMoveMonitor implements IDisposable {\r\n\r\n\tprivate readonly _hooks = new DisposableStore();\r\n\tprivate _mouseMoveEventMerger: IEventMerger | null = null;\r\n\tprivate _mouseMoveCallback: IMouseMoveCallback | null = null;\r\n\tprivate _onStopCallback: IOnStopCallback | null = null;\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis.stopMonitoring(false);\r\n\t\tthis._hooks.dispose();\r\n\t}\r\n\r\n\tpublic stopMonitoring(invokeStopCallback: boolean, browserEvent?: MouseEvent | KeyboardEvent): void {\r\n\t\tif (!this.isMonitoring()) {\r\n\t\t\t// Not monitoring\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// Unhook\r\n\t\tthis._hooks.clear();\r\n\t\tthis._mouseMoveEventMerger = null;\r\n\t\tthis._mouseMoveCallback = null;\r\n\t\tconst onStopCallback = this._onStopCallback;\r\n\t\tthis._onStopCallback = null;\r\n\r\n\t\tif (invokeStopCallback && onStopCallback) {\r\n\t\t\tonStopCallback(browserEvent);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic isMonitoring(): boolean {\r\n\t\treturn !!this._mouseMoveEventMerger;\r\n\t}\r\n\r\n\tpublic startMonitoring(\r\n\t\tinitialElement: HTMLElement,\r\n\t\tinitialButtons: number,\r\n\t\tmouseMoveEventMerger: IEventMerger,\r\n\t\tmouseMoveCallback: IMouseMoveCallback,\r\n\t\tonStopCallback: IOnStopCallback\r\n\t): void {\r\n\t\tif (this.isMonitoring()) {\r\n\t\t\t// I am already hooked\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._mouseMoveEventMerger = mouseMoveEventMerger;\r\n\t\tthis._mouseMoveCallback = mouseMoveCallback;\r\n\t\tthis._onStopCallback = onStopCallback;\r\n\r\n\t\tconst windowChain = IframeUtils.getSameOriginWindowChain();\r\n\t\tconst mouseMove = 'mousemove';\r\n\t\tconst mouseUp = 'mouseup';\r\n\r\n\t\tconst listenTo: (Document | ShadowRoot)[] = windowChain.map(element => element.window.document);\r\n\t\tconst shadowRoot = dom.getShadowRoot(initialElement);\r\n\t\tif (shadowRoot) {\r\n\t\t\tlistenTo.unshift(shadowRoot);\r\n\t\t}\r\n\r\n\t\tfor (const element of listenTo) {\r\n\t\t\tthis._hooks.add(dom.addDisposableThrottledListener(element, mouseMove,\r\n\t\t\t\t(data: R) => {\r\n\t\t\t\t\tif (data.buttons !== initialButtons) {\r\n\t\t\t\t\t\t// Buttons state has changed in the meantime\r\n\t\t\t\t\t\tthis.stopMonitoring(true);\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tthis._mouseMoveCallback!(data);\r\n\t\t\t\t},\r\n\t\t\t\t(lastEvent: R | null, currentEvent) => this._mouseMoveEventMerger!(lastEvent, currentEvent as MouseEvent)\r\n\t\t\t));\r\n\t\t\tthis._hooks.add(dom.addDisposableListener(element, mouseUp, (e: MouseEvent) => this.stopMonitoring(true)));\r\n\t\t}\r\n\r\n\t\tif (IframeUtils.hasDifferentOriginAncestor()) {\r\n\t\t\tlet lastSameOriginAncestor = windowChain[windowChain.length - 1];\r\n\t\t\t// We might miss a mouse up if it happens outside the iframe\r\n\t\t\t// This one is for Chrome\r\n\t\t\tthis._hooks.add(dom.addDisposableListener(lastSameOriginAncestor.window.document, 'mouseout', (browserEvent: MouseEvent) => {\r\n\t\t\t\tlet e = new StandardMouseEvent(browserEvent);\r\n\t\t\t\tif (e.target.tagName.toLowerCase() === 'html') {\r\n\t\t\t\t\tthis.stopMonitoring(true);\r\n\t\t\t\t}\r\n\t\t\t}));\r\n\t\t\t// This one is for FF\r\n\t\t\tthis._hooks.add(dom.addDisposableListener(lastSameOriginAncestor.window.document, 'mouseover', (browserEvent: MouseEvent) => {\r\n\t\t\t\tlet e = new StandardMouseEvent(browserEvent);\r\n\t\t\t\tif (e.target.tagName.toLowerCase() === 'html') {\r\n\t\t\t\t\tthis.stopMonitoring(true);\r\n\t\t\t\t}\r\n\t\t\t}));\r\n\t\t\t// This one is for IE\r\n\t\t\tthis._hooks.add(dom.addDisposableListener(lastSameOriginAncestor.window.document.body, 'mouseleave', (browserEvent: MouseEvent) => {\r\n\t\t\t\tthis.stopMonitoring(true);\r\n\t\t\t}));\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as arrays from 'vs/base/common/arrays';\r\nimport { IDisposable, Disposable } from 'vs/base/common/lifecycle';\r\nimport * as DomUtils from 'vs/base/browser/dom';\r\nimport { memoize } from 'vs/base/common/decorators';\r\n\r\nexport namespace EventType {\r\n\texport const Tap = '-monaco-gesturetap';\r\n\texport const Change = '-monaco-gesturechange';\r\n\texport const Start = '-monaco-gesturestart';\r\n\texport const End = '-monaco-gesturesend';\r\n\texport const Contextmenu = '-monaco-gesturecontextmenu';\r\n}\r\n\r\ninterface TouchData {\r\n\tid: number;\r\n\tinitialTarget: EventTarget;\r\n\tinitialTimeStamp: number;\r\n\tinitialPageX: number;\r\n\tinitialPageY: number;\r\n\trollingTimestamps: number[];\r\n\trollingPageX: number[];\r\n\trollingPageY: number[];\r\n}\r\n\r\nexport interface GestureEvent extends MouseEvent {\r\n\tinitialTarget: EventTarget | undefined;\r\n\ttranslationX: number;\r\n\ttranslationY: number;\r\n\tpageX: number;\r\n\tpageY: number;\r\n\ttapCount: number;\r\n}\r\n\r\ninterface Touch {\r\n\tidentifier: number;\r\n\tpageX: number;\r\n\tpageY: number;\r\n\ttarget: Element;\r\n}\r\n\r\ninterface TouchList {\r\n\t[i: number]: Touch;\r\n\tlength: number;\r\n\titem(index: number): Touch;\r\n}\r\n\r\ninterface TouchEvent extends Event {\r\n\ttouches: TouchList;\r\n\ttargetTouches: TouchList;\r\n\tchangedTouches: TouchList;\r\n}\r\n\r\nexport class Gesture extends Disposable {\r\n\r\n\tprivate static readonly SCROLL_FRICTION = -0.005;\r\n\tprivate static INSTANCE: Gesture;\r\n\tprivate static readonly HOLD_DELAY = 700;\r\n\r\n\tprivate dispatched = false;\r\n\tprivate targets: HTMLElement[];\r\n\tprivate ignoreTargets: HTMLElement[];\r\n\tprivate handle: IDisposable | null;\r\n\r\n\tprivate activeTouches: { [id: number]: TouchData; };\r\n\r\n\tprivate _lastSetTapCountTime: number;\r\n\r\n\tprivate static readonly CLEAR_TAP_COUNT_TIME = 400; // ms\r\n\r\n\r\n\tprivate constructor() {\r\n\t\tsuper();\r\n\r\n\t\tthis.activeTouches = {};\r\n\t\tthis.handle = null;\r\n\t\tthis.targets = [];\r\n\t\tthis.ignoreTargets = [];\r\n\t\tthis._lastSetTapCountTime = 0;\r\n\t\tthis._register(DomUtils.addDisposableListener(document, 'touchstart', (e: TouchEvent) => this.onTouchStart(e), { passive: false }));\r\n\t\tthis._register(DomUtils.addDisposableListener(document, 'touchend', (e: TouchEvent) => this.onTouchEnd(e)));\r\n\t\tthis._register(DomUtils.addDisposableListener(document, 'touchmove', (e: TouchEvent) => this.onTouchMove(e), { passive: false }));\r\n\t}\r\n\r\n\tpublic static addTarget(element: HTMLElement): IDisposable {\r\n\t\tif (!Gesture.isTouchDevice()) {\r\n\t\t\treturn Disposable.None;\r\n\t\t}\r\n\t\tif (!Gesture.INSTANCE) {\r\n\t\t\tGesture.INSTANCE = new Gesture();\r\n\t\t}\r\n\r\n\t\tGesture.INSTANCE.targets.push(element);\r\n\r\n\t\treturn {\r\n\t\t\tdispose: () => {\r\n\t\t\t\tGesture.INSTANCE.targets = Gesture.INSTANCE.targets.filter(t => t !== element);\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\tpublic static ignoreTarget(element: HTMLElement): IDisposable {\r\n\t\tif (!Gesture.isTouchDevice()) {\r\n\t\t\treturn Disposable.None;\r\n\t\t}\r\n\t\tif (!Gesture.INSTANCE) {\r\n\t\t\tGesture.INSTANCE = new Gesture();\r\n\t\t}\r\n\r\n\t\tGesture.INSTANCE.ignoreTargets.push(element);\r\n\r\n\t\treturn {\r\n\t\t\tdispose: () => {\r\n\t\t\t\tGesture.INSTANCE.ignoreTargets = Gesture.INSTANCE.ignoreTargets.filter(t => t !== element);\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\t@memoize\r\n\tprivate static isTouchDevice(): boolean {\r\n\t\t// `'ontouchstart' in window` always evaluates to true with typescript's modern typings. This causes `window` to be\r\n\t\t// `never` later in `window.navigator`. That's why we need the explicit `window as Window` cast\r\n\t\treturn 'ontouchstart' in window || navigator.maxTouchPoints > 0 || (window as Window).navigator.msMaxTouchPoints > 0;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tif (this.handle) {\r\n\t\t\tthis.handle.dispose();\r\n\t\t\tthis.handle = null;\r\n\t\t}\r\n\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tprivate onTouchStart(e: TouchEvent): void {\r\n\t\tlet timestamp = Date.now(); // use Date.now() because on FF e.timeStamp is not epoch based.\r\n\r\n\t\tif (this.handle) {\r\n\t\t\tthis.handle.dispose();\r\n\t\t\tthis.handle = null;\r\n\t\t}\r\n\r\n\t\tfor (let i = 0, len = e.targetTouches.length; i < len; i++) {\r\n\t\t\tlet touch = e.targetTouches.item(i);\r\n\r\n\t\t\tthis.activeTouches[touch.identifier] = {\r\n\t\t\t\tid: touch.identifier,\r\n\t\t\t\tinitialTarget: touch.target,\r\n\t\t\t\tinitialTimeStamp: timestamp,\r\n\t\t\t\tinitialPageX: touch.pageX,\r\n\t\t\t\tinitialPageY: touch.pageY,\r\n\t\t\t\trollingTimestamps: [timestamp],\r\n\t\t\t\trollingPageX: [touch.pageX],\r\n\t\t\t\trollingPageY: [touch.pageY]\r\n\t\t\t};\r\n\r\n\t\t\tlet evt = this.newGestureEvent(EventType.Start, touch.target);\r\n\t\t\tevt.pageX = touch.pageX;\r\n\t\t\tevt.pageY = touch.pageY;\r\n\t\t\tthis.dispatchEvent(evt);\r\n\t\t}\r\n\r\n\t\tif (this.dispatched) {\r\n\t\t\te.preventDefault();\r\n\t\t\te.stopPropagation();\r\n\t\t\tthis.dispatched = false;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate onTouchEnd(e: TouchEvent): void {\r\n\t\tlet timestamp = Date.now(); // use Date.now() because on FF e.timeStamp is not epoch based.\r\n\r\n\t\tlet activeTouchCount = Object.keys(this.activeTouches).length;\r\n\r\n\t\tfor (let i = 0, len = e.changedTouches.length; i < len; i++) {\r\n\r\n\t\t\tlet touch = e.changedTouches.item(i);\r\n\r\n\t\t\tif (!this.activeTouches.hasOwnProperty(String(touch.identifier))) {\r\n\t\t\t\tconsole.warn('move of an UNKNOWN touch', touch);\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tlet data = this.activeTouches[touch.identifier],\r\n\t\t\t\tholdTime = Date.now() - data.initialTimeStamp;\r\n\r\n\t\t\tif (holdTime < Gesture.HOLD_DELAY\r\n\t\t\t\t&& Math.abs(data.initialPageX - arrays.tail(data.rollingPageX)) < 30\r\n\t\t\t\t&& Math.abs(data.initialPageY - arrays.tail(data.rollingPageY)) < 30) {\r\n\r\n\t\t\t\tlet evt = this.newGestureEvent(EventType.Tap, data.initialTarget);\r\n\t\t\t\tevt.pageX = arrays.tail(data.rollingPageX);\r\n\t\t\t\tevt.pageY = arrays.tail(data.rollingPageY);\r\n\t\t\t\tthis.dispatchEvent(evt);\r\n\r\n\t\t\t} else if (holdTime >= Gesture.HOLD_DELAY\r\n\t\t\t\t&& Math.abs(data.initialPageX - arrays.tail(data.rollingPageX)) < 30\r\n\t\t\t\t&& Math.abs(data.initialPageY - arrays.tail(data.rollingPageY)) < 30) {\r\n\r\n\t\t\t\tlet evt = this.newGestureEvent(EventType.Contextmenu, data.initialTarget);\r\n\t\t\t\tevt.pageX = arrays.tail(data.rollingPageX);\r\n\t\t\t\tevt.pageY = arrays.tail(data.rollingPageY);\r\n\t\t\t\tthis.dispatchEvent(evt);\r\n\r\n\t\t\t} else if (activeTouchCount === 1) {\r\n\t\t\t\tlet finalX = arrays.tail(data.rollingPageX);\r\n\t\t\t\tlet finalY = arrays.tail(data.rollingPageY);\r\n\r\n\t\t\t\tlet deltaT = arrays.tail(data.rollingTimestamps) - data.rollingTimestamps[0];\r\n\t\t\t\tlet deltaX = finalX - data.rollingPageX[0];\r\n\t\t\t\tlet deltaY = finalY - data.rollingPageY[0];\r\n\r\n\t\t\t\t// We need to get all the dispatch targets on the start of the inertia event\r\n\t\t\t\tconst dispatchTo = this.targets.filter(t => data.initialTarget instanceof Node && t.contains(data.initialTarget));\r\n\t\t\t\tthis.inertia(dispatchTo, timestamp,\t\t// time now\r\n\t\t\t\t\tMath.abs(deltaX) / deltaT,\t// speed\r\n\t\t\t\t\tdeltaX > 0 ? 1 : -1,\t\t// x direction\r\n\t\t\t\t\tfinalX,\t\t\t\t\t\t// x now\r\n\t\t\t\t\tMath.abs(deltaY) / deltaT, // y speed\r\n\t\t\t\t\tdeltaY > 0 ? 1 : -1,\t\t// y direction\r\n\t\t\t\t\tfinalY\t\t\t\t\t\t// y now\r\n\t\t\t\t);\r\n\t\t\t}\r\n\r\n\r\n\t\t\tthis.dispatchEvent(this.newGestureEvent(EventType.End, data.initialTarget));\r\n\t\t\t// forget about this touch\r\n\t\t\tdelete this.activeTouches[touch.identifier];\r\n\t\t}\r\n\r\n\t\tif (this.dispatched) {\r\n\t\t\te.preventDefault();\r\n\t\t\te.stopPropagation();\r\n\t\t\tthis.dispatched = false;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate newGestureEvent(type: string, initialTarget?: EventTarget): GestureEvent {\r\n\t\tlet event = document.createEvent('CustomEvent') as unknown as GestureEvent;\r\n\t\tevent.initEvent(type, false, true);\r\n\t\tevent.initialTarget = initialTarget;\r\n\t\tevent.tapCount = 0;\r\n\t\treturn event;\r\n\t}\r\n\r\n\tprivate dispatchEvent(event: GestureEvent): void {\r\n\t\tif (event.type === EventType.Tap) {\r\n\t\t\tconst currentTime = (new Date()).getTime();\r\n\t\t\tlet setTapCount = 0;\r\n\t\t\tif (currentTime - this._lastSetTapCountTime > Gesture.CLEAR_TAP_COUNT_TIME) {\r\n\t\t\t\tsetTapCount = 1;\r\n\t\t\t} else {\r\n\t\t\t\tsetTapCount = 2;\r\n\t\t\t}\r\n\r\n\t\t\tthis._lastSetTapCountTime = currentTime;\r\n\t\t\tevent.tapCount = setTapCount;\r\n\t\t} else if (event.type === EventType.Change || event.type === EventType.Contextmenu) {\r\n\t\t\t// tap is canceled by scrolling or context menu\r\n\t\t\tthis._lastSetTapCountTime = 0;\r\n\t\t}\r\n\r\n\t\tfor (let i = 0; i < this.ignoreTargets.length; i++) {\r\n\t\t\tif (event.initialTarget instanceof Node && this.ignoreTargets[i].contains(event.initialTarget)) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis.targets.forEach(target => {\r\n\t\t\tif (event.initialTarget instanceof Node && target.contains(event.initialTarget)) {\r\n\t\t\t\ttarget.dispatchEvent(event);\r\n\t\t\t\tthis.dispatched = true;\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprivate inertia(dispatchTo: EventTarget[], t1: number, vX: number, dirX: number, x: number, vY: number, dirY: number, y: number): void {\r\n\t\tthis.handle = DomUtils.scheduleAtNextAnimationFrame(() => {\r\n\t\t\tlet now = Date.now();\r\n\r\n\t\t\t// velocity: old speed + accel_over_time\r\n\t\t\tlet deltaT = now - t1,\r\n\t\t\t\tdelta_pos_x = 0, delta_pos_y = 0,\r\n\t\t\t\tstopped = true;\r\n\r\n\t\t\tvX += Gesture.SCROLL_FRICTION * deltaT;\r\n\t\t\tvY += Gesture.SCROLL_FRICTION * deltaT;\r\n\r\n\t\t\tif (vX > 0) {\r\n\t\t\t\tstopped = false;\r\n\t\t\t\tdelta_pos_x = dirX * vX * deltaT;\r\n\t\t\t}\r\n\r\n\t\t\tif (vY > 0) {\r\n\t\t\t\tstopped = false;\r\n\t\t\t\tdelta_pos_y = dirY * vY * deltaT;\r\n\t\t\t}\r\n\r\n\t\t\t// dispatch translation event\r\n\t\t\tlet evt = this.newGestureEvent(EventType.Change);\r\n\t\t\tevt.translationX = delta_pos_x;\r\n\t\t\tevt.translationY = delta_pos_y;\r\n\t\t\tdispatchTo.forEach(d => d.dispatchEvent(evt));\r\n\r\n\t\t\tif (!stopped) {\r\n\t\t\t\tthis.inertia(dispatchTo, now, vX, dirX, x + delta_pos_x, vY, dirY, y + delta_pos_y);\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprivate onTouchMove(e: TouchEvent): void {\r\n\t\tlet timestamp = Date.now(); // use Date.now() because on FF e.timeStamp is not epoch based.\r\n\r\n\t\tfor (let i = 0, len = e.changedTouches.length; i < len; i++) {\r\n\r\n\t\t\tlet touch = e.changedTouches.item(i);\r\n\r\n\t\t\tif (!this.activeTouches.hasOwnProperty(String(touch.identifier))) {\r\n\t\t\t\tconsole.warn('end of an UNKNOWN touch', touch);\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tlet data = this.activeTouches[touch.identifier];\r\n\r\n\t\t\tlet evt = this.newGestureEvent(EventType.Change, data.initialTarget);\r\n\t\t\tevt.translationX = touch.pageX - arrays.tail(data.rollingPageX);\r\n\t\t\tevt.translationY = touch.pageY - arrays.tail(data.rollingPageY);\r\n\t\t\tevt.pageX = touch.pageX;\r\n\t\t\tevt.pageY = touch.pageY;\r\n\t\t\tthis.dispatchEvent(evt);\r\n\r\n\t\t\t// only keep a few data points, to average the final speed\r\n\t\t\tif (data.rollingPageX.length > 3) {\r\n\t\t\t\tdata.rollingPageX.shift();\r\n\t\t\t\tdata.rollingPageY.shift();\r\n\t\t\t\tdata.rollingTimestamps.shift();\r\n\t\t\t}\r\n\r\n\t\t\tdata.rollingPageX.push(touch.pageX);\r\n\t\t\tdata.rollingPageY.push(touch.pageY);\r\n\t\t\tdata.rollingTimestamps.push(timestamp);\r\n\t\t}\r\n\r\n\t\tif (this.dispatched) {\r\n\t\t\te.preventDefault();\r\n\t\t\te.stopPropagation();\r\n\t\t\tthis.dispatched = false;\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { CSSIcon } from 'vs/base/common/codicons';\r\n\r\nconst labelWithIconsRegex = /(\\\\)?\\$\\(([a-z\\-]+(?:~[a-z\\-]+)?)\\)/gi;\r\n\r\nexport function renderLabelWithIcons(text: string): Array {\r\n\tconst elements = new Array();\r\n\tlet match: RegExpMatchArray | null;\r\n\r\n\tlet textStart = 0, textStop = 0;\r\n\twhile ((match = labelWithIconsRegex.exec(text)) !== null) {\r\n\t\ttextStop = match.index || 0;\r\n\t\telements.push(text.substring(textStart, textStop));\r\n\t\ttextStart = (match.index || 0) + match[0].length;\r\n\r\n\t\tconst [, escaped, codicon] = match;\r\n\t\telements.push(escaped ? `$(${codicon})` : renderIcon({ id: codicon }));\r\n\t}\r\n\r\n\tif (textStart < text.length) {\r\n\t\telements.push(text.substring(textStart));\r\n\t}\r\n\treturn elements;\r\n}\r\n\r\nexport function renderIcon(icon: CSSIcon): HTMLSpanElement {\r\n\tconst node = dom.$(`span`);\r\n\tnode.classList.add(...CSSIcon.asClassNameArray(icon));\r\n\treturn node;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as objects from 'vs/base/common/objects';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';\r\n\r\nexport interface IHighlight {\r\n\tstart: number;\r\n\tend: number;\r\n\textraClasses?: string;\r\n}\r\n\r\nexport class HighlightedLabel {\r\n\r\n\tprivate readonly domNode: HTMLElement;\r\n\tprivate text: string = '';\r\n\tprivate title: string = '';\r\n\tprivate highlights: IHighlight[] = [];\r\n\tprivate didEverRender: boolean = false;\r\n\r\n\tconstructor(container: HTMLElement, private supportIcons: boolean) {\r\n\t\tthis.domNode = document.createElement('span');\r\n\t\tthis.domNode.className = 'monaco-highlighted-label';\r\n\r\n\t\tcontainer.appendChild(this.domNode);\r\n\t}\r\n\r\n\tget element(): HTMLElement {\r\n\t\treturn this.domNode;\r\n\t}\r\n\r\n\tset(text: string | undefined, highlights: IHighlight[] = [], title: string = '', escapeNewLines?: boolean) {\r\n\t\tif (!text) {\r\n\t\t\ttext = '';\r\n\t\t}\r\n\t\tif (escapeNewLines) {\r\n\t\t\t// adjusts highlights inplace\r\n\t\t\ttext = HighlightedLabel.escapeNewLines(text, highlights);\r\n\t\t}\r\n\t\tif (this.didEverRender && this.text === text && this.title === title && objects.equals(this.highlights, highlights)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.text = text;\r\n\t\tthis.title = title;\r\n\t\tthis.highlights = highlights;\r\n\t\tthis.render();\r\n\t}\r\n\r\n\tprivate render(): void {\r\n\r\n\t\tconst children: HTMLSpanElement[] = [];\r\n\t\tlet pos = 0;\r\n\r\n\t\tfor (const highlight of this.highlights) {\r\n\t\t\tif (highlight.end === highlight.start) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (pos < highlight.start) {\r\n\t\t\t\tconst substring = this.text.substring(pos, highlight.start);\r\n\t\t\t\tchildren.push(dom.$('span', undefined, ...this.supportIcons ? renderLabelWithIcons(substring) : [substring]));\r\n\t\t\t\tpos = highlight.end;\r\n\t\t\t}\r\n\r\n\t\t\tconst substring = this.text.substring(highlight.start, highlight.end);\r\n\t\t\tconst element = dom.$('span.highlight', undefined, ...this.supportIcons ? renderLabelWithIcons(substring) : [substring]);\r\n\t\t\tif (highlight.extraClasses) {\r\n\t\t\t\telement.classList.add(highlight.extraClasses);\r\n\t\t\t}\r\n\t\t\tchildren.push(element);\r\n\t\t\tpos = highlight.end;\r\n\t\t}\r\n\r\n\t\tif (pos < this.text.length) {\r\n\t\t\tconst substring = this.text.substring(pos,);\r\n\t\t\tchildren.push(dom.$('span', undefined, ...this.supportIcons ? renderLabelWithIcons(substring) : [substring]));\r\n\t\t}\r\n\r\n\t\tdom.reset(this.domNode, ...children);\r\n\t\tif (this.title) {\r\n\t\t\tthis.domNode.title = this.title;\r\n\t\t} else {\r\n\t\t\tthis.domNode.removeAttribute('title');\r\n\t\t}\r\n\t\tthis.didEverRender = true;\r\n\t}\r\n\r\n\tstatic escapeNewLines(text: string, highlights: IHighlight[]): string {\r\n\r\n\t\tlet total = 0;\r\n\t\tlet extra = 0;\r\n\r\n\t\treturn text.replace(/\\r\\n|\\r|\\n/g, (match, offset) => {\r\n\t\t\textra = match === '\\r\\n' ? -1 : 0;\r\n\t\t\toffset += total;\r\n\r\n\t\t\tfor (const highlight of highlights) {\r\n\t\t\t\tif (highlight.end <= offset) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\tif (highlight.start >= offset) {\r\n\t\t\t\t\thighlight.start += extra;\r\n\t\t\t\t}\r\n\t\t\t\tif (highlight.end >= offset) {\r\n\t\t\t\t\thighlight.end += extra;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\ttotal += extra;\r\n\t\t\treturn '\\u23CE';\r\n\t\t});\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IListRenderer } from './list';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { $ } from 'vs/base/browser/dom';\r\n\r\nexport interface IRow {\r\n\tdomNode: HTMLElement;\r\n\ttemplateId: string;\r\n\ttemplateData: any;\r\n}\r\n\r\nfunction removeFromParent(element: HTMLElement): void {\r\n\ttry {\r\n\t\tif (element.parentElement) {\r\n\t\t\telement.parentElement.removeChild(element);\r\n\t\t}\r\n\t} catch (e) {\r\n\t\t// this will throw if this happens due to a blur event, nasty business\r\n\t}\r\n}\r\n\r\nexport class RowCache implements IDisposable {\r\n\r\n\tprivate cache = new Map();\r\n\r\n\tconstructor(private renderers: Map>) { }\r\n\r\n\t/**\r\n\t * Returns a row either by creating a new one or reusing\r\n\t * a previously released row which shares the same templateId.\r\n\t */\r\n\talloc(templateId: string): IRow {\r\n\t\tlet result = this.getTemplateCache(templateId).pop();\r\n\r\n\t\tif (!result) {\r\n\t\t\tconst domNode = $('.monaco-list-row');\r\n\t\t\tconst renderer = this.getRenderer(templateId);\r\n\t\t\tconst templateData = renderer.renderTemplate(domNode);\r\n\t\t\tresult = { domNode, templateId, templateData };\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\t/**\r\n\t * Releases the row for eventual reuse.\r\n\t */\r\n\trelease(row: IRow): void {\r\n\t\tif (!row) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.releaseRow(row);\r\n\t}\r\n\r\n\tprivate releaseRow(row: IRow): void {\r\n\t\tconst { domNode, templateId } = row;\r\n\t\tif (domNode) {\r\n\t\t\tdomNode.classList.remove('scrolling');\r\n\t\t\tremoveFromParent(domNode);\r\n\t\t}\r\n\r\n\t\tconst cache = this.getTemplateCache(templateId);\r\n\t\tcache.push(row);\r\n\t}\r\n\r\n\tprivate getTemplateCache(templateId: string): IRow[] {\r\n\t\tlet result = this.cache.get(templateId);\r\n\r\n\t\tif (!result) {\r\n\t\t\tresult = [];\r\n\t\t\tthis.cache.set(templateId, result);\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis.cache.forEach((cachedRows, templateId) => {\r\n\t\t\tfor (const cachedRow of cachedRows) {\r\n\t\t\t\tconst renderer = this.getRenderer(templateId);\r\n\t\t\t\trenderer.disposeTemplate(cachedRow.templateData);\r\n\t\t\t\tcachedRow.templateData = null;\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tthis.cache.clear();\r\n\t}\r\n\r\n\tprivate getRenderer(templateId: string): IListRenderer {\r\n\t\tconst renderer = this.renderers.get(templateId);\r\n\t\tif (!renderer) {\r\n\t\t\tthrow new Error(`No renderer found for ${templateId}`);\r\n\t\t}\r\n\t\treturn renderer;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { IMouseEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { Gesture } from 'vs/base/browser/touch';\r\n\r\nexport abstract class Widget extends Disposable {\r\n\r\n\tprotected onclick(domNode: HTMLElement, listener: (e: IMouseEvent) => void): void {\r\n\t\tthis._register(dom.addDisposableListener(domNode, dom.EventType.CLICK, (e: MouseEvent) => listener(new StandardMouseEvent(e))));\r\n\t}\r\n\r\n\tprotected onmousedown(domNode: HTMLElement, listener: (e: IMouseEvent) => void): void {\r\n\t\tthis._register(dom.addDisposableListener(domNode, dom.EventType.MOUSE_DOWN, (e: MouseEvent) => listener(new StandardMouseEvent(e))));\r\n\t}\r\n\r\n\tprotected onmouseover(domNode: HTMLElement, listener: (e: IMouseEvent) => void): void {\r\n\t\tthis._register(dom.addDisposableListener(domNode, dom.EventType.MOUSE_OVER, (e: MouseEvent) => listener(new StandardMouseEvent(e))));\r\n\t}\r\n\r\n\tprotected onnonbubblingmouseout(domNode: HTMLElement, listener: (e: IMouseEvent) => void): void {\r\n\t\tthis._register(dom.addDisposableNonBubblingMouseOutListener(domNode, (e: MouseEvent) => listener(new StandardMouseEvent(e))));\r\n\t}\r\n\r\n\tprotected onkeydown(domNode: HTMLElement, listener: (e: IKeyboardEvent) => void): void {\r\n\t\tthis._register(dom.addDisposableListener(domNode, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => listener(new StandardKeyboardEvent(e))));\r\n\t}\r\n\r\n\tprotected onkeyup(domNode: HTMLElement, listener: (e: IKeyboardEvent) => void): void {\r\n\t\tthis._register(dom.addDisposableListener(domNode, dom.EventType.KEY_UP, (e: KeyboardEvent) => listener(new StandardKeyboardEvent(e))));\r\n\t}\r\n\r\n\tprotected oninput(domNode: HTMLElement, listener: (e: Event) => void): void {\r\n\t\tthis._register(dom.addDisposableListener(domNode, dom.EventType.INPUT, listener));\r\n\t}\r\n\r\n\tprotected onblur(domNode: HTMLElement, listener: (e: Event) => void): void {\r\n\t\tthis._register(dom.addDisposableListener(domNode, dom.EventType.BLUR, listener));\r\n\t}\r\n\r\n\tprotected onfocus(domNode: HTMLElement, listener: (e: Event) => void): void {\r\n\t\tthis._register(dom.addDisposableListener(domNode, dom.EventType.FOCUS, listener));\r\n\t}\r\n\r\n\tprotected ignoreGesture(domNode: HTMLElement): void {\r\n\t\tGesture.ignoreTarget(domNode);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { GlobalMouseMoveMonitor, IStandardMouseMoveEventData, standardMouseMoveMerger } from 'vs/base/browser/globalMouseMoveMonitor';\r\nimport { IMouseEvent } from 'vs/base/browser/mouseEvent';\r\nimport { Widget } from 'vs/base/browser/ui/widget';\r\nimport { IntervalTimer, TimeoutTimer } from 'vs/base/common/async';\r\nimport { Codicon } from 'vs/base/common/codicons';\r\n\r\n/**\r\n * The arrow image size.\r\n */\r\nexport const ARROW_IMG_SIZE = 11;\r\n\r\nexport interface ScrollbarArrowOptions {\r\n\tonActivate: () => void;\r\n\tclassName: string;\r\n\ticon: Codicon;\r\n\r\n\tbgWidth: number;\r\n\tbgHeight: number;\r\n\r\n\ttop?: number;\r\n\tleft?: number;\r\n\tbottom?: number;\r\n\tright?: number;\r\n}\r\n\r\nexport class ScrollbarArrow extends Widget {\r\n\r\n\tprivate _onActivate: () => void;\r\n\tpublic bgDomNode: HTMLElement;\r\n\tpublic domNode: HTMLElement;\r\n\tprivate _mousedownRepeatTimer: IntervalTimer;\r\n\tprivate _mousedownScheduleRepeatTimer: TimeoutTimer;\r\n\tprivate _mouseMoveMonitor: GlobalMouseMoveMonitor;\r\n\r\n\tconstructor(opts: ScrollbarArrowOptions) {\r\n\t\tsuper();\r\n\t\tthis._onActivate = opts.onActivate;\r\n\r\n\t\tthis.bgDomNode = document.createElement('div');\r\n\t\tthis.bgDomNode.className = 'arrow-background';\r\n\t\tthis.bgDomNode.style.position = 'absolute';\r\n\t\tthis.bgDomNode.style.width = opts.bgWidth + 'px';\r\n\t\tthis.bgDomNode.style.height = opts.bgHeight + 'px';\r\n\t\tif (typeof opts.top !== 'undefined') {\r\n\t\t\tthis.bgDomNode.style.top = '0px';\r\n\t\t}\r\n\t\tif (typeof opts.left !== 'undefined') {\r\n\t\t\tthis.bgDomNode.style.left = '0px';\r\n\t\t}\r\n\t\tif (typeof opts.bottom !== 'undefined') {\r\n\t\t\tthis.bgDomNode.style.bottom = '0px';\r\n\t\t}\r\n\t\tif (typeof opts.right !== 'undefined') {\r\n\t\t\tthis.bgDomNode.style.right = '0px';\r\n\t\t}\r\n\r\n\t\tthis.domNode = document.createElement('div');\r\n\t\tthis.domNode.className = opts.className;\r\n\t\tthis.domNode.classList.add(...opts.icon.classNamesArray);\r\n\r\n\t\tthis.domNode.style.position = 'absolute';\r\n\t\tthis.domNode.style.width = ARROW_IMG_SIZE + 'px';\r\n\t\tthis.domNode.style.height = ARROW_IMG_SIZE + 'px';\r\n\t\tif (typeof opts.top !== 'undefined') {\r\n\t\t\tthis.domNode.style.top = opts.top + 'px';\r\n\t\t}\r\n\t\tif (typeof opts.left !== 'undefined') {\r\n\t\t\tthis.domNode.style.left = opts.left + 'px';\r\n\t\t}\r\n\t\tif (typeof opts.bottom !== 'undefined') {\r\n\t\t\tthis.domNode.style.bottom = opts.bottom + 'px';\r\n\t\t}\r\n\t\tif (typeof opts.right !== 'undefined') {\r\n\t\t\tthis.domNode.style.right = opts.right + 'px';\r\n\t\t}\r\n\r\n\t\tthis._mouseMoveMonitor = this._register(new GlobalMouseMoveMonitor());\r\n\t\tthis.onmousedown(this.bgDomNode, (e) => this._arrowMouseDown(e));\r\n\t\tthis.onmousedown(this.domNode, (e) => this._arrowMouseDown(e));\r\n\r\n\t\tthis._mousedownRepeatTimer = this._register(new IntervalTimer());\r\n\t\tthis._mousedownScheduleRepeatTimer = this._register(new TimeoutTimer());\r\n\t}\r\n\r\n\tprivate _arrowMouseDown(e: IMouseEvent): void {\r\n\t\tconst scheduleRepeater = () => {\r\n\t\t\tthis._mousedownRepeatTimer.cancelAndSet(() => this._onActivate(), 1000 / 24);\r\n\t\t};\r\n\r\n\t\tthis._onActivate();\r\n\t\tthis._mousedownRepeatTimer.cancel();\r\n\t\tthis._mousedownScheduleRepeatTimer.cancelAndSet(scheduleRepeater, 200);\r\n\r\n\t\tthis._mouseMoveMonitor.startMonitoring(\r\n\t\t\te.target,\r\n\t\t\te.buttons,\r\n\t\t\tstandardMouseMoveMerger,\r\n\t\t\t(mouseMoveData: IStandardMouseMoveEventData) => {\r\n\t\t\t\t/* Intentional empty */\r\n\t\t\t},\r\n\t\t\t() => {\r\n\t\t\t\tthis._mousedownRepeatTimer.cancel();\r\n\t\t\t\tthis._mousedownScheduleRepeatTimer.cancel();\r\n\t\t\t}\r\n\t\t);\r\n\r\n\t\te.preventDefault();\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { GlobalMouseMoveMonitor, IStandardMouseMoveEventData, standardMouseMoveMerger } from 'vs/base/browser/globalMouseMoveMonitor';\r\nimport { IMouseEvent, StandardWheelEvent } from 'vs/base/browser/mouseEvent';\r\nimport { ScrollbarArrow, ScrollbarArrowOptions } from 'vs/base/browser/ui/scrollbar/scrollbarArrow';\r\nimport { ScrollbarState } from 'vs/base/browser/ui/scrollbar/scrollbarState';\r\nimport { ScrollbarVisibilityController } from 'vs/base/browser/ui/scrollbar/scrollbarVisibilityController';\r\nimport { Widget } from 'vs/base/browser/ui/widget';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport { INewScrollPosition, Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable';\r\n\r\n/**\r\n * The orthogonal distance to the slider at which dragging \"resets\". This implements \"snapping\"\r\n */\r\nconst MOUSE_DRAG_RESET_DISTANCE = 140;\r\n\r\nexport interface ISimplifiedMouseEvent {\r\n\tposx: number;\r\n\tposy: number;\r\n}\r\n\r\nexport interface ScrollbarHost {\r\n\tonMouseWheel(mouseWheelEvent: StandardWheelEvent): void;\r\n\tonDragStart(): void;\r\n\tonDragEnd(): void;\r\n}\r\n\r\nexport interface AbstractScrollbarOptions {\r\n\tlazyRender: boolean;\r\n\thost: ScrollbarHost;\r\n\tscrollbarState: ScrollbarState;\r\n\tvisibility: ScrollbarVisibility;\r\n\textraScrollbarClassName: string;\r\n\tscrollable: Scrollable;\r\n\tscrollByPage: boolean;\r\n}\r\n\r\nexport abstract class AbstractScrollbar extends Widget {\r\n\r\n\tprotected _host: ScrollbarHost;\r\n\tprotected _scrollable: Scrollable;\r\n\tprotected _scrollByPage: boolean;\r\n\tprivate _lazyRender: boolean;\r\n\tprotected _scrollbarState: ScrollbarState;\r\n\tprivate _visibilityController: ScrollbarVisibilityController;\r\n\tprivate _mouseMoveMonitor: GlobalMouseMoveMonitor;\r\n\r\n\tpublic domNode: FastDomNode;\r\n\tpublic slider!: FastDomNode;\r\n\r\n\tprotected _shouldRender: boolean;\r\n\r\n\tconstructor(opts: AbstractScrollbarOptions) {\r\n\t\tsuper();\r\n\t\tthis._lazyRender = opts.lazyRender;\r\n\t\tthis._host = opts.host;\r\n\t\tthis._scrollable = opts.scrollable;\r\n\t\tthis._scrollByPage = opts.scrollByPage;\r\n\t\tthis._scrollbarState = opts.scrollbarState;\r\n\t\tthis._visibilityController = this._register(new ScrollbarVisibilityController(opts.visibility, 'visible scrollbar ' + opts.extraScrollbarClassName, 'invisible scrollbar ' + opts.extraScrollbarClassName));\r\n\t\tthis._visibilityController.setIsNeeded(this._scrollbarState.isNeeded());\r\n\t\tthis._mouseMoveMonitor = this._register(new GlobalMouseMoveMonitor());\r\n\t\tthis._shouldRender = true;\r\n\t\tthis.domNode = createFastDomNode(document.createElement('div'));\r\n\t\tthis.domNode.setAttribute('role', 'presentation');\r\n\t\tthis.domNode.setAttribute('aria-hidden', 'true');\r\n\r\n\t\tthis._visibilityController.setDomNode(this.domNode);\r\n\t\tthis.domNode.setPosition('absolute');\r\n\r\n\t\tthis.onmousedown(this.domNode.domNode, (e) => this._domNodeMouseDown(e));\r\n\t}\r\n\r\n\t// ----------------- creation\r\n\r\n\t/**\r\n\t * Creates the dom node for an arrow & adds it to the container\r\n\t */\r\n\tprotected _createArrow(opts: ScrollbarArrowOptions): void {\r\n\t\tconst arrow = this._register(new ScrollbarArrow(opts));\r\n\t\tthis.domNode.domNode.appendChild(arrow.bgDomNode);\r\n\t\tthis.domNode.domNode.appendChild(arrow.domNode);\r\n\t}\r\n\r\n\t/**\r\n\t * Creates the slider dom node, adds it to the container & hooks up the events\r\n\t */\r\n\tprotected _createSlider(top: number, left: number, width: number | undefined, height: number | undefined): void {\r\n\t\tthis.slider = createFastDomNode(document.createElement('div'));\r\n\t\tthis.slider.setClassName('slider');\r\n\t\tthis.slider.setPosition('absolute');\r\n\t\tthis.slider.setTop(top);\r\n\t\tthis.slider.setLeft(left);\r\n\t\tif (typeof width === 'number') {\r\n\t\t\tthis.slider.setWidth(width);\r\n\t\t}\r\n\t\tif (typeof height === 'number') {\r\n\t\t\tthis.slider.setHeight(height);\r\n\t\t}\r\n\t\tthis.slider.setLayerHinting(true);\r\n\t\tthis.slider.setContain('strict');\r\n\r\n\t\tthis.domNode.domNode.appendChild(this.slider.domNode);\r\n\r\n\t\tthis.onmousedown(this.slider.domNode, (e) => {\r\n\t\t\tif (e.leftButton) {\r\n\t\t\t\te.preventDefault();\r\n\t\t\t\tthis._sliderMouseDown(e, () => { /*nothing to do*/ });\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tthis.onclick(this.slider.domNode, e => {\r\n\t\t\tif (e.leftButton) {\r\n\t\t\t\te.stopPropagation();\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\t// ----------------- Update state\r\n\r\n\tprotected _onElementSize(visibleSize: number): boolean {\r\n\t\tif (this._scrollbarState.setVisibleSize(visibleSize)) {\r\n\t\t\tthis._visibilityController.setIsNeeded(this._scrollbarState.isNeeded());\r\n\t\t\tthis._shouldRender = true;\r\n\t\t\tif (!this._lazyRender) {\r\n\t\t\t\tthis.render();\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this._shouldRender;\r\n\t}\r\n\r\n\tprotected _onElementScrollSize(elementScrollSize: number): boolean {\r\n\t\tif (this._scrollbarState.setScrollSize(elementScrollSize)) {\r\n\t\t\tthis._visibilityController.setIsNeeded(this._scrollbarState.isNeeded());\r\n\t\t\tthis._shouldRender = true;\r\n\t\t\tif (!this._lazyRender) {\r\n\t\t\t\tthis.render();\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this._shouldRender;\r\n\t}\r\n\r\n\tprotected _onElementScrollPosition(elementScrollPosition: number): boolean {\r\n\t\tif (this._scrollbarState.setScrollPosition(elementScrollPosition)) {\r\n\t\t\tthis._visibilityController.setIsNeeded(this._scrollbarState.isNeeded());\r\n\t\t\tthis._shouldRender = true;\r\n\t\t\tif (!this._lazyRender) {\r\n\t\t\t\tthis.render();\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this._shouldRender;\r\n\t}\r\n\r\n\t// ----------------- rendering\r\n\r\n\tpublic beginReveal(): void {\r\n\t\tthis._visibilityController.setShouldBeVisible(true);\r\n\t}\r\n\r\n\tpublic beginHide(): void {\r\n\t\tthis._visibilityController.setShouldBeVisible(false);\r\n\t}\r\n\r\n\tpublic render(): void {\r\n\t\tif (!this._shouldRender) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._shouldRender = false;\r\n\r\n\t\tthis._renderDomNode(this._scrollbarState.getRectangleLargeSize(), this._scrollbarState.getRectangleSmallSize());\r\n\t\tthis._updateSlider(this._scrollbarState.getSliderSize(), this._scrollbarState.getArrowSize() + this._scrollbarState.getSliderPosition());\r\n\t}\r\n\t// ----------------- DOM events\r\n\r\n\tprivate _domNodeMouseDown(e: IMouseEvent): void {\r\n\t\tif (e.target !== this.domNode.domNode) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._onMouseDown(e);\r\n\t}\r\n\r\n\tpublic delegateMouseDown(e: IMouseEvent): void {\r\n\t\tconst domTop = this.domNode.domNode.getClientRects()[0].top;\r\n\t\tconst sliderStart = domTop + this._scrollbarState.getSliderPosition();\r\n\t\tconst sliderStop = domTop + this._scrollbarState.getSliderPosition() + this._scrollbarState.getSliderSize();\r\n\t\tconst mousePos = this._sliderMousePosition(e);\r\n\t\tif (sliderStart <= mousePos && mousePos <= sliderStop) {\r\n\t\t\t// Act as if it was a mouse down on the slider\r\n\t\t\tif (e.leftButton) {\r\n\t\t\t\te.preventDefault();\r\n\t\t\t\tthis._sliderMouseDown(e, () => { /*nothing to do*/ });\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\t// Act as if it was a mouse down on the scrollbar\r\n\t\t\tthis._onMouseDown(e);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _onMouseDown(e: IMouseEvent): void {\r\n\t\tlet offsetX: number;\r\n\t\tlet offsetY: number;\r\n\t\tif (e.target === this.domNode.domNode && typeof e.browserEvent.offsetX === 'number' && typeof e.browserEvent.offsetY === 'number') {\r\n\t\t\toffsetX = e.browserEvent.offsetX;\r\n\t\t\toffsetY = e.browserEvent.offsetY;\r\n\t\t} else {\r\n\t\t\tconst domNodePosition = dom.getDomNodePagePosition(this.domNode.domNode);\r\n\t\t\toffsetX = e.posx - domNodePosition.left;\r\n\t\t\toffsetY = e.posy - domNodePosition.top;\r\n\t\t}\r\n\r\n\t\tconst offset = this._mouseDownRelativePosition(offsetX, offsetY);\r\n\t\tthis._setDesiredScrollPositionNow(\r\n\t\t\tthis._scrollByPage\r\n\t\t\t\t? this._scrollbarState.getDesiredScrollPositionFromOffsetPaged(offset)\r\n\t\t\t\t: this._scrollbarState.getDesiredScrollPositionFromOffset(offset)\r\n\t\t);\r\n\r\n\t\tif (e.leftButton) {\r\n\t\t\te.preventDefault();\r\n\t\t\tthis._sliderMouseDown(e, () => { /*nothing to do*/ });\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _sliderMouseDown(e: IMouseEvent, onDragFinished: () => void): void {\r\n\t\tconst initialMousePosition = this._sliderMousePosition(e);\r\n\t\tconst initialMouseOrthogonalPosition = this._sliderOrthogonalMousePosition(e);\r\n\t\tconst initialScrollbarState = this._scrollbarState.clone();\r\n\t\tthis.slider.toggleClassName('active', true);\r\n\r\n\t\tthis._mouseMoveMonitor.startMonitoring(\r\n\t\t\te.target,\r\n\t\t\te.buttons,\r\n\t\t\tstandardMouseMoveMerger,\r\n\t\t\t(mouseMoveData: IStandardMouseMoveEventData) => {\r\n\t\t\t\tconst mouseOrthogonalPosition = this._sliderOrthogonalMousePosition(mouseMoveData);\r\n\t\t\t\tconst mouseOrthogonalDelta = Math.abs(mouseOrthogonalPosition - initialMouseOrthogonalPosition);\r\n\r\n\t\t\t\tif (platform.isWindows && mouseOrthogonalDelta > MOUSE_DRAG_RESET_DISTANCE) {\r\n\t\t\t\t\t// The mouse has wondered away from the scrollbar => reset dragging\r\n\t\t\t\t\tthis._setDesiredScrollPositionNow(initialScrollbarState.getScrollPosition());\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst mousePosition = this._sliderMousePosition(mouseMoveData);\r\n\t\t\t\tconst mouseDelta = mousePosition - initialMousePosition;\r\n\t\t\t\tthis._setDesiredScrollPositionNow(initialScrollbarState.getDesiredScrollPositionFromDelta(mouseDelta));\r\n\t\t\t},\r\n\t\t\t() => {\r\n\t\t\t\tthis.slider.toggleClassName('active', false);\r\n\t\t\t\tthis._host.onDragEnd();\r\n\t\t\t\tonDragFinished();\r\n\t\t\t}\r\n\t\t);\r\n\r\n\t\tthis._host.onDragStart();\r\n\t}\r\n\r\n\tprivate _setDesiredScrollPositionNow(_desiredScrollPosition: number): void {\r\n\r\n\t\tconst desiredScrollPosition: INewScrollPosition = {};\r\n\t\tthis.writeScrollPosition(desiredScrollPosition, _desiredScrollPosition);\r\n\r\n\t\tthis._scrollable.setScrollPositionNow(desiredScrollPosition);\r\n\t}\r\n\r\n\tpublic updateScrollbarSize(scrollbarSize: number): void {\r\n\t\tthis._updateScrollbarSize(scrollbarSize);\r\n\t\tthis._scrollbarState.setScrollbarSize(scrollbarSize);\r\n\t\tthis._shouldRender = true;\r\n\t\tif (!this._lazyRender) {\r\n\t\t\tthis.render();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic isNeeded(): boolean {\r\n\t\treturn this._scrollbarState.isNeeded();\r\n\t}\r\n\r\n\t// ----------------- Overwrite these\r\n\r\n\tprotected abstract _renderDomNode(largeSize: number, smallSize: number): void;\r\n\tprotected abstract _updateSlider(sliderSize: number, sliderPosition: number): void;\r\n\r\n\tprotected abstract _mouseDownRelativePosition(offsetX: number, offsetY: number): number;\r\n\tprotected abstract _sliderMousePosition(e: ISimplifiedMouseEvent): number;\r\n\tprotected abstract _sliderOrthogonalMousePosition(e: ISimplifiedMouseEvent): number;\r\n\tprotected abstract _updateScrollbarSize(size: number): void;\r\n\r\n\tpublic abstract writeScrollPosition(target: INewScrollPosition, scrollPosition: number): void;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { StandardWheelEvent } from 'vs/base/browser/mouseEvent';\r\nimport { AbstractScrollbar, ISimplifiedMouseEvent, ScrollbarHost } from 'vs/base/browser/ui/scrollbar/abstractScrollbar';\r\nimport { ScrollableElementResolvedOptions } from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';\r\nimport { ARROW_IMG_SIZE } from 'vs/base/browser/ui/scrollbar/scrollbarArrow';\r\nimport { ScrollbarState } from 'vs/base/browser/ui/scrollbar/scrollbarState';\r\nimport { INewScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable';\r\nimport { Codicon, registerCodicon } from 'vs/base/common/codicons';\r\n\r\n\r\nconst scrollbarButtonLeftIcon = registerCodicon('scrollbar-button-left', Codicon.triangleLeft);\r\nconst scrollbarButtonRightIcon = registerCodicon('scrollbar-button-right', Codicon.triangleRight);\r\n\r\nexport class HorizontalScrollbar extends AbstractScrollbar {\r\n\r\n\tconstructor(scrollable: Scrollable, options: ScrollableElementResolvedOptions, host: ScrollbarHost) {\r\n\t\tconst scrollDimensions = scrollable.getScrollDimensions();\r\n\t\tconst scrollPosition = scrollable.getCurrentScrollPosition();\r\n\t\tsuper({\r\n\t\t\tlazyRender: options.lazyRender,\r\n\t\t\thost: host,\r\n\t\t\tscrollbarState: new ScrollbarState(\r\n\t\t\t\t(options.horizontalHasArrows ? options.arrowSize : 0),\r\n\t\t\t\t(options.horizontal === ScrollbarVisibility.Hidden ? 0 : options.horizontalScrollbarSize),\r\n\t\t\t\t(options.vertical === ScrollbarVisibility.Hidden ? 0 : options.verticalScrollbarSize),\r\n\t\t\t\tscrollDimensions.width,\r\n\t\t\t\tscrollDimensions.scrollWidth,\r\n\t\t\t\tscrollPosition.scrollLeft\r\n\t\t\t),\r\n\t\t\tvisibility: options.horizontal,\r\n\t\t\textraScrollbarClassName: 'horizontal',\r\n\t\t\tscrollable: scrollable,\r\n\t\t\tscrollByPage: options.scrollByPage\r\n\t\t});\r\n\r\n\t\tif (options.horizontalHasArrows) {\r\n\t\t\tconst arrowDelta = (options.arrowSize - ARROW_IMG_SIZE) / 2;\r\n\t\t\tconst scrollbarDelta = (options.horizontalScrollbarSize - ARROW_IMG_SIZE) / 2;\r\n\r\n\t\t\tthis._createArrow({\r\n\t\t\t\tclassName: 'scra',\r\n\t\t\t\ticon: scrollbarButtonLeftIcon,\r\n\t\t\t\ttop: scrollbarDelta,\r\n\t\t\t\tleft: arrowDelta,\r\n\t\t\t\tbottom: undefined,\r\n\t\t\t\tright: undefined,\r\n\t\t\t\tbgWidth: options.arrowSize,\r\n\t\t\t\tbgHeight: options.horizontalScrollbarSize,\r\n\t\t\t\tonActivate: () => this._host.onMouseWheel(new StandardWheelEvent(null, 1, 0)),\r\n\t\t\t});\r\n\r\n\t\t\tthis._createArrow({\r\n\t\t\t\tclassName: 'scra',\r\n\t\t\t\ticon: scrollbarButtonRightIcon,\r\n\t\t\t\ttop: scrollbarDelta,\r\n\t\t\t\tleft: undefined,\r\n\t\t\t\tbottom: undefined,\r\n\t\t\t\tright: arrowDelta,\r\n\t\t\t\tbgWidth: options.arrowSize,\r\n\t\t\t\tbgHeight: options.horizontalScrollbarSize,\r\n\t\t\t\tonActivate: () => this._host.onMouseWheel(new StandardWheelEvent(null, -1, 0)),\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tthis._createSlider(Math.floor((options.horizontalScrollbarSize - options.horizontalSliderSize) / 2), 0, undefined, options.horizontalSliderSize);\r\n\t}\r\n\r\n\tprotected _updateSlider(sliderSize: number, sliderPosition: number): void {\r\n\t\tthis.slider.setWidth(sliderSize);\r\n\t\tthis.slider.setLeft(sliderPosition);\r\n\t}\r\n\r\n\tprotected _renderDomNode(largeSize: number, smallSize: number): void {\r\n\t\tthis.domNode.setWidth(largeSize);\r\n\t\tthis.domNode.setHeight(smallSize);\r\n\t\tthis.domNode.setLeft(0);\r\n\t\tthis.domNode.setBottom(0);\r\n\t}\r\n\r\n\tpublic onDidScroll(e: ScrollEvent): boolean {\r\n\t\tthis._shouldRender = this._onElementScrollSize(e.scrollWidth) || this._shouldRender;\r\n\t\tthis._shouldRender = this._onElementScrollPosition(e.scrollLeft) || this._shouldRender;\r\n\t\tthis._shouldRender = this._onElementSize(e.width) || this._shouldRender;\r\n\t\treturn this._shouldRender;\r\n\t}\r\n\r\n\tprotected _mouseDownRelativePosition(offsetX: number, offsetY: number): number {\r\n\t\treturn offsetX;\r\n\t}\r\n\r\n\tprotected _sliderMousePosition(e: ISimplifiedMouseEvent): number {\r\n\t\treturn e.posx;\r\n\t}\r\n\r\n\tprotected _sliderOrthogonalMousePosition(e: ISimplifiedMouseEvent): number {\r\n\t\treturn e.posy;\r\n\t}\r\n\r\n\tprotected _updateScrollbarSize(size: number): void {\r\n\t\tthis.slider.setHeight(size);\r\n\t}\r\n\r\n\tpublic writeScrollPosition(target: INewScrollPosition, scrollPosition: number): void {\r\n\t\ttarget.scrollLeft = scrollPosition;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { StandardWheelEvent } from 'vs/base/browser/mouseEvent';\r\nimport { AbstractScrollbar, ISimplifiedMouseEvent, ScrollbarHost } from 'vs/base/browser/ui/scrollbar/abstractScrollbar';\r\nimport { ScrollableElementResolvedOptions } from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';\r\nimport { ARROW_IMG_SIZE } from 'vs/base/browser/ui/scrollbar/scrollbarArrow';\r\nimport { ScrollbarState } from 'vs/base/browser/ui/scrollbar/scrollbarState';\r\nimport { INewScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable';\r\nimport { Codicon, registerCodicon } from 'vs/base/common/codicons';\r\n\r\nconst scrollbarButtonUpIcon = registerCodicon('scrollbar-button-up', Codicon.triangleUp);\r\nconst scrollbarButtonDownIcon = registerCodicon('scrollbar-button-down', Codicon.triangleDown);\r\n\r\nexport class VerticalScrollbar extends AbstractScrollbar {\r\n\r\n\tconstructor(scrollable: Scrollable, options: ScrollableElementResolvedOptions, host: ScrollbarHost) {\r\n\t\tconst scrollDimensions = scrollable.getScrollDimensions();\r\n\t\tconst scrollPosition = scrollable.getCurrentScrollPosition();\r\n\t\tsuper({\r\n\t\t\tlazyRender: options.lazyRender,\r\n\t\t\thost: host,\r\n\t\t\tscrollbarState: new ScrollbarState(\r\n\t\t\t\t(options.verticalHasArrows ? options.arrowSize : 0),\r\n\t\t\t\t(options.vertical === ScrollbarVisibility.Hidden ? 0 : options.verticalScrollbarSize),\r\n\t\t\t\t// give priority to vertical scroll bar over horizontal and let it scroll all the way to the bottom\r\n\t\t\t\t0,\r\n\t\t\t\tscrollDimensions.height,\r\n\t\t\t\tscrollDimensions.scrollHeight,\r\n\t\t\t\tscrollPosition.scrollTop\r\n\t\t\t),\r\n\t\t\tvisibility: options.vertical,\r\n\t\t\textraScrollbarClassName: 'vertical',\r\n\t\t\tscrollable: scrollable,\r\n\t\t\tscrollByPage: options.scrollByPage\r\n\t\t});\r\n\r\n\t\tif (options.verticalHasArrows) {\r\n\t\t\tconst arrowDelta = (options.arrowSize - ARROW_IMG_SIZE) / 2;\r\n\t\t\tconst scrollbarDelta = (options.verticalScrollbarSize - ARROW_IMG_SIZE) / 2;\r\n\r\n\t\t\tthis._createArrow({\r\n\t\t\t\tclassName: 'scra',\r\n\t\t\t\ticon: scrollbarButtonUpIcon,\r\n\t\t\t\ttop: arrowDelta,\r\n\t\t\t\tleft: scrollbarDelta,\r\n\t\t\t\tbottom: undefined,\r\n\t\t\t\tright: undefined,\r\n\t\t\t\tbgWidth: options.verticalScrollbarSize,\r\n\t\t\t\tbgHeight: options.arrowSize,\r\n\t\t\t\tonActivate: () => this._host.onMouseWheel(new StandardWheelEvent(null, 0, 1)),\r\n\t\t\t});\r\n\r\n\t\t\tthis._createArrow({\r\n\t\t\t\tclassName: 'scra',\r\n\t\t\t\ticon: scrollbarButtonDownIcon,\r\n\t\t\t\ttop: undefined,\r\n\t\t\t\tleft: scrollbarDelta,\r\n\t\t\t\tbottom: arrowDelta,\r\n\t\t\t\tright: undefined,\r\n\t\t\t\tbgWidth: options.verticalScrollbarSize,\r\n\t\t\t\tbgHeight: options.arrowSize,\r\n\t\t\t\tonActivate: () => this._host.onMouseWheel(new StandardWheelEvent(null, 0, -1)),\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tthis._createSlider(0, Math.floor((options.verticalScrollbarSize - options.verticalSliderSize) / 2), options.verticalSliderSize, undefined);\r\n\t}\r\n\r\n\tprotected _updateSlider(sliderSize: number, sliderPosition: number): void {\r\n\t\tthis.slider.setHeight(sliderSize);\r\n\t\tthis.slider.setTop(sliderPosition);\r\n\t}\r\n\r\n\tprotected _renderDomNode(largeSize: number, smallSize: number): void {\r\n\t\tthis.domNode.setWidth(smallSize);\r\n\t\tthis.domNode.setHeight(largeSize);\r\n\t\tthis.domNode.setRight(0);\r\n\t\tthis.domNode.setTop(0);\r\n\t}\r\n\r\n\tpublic onDidScroll(e: ScrollEvent): boolean {\r\n\t\tthis._shouldRender = this._onElementScrollSize(e.scrollHeight) || this._shouldRender;\r\n\t\tthis._shouldRender = this._onElementScrollPosition(e.scrollTop) || this._shouldRender;\r\n\t\tthis._shouldRender = this._onElementSize(e.height) || this._shouldRender;\r\n\t\treturn this._shouldRender;\r\n\t}\r\n\r\n\tprotected _mouseDownRelativePosition(offsetX: number, offsetY: number): number {\r\n\t\treturn offsetY;\r\n\t}\r\n\r\n\tprotected _sliderMousePosition(e: ISimplifiedMouseEvent): number {\r\n\t\treturn e.posy;\r\n\t}\r\n\r\n\tprotected _sliderOrthogonalMousePosition(e: ISimplifiedMouseEvent): number {\r\n\t\treturn e.posx;\r\n\t}\r\n\r\n\tprotected _updateScrollbarSize(size: number): void {\r\n\t\tthis.slider.setWidth(size);\r\n\t}\r\n\r\n\tpublic writeScrollPosition(target: INewScrollPosition, scrollPosition: number): void {\r\n\t\ttarget.scrollTop = scrollPosition;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as extpath from 'vs/base/common/extpath';\r\nimport * as paths from 'vs/base/common/path';\r\nimport { URI, uriToFsPath } from 'vs/base/common/uri';\r\nimport { compare as strCompare } from 'vs/base/common/strings';\r\nimport { Schemas } from 'vs/base/common/network';\r\nimport { CharCode } from 'vs/base/common/charCode';\r\n\r\nexport function originalFSPath(uri: URI): string {\r\n\treturn uriToFsPath(uri, true);\r\n}\r\n\r\n//#region IExtUri\r\n\r\nexport interface IExtUri {\r\n}\r\n\r\nexport class ExtUri implements IExtUri {\r\n\r\n\tconstructor(private _ignorePathCasing: (uri: URI) => boolean) { }\r\n\r\n\tcompare(uri1: URI, uri2: URI, ignoreFragment: boolean = false): number {\r\n\t\tif (uri1 === uri2) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t\treturn strCompare(this.getComparisonKey(uri1, ignoreFragment), this.getComparisonKey(uri2, ignoreFragment));\r\n\t}\r\n\r\n\tisEqual(uri1: URI | undefined, uri2: URI | undefined, ignoreFragment: boolean = false): boolean {\r\n\t\tif (uri1 === uri2) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (!uri1 || !uri2) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn this.getComparisonKey(uri1, ignoreFragment) === this.getComparisonKey(uri2, ignoreFragment);\r\n\t}\r\n\r\n\tgetComparisonKey(uri: URI, ignoreFragment: boolean = false): string {\r\n\t\treturn uri.with({\r\n\t\t\tpath: this._ignorePathCasing(uri) ? uri.path.toLowerCase() : undefined,\r\n\t\t\tfragment: ignoreFragment ? null : undefined\r\n\t\t}).toString();\r\n\t}\r\n\r\n\t// --- path math\r\n\r\n\tjoinPath(resource: URI, ...pathFragment: string[]): URI {\r\n\t\treturn URI.joinPath(resource, ...pathFragment);\r\n\t}\r\n\r\n\tbasenameOrAuthority(resource: URI): string {\r\n\t\treturn basename(resource) || resource.authority;\r\n\t}\r\n\r\n\tbasename(resource: URI): string {\r\n\t\treturn paths.posix.basename(resource.path);\r\n\t}\r\n\r\n\tdirname(resource: URI): URI {\r\n\t\tif (resource.path.length === 0) {\r\n\t\t\treturn resource;\r\n\t\t}\r\n\t\tlet dirname;\r\n\t\tif (resource.scheme === Schemas.file) {\r\n\t\t\tdirname = URI.file(paths.dirname(originalFSPath(resource))).path;\r\n\t\t} else {\r\n\t\t\tdirname = paths.posix.dirname(resource.path);\r\n\t\t\tif (resource.authority && dirname.length && dirname.charCodeAt(0) !== CharCode.Slash) {\r\n\t\t\t\tconsole.error(`dirname(\"${resource.toString})) resulted in a relative path`);\r\n\t\t\t\tdirname = '/'; // If a URI contains an authority component, then the path component must either be empty or begin with a CharCode.Slash (\"/\") character\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn resource.with({\r\n\t\t\tpath: dirname\r\n\t\t});\r\n\t}\r\n\r\n\tnormalizePath(resource: URI): URI {\r\n\t\tif (!resource.path.length) {\r\n\t\t\treturn resource;\r\n\t\t}\r\n\t\tlet normalizedPath: string;\r\n\t\tif (resource.scheme === Schemas.file) {\r\n\t\t\tnormalizedPath = URI.file(paths.normalize(originalFSPath(resource))).path;\r\n\t\t} else {\r\n\t\t\tnormalizedPath = paths.posix.normalize(resource.path);\r\n\t\t}\r\n\t\treturn resource.with({\r\n\t\t\tpath: normalizedPath\r\n\t\t});\r\n\t}\r\n\r\n\tresolvePath(base: URI, path: string): URI {\r\n\t\tif (base.scheme === Schemas.file) {\r\n\t\t\tconst newURI = URI.file(paths.resolve(originalFSPath(base), path));\r\n\t\t\treturn base.with({\r\n\t\t\t\tauthority: newURI.authority,\r\n\t\t\t\tpath: newURI.path\r\n\t\t\t});\r\n\t\t}\r\n\t\tif (path.indexOf('/') === -1) { // no slashes? it's likely a Windows path\r\n\t\t\tpath = extpath.toSlashes(path);\r\n\t\t\tif (/^[a-zA-Z]:(\\/|$)/.test(path)) { // starts with a drive letter\r\n\t\t\t\tpath = '/' + path;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn base.with({\r\n\t\t\tpath: paths.posix.resolve(base.path, path)\r\n\t\t});\r\n\t}\r\n}\r\n\r\n\r\n/**\r\n * Unbiased utility that takes uris \"as they are\". This means it can be interchanged with\r\n * uri#toString() usages. The following is true\r\n * ```\r\n * assertEqual(aUri.toString() === bUri.toString(), exturi.isEqual(aUri, bUri))\r\n * ```\r\n */\r\nexport const extUri = new ExtUri(() => false);\r\n\r\nexport const isEqual = extUri.isEqual.bind(extUri);\r\nexport const basenameOrAuthority = extUri.basenameOrAuthority.bind(extUri);\r\nexport const basename = extUri.basename.bind(extUri);\r\nexport const dirname = extUri.dirname.bind(extUri);\r\nexport const joinPath = extUri.joinPath.bind(extUri);\r\nexport const normalizePath = extUri.normalizePath.bind(extUri);\r\nexport const resolvePath = extUri.resolvePath.bind(extUri);\r\n\r\n/**\r\n * Data URI related helpers.\r\n */\r\nexport namespace DataUri {\r\n\r\n\texport const META_DATA_LABEL = 'label';\r\n\texport const META_DATA_DESCRIPTION = 'description';\r\n\texport const META_DATA_SIZE = 'size';\r\n\texport const META_DATA_MIME = 'mime';\r\n\r\n\texport function parseMetaData(dataUri: URI): Map {\r\n\t\tconst metadata = new Map();\r\n\r\n\t\t// Given a URI of: data:image/png;size:2313;label:SomeLabel;description:SomeDescription;base64,77+9UE5...\r\n\t\t// the metadata is: size:2313;label:SomeLabel;description:SomeDescription\r\n\t\tconst meta = dataUri.path.substring(dataUri.path.indexOf(';') + 1, dataUri.path.lastIndexOf(';'));\r\n\t\tmeta.split(';').forEach(property => {\r\n\t\t\tconst [key, value] = property.split(':');\r\n\t\t\tif (key && value) {\r\n\t\t\t\tmetadata.set(key, value);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\t// Given a URI of: data:image/png;size:2313;label:SomeLabel;description:SomeDescription;base64,77+9UE5...\r\n\t\t// the mime is: image/png\r\n\t\tconst mime = dataUri.path.substring(0, dataUri.path.indexOf(';'));\r\n\t\tif (mime) {\r\n\t\t\tmetadata.set(META_DATA_MIME, mime);\r\n\t\t}\r\n\r\n\t\treturn metadata;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as DOM from 'vs/base/browser/dom';\r\nimport { createElement, FormattedTextRenderOptions } from 'vs/base/browser/formattedTextRenderer';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport { IMarkdownString, parseHrefAndDimensions, removeMarkdownEscapes } from 'vs/base/common/htmlContent';\r\nimport { defaultGenerator } from 'vs/base/common/idGenerator';\r\nimport * as marked from 'vs/base/common/marked/marked';\r\nimport { insane, InsaneOptions } from 'vs/base/common/insane/insane';\r\nimport { parse } from 'vs/base/common/marshalling';\r\nimport { cloneAndChange } from 'vs/base/common/objects';\r\nimport { escape } from 'vs/base/common/strings';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { FileAccess, Schemas } from 'vs/base/common/network';\r\nimport { markdownEscapeEscapedIcons } from 'vs/base/common/iconLabels';\r\nimport { resolvePath } from 'vs/base/common/resources';\r\nimport { StandardMouseEvent } from 'vs/base/browser/mouseEvent';\r\nimport { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';\r\nimport { Event } from 'vs/base/common/event';\r\nimport { domEvent } from 'vs/base/browser/event';\r\n\r\nexport interface MarkedOptions extends marked.MarkedOptions {\r\n}\r\n\r\nexport interface MarkdownRenderOptions extends FormattedTextRenderOptions {\r\n\tcodeBlockRenderer?: (modeId: string, value: string) => Promise;\r\n\tasyncRenderCallback?: () => void;\r\n\tbaseUrl?: URI;\r\n}\r\n\r\nconst _ttpInsane = window.trustedTypes?.createPolicy('insane', {\r\n\tcreateHTML(value, options: InsaneOptions): string {\r\n\t\treturn insane(value, options);\r\n\t}\r\n});\r\n\r\n/**\r\n * Low-level way create a html element from a markdown string.\r\n *\r\n * **Note** that for most cases you should be using [`MarkdownRenderer`](./src/vs/editor/browser/core/markdownRenderer.ts)\r\n * which comes with support for pretty code block rendering and which uses the default way of handling links.\r\n */\r\nexport function renderMarkdown(markdown: IMarkdownString, options: MarkdownRenderOptions = {}, markedOptions: MarkedOptions = {}): HTMLElement {\r\n\tconst element = createElement(options);\r\n\r\n\tconst _uriMassage = function (part: string): string {\r\n\t\tlet data: any;\r\n\t\ttry {\r\n\t\t\tdata = parse(decodeURIComponent(part));\r\n\t\t} catch (e) {\r\n\t\t\t// ignore\r\n\t\t}\r\n\t\tif (!data) {\r\n\t\t\treturn part;\r\n\t\t}\r\n\t\tdata = cloneAndChange(data, value => {\r\n\t\t\tif (markdown.uris && markdown.uris[value]) {\r\n\t\t\t\treturn URI.revive(markdown.uris[value]);\r\n\t\t\t} else {\r\n\t\t\t\treturn undefined;\r\n\t\t\t}\r\n\t\t});\r\n\t\treturn encodeURIComponent(JSON.stringify(data));\r\n\t};\r\n\r\n\tconst _href = function (href: string, isDomUri: boolean): string {\r\n\t\tconst data = markdown.uris && markdown.uris[href];\r\n\t\tif (!data) {\r\n\t\t\treturn href; // no uri exists\r\n\t\t}\r\n\t\tlet uri = URI.revive(data);\r\n\t\tif (URI.parse(href).toString() === uri.toString()) {\r\n\t\t\treturn href; // no tranformation performed\r\n\t\t}\r\n\t\tif (isDomUri) {\r\n\t\t\t// this URI will end up as \"src\"-attribute of a dom node\r\n\t\t\t// and because of that special rewriting needs to be done\r\n\t\t\t// so that the URI uses a protocol that's understood by\r\n\t\t\t// browsers (like http or https)\r\n\t\t\treturn FileAccess.asBrowserUri(uri).toString(true);\r\n\t\t}\r\n\t\tif (uri.query) {\r\n\t\t\turi = uri.with({ query: _uriMassage(uri.query) });\r\n\t\t}\r\n\t\treturn uri.toString();\r\n\t};\r\n\r\n\t// signal to code-block render that the\r\n\t// element has been created\r\n\tlet signalInnerHTML: () => void;\r\n\tconst withInnerHTML = new Promise(c => signalInnerHTML = c);\r\n\r\n\tconst renderer = new marked.Renderer();\r\n\trenderer.image = (href: string, title: string, text: string) => {\r\n\t\tlet dimensions: string[] = [];\r\n\t\tlet attributes: string[] = [];\r\n\t\tif (href) {\r\n\t\t\t({ href, dimensions } = parseHrefAndDimensions(href));\r\n\t\t\thref = _href(href, true);\r\n\t\t\ttry {\r\n\t\t\t\tconst hrefAsUri = URI.parse(href);\r\n\t\t\t\tif (options.baseUrl && hrefAsUri.scheme === Schemas.file) { // absolute or relative local path, or file: uri\r\n\t\t\t\t\thref = resolvePath(options.baseUrl, href).toString();\r\n\t\t\t\t}\r\n\t\t\t} catch (err) { }\r\n\r\n\t\t\tattributes.push(`src=\"${href}\"`);\r\n\t\t}\r\n\t\tif (text) {\r\n\t\t\tattributes.push(`alt=\"${text}\"`);\r\n\t\t}\r\n\t\tif (title) {\r\n\t\t\tattributes.push(`title=\"${title}\"`);\r\n\t\t}\r\n\t\tif (dimensions.length) {\r\n\t\t\tattributes = attributes.concat(dimensions);\r\n\t\t}\r\n\t\treturn '';\r\n\t};\r\n\trenderer.link = (href, title, text): string => {\r\n\t\t// Remove markdown escapes. Workaround for https://github.com/chjj/marked/issues/829\r\n\t\tif (href === text) { // raw link case\r\n\t\t\ttext = removeMarkdownEscapes(text);\r\n\t\t}\r\n\t\thref = _href(href, false);\r\n\t\tif (options.baseUrl) {\r\n\t\t\tconst hasScheme = /^\\w[\\w\\d+.-]*:/.test(href);\r\n\t\t\tif (!hasScheme) {\r\n\t\t\t\thref = resolvePath(options.baseUrl, href).toString();\r\n\t\t\t}\r\n\t\t}\r\n\t\ttitle = removeMarkdownEscapes(title);\r\n\t\thref = removeMarkdownEscapes(href);\r\n\t\tif (\r\n\t\t\t!href\r\n\t\t\t|| href.match(/^data:|javascript:/i)\r\n\t\t\t|| (href.match(/^command:/i) && !markdown.isTrusted)\r\n\t\t\t|| href.match(/^command:(\\/\\/\\/)?_workbench\\.downloadResource/i)\r\n\t\t) {\r\n\t\t\t// drop the link\r\n\t\t\treturn text;\r\n\r\n\t\t} else {\r\n\t\t\t// HTML Encode href\r\n\t\t\thref = href.replace(/&/g, '&')\r\n\t\t\t\t.replace(//g, '>')\r\n\t\t\t\t.replace(/\"/g, '"')\r\n\t\t\t\t.replace(/'/g, ''');\r\n\t\t\treturn `
    ${text}`;\r\n\t\t}\r\n\t};\r\n\trenderer.paragraph = (text): string => {\r\n\t\tif (markdown.supportThemeIcons) {\r\n\t\t\tconst elements = renderLabelWithIcons(text);\r\n\t\t\ttext = elements.map(e => typeof e === 'string' ? e : e.outerHTML).join('');\r\n\t\t}\r\n\t\treturn `

    ${text}

    `;\r\n\t};\r\n\r\n\tif (options.codeBlockRenderer) {\r\n\t\trenderer.code = (code, lang) => {\r\n\t\t\tconst value = options.codeBlockRenderer!(lang, code);\r\n\t\t\t// when code-block rendering is async we return sync\r\n\t\t\t// but update the node with the real result later.\r\n\t\t\tconst id = defaultGenerator.nextId();\r\n\t\t\tconst promise = Promise.all([value, withInnerHTML]).then(values => {\r\n\t\t\t\tconst span = element.querySelector(`div[data-code=\"${id}\"]`);\r\n\t\t\t\tif (span) {\r\n\t\t\t\t\tDOM.reset(span, values[0]);\r\n\t\t\t\t}\r\n\t\t\t}).catch(_err => {\r\n\t\t\t\t// ignore\r\n\t\t\t});\r\n\r\n\t\t\tif (options.asyncRenderCallback) {\r\n\t\t\t\tpromise.then(options.asyncRenderCallback);\r\n\t\t\t}\r\n\r\n\t\t\treturn `
    ${escape(code)}
    `;\r\n\t\t};\r\n\t}\r\n\r\n\tif (options.actionHandler) {\r\n\t\toptions.actionHandler.disposeables.add(Event.any(domEvent(element, 'click'), domEvent(element, 'auxclick'))(e => {\r\n\t\t\tconst mouseEvent = new StandardMouseEvent(e);\r\n\t\t\tif (!mouseEvent.leftButton && !mouseEvent.middleButton) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tlet target: HTMLElement | null = mouseEvent.target;\r\n\t\t\tif (target.tagName !== 'A') {\r\n\t\t\t\ttarget = target.parentElement;\r\n\t\t\t\tif (!target || target.tagName !== 'A') {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\ttry {\r\n\t\t\t\tconst href = target.dataset['href'];\r\n\t\t\t\tif (href) {\r\n\t\t\t\t\toptions.actionHandler!.callback(href, mouseEvent);\r\n\t\t\t\t}\r\n\t\t\t} catch (err) {\r\n\t\t\t\tonUnexpectedError(err);\r\n\t\t\t} finally {\r\n\t\t\t\tmouseEvent.preventDefault();\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\t// Use our own sanitizer so that we can let through only spans.\r\n\t// Otherwise, we'd be letting all html be rendered.\r\n\t// If we want to allow markdown permitted tags, then we can delete sanitizer and sanitize.\r\n\t// We always pass the output through insane after this so that we don't rely on\r\n\t// marked for sanitization.\r\n\tmarkedOptions.sanitizer = (html: string): string => {\r\n\t\tconst match = markdown.isTrusted ? html.match(/^(]+>)|(<\\/\\s*span>)$/) : undefined;\r\n\t\treturn match ? html : '';\r\n\t};\r\n\tmarkedOptions.sanitize = true;\r\n\tmarkedOptions.silent = true;\r\n\r\n\tmarkedOptions.renderer = renderer;\r\n\r\n\t// values that are too long will freeze the UI\r\n\tlet value = markdown.value ?? '';\r\n\tif (value.length > 100_000) {\r\n\t\tvalue = `${value.substr(0, 100_000)}…`;\r\n\t}\r\n\t// escape theme icons\r\n\tif (markdown.supportThemeIcons) {\r\n\t\tvalue = markdownEscapeEscapedIcons(value);\r\n\t}\r\n\r\n\tconst renderedMarkdown = marked.parse(value, markedOptions);\r\n\r\n\t// sanitize with insane\r\n\telement.innerHTML = sanitizeRenderedMarkdown(markdown, renderedMarkdown) as string;\r\n\r\n\t// signal that async code blocks can be now be inserted\r\n\tsignalInnerHTML!();\r\n\r\n\t// signal size changes for image tags\r\n\tif (options.asyncRenderCallback) {\r\n\t\tfor (const img of element.getElementsByTagName('img')) {\r\n\t\t\tconst listener = DOM.addDisposableListener(img, 'load', () => {\r\n\t\t\t\tlistener.dispose();\r\n\t\t\t\toptions.asyncRenderCallback!();\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\r\n\treturn element;\r\n}\r\n\r\nfunction sanitizeRenderedMarkdown(\r\n\toptions: { isTrusted?: boolean },\r\n\trenderedMarkdown: string,\r\n): string | TrustedHTML {\r\n\tconst insaneOptions = getInsaneOptions(options);\r\n\treturn _ttpInsane?.createHTML(renderedMarkdown, insaneOptions) ?? insane(renderedMarkdown, insaneOptions);\r\n}\r\n\r\nfunction getInsaneOptions(options: { readonly isTrusted?: boolean }): InsaneOptions {\r\n\tconst allowedSchemes = [\r\n\t\tSchemas.http,\r\n\t\tSchemas.https,\r\n\t\tSchemas.mailto,\r\n\t\tSchemas.data,\r\n\t\tSchemas.file,\r\n\t\tSchemas.vscodeRemote,\r\n\t\tSchemas.vscodeRemoteResource,\r\n\t];\r\n\r\n\tif (options.isTrusted) {\r\n\t\tallowedSchemes.push(Schemas.command);\r\n\t}\r\n\r\n\treturn {\r\n\t\tallowedSchemes,\r\n\t\t// allowedTags should included everything that markdown renders to.\r\n\t\t// Since we have our own sanitize function for marked, it's possible we missed some tag so let insane make sure.\r\n\t\t// HTML tags that can result from markdown are from reading https://spec.commonmark.org/0.29/\r\n\t\t// HTML table tags that can result from markdown are from https://github.github.com/gfm/#tables-extension-\r\n\t\tallowedTags: ['ul', 'li', 'p', 'code', 'blockquote', 'ol', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'em', 'pre', 'table', 'thead', 'tbody', 'tr', 'th', 'td', 'div', 'del', 'a', 'strong', 'br', 'img', 'span'],\r\n\t\tallowedAttributes: {\r\n\t\t\t'a': ['href', 'name', 'target', 'data-href'],\r\n\t\t\t'img': ['src', 'title', 'alt', 'width', 'height'],\r\n\t\t\t'div': ['class', 'data-code'],\r\n\t\t\t'span': ['class', 'style'],\r\n\t\t\t// https://github.com/microsoft/vscode/issues/95937\r\n\t\t\t'th': ['align'],\r\n\t\t\t'td': ['align']\r\n\t\t},\r\n\t\tfilter(token: { tag: string; attrs: { readonly [key: string]: string; }; }): boolean {\r\n\t\t\tif (token.tag === 'span' && options.isTrusted) {\r\n\t\t\t\tif (token.attrs['style'] && (Object.keys(token.attrs).length === 1)) {\r\n\t\t\t\t\treturn !!token.attrs['style'].match(/^(color\\:#[0-9a-fA-F]+;)?(background-color\\:#[0-9a-fA-F]+;)?$/);\r\n\t\t\t\t} else if (token.attrs['class']) {\r\n\t\t\t\t\t// The class should match codicon rendering in src\\vs\\base\\common\\codicons.ts\r\n\t\t\t\t\treturn !!token.attrs['class'].match(/^codicon codicon-[a-z\\-]+( codicon-modifier-[a-z\\-]+)?$/);\r\n\t\t\t\t}\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t}\r\n\t};\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { Schemas } from 'vs/base/common/network';\r\nimport { isWindows } from 'vs/base/common/platform';\r\nimport { basename } from 'vs/base/common/resources';\r\nimport { hasDriveLetter, isRootOrDriveLetter } from 'vs/base/common/extpath';\r\n\r\nexport interface IWorkspaceFolderProvider {\r\n}\r\n\r\nexport function getBaseLabel(resource: URI | string): string;\r\nexport function getBaseLabel(resource: URI | string | undefined): string | undefined;\r\nexport function getBaseLabel(resource: URI | string | undefined): string | undefined {\r\n\tif (!resource) {\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tif (typeof resource === 'string') {\r\n\t\tresource = URI.file(resource);\r\n\t}\r\n\r\n\tconst base = basename(resource) || (resource.scheme === Schemas.file ? resource.fsPath : resource.path) /* can be empty string if '/' is passed in */;\r\n\r\n\t// convert c: => C:\r\n\tif (isWindows && isRootOrDriveLetter(base)) {\r\n\t\treturn normalizeDriveLetter(base);\r\n\t}\r\n\r\n\treturn base;\r\n}\r\n\r\nexport function normalizeDriveLetter(path: string): string {\r\n\tif (hasDriveLetter(path)) {\r\n\t\treturn path.charAt(0).toUpperCase() + path.slice(1);\r\n\t}\r\n\r\n\treturn path;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { basename, posix } from 'vs/base/common/path';\r\nimport { startsWithUTF8BOM } from 'vs/base/common/strings';\r\nimport { match } from 'vs/base/common/glob';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { Schemas } from 'vs/base/common/network';\r\nimport { DataUri } from 'vs/base/common/resources';\r\n\r\nexport const MIME_TEXT = 'text/plain';\r\nexport const MIME_UNKNOWN = 'application/unknown';\r\n\r\nexport interface ITextMimeAssociation {\r\n\treadonly id: string;\r\n\treadonly mime: string;\r\n\treadonly filename?: string;\r\n\treadonly extension?: string;\r\n\treadonly filepattern?: string;\r\n\treadonly firstline?: RegExp;\r\n\treadonly userConfigured?: boolean;\r\n}\r\n\r\ninterface ITextMimeAssociationItem extends ITextMimeAssociation {\r\n\treadonly filenameLowercase?: string;\r\n\treadonly extensionLowercase?: string;\r\n\treadonly filepatternLowercase?: string;\r\n\treadonly filepatternOnPath?: boolean;\r\n}\r\n\r\nlet registeredAssociations: ITextMimeAssociationItem[] = [];\r\nlet nonUserRegisteredAssociations: ITextMimeAssociationItem[] = [];\r\nlet userRegisteredAssociations: ITextMimeAssociationItem[] = [];\r\n\r\n/**\r\n * Associate a text mime to the registry.\r\n */\r\nexport function registerTextMime(association: ITextMimeAssociation, warnOnOverwrite = false): void {\r\n\r\n\t// Register\r\n\tconst associationItem = toTextMimeAssociationItem(association);\r\n\tregisteredAssociations.push(associationItem);\r\n\tif (!associationItem.userConfigured) {\r\n\t\tnonUserRegisteredAssociations.push(associationItem);\r\n\t} else {\r\n\t\tuserRegisteredAssociations.push(associationItem);\r\n\t}\r\n\r\n\t// Check for conflicts unless this is a user configured association\r\n\tif (warnOnOverwrite && !associationItem.userConfigured) {\r\n\t\tregisteredAssociations.forEach(a => {\r\n\t\t\tif (a.mime === associationItem.mime || a.userConfigured) {\r\n\t\t\t\treturn; // same mime or userConfigured is ok\r\n\t\t\t}\r\n\r\n\t\t\tif (associationItem.extension && a.extension === associationItem.extension) {\r\n\t\t\t\tconsole.warn(`Overwriting extension <<${associationItem.extension}>> to now point to mime <<${associationItem.mime}>>`);\r\n\t\t\t}\r\n\r\n\t\t\tif (associationItem.filename && a.filename === associationItem.filename) {\r\n\t\t\t\tconsole.warn(`Overwriting filename <<${associationItem.filename}>> to now point to mime <<${associationItem.mime}>>`);\r\n\t\t\t}\r\n\r\n\t\t\tif (associationItem.filepattern && a.filepattern === associationItem.filepattern) {\r\n\t\t\t\tconsole.warn(`Overwriting filepattern <<${associationItem.filepattern}>> to now point to mime <<${associationItem.mime}>>`);\r\n\t\t\t}\r\n\r\n\t\t\tif (associationItem.firstline && a.firstline === associationItem.firstline) {\r\n\t\t\t\tconsole.warn(`Overwriting firstline <<${associationItem.firstline}>> to now point to mime <<${associationItem.mime}>>`);\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n\r\nfunction toTextMimeAssociationItem(association: ITextMimeAssociation): ITextMimeAssociationItem {\r\n\treturn {\r\n\t\tid: association.id,\r\n\t\tmime: association.mime,\r\n\t\tfilename: association.filename,\r\n\t\textension: association.extension,\r\n\t\tfilepattern: association.filepattern,\r\n\t\tfirstline: association.firstline,\r\n\t\tuserConfigured: association.userConfigured,\r\n\t\tfilenameLowercase: association.filename ? association.filename.toLowerCase() : undefined,\r\n\t\textensionLowercase: association.extension ? association.extension.toLowerCase() : undefined,\r\n\t\tfilepatternLowercase: association.filepattern ? association.filepattern.toLowerCase() : undefined,\r\n\t\tfilepatternOnPath: association.filepattern ? association.filepattern.indexOf(posix.sep) >= 0 : false\r\n\t};\r\n}\r\n\r\n/**\r\n * Given a file, return the best matching mime type for it\r\n */\r\nexport function guessMimeTypes(resource: URI | null, firstLine?: string): string[] {\r\n\tlet path: string | undefined;\r\n\tif (resource) {\r\n\t\tswitch (resource.scheme) {\r\n\t\t\tcase Schemas.file:\r\n\t\t\t\tpath = resource.fsPath;\r\n\t\t\t\tbreak;\r\n\t\t\tcase Schemas.data:\r\n\t\t\t\tconst metadata = DataUri.parseMetaData(resource);\r\n\t\t\t\tpath = metadata.get(DataUri.META_DATA_LABEL);\r\n\t\t\t\tbreak;\r\n\t\t\tdefault:\r\n\t\t\t\tpath = resource.path;\r\n\t\t}\r\n\t}\r\n\r\n\tif (!path) {\r\n\t\treturn [MIME_UNKNOWN];\r\n\t}\r\n\r\n\tpath = path.toLowerCase();\r\n\r\n\tconst filename = basename(path);\r\n\r\n\t// 1.) User configured mappings have highest priority\r\n\tconst configuredMime = guessMimeTypeByPath(path, filename, userRegisteredAssociations);\r\n\tif (configuredMime) {\r\n\t\treturn [configuredMime, MIME_TEXT];\r\n\t}\r\n\r\n\t// 2.) Registered mappings have middle priority\r\n\tconst registeredMime = guessMimeTypeByPath(path, filename, nonUserRegisteredAssociations);\r\n\tif (registeredMime) {\r\n\t\treturn [registeredMime, MIME_TEXT];\r\n\t}\r\n\r\n\t// 3.) Firstline has lowest priority\r\n\tif (firstLine) {\r\n\t\tconst firstlineMime = guessMimeTypeByFirstline(firstLine);\r\n\t\tif (firstlineMime) {\r\n\t\t\treturn [firstlineMime, MIME_TEXT];\r\n\t\t}\r\n\t}\r\n\r\n\treturn [MIME_UNKNOWN];\r\n}\r\n\r\nfunction guessMimeTypeByPath(path: string, filename: string, associations: ITextMimeAssociationItem[]): string | null {\r\n\tlet filenameMatch: ITextMimeAssociationItem | null = null;\r\n\tlet patternMatch: ITextMimeAssociationItem | null = null;\r\n\tlet extensionMatch: ITextMimeAssociationItem | null = null;\r\n\r\n\t// We want to prioritize associations based on the order they are registered so that the last registered\r\n\t// association wins over all other. This is for https://github.com/microsoft/vscode/issues/20074\r\n\tfor (let i = associations.length - 1; i >= 0; i--) {\r\n\t\tconst association = associations[i];\r\n\r\n\t\t// First exact name match\r\n\t\tif (filename === association.filenameLowercase) {\r\n\t\t\tfilenameMatch = association;\r\n\t\t\tbreak; // take it!\r\n\t\t}\r\n\r\n\t\t// Longest pattern match\r\n\t\tif (association.filepattern) {\r\n\t\t\tif (!patternMatch || association.filepattern.length > patternMatch.filepattern!.length) {\r\n\t\t\t\tconst target = association.filepatternOnPath ? path : filename; // match on full path if pattern contains path separator\r\n\t\t\t\tif (match(association.filepatternLowercase!, target)) {\r\n\t\t\t\t\tpatternMatch = association;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Longest extension match\r\n\t\tif (association.extension) {\r\n\t\t\tif (!extensionMatch || association.extension.length > extensionMatch.extension!.length) {\r\n\t\t\t\tif (filename.endsWith(association.extensionLowercase!)) {\r\n\t\t\t\t\textensionMatch = association;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t// 1.) Exact name match has second highest prio\r\n\tif (filenameMatch) {\r\n\t\treturn filenameMatch.mime;\r\n\t}\r\n\r\n\t// 2.) Match on pattern\r\n\tif (patternMatch) {\r\n\t\treturn patternMatch.mime;\r\n\t}\r\n\r\n\t// 3.) Match on extension comes next\r\n\tif (extensionMatch) {\r\n\t\treturn extensionMatch.mime;\r\n\t}\r\n\r\n\treturn null;\r\n}\r\n\r\nfunction guessMimeTypeByFirstline(firstLine: string): string | null {\r\n\tif (startsWithUTF8BOM(firstLine)) {\r\n\t\tfirstLine = firstLine.substr(1);\r\n\t}\r\n\r\n\tif (firstLine.length > 0) {\r\n\r\n\t\t// We want to prioritize associations based on the order they are registered so that the last registered\r\n\t\t// association wins over all other. This is for https://github.com/microsoft/vscode/issues/20074\r\n\t\tfor (let i = registeredAssociations.length - 1; i >= 0; i--) {\r\n\t\t\tconst association = registeredAssociations[i];\r\n\t\t\tif (!association.firstline) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tconst matches = firstLine.match(association.firstline);\r\n\t\t\tif (matches && matches.length > 0) {\r\n\t\t\t\treturn association.mime;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\treturn null;\r\n}\r\n","\r\n\r\n// prep-work\r\nconst _data = new Uint8Array(16);\r\nconst _hex: string[] = [];\r\nfor (let i = 0; i < 256; i++) {\r\n\t_hex.push(i.toString(16).padStart(2, '0'));\r\n}\r\n\r\n// todo@jrieken\r\n// 1. node nodejs use`crypto#randomBytes`, see: https://nodejs.org/docs/latest/api/crypto.html#crypto_crypto_randombytes_size_callback\r\n// 2. use browser-crypto\r\nconst _fillRandomValues = function (bucket: Uint8Array): Uint8Array {\r\n\tfor (let i = 0; i < bucket.length; i++) {\r\n\t\tbucket[i] = Math.floor(Math.random() * 256);\r\n\t}\r\n\treturn bucket;\r\n};\r\n\r\nexport function generateUuid(): string {\r\n\t// get data\r\n\t_fillRandomValues(_data);\r\n\r\n\t// set version bits\r\n\t_data[6] = (_data[6] & 0x0f) | 0x40;\r\n\t_data[8] = (_data[8] & 0x3f) | 0x80;\r\n\r\n\t// print as string\r\n\tlet i = 0;\r\n\tlet result = '';\r\n\tresult += _hex[_data[i++]];\r\n\tresult += _hex[_data[i++]];\r\n\tresult += _hex[_data[i++]];\r\n\tresult += _hex[_data[i++]];\r\n\tresult += '-';\r\n\tresult += _hex[_data[i++]];\r\n\tresult += _hex[_data[i++]];\r\n\tresult += '-';\r\n\tresult += _hex[_data[i++]];\r\n\tresult += _hex[_data[i++]];\r\n\tresult += '-';\r\n\tresult += _hex[_data[i++]];\r\n\tresult += _hex[_data[i++]];\r\n\tresult += '-';\r\n\tresult += _hex[_data[i++]];\r\n\tresult += _hex[_data[i++]];\r\n\tresult += _hex[_data[i++]];\r\n\tresult += _hex[_data[i++]];\r\n\tresult += _hex[_data[i++]];\r\n\tresult += _hex[_data[i++]];\r\n\treturn result;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { transformErrorForSerialization } from 'vs/base/common/errors';\r\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\r\nimport { isWeb } from 'vs/base/common/platform';\r\nimport * as types from 'vs/base/common/types';\r\n\r\nconst INITIALIZE = '$initialize';\r\n\r\nexport interface IWorker extends IDisposable {\r\n\tgetId(): number;\r\n\tpostMessage(message: any, transfer: ArrayBuffer[]): void;\r\n}\r\n\r\nexport interface IWorkerCallback {\r\n\t(message: any): void;\r\n}\r\n\r\nexport interface IWorkerFactory {\r\n\tcreate(moduleId: string, callback: IWorkerCallback, onErrorCallback: (err: any) => void): IWorker;\r\n}\r\n\r\nlet webWorkerWarningLogged = false;\r\nexport function logOnceWebWorkerWarning(err: any): void {\r\n\tif (!isWeb) {\r\n\t\t// running tests\r\n\t\treturn;\r\n\t}\r\n\tif (!webWorkerWarningLogged) {\r\n\t\twebWorkerWarningLogged = true;\r\n\t\tconsole.warn('Could not create web worker(s). Falling back to loading web worker code in main thread, which might cause UI freezes. Please see https://github.com/microsoft/monaco-editor#faq');\r\n\t}\r\n\tconsole.warn(err.message);\r\n}\r\n\r\ninterface IMessage {\r\n\tvsWorker: number;\r\n\treq?: string;\r\n\tseq?: string;\r\n}\r\n\r\ninterface IRequestMessage extends IMessage {\r\n\treq: string;\r\n\tmethod: string;\r\n\targs: any[];\r\n}\r\n\r\ninterface IReplyMessage extends IMessage {\r\n\tseq: string;\r\n\terr: any;\r\n\tres: any;\r\n}\r\n\r\ninterface IMessageReply {\r\n\tresolve: (value?: any) => void;\r\n\treject: (error?: any) => void;\r\n}\r\n\r\ninterface IMessageHandler {\r\n\tsendMessage(msg: any, transfer?: ArrayBuffer[]): void;\r\n\thandleMessage(method: string, args: any[]): Promise;\r\n}\r\n\r\nclass SimpleWorkerProtocol {\r\n\r\n\tprivate _workerId: number;\r\n\tprivate _lastSentReq: number;\r\n\tprivate _pendingReplies: { [req: string]: IMessageReply; };\r\n\tprivate _handler: IMessageHandler;\r\n\r\n\tconstructor(handler: IMessageHandler) {\r\n\t\tthis._workerId = -1;\r\n\t\tthis._handler = handler;\r\n\t\tthis._lastSentReq = 0;\r\n\t\tthis._pendingReplies = Object.create(null);\r\n\t}\r\n\r\n\tpublic setWorkerId(workerId: number): void {\r\n\t\tthis._workerId = workerId;\r\n\t}\r\n\r\n\tpublic sendMessage(method: string, args: any[]): Promise {\r\n\t\tlet req = String(++this._lastSentReq);\r\n\t\treturn new Promise((resolve, reject) => {\r\n\t\t\tthis._pendingReplies[req] = {\r\n\t\t\t\tresolve: resolve,\r\n\t\t\t\treject: reject\r\n\t\t\t};\r\n\t\t\tthis._send({\r\n\t\t\t\tvsWorker: this._workerId,\r\n\t\t\t\treq: req,\r\n\t\t\t\tmethod: method,\r\n\t\t\t\targs: args\r\n\t\t\t});\r\n\t\t});\r\n\t}\r\n\r\n\tpublic handleMessage(message: IMessage): void {\r\n\t\tif (!message || !message.vsWorker) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (this._workerId !== -1 && message.vsWorker !== this._workerId) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._handleMessage(message);\r\n\t}\r\n\r\n\tprivate _handleMessage(msg: IMessage): void {\r\n\t\tif (msg.seq) {\r\n\t\t\tlet replyMessage = msg;\r\n\t\t\tif (!this._pendingReplies[replyMessage.seq]) {\r\n\t\t\t\tconsole.warn('Got reply to unknown seq');\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tlet reply = this._pendingReplies[replyMessage.seq];\r\n\t\t\tdelete this._pendingReplies[replyMessage.seq];\r\n\r\n\t\t\tif (replyMessage.err) {\r\n\t\t\t\tlet err = replyMessage.err;\r\n\t\t\t\tif (replyMessage.err.$isError) {\r\n\t\t\t\t\terr = new Error();\r\n\t\t\t\t\terr.name = replyMessage.err.name;\r\n\t\t\t\t\terr.message = replyMessage.err.message;\r\n\t\t\t\t\terr.stack = replyMessage.err.stack;\r\n\t\t\t\t}\r\n\t\t\t\treply.reject(err);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\treply.resolve(replyMessage.res);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet requestMessage = msg;\r\n\t\tlet req = requestMessage.req;\r\n\t\tlet result = this._handler.handleMessage(requestMessage.method, requestMessage.args);\r\n\t\tresult.then((r) => {\r\n\t\t\tthis._send({\r\n\t\t\t\tvsWorker: this._workerId,\r\n\t\t\t\tseq: req,\r\n\t\t\t\tres: r,\r\n\t\t\t\terr: undefined\r\n\t\t\t});\r\n\t\t}, (e) => {\r\n\t\t\tif (e.detail instanceof Error) {\r\n\t\t\t\t// Loading errors have a detail property that points to the actual error\r\n\t\t\t\te.detail = transformErrorForSerialization(e.detail);\r\n\t\t\t}\r\n\t\t\tthis._send({\r\n\t\t\t\tvsWorker: this._workerId,\r\n\t\t\t\tseq: req,\r\n\t\t\t\tres: undefined,\r\n\t\t\t\terr: transformErrorForSerialization(e)\r\n\t\t\t});\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _send(msg: IRequestMessage | IReplyMessage): void {\r\n\t\tlet transfer: ArrayBuffer[] = [];\r\n\t\tif (msg.req) {\r\n\t\t\tconst m = msg;\r\n\t\t\tfor (let i = 0; i < m.args.length; i++) {\r\n\t\t\t\tif (m.args[i] instanceof ArrayBuffer) {\r\n\t\t\t\t\ttransfer.push(m.args[i]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tconst m = msg;\r\n\t\t\tif (m.res instanceof ArrayBuffer) {\r\n\t\t\t\ttransfer.push(m.res);\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis._handler.sendMessage(msg, transfer);\r\n\t}\r\n}\r\n\r\nexport interface IWorkerClient {\r\n\tgetProxyObject(): Promise;\r\n\tdispose(): void;\r\n}\r\n\r\n/**\r\n * Main thread side\r\n */\r\nexport class SimpleWorkerClient extends Disposable implements IWorkerClient {\r\n\r\n\tprivate readonly _worker: IWorker;\r\n\tprivate readonly _onModuleLoaded: Promise;\r\n\tprivate readonly _protocol: SimpleWorkerProtocol;\r\n\tprivate readonly _lazyProxy: Promise;\r\n\r\n\tconstructor(workerFactory: IWorkerFactory, moduleId: string, host: H) {\r\n\t\tsuper();\r\n\r\n\t\tlet lazyProxyReject: ((err: any) => void) | null = null;\r\n\r\n\t\tthis._worker = this._register(workerFactory.create(\r\n\t\t\t'vs/base/common/worker/simpleWorker',\r\n\t\t\t(msg: any) => {\r\n\t\t\t\tthis._protocol.handleMessage(msg);\r\n\t\t\t},\r\n\t\t\t(err: any) => {\r\n\t\t\t\t// in Firefox, web workers fail lazily :(\r\n\t\t\t\t// we will reject the proxy\r\n\t\t\t\tif (lazyProxyReject) {\r\n\t\t\t\t\tlazyProxyReject(err);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t));\r\n\r\n\t\tthis._protocol = new SimpleWorkerProtocol({\r\n\t\t\tsendMessage: (msg: any, transfer: ArrayBuffer[]): void => {\r\n\t\t\t\tthis._worker.postMessage(msg, transfer);\r\n\t\t\t},\r\n\t\t\thandleMessage: (method: string, args: any[]): Promise => {\r\n\t\t\t\tif (typeof (host as any)[method] !== 'function') {\r\n\t\t\t\t\treturn Promise.reject(new Error('Missing method ' + method + ' on main thread host.'));\r\n\t\t\t\t}\r\n\r\n\t\t\t\ttry {\r\n\t\t\t\t\treturn Promise.resolve((host as any)[method].apply(host, args));\r\n\t\t\t\t} catch (e) {\r\n\t\t\t\t\treturn Promise.reject(e);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\t\tthis._protocol.setWorkerId(this._worker.getId());\r\n\r\n\t\t// Gather loader configuration\r\n\t\tlet loaderConfiguration: any = null;\r\n\t\tif (typeof (self).require !== 'undefined' && typeof (self).require.getConfig === 'function') {\r\n\t\t\t// Get the configuration from the Monaco AMD Loader\r\n\t\t\tloaderConfiguration = (self).require.getConfig();\r\n\t\t} else if (typeof (self).requirejs !== 'undefined') {\r\n\t\t\t// Get the configuration from requirejs\r\n\t\t\tloaderConfiguration = (self).requirejs.s.contexts._.config;\r\n\t\t}\r\n\r\n\t\tconst hostMethods = types.getAllMethodNames(host);\r\n\r\n\t\t// Send initialize message\r\n\t\tthis._onModuleLoaded = this._protocol.sendMessage(INITIALIZE, [\r\n\t\t\tthis._worker.getId(),\r\n\t\t\tJSON.parse(JSON.stringify(loaderConfiguration)),\r\n\t\t\tmoduleId,\r\n\t\t\thostMethods,\r\n\t\t]);\r\n\r\n\t\t// Create proxy to loaded code\r\n\t\tconst proxyMethodRequest = (method: string, args: any[]): Promise => {\r\n\t\t\treturn this._request(method, args);\r\n\t\t};\r\n\r\n\t\tthis._lazyProxy = new Promise((resolve, reject) => {\r\n\t\t\tlazyProxyReject = reject;\r\n\t\t\tthis._onModuleLoaded.then((availableMethods: string[]) => {\r\n\t\t\t\tresolve(types.createProxyObject(availableMethods, proxyMethodRequest));\r\n\t\t\t}, (e) => {\r\n\t\t\t\treject(e);\r\n\t\t\t\tthis._onError('Worker failed to load ' + moduleId, e);\r\n\t\t\t});\r\n\t\t});\r\n\t}\r\n\r\n\tpublic getProxyObject(): Promise {\r\n\t\treturn this._lazyProxy;\r\n\t}\r\n\r\n\tprivate _request(method: string, args: any[]): Promise {\r\n\t\treturn new Promise((resolve, reject) => {\r\n\t\t\tthis._onModuleLoaded.then(() => {\r\n\t\t\t\tthis._protocol.sendMessage(method, args).then(resolve, reject);\r\n\t\t\t}, reject);\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _onError(message: string, error?: any): void {\r\n\t\tconsole.error(message);\r\n\t\tconsole.info(error);\r\n\t}\r\n}\r\n\r\nexport interface IRequestHandler {\r\n\t_requestHandlerBrand: any;\r\n\t[prop: string]: any;\r\n}\r\n\r\nexport interface IRequestHandlerFactory {\r\n\t(host: H): IRequestHandler;\r\n}\r\n\r\n/**\r\n * Worker side\r\n */\r\nexport class SimpleWorkerServer {\r\n\r\n\tprivate _requestHandlerFactory: IRequestHandlerFactory | null;\r\n\tprivate _requestHandler: IRequestHandler | null;\r\n\tprivate _protocol: SimpleWorkerProtocol;\r\n\r\n\tconstructor(postMessage: (msg: any, transfer?: ArrayBuffer[]) => void, requestHandlerFactory: IRequestHandlerFactory | null) {\r\n\t\tthis._requestHandlerFactory = requestHandlerFactory;\r\n\t\tthis._requestHandler = null;\r\n\t\tthis._protocol = new SimpleWorkerProtocol({\r\n\t\t\tsendMessage: (msg: any, transfer: ArrayBuffer[]): void => {\r\n\t\t\t\tpostMessage(msg, transfer);\r\n\t\t\t},\r\n\t\t\thandleMessage: (method: string, args: any[]): Promise => this._handleMessage(method, args)\r\n\t\t});\r\n\t}\r\n\r\n\tpublic onmessage(msg: any): void {\r\n\t\tthis._protocol.handleMessage(msg);\r\n\t}\r\n\r\n\tprivate _handleMessage(method: string, args: any[]): Promise {\r\n\t\tif (method === INITIALIZE) {\r\n\t\t\treturn this.initialize(args[0], args[1], args[2], args[3]);\r\n\t\t}\r\n\r\n\t\tif (!this._requestHandler || typeof this._requestHandler[method] !== 'function') {\r\n\t\t\treturn Promise.reject(new Error('Missing requestHandler or method: ' + method));\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\treturn Promise.resolve(this._requestHandler[method].apply(this._requestHandler, args));\r\n\t\t} catch (e) {\r\n\t\t\treturn Promise.reject(e);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate initialize(workerId: number, loaderConfig: any, moduleId: string, hostMethods: string[]): Promise {\r\n\t\tthis._protocol.setWorkerId(workerId);\r\n\r\n\t\tconst proxyMethodRequest = (method: string, args: any[]): Promise => {\r\n\t\t\treturn this._protocol.sendMessage(method, args);\r\n\t\t};\r\n\r\n\t\tconst hostProxy = types.createProxyObject(hostMethods, proxyMethodRequest);\r\n\r\n\t\tif (this._requestHandlerFactory) {\r\n\t\t\t// static request handler\r\n\t\t\tthis._requestHandler = this._requestHandlerFactory(hostProxy);\r\n\t\t\treturn Promise.resolve(types.getAllMethodNames(this._requestHandler));\r\n\t\t}\r\n\r\n\t\tif (loaderConfig) {\r\n\t\t\t// Remove 'baseUrl', handling it is beyond scope for now\r\n\t\t\tif (typeof loaderConfig.baseUrl !== 'undefined') {\r\n\t\t\t\tdelete loaderConfig['baseUrl'];\r\n\t\t\t}\r\n\t\t\tif (typeof loaderConfig.paths !== 'undefined') {\r\n\t\t\t\tif (typeof loaderConfig.paths.vs !== 'undefined') {\r\n\t\t\t\t\tdelete loaderConfig.paths['vs'];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (typeof loaderConfig.trustedTypesPolicy !== undefined) {\r\n\t\t\t\t// don't use, it has been destroyed during serialize\r\n\t\t\t\tdelete loaderConfig['trustedTypesPolicy'];\r\n\t\t\t}\r\n\r\n\t\t\t// Since this is in a web worker, enable catching errors\r\n\t\t\tloaderConfig.catchError = true;\r\n\t\t\t(self).require.config(loaderConfig);\r\n\t\t}\r\n\r\n\t\treturn new Promise((resolve, reject) => {\r\n\t\t\t// Use the global require to be sure to get the global config\r\n\t\t\t(self).require([moduleId], (module: { create: IRequestHandlerFactory }) => {\r\n\t\t\t\tthis._requestHandler = module.create(hostProxy);\r\n\r\n\t\t\t\tif (!this._requestHandler) {\r\n\t\t\t\t\treject(new Error(`No RequestHandler!`));\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tresolve(types.getAllMethodNames(this._requestHandler));\r\n\t\t\t}, reject);\r\n\t\t});\r\n\t}\r\n}\r\n\r\n/**\r\n * Called on the worker side\r\n */\r\nexport function create(postMessage: (msg: string) => void): SimpleWorkerServer {\r\n\treturn new SimpleWorkerServer(postMessage, null);\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { ResolvedKeybinding } from 'vs/base/common/keyCodes';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { Event } from 'vs/base/common/event';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { IMatch } from 'vs/base/common/filters';\r\n\r\nexport interface IQuickPickItemHighlights {\r\n\tlabel?: IMatch[];\r\n\tdescription?: IMatch[];\r\n\tdetail?: IMatch[];\r\n}\r\n\r\nexport interface IQuickPickItem {\r\n\ttype?: 'item';\r\n\tlabel: string;\r\n\tmeta?: string;\r\n\tariaLabel?: string;\r\n\tdescription?: string;\r\n\tdetail?: string;\r\n\t/**\r\n\t * Allows to show a keybinding next to the item to indicate\r\n\t * how the item can be triggered outside of the picker using\r\n\t * keyboard shortcut.\r\n\t */\r\n\tkeybinding?: ResolvedKeybinding;\r\n\ticonClasses?: string[];\r\n\titalic?: boolean;\r\n\tstrikethrough?: boolean;\r\n\thighlights?: IQuickPickItemHighlights;\r\n\tbuttons?: IQuickInputButton[];\r\n\tpicked?: boolean;\r\n\talwaysShow?: boolean;\r\n}\r\n\r\nexport interface IQuickPickSeparator {\r\n\ttype: 'separator';\r\n\tlabel?: string;\r\n}\r\n\r\nexport interface IKeyMods {\r\n\treadonly ctrlCmd: boolean;\r\n\treadonly alt: boolean;\r\n}\r\n\r\nexport const NO_KEY_MODS: IKeyMods = { ctrlCmd: false, alt: false };\r\n\r\nexport interface IQuickNavigateConfiguration {\r\n\tkeybindings: ResolvedKeybinding[];\r\n}\r\n\r\nexport interface IPickOptions {\r\n\r\n\t/**\r\n\t * an optional string to show as placeholder in the input box to guide the user what she picks on\r\n\t */\r\n\tplaceHolder?: string;\r\n\r\n\t/**\r\n\t * an optional flag to include the description when filtering the picks\r\n\t */\r\n\tmatchOnDescription?: boolean;\r\n\r\n\t/**\r\n\t * an optional flag to include the detail when filtering the picks\r\n\t */\r\n\tmatchOnDetail?: boolean;\r\n\r\n\t/**\r\n\t * an optional flag to filter the picks based on label. Defaults to true.\r\n\t */\r\n\tmatchOnLabel?: boolean;\r\n\r\n\t/**\r\n\t * an option flag to control whether focus is always automatically brought to a list item. Defaults to true.\r\n\t */\r\n\tautoFocusOnList?: boolean;\r\n\r\n\t/**\r\n\t * an optional flag to not close the picker on focus lost\r\n\t */\r\n\tignoreFocusLost?: boolean;\r\n\r\n\t/**\r\n\t * an optional flag to make this picker multi-select\r\n\t */\r\n\tcanPickMany?: boolean;\r\n\r\n\t/**\r\n\t * enables quick navigate in the picker to open an element without typing\r\n\t */\r\n\tquickNavigate?: IQuickNavigateConfiguration;\r\n\r\n\t/**\r\n\t * a context key to set when this picker is active\r\n\t */\r\n\tcontextKey?: string;\r\n\r\n\t/**\r\n\t * an optional property for the item to focus initially.\r\n\t */\r\n\tactiveItem?: Promise | T;\r\n\r\n\tonKeyMods?: (keyMods: IKeyMods) => void;\r\n\tonDidFocus?: (entry: T) => void;\r\n\tonDidTriggerItemButton?: (context: IQuickPickItemButtonContext) => void;\r\n}\r\n\r\nexport interface IQuickInput extends IDisposable {\r\n\r\n\treadonly onDidHide: Event;\r\n\r\n\tcontextKey: string | undefined;\r\n\r\n\tbusy: boolean;\r\n\r\n\tignoreFocusOut: boolean;\r\n\r\n\tshow(): void;\r\n\r\n\thide(): void;\r\n}\r\n\r\nexport interface IQuickPickAcceptEvent {\r\n\r\n\t/**\r\n\t * Signals if the picker item is to be accepted\r\n\t * in the background while keeping the picker open.\r\n\t */\r\n\tinBackground: boolean;\r\n}\r\n\r\nexport enum ItemActivation {\r\n\tNONE,\r\n\tFIRST,\r\n\tSECOND,\r\n\tLAST\r\n}\r\n\r\nexport interface IQuickPick extends IQuickInput {\r\n\r\n\tvalue: string;\r\n\r\n\t/**\r\n\t * A method that allows to massage the value used\r\n\t * for filtering, e.g, to remove certain parts.\r\n\t */\r\n\tfilterValue: (value: string) => string;\r\n\r\n\tariaLabel: string | undefined;\r\n\r\n\tplaceholder: string | undefined;\r\n\r\n\treadonly onDidChangeValue: Event;\r\n\r\n\treadonly onDidAccept: Event;\r\n\r\n\t/**\r\n\t * If enabled, will fire the `onDidAccept` event when\r\n\t * pressing the arrow-right key with the idea of accepting\r\n\t * the selected item without closing the picker.\r\n\t */\r\n\tcanAcceptInBackground: boolean;\r\n\r\n\treadonly onDidTriggerItemButton: Event>;\r\n\r\n\titems: ReadonlyArray;\r\n\r\n\tcanSelectMany: boolean;\r\n\r\n\tmatchOnDescription: boolean;\r\n\r\n\tmatchOnDetail: boolean;\r\n\r\n\tmatchOnLabel: boolean;\r\n\r\n\tsortByLabel: boolean;\r\n\r\n\tautoFocusOnList: boolean;\r\n\r\n\tquickNavigate: IQuickNavigateConfiguration | undefined;\r\n\r\n\tactiveItems: ReadonlyArray;\r\n\r\n\treadonly onDidChangeActive: Event;\r\n\r\n\t/**\r\n\t * Allows to control which entry should be activated by default.\r\n\t */\r\n\titemActivation: ItemActivation;\r\n\r\n\tselectedItems: ReadonlyArray;\r\n\r\n\treadonly onDidChangeSelection: Event;\r\n\r\n\treadonly keyMods: IKeyMods;\r\n\r\n\tvalueSelection: Readonly<[number, number]> | undefined;\r\n\r\n\t/**\r\n\t * Hides the input box from the picker UI. This is typically used\r\n\t * in combination with quick-navigation where no search UI should\r\n\t * be presented.\r\n\t */\r\n\thideInput: boolean;\r\n}\r\n\r\nexport interface IQuickInputButton {\r\n\t/** iconPath or iconClass required */\r\n\ticonPath?: { dark: URI; light?: URI; };\r\n\t/** iconPath or iconClass required */\r\n\ticonClass?: string;\r\n\ttooltip?: string;\r\n\t/**\r\n\t * Whether to always show the button. By default buttons\r\n\t * are only visible when hovering over them with the mouse\r\n\t */\r\n\talwaysVisible?: boolean;\r\n}\r\n\r\nexport interface IQuickPickItemButtonEvent {\r\n\tbutton: IQuickInputButton;\r\n\titem: T;\r\n}\r\n\r\nexport interface IQuickPickItemButtonContext extends IQuickPickItemButtonEvent {\r\n\tremoveItem(): void;\r\n}\r\n\r\nexport type QuickPickInput = T | IQuickPickSeparator;\r\n\r\n//#endregion\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { globals } from 'vs/base/common/platform';\r\nimport { IWorker, IWorkerCallback, IWorkerFactory, logOnceWebWorkerWarning } from 'vs/base/common/worker/simpleWorker';\r\n\r\nconst ttPolicy = window.trustedTypes?.createPolicy('defaultWorkerFactory', { createScriptURL: value => value });\r\n\r\nfunction getWorker(workerId: string, label: string): Worker | Promise {\r\n\t// Option for hosts to overwrite the worker script (used in the standalone editor)\r\n\tif (globals.MonacoEnvironment) {\r\n\t\tif (typeof globals.MonacoEnvironment.getWorker === 'function') {\r\n\t\t\treturn globals.MonacoEnvironment.getWorker(workerId, label);\r\n\t\t}\r\n\t\tif (typeof globals.MonacoEnvironment.getWorkerUrl === 'function') {\r\n\t\t\tconst wokerUrl = globals.MonacoEnvironment.getWorkerUrl(workerId, label);\r\n\t\t\treturn new Worker(ttPolicy ? ttPolicy.createScriptURL(wokerUrl) as unknown as string : wokerUrl, { name: label });\r\n\t\t}\r\n\t}\r\n\t// ESM-comment-begin\r\n\tif (typeof require === 'function') {\r\n\t\t// check if the JS lives on a different origin\r\n\t\tconst workerMain = require.toUrl('./' + workerId); // explicitly using require.toUrl(), see https://github.com/microsoft/vscode/issues/107440#issuecomment-698982321\r\n\t\tconst workerUrl = getWorkerBootstrapUrl(workerMain, label);\r\n\t\treturn new Worker(ttPolicy ? ttPolicy.createScriptURL(workerUrl) as unknown as string : workerUrl, { name: label });\r\n\t}\r\n\t// ESM-comment-end\r\n\tthrow new Error(`You must define a function MonacoEnvironment.getWorkerUrl or MonacoEnvironment.getWorker`);\r\n}\r\n\r\n// ESM-comment-begin\r\nexport function getWorkerBootstrapUrl(scriptPath: string, label: string, forceDataUri: boolean = false): string {\r\n\tif (forceDataUri || /^((http:)|(https:)|(file:))/.test(scriptPath)) {\r\n\t\tconst currentUrl = String(window.location);\r\n\t\tconst currentOrigin = currentUrl.substr(0, currentUrl.length - window.location.hash.length - window.location.search.length - window.location.pathname.length);\r\n\t\tif (forceDataUri || scriptPath.substring(0, currentOrigin.length) !== currentOrigin) {\r\n\t\t\t// this is the cross-origin case\r\n\t\t\t// i.e. the webpage is running at a different origin than where the scripts are loaded from\r\n\t\t\tconst myPath = 'vs/base/worker/defaultWorkerFactory.js';\r\n\t\t\tconst workerBaseUrl = require.toUrl(myPath).slice(0, -myPath.length); // explicitly using require.toUrl(), see https://github.com/microsoft/vscode/issues/107440#issuecomment-698982321\r\n\t\t\tconst js = `/*${label}*/self.MonacoEnvironment={baseUrl: '${workerBaseUrl}'};importScripts('${scriptPath}');/*${label}*/`;\r\n\t\t\tif (forceDataUri) {\r\n\t\t\t\tconst url = `data:text/javascript;charset=utf-8,${encodeURIComponent(js)}`;\r\n\t\t\t\treturn url;\r\n\t\t\t}\r\n\t\t\tconst blob = new Blob([js], { type: 'application/javascript' });\r\n\t\t\treturn URL.createObjectURL(blob);\r\n\t\t}\r\n\t}\r\n\treturn scriptPath + '#' + label;\r\n}\r\n// ESM-comment-end\r\n\r\nfunction isPromiseLike(obj: any): obj is PromiseLike {\r\n\tif (typeof obj.then === 'function') {\r\n\t\treturn true;\r\n\t}\r\n\treturn false;\r\n}\r\n\r\n/**\r\n * A worker that uses HTML5 web workers so that is has\r\n * its own global scope and its own thread.\r\n */\r\nclass WebWorker implements IWorker {\r\n\r\n\tprivate id: number;\r\n\tprivate worker: Promise | null;\r\n\r\n\tconstructor(moduleId: string, id: number, label: string, onMessageCallback: IWorkerCallback, onErrorCallback: (err: any) => void) {\r\n\t\tthis.id = id;\r\n\t\tconst workerOrPromise = getWorker('workerMain.js', label);\r\n\t\tif (isPromiseLike(workerOrPromise)) {\r\n\t\t\tthis.worker = workerOrPromise;\r\n\t\t} else {\r\n\t\t\tthis.worker = Promise.resolve(workerOrPromise);\r\n\t\t}\r\n\t\tthis.postMessage(moduleId, []);\r\n\t\tthis.worker.then((w) => {\r\n\t\t\tw.onmessage = function (ev: any) {\r\n\t\t\t\tonMessageCallback(ev.data);\r\n\t\t\t};\r\n\t\t\t(w).onmessageerror = onErrorCallback;\r\n\t\t\tif (typeof w.addEventListener === 'function') {\r\n\t\t\t\tw.addEventListener('error', onErrorCallback);\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic getId(): number {\r\n\t\treturn this.id;\r\n\t}\r\n\r\n\tpublic postMessage(message: any, transfer: Transferable[]): void {\r\n\t\tif (this.worker) {\r\n\t\t\tthis.worker.then(w => w.postMessage(message, transfer));\r\n\t\t}\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tif (this.worker) {\r\n\t\t\tthis.worker.then(w => w.terminate());\r\n\t\t}\r\n\t\tthis.worker = null;\r\n\t}\r\n}\r\n\r\nexport class DefaultWorkerFactory implements IWorkerFactory {\r\n\r\n\tprivate static LAST_WORKER_ID = 0;\r\n\r\n\tprivate _label: string | undefined;\r\n\tprivate _webWorkerFailedBeforeError: any;\r\n\r\n\tconstructor(label: string | undefined) {\r\n\t\tthis._label = label;\r\n\t\tthis._webWorkerFailedBeforeError = false;\r\n\t}\r\n\r\n\tpublic create(moduleId: string, onMessageCallback: IWorkerCallback, onErrorCallback: (err: any) => void): IWorker {\r\n\t\tlet workerId = (++DefaultWorkerFactory.LAST_WORKER_ID);\r\n\r\n\t\tif (this._webWorkerFailedBeforeError) {\r\n\t\t\tthrow this._webWorkerFailedBeforeError;\r\n\t\t}\r\n\r\n\t\treturn new WebWorker(moduleId, workerId, this._label || 'anonymous' + workerId, onMessageCallback, (err) => {\r\n\t\t\tlogOnceWebWorkerWarning(err);\r\n\t\t\tthis._webWorkerFailedBeforeError = err;\r\n\t\t\tonErrorCallback(err);\r\n\t\t});\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./aria';\r\nimport { isMacintosh } from 'vs/base/common/platform';\r\nimport * as dom from 'vs/base/browser/dom';\r\n\r\n// Use a max length since we are inserting the whole msg in the DOM and that can cause browsers to freeze for long messages #94233\r\nconst MAX_MESSAGE_LENGTH = 20000;\r\nlet ariaContainer: HTMLElement;\r\nlet alertContainer: HTMLElement;\r\nlet alertContainer2: HTMLElement;\r\nlet statusContainer: HTMLElement;\r\nlet statusContainer2: HTMLElement;\r\nexport function setARIAContainer(parent: HTMLElement) {\r\n\tariaContainer = document.createElement('div');\r\n\tariaContainer.className = 'monaco-aria-container';\r\n\r\n\tconst createAlertContainer = () => {\r\n\t\tconst element = document.createElement('div');\r\n\t\telement.className = 'monaco-alert';\r\n\t\telement.setAttribute('role', 'alert');\r\n\t\telement.setAttribute('aria-atomic', 'true');\r\n\t\tariaContainer.appendChild(element);\r\n\t\treturn element;\r\n\t};\r\n\talertContainer = createAlertContainer();\r\n\talertContainer2 = createAlertContainer();\r\n\r\n\tconst createStatusContainer = () => {\r\n\t\tconst element = document.createElement('div');\r\n\t\telement.className = 'monaco-status';\r\n\t\telement.setAttribute('role', 'complementary');\r\n\t\telement.setAttribute('aria-live', 'polite');\r\n\t\telement.setAttribute('aria-atomic', 'true');\r\n\t\tariaContainer.appendChild(element);\r\n\t\treturn element;\r\n\t};\r\n\tstatusContainer = createStatusContainer();\r\n\tstatusContainer2 = createStatusContainer();\r\n\r\n\tparent.appendChild(ariaContainer);\r\n}\r\n/**\r\n * Given the provided message, will make sure that it is read as alert to screen readers.\r\n */\r\nexport function alert(msg: string): void {\r\n\tif (!ariaContainer) {\r\n\t\treturn;\r\n\t}\r\n\r\n\t// Use alternate containers such that duplicated messages get read out by screen readers #99466\r\n\tif (alertContainer.textContent !== msg) {\r\n\t\tdom.clearNode(alertContainer2);\r\n\t\tinsertMessage(alertContainer, msg);\r\n\t} else {\r\n\t\tdom.clearNode(alertContainer);\r\n\t\tinsertMessage(alertContainer2, msg);\r\n\t}\r\n}\r\n\r\n/**\r\n * Given the provided message, will make sure that it is read as status to screen readers.\r\n */\r\nexport function status(msg: string): void {\r\n\tif (!ariaContainer) {\r\n\t\treturn;\r\n\t}\r\n\r\n\tif (isMacintosh) {\r\n\t\talert(msg); // VoiceOver does not seem to support status role\r\n\t} else {\r\n\t\tif (statusContainer.textContent !== msg) {\r\n\t\t\tdom.clearNode(statusContainer2);\r\n\t\t\tinsertMessage(statusContainer, msg);\r\n\t\t} else {\r\n\t\t\tdom.clearNode(statusContainer);\r\n\t\t\tinsertMessage(statusContainer2, msg);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction insertMessage(target: HTMLElement, msg: string): void {\r\n\tdom.clearNode(target);\r\n\tif (msg.length > MAX_MESSAGE_LENGTH) {\r\n\t\tmsg = msg.substr(0, MAX_MESSAGE_LENGTH);\r\n\t}\r\n\ttarget.textContent = msg;\r\n\r\n\t// See https://www.paciellogroup.com/blog/2012/06/html5-accessibility-chops-aria-rolealert-browser-support/\r\n\ttarget.style.visibility = 'hidden';\r\n\ttarget.style.visibility = 'visible';\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./button';\r\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { KeyCode } from 'vs/base/common/keyCodes';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { mixin } from 'vs/base/common/objects';\r\nimport { Event as BaseEvent, Emitter } from 'vs/base/common/event';\r\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\r\nimport { Gesture, EventType as TouchEventType } from 'vs/base/browser/touch';\r\nimport { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';\r\nimport { addDisposableListener, IFocusTracker, EventType, EventHelper, trackFocus, reset, removeTabIndexAndUpdateFocus } from 'vs/base/browser/dom';\r\n\r\nexport interface IButtonOptions extends IButtonStyles {\r\n\treadonly title?: boolean | string;\r\n\treadonly supportIcons?: boolean;\r\n\treadonly secondary?: boolean;\r\n}\r\n\r\nexport interface IButtonStyles {\r\n\tbuttonBackground?: Color;\r\n\tbuttonHoverBackground?: Color;\r\n\tbuttonForeground?: Color;\r\n\tbuttonSecondaryBackground?: Color;\r\n\tbuttonSecondaryHoverBackground?: Color;\r\n\tbuttonSecondaryForeground?: Color;\r\n\tbuttonBorder?: Color;\r\n}\r\n\r\nconst defaultOptions: IButtonStyles = {\r\n\tbuttonBackground: Color.fromHex('#0E639C'),\r\n\tbuttonHoverBackground: Color.fromHex('#006BB3'),\r\n\tbuttonForeground: Color.white\r\n};\r\n\r\nexport interface IButton extends IDisposable {\r\n}\r\n\r\nexport class Button extends Disposable implements IButton {\r\n\r\n\tprivate _element: HTMLElement;\r\n\tprivate options: IButtonOptions;\r\n\r\n\tprivate buttonBackground: Color | undefined;\r\n\tprivate buttonHoverBackground: Color | undefined;\r\n\tprivate buttonForeground: Color | undefined;\r\n\tprivate buttonSecondaryBackground: Color | undefined;\r\n\tprivate buttonSecondaryHoverBackground: Color | undefined;\r\n\tprivate buttonSecondaryForeground: Color | undefined;\r\n\tprivate buttonBorder: Color | undefined;\r\n\r\n\tprivate _onDidClick = this._register(new Emitter());\r\n\tget onDidClick(): BaseEvent { return this._onDidClick.event; }\r\n\r\n\tprivate focusTracker: IFocusTracker;\r\n\r\n\tconstructor(container: HTMLElement, options?: IButtonOptions) {\r\n\t\tsuper();\r\n\r\n\t\tthis.options = options || Object.create(null);\r\n\t\tmixin(this.options, defaultOptions, false);\r\n\r\n\t\tthis.buttonForeground = this.options.buttonForeground;\r\n\t\tthis.buttonBackground = this.options.buttonBackground;\r\n\t\tthis.buttonHoverBackground = this.options.buttonHoverBackground;\r\n\r\n\t\tthis.buttonSecondaryForeground = this.options.buttonSecondaryForeground;\r\n\t\tthis.buttonSecondaryBackground = this.options.buttonSecondaryBackground;\r\n\t\tthis.buttonSecondaryHoverBackground = this.options.buttonSecondaryHoverBackground;\r\n\r\n\t\tthis.buttonBorder = this.options.buttonBorder;\r\n\r\n\t\tthis._element = document.createElement('a');\r\n\t\tthis._element.classList.add('monaco-button');\r\n\t\tthis._element.tabIndex = 0;\r\n\t\tthis._element.setAttribute('role', 'button');\r\n\r\n\t\tcontainer.appendChild(this._element);\r\n\r\n\t\tthis._register(Gesture.addTarget(this._element));\r\n\r\n\t\t[EventType.CLICK, TouchEventType.Tap].forEach(eventType => {\r\n\t\t\tthis._register(addDisposableListener(this._element, eventType, e => {\r\n\t\t\t\tif (!this.enabled) {\r\n\t\t\t\t\tEventHelper.stop(e);\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis._onDidClick.fire(e);\r\n\t\t\t}));\r\n\t\t});\r\n\r\n\t\tthis._register(addDisposableListener(this._element, EventType.KEY_DOWN, e => {\r\n\t\t\tconst event = new StandardKeyboardEvent(e);\r\n\t\t\tlet eventHandled = false;\r\n\t\t\tif (this.enabled && (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space))) {\r\n\t\t\t\tthis._onDidClick.fire(e);\r\n\t\t\t\teventHandled = true;\r\n\t\t\t} else if (event.equals(KeyCode.Escape)) {\r\n\t\t\t\tthis._element.blur();\r\n\t\t\t\teventHandled = true;\r\n\t\t\t}\r\n\r\n\t\t\tif (eventHandled) {\r\n\t\t\t\tEventHelper.stop(event, true);\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._register(addDisposableListener(this._element, EventType.MOUSE_OVER, e => {\r\n\t\t\tif (!this._element.classList.contains('disabled')) {\r\n\t\t\t\tthis.setHoverBackground();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._register(addDisposableListener(this._element, EventType.MOUSE_OUT, e => {\r\n\t\t\tthis.applyStyles(); // restore standard styles\r\n\t\t}));\r\n\r\n\t\t// Also set hover background when button is focused for feedback\r\n\t\tthis.focusTracker = this._register(trackFocus(this._element));\r\n\t\tthis._register(this.focusTracker.onDidFocus(() => this.setHoverBackground()));\r\n\t\tthis._register(this.focusTracker.onDidBlur(() => this.applyStyles())); // restore standard styles\r\n\r\n\t\tthis.applyStyles();\r\n\t}\r\n\r\n\tprivate setHoverBackground(): void {\r\n\t\tlet hoverBackground;\r\n\t\tif (this.options.secondary) {\r\n\t\t\thoverBackground = this.buttonSecondaryHoverBackground ? this.buttonSecondaryHoverBackground.toString() : null;\r\n\t\t} else {\r\n\t\t\thoverBackground = this.buttonHoverBackground ? this.buttonHoverBackground.toString() : null;\r\n\t\t}\r\n\t\tif (hoverBackground) {\r\n\t\t\tthis._element.style.backgroundColor = hoverBackground;\r\n\t\t}\r\n\t}\r\n\r\n\tstyle(styles: IButtonStyles): void {\r\n\t\tthis.buttonForeground = styles.buttonForeground;\r\n\t\tthis.buttonBackground = styles.buttonBackground;\r\n\t\tthis.buttonHoverBackground = styles.buttonHoverBackground;\r\n\t\tthis.buttonSecondaryForeground = styles.buttonSecondaryForeground;\r\n\t\tthis.buttonSecondaryBackground = styles.buttonSecondaryBackground;\r\n\t\tthis.buttonSecondaryHoverBackground = styles.buttonSecondaryHoverBackground;\r\n\t\tthis.buttonBorder = styles.buttonBorder;\r\n\r\n\t\tthis.applyStyles();\r\n\t}\r\n\r\n\tprivate applyStyles(): void {\r\n\t\tif (this._element) {\r\n\t\t\tlet background, foreground;\r\n\t\t\tif (this.options.secondary) {\r\n\t\t\t\tforeground = this.buttonSecondaryForeground ? this.buttonSecondaryForeground.toString() : '';\r\n\t\t\t\tbackground = this.buttonSecondaryBackground ? this.buttonSecondaryBackground.toString() : '';\r\n\t\t\t} else {\r\n\t\t\t\tforeground = this.buttonForeground ? this.buttonForeground.toString() : '';\r\n\t\t\t\tbackground = this.buttonBackground ? this.buttonBackground.toString() : '';\r\n\t\t\t}\r\n\r\n\t\t\tconst border = this.buttonBorder ? this.buttonBorder.toString() : '';\r\n\r\n\t\t\tthis._element.style.color = foreground;\r\n\t\t\tthis._element.style.backgroundColor = background;\r\n\r\n\t\t\tthis._element.style.borderWidth = border ? '1px' : '';\r\n\t\t\tthis._element.style.borderStyle = border ? 'solid' : '';\r\n\t\t\tthis._element.style.borderColor = border;\r\n\t\t}\r\n\t}\r\n\r\n\tget element(): HTMLElement {\r\n\t\treturn this._element;\r\n\t}\r\n\r\n\tset label(value: string) {\r\n\t\tthis._element.classList.add('monaco-text-button');\r\n\t\tif (this.options.supportIcons) {\r\n\t\t\treset(this._element, ...renderLabelWithIcons(value));\r\n\t\t} else {\r\n\t\t\tthis._element.textContent = value;\r\n\t\t}\r\n\t\tif (typeof this.options.title === 'string') {\r\n\t\t\tthis._element.title = this.options.title;\r\n\t\t} else if (this.options.title) {\r\n\t\t\tthis._element.title = value;\r\n\t\t}\r\n\t}\r\n\r\n\tset enabled(value: boolean) {\r\n\t\tif (value) {\r\n\t\t\tthis._element.classList.remove('disabled');\r\n\t\t\tthis._element.setAttribute('aria-disabled', String(false));\r\n\t\t\tthis._element.tabIndex = 0;\r\n\t\t} else {\r\n\t\t\tthis._element.classList.add('disabled');\r\n\t\t\tthis._element.setAttribute('aria-disabled', String(true));\r\n\t\t\tremoveTabIndexAndUpdateFocus(this._element);\r\n\t\t}\r\n\t}\r\n\r\n\tget enabled() {\r\n\t\treturn !this._element.classList.contains('disabled');\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./checkbox';\r\nimport * as DOM from 'vs/base/browser/dom';\r\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { Widget } from 'vs/base/browser/ui/widget';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { KeyCode } from 'vs/base/common/keyCodes';\r\nimport { CSSIcon } from 'vs/base/common/codicons';\r\n\r\nexport interface ICheckboxOpts extends ICheckboxStyles {\r\n\treadonly actionClassName?: string;\r\n\treadonly icon?: CSSIcon;\r\n\treadonly title: string;\r\n\treadonly isChecked: boolean;\r\n}\r\n\r\nexport interface ICheckboxStyles {\r\n\tinputActiveOptionBorder?: Color;\r\n\tinputActiveOptionForeground?: Color;\r\n\tinputActiveOptionBackground?: Color;\r\n}\r\n\r\nconst defaultOpts = {\r\n\tinputActiveOptionBorder: Color.fromHex('#007ACC00'),\r\n\tinputActiveOptionForeground: Color.fromHex('#FFFFFF'),\r\n\tinputActiveOptionBackground: Color.fromHex('#0E639C50')\r\n};\r\n\r\nexport class Checkbox extends Widget {\r\n\r\n\tprivate readonly _onChange = this._register(new Emitter());\r\n\treadonly onChange: Event = this._onChange.event;\r\n\r\n\tprivate readonly _onKeyDown = this._register(new Emitter());\r\n\treadonly onKeyDown: Event = this._onKeyDown.event;\r\n\r\n\tprivate readonly _opts: ICheckboxOpts;\r\n\treadonly domNode: HTMLElement;\r\n\r\n\tprivate _checked: boolean;\r\n\r\n\tconstructor(opts: ICheckboxOpts) {\r\n\t\tsuper();\r\n\r\n\t\tthis._opts = { ...defaultOpts, ...opts };\r\n\t\tthis._checked = this._opts.isChecked;\r\n\r\n\t\tconst classes = ['monaco-custom-checkbox'];\r\n\t\tif (this._opts.icon) {\r\n\t\t\tclasses.push(...CSSIcon.asClassNameArray(this._opts.icon));\r\n\t\t}\r\n\t\tif (this._opts.actionClassName) {\r\n\t\t\tclasses.push(...this._opts.actionClassName.split(' '));\r\n\t\t}\r\n\t\tif (this._checked) {\r\n\t\t\tclasses.push('checked');\r\n\t\t}\r\n\r\n\t\tthis.domNode = document.createElement('div');\r\n\t\tthis.domNode.title = this._opts.title;\r\n\t\tthis.domNode.classList.add(...classes);\r\n\t\tthis.domNode.tabIndex = 0;\r\n\t\tthis.domNode.setAttribute('role', 'checkbox');\r\n\t\tthis.domNode.setAttribute('aria-checked', String(this._checked));\r\n\t\tthis.domNode.setAttribute('aria-label', this._opts.title);\r\n\r\n\t\tthis.applyStyles();\r\n\r\n\t\tthis.onclick(this.domNode, (ev) => {\r\n\t\t\tthis.checked = !this._checked;\r\n\t\t\tthis._onChange.fire(false);\r\n\t\t\tev.preventDefault();\r\n\t\t});\r\n\r\n\t\tthis.ignoreGesture(this.domNode);\r\n\r\n\t\tthis.onkeydown(this.domNode, (keyboardEvent) => {\r\n\t\t\tif (keyboardEvent.keyCode === KeyCode.Space || keyboardEvent.keyCode === KeyCode.Enter) {\r\n\t\t\t\tthis.checked = !this._checked;\r\n\t\t\t\tthis._onChange.fire(true);\r\n\t\t\t\tkeyboardEvent.preventDefault();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tthis._onKeyDown.fire(keyboardEvent);\r\n\t\t});\r\n\t}\r\n\r\n\tget enabled(): boolean {\r\n\t\treturn this.domNode.getAttribute('aria-disabled') !== 'true';\r\n\t}\r\n\r\n\tfocus(): void {\r\n\t\tthis.domNode.focus();\r\n\t}\r\n\r\n\tget checked(): boolean {\r\n\t\treturn this._checked;\r\n\t}\r\n\r\n\tset checked(newIsChecked: boolean) {\r\n\t\tthis._checked = newIsChecked;\r\n\r\n\t\tthis.domNode.setAttribute('aria-checked', String(this._checked));\r\n\t\tthis.domNode.classList.toggle('checked', this._checked);\r\n\r\n\t\tthis.applyStyles();\r\n\t}\r\n\r\n\twidth(): number {\r\n\t\treturn 2 /*marginleft*/ + 2 /*border*/ + 2 /*padding*/ + 16 /* icon width */;\r\n\t}\r\n\r\n\tstyle(styles: ICheckboxStyles): void {\r\n\t\tif (styles.inputActiveOptionBorder) {\r\n\t\t\tthis._opts.inputActiveOptionBorder = styles.inputActiveOptionBorder;\r\n\t\t}\r\n\t\tif (styles.inputActiveOptionForeground) {\r\n\t\t\tthis._opts.inputActiveOptionForeground = styles.inputActiveOptionForeground;\r\n\t\t}\r\n\t\tif (styles.inputActiveOptionBackground) {\r\n\t\t\tthis._opts.inputActiveOptionBackground = styles.inputActiveOptionBackground;\r\n\t\t}\r\n\t\tthis.applyStyles();\r\n\t}\r\n\r\n\tprotected applyStyles(): void {\r\n\t\tif (this.domNode) {\r\n\t\t\tthis.domNode.style.borderColor = this._checked && this._opts.inputActiveOptionBorder ? this._opts.inputActiveOptionBorder.toString() : 'transparent';\r\n\t\t\tthis.domNode.style.color = this._checked && this._opts.inputActiveOptionForeground ? this._opts.inputActiveOptionForeground.toString() : 'inherit';\r\n\t\t\tthis.domNode.style.backgroundColor = this._checked && this._opts.inputActiveOptionBackground ? this._opts.inputActiveOptionBackground.toString() : 'transparent';\r\n\t\t}\r\n\t}\r\n\r\n\tenable(): void {\r\n\t\tthis.domNode.tabIndex = 0;\r\n\t\tthis.domNode.setAttribute('aria-disabled', String(false));\r\n\t}\r\n\r\n\tdisable(): void {\r\n\t\tDOM.removeTabIndexAndUpdateFocus(this.domNode);\r\n\t\tthis.domNode.setAttribute('aria-disabled', String(true));\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./codicon/codicon';\r\nimport 'vs/css!./codicon/codicon-modifiers';\r\n\r\nimport { Codicon } from 'vs/base/common/codicons';\r\n\r\nexport function formatRule(c: Codicon) {\r\n\tlet def = c.definition;\r\n\twhile (def instanceof Codicon) {\r\n\t\tdef = def.definition;\r\n\t}\r\n\treturn `.codicon-${c.id}:before { content: '${def.character}'; }`;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./contextview';\r\nimport * as DOM from 'vs/base/browser/dom';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport { IDisposable, toDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { Range } from 'vs/base/common/range';\r\nimport { BrowserFeatures } from 'vs/base/browser/canIUse';\r\n\r\nexport const enum ContextViewDOMPosition {\r\n\tABSOLUTE = 1,\r\n\tFIXED,\r\n\tFIXED_SHADOW\r\n}\r\n\r\nexport interface IAnchor {\r\n\tx: number;\r\n\ty: number;\r\n\twidth?: number;\r\n\theight?: number;\r\n}\r\n\r\nexport const enum AnchorAlignment {\r\n\tLEFT, RIGHT\r\n}\r\n\r\nexport const enum AnchorPosition {\r\n\tBELOW, ABOVE\r\n}\r\n\r\nexport const enum AnchorAxisAlignment {\r\n\tVERTICAL, HORIZONTAL\r\n}\r\n\r\nexport interface IDelegate {\r\n\tgetAnchor(): HTMLElement | IAnchor;\r\n\trender(container: HTMLElement): IDisposable | null;\r\n\tfocus?(): void;\r\n\tlayout?(): void;\r\n\tanchorAlignment?: AnchorAlignment; // default: left\r\n\tanchorPosition?: AnchorPosition; // default: below\r\n\tanchorAxisAlignment?: AnchorAxisAlignment; // default: vertical\r\n\tcanRelayout?: boolean; // default: true\r\n\tonDOMEvent?(e: Event, activeElement: HTMLElement): void;\r\n\tonHide?(data?: any): void;\r\n}\r\n\r\nexport interface IContextViewProvider {\r\n\tshowContextView(delegate: IDelegate, container?: HTMLElement): void;\r\n\thideContextView(): void;\r\n\tlayout(): void;\r\n}\r\n\r\nexport interface IPosition {\r\n\ttop: number;\r\n\tleft: number;\r\n}\r\n\r\nexport interface ISize {\r\n\twidth: number;\r\n\theight: number;\r\n}\r\n\r\nexport interface IView extends IPosition, ISize { }\r\n\r\nexport const enum LayoutAnchorPosition {\r\n\tBefore,\r\n\tAfter\r\n}\r\n\r\nexport enum LayoutAnchorMode {\r\n\tAVOID,\r\n\tALIGN\r\n}\r\n\r\nexport interface ILayoutAnchor {\r\n\toffset: number;\r\n\tsize: number;\r\n\tmode?: LayoutAnchorMode; // default: AVOID\r\n\tposition: LayoutAnchorPosition;\r\n}\r\n\r\n/**\r\n * Lays out a one dimensional view next to an anchor in a viewport.\r\n *\r\n * @returns The view offset within the viewport.\r\n */\r\nexport function layout(viewportSize: number, viewSize: number, anchor: ILayoutAnchor): number {\r\n\tconst layoutAfterAnchorBoundary = anchor.mode === LayoutAnchorMode.ALIGN ? anchor.offset : anchor.offset + anchor.size;\r\n\tconst layoutBeforeAnchorBoundary = anchor.mode === LayoutAnchorMode.ALIGN ? anchor.offset + anchor.size : anchor.offset;\r\n\r\n\tif (anchor.position === LayoutAnchorPosition.Before) {\r\n\t\tif (viewSize <= viewportSize - layoutAfterAnchorBoundary) {\r\n\t\t\treturn layoutAfterAnchorBoundary; // happy case, lay it out after the anchor\r\n\t\t}\r\n\r\n\t\tif (viewSize <= layoutBeforeAnchorBoundary) {\r\n\t\t\treturn layoutBeforeAnchorBoundary - viewSize; // ok case, lay it out before the anchor\r\n\t\t}\r\n\r\n\t\treturn Math.max(viewportSize - viewSize, 0); // sad case, lay it over the anchor\r\n\t} else {\r\n\t\tif (viewSize <= layoutBeforeAnchorBoundary) {\r\n\t\t\treturn layoutBeforeAnchorBoundary - viewSize; // happy case, lay it out before the anchor\r\n\t\t}\r\n\r\n\t\tif (viewSize <= viewportSize - layoutAfterAnchorBoundary) {\r\n\t\t\treturn layoutAfterAnchorBoundary; // ok case, lay it out after the anchor\r\n\t\t}\r\n\r\n\t\treturn 0; // sad case, lay it over the anchor\r\n\t}\r\n}\r\n\r\nexport class ContextView extends Disposable {\r\n\r\n\tprivate static readonly BUBBLE_UP_EVENTS = ['click', 'keydown', 'focus', 'blur'];\r\n\tprivate static readonly BUBBLE_DOWN_EVENTS = ['click'];\r\n\r\n\tprivate container: HTMLElement | null = null;\r\n\tprivate view: HTMLElement;\r\n\tprivate useFixedPosition: boolean;\r\n\tprivate useShadowDOM: boolean;\r\n\tprivate delegate: IDelegate | null = null;\r\n\tprivate toDisposeOnClean: IDisposable = Disposable.None;\r\n\tprivate toDisposeOnSetContainer: IDisposable = Disposable.None;\r\n\tprivate shadowRoot: ShadowRoot | null = null;\r\n\tprivate shadowRootHostElement: HTMLElement | null = null;\r\n\r\n\tconstructor(container: HTMLElement, domPosition: ContextViewDOMPosition) {\r\n\t\tsuper();\r\n\r\n\t\tthis.view = DOM.$('.context-view');\r\n\t\tthis.useFixedPosition = false;\r\n\t\tthis.useShadowDOM = false;\r\n\r\n\t\tDOM.hide(this.view);\r\n\r\n\t\tthis.setContainer(container, domPosition);\r\n\r\n\t\tthis._register(toDisposable(() => this.setContainer(null, ContextViewDOMPosition.ABSOLUTE)));\r\n\t}\r\n\r\n\tsetContainer(container: HTMLElement | null, domPosition: ContextViewDOMPosition): void {\r\n\t\tif (this.container) {\r\n\t\t\tthis.toDisposeOnSetContainer.dispose();\r\n\r\n\t\t\tif (this.shadowRoot) {\r\n\t\t\t\tthis.shadowRoot.removeChild(this.view);\r\n\t\t\t\tthis.shadowRoot = null;\r\n\t\t\t\tthis.shadowRootHostElement?.remove();\r\n\t\t\t\tthis.shadowRootHostElement = null;\r\n\t\t\t} else {\r\n\t\t\t\tthis.container.removeChild(this.view);\r\n\t\t\t}\r\n\r\n\t\t\tthis.container = null;\r\n\t\t}\r\n\t\tif (container) {\r\n\t\t\tthis.container = container;\r\n\r\n\t\t\tthis.useFixedPosition = domPosition !== ContextViewDOMPosition.ABSOLUTE;\r\n\t\t\tthis.useShadowDOM = domPosition === ContextViewDOMPosition.FIXED_SHADOW;\r\n\r\n\t\t\tif (this.useShadowDOM) {\r\n\t\t\t\tthis.shadowRootHostElement = DOM.$('.shadow-root-host');\r\n\t\t\t\tthis.container.appendChild(this.shadowRootHostElement);\r\n\t\t\t\tthis.shadowRoot = this.shadowRootHostElement.attachShadow({ mode: 'open' });\r\n\t\t\t\tconst style = document.createElement('style');\r\n\t\t\t\tstyle.textContent = SHADOW_ROOT_CSS;\r\n\t\t\t\tthis.shadowRoot.appendChild(style);\r\n\t\t\t\tthis.shadowRoot.appendChild(this.view);\r\n\t\t\t\tthis.shadowRoot.appendChild(DOM.$('slot'));\r\n\t\t\t} else {\r\n\t\t\t\tthis.container.appendChild(this.view);\r\n\t\t\t}\r\n\r\n\t\t\tconst toDisposeOnSetContainer = new DisposableStore();\r\n\r\n\t\t\tContextView.BUBBLE_UP_EVENTS.forEach(event => {\r\n\t\t\t\ttoDisposeOnSetContainer.add(DOM.addStandardDisposableListener(this.container!, event, (e: Event) => {\r\n\t\t\t\t\tthis.onDOMEvent(e, false);\r\n\t\t\t\t}));\r\n\t\t\t});\r\n\r\n\t\t\tContextView.BUBBLE_DOWN_EVENTS.forEach(event => {\r\n\t\t\t\ttoDisposeOnSetContainer.add(DOM.addStandardDisposableListener(this.container!, event, (e: Event) => {\r\n\t\t\t\t\tthis.onDOMEvent(e, true);\r\n\t\t\t\t}, true));\r\n\t\t\t});\r\n\r\n\t\t\tthis.toDisposeOnSetContainer = toDisposeOnSetContainer;\r\n\t\t}\r\n\t}\r\n\r\n\tshow(delegate: IDelegate): void {\r\n\t\tif (this.isVisible()) {\r\n\t\t\tthis.hide();\r\n\t\t}\r\n\r\n\t\t// Show static box\r\n\t\tDOM.clearNode(this.view);\r\n\t\tthis.view.className = 'context-view';\r\n\t\tthis.view.style.top = '0px';\r\n\t\tthis.view.style.left = '0px';\r\n\t\tthis.view.style.zIndex = '2500';\r\n\t\tthis.view.style.position = this.useFixedPosition ? 'fixed' : 'absolute';\r\n\t\tDOM.show(this.view);\r\n\r\n\t\t// Render content\r\n\t\tthis.toDisposeOnClean = delegate.render(this.view) || Disposable.None;\r\n\r\n\t\t// Set active delegate\r\n\t\tthis.delegate = delegate;\r\n\r\n\t\t// Layout\r\n\t\tthis.doLayout();\r\n\r\n\t\t// Focus\r\n\t\tif (this.delegate.focus) {\r\n\t\t\tthis.delegate.focus();\r\n\t\t}\r\n\t}\r\n\r\n\tgetViewElement(): HTMLElement {\r\n\t\treturn this.view;\r\n\t}\r\n\r\n\tlayout(): void {\r\n\t\tif (!this.isVisible()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this.delegate!.canRelayout === false && !(platform.isIOS && BrowserFeatures.pointerEvents)) {\r\n\t\t\tthis.hide();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this.delegate!.layout) {\r\n\t\t\tthis.delegate!.layout!();\r\n\t\t}\r\n\r\n\t\tthis.doLayout();\r\n\t}\r\n\r\n\tprivate doLayout(): void {\r\n\t\t// Check that we still have a delegate - this.delegate.layout may have hidden\r\n\t\tif (!this.isVisible()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// Get anchor\r\n\t\tlet anchor = this.delegate!.getAnchor();\r\n\r\n\t\t// Compute around\r\n\t\tlet around: IView;\r\n\r\n\t\t// Get the element's position and size (to anchor the view)\r\n\t\tif (DOM.isHTMLElement(anchor)) {\r\n\t\t\tlet elementPosition = DOM.getDomNodePagePosition(anchor);\r\n\r\n\t\t\taround = {\r\n\t\t\t\ttop: elementPosition.top,\r\n\t\t\t\tleft: elementPosition.left,\r\n\t\t\t\twidth: elementPosition.width,\r\n\t\t\t\theight: elementPosition.height\r\n\t\t\t};\r\n\t\t} else {\r\n\t\t\taround = {\r\n\t\t\t\ttop: anchor.y,\r\n\t\t\t\tleft: anchor.x,\r\n\t\t\t\twidth: anchor.width || 1,\r\n\t\t\t\theight: anchor.height || 2\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tconst viewSizeWidth = DOM.getTotalWidth(this.view);\r\n\t\tconst viewSizeHeight = DOM.getTotalHeight(this.view);\r\n\r\n\t\tconst anchorPosition = this.delegate!.anchorPosition || AnchorPosition.BELOW;\r\n\t\tconst anchorAlignment = this.delegate!.anchorAlignment || AnchorAlignment.LEFT;\r\n\t\tconst anchorAxisAlignment = this.delegate!.anchorAxisAlignment || AnchorAxisAlignment.VERTICAL;\r\n\r\n\t\tlet top: number;\r\n\t\tlet left: number;\r\n\r\n\t\tif (anchorAxisAlignment === AnchorAxisAlignment.VERTICAL) {\r\n\t\t\tconst verticalAnchor: ILayoutAnchor = { offset: around.top - window.pageYOffset, size: around.height, position: anchorPosition === AnchorPosition.BELOW ? LayoutAnchorPosition.Before : LayoutAnchorPosition.After };\r\n\t\t\tconst horizontalAnchor: ILayoutAnchor = { offset: around.left, size: around.width, position: anchorAlignment === AnchorAlignment.LEFT ? LayoutAnchorPosition.Before : LayoutAnchorPosition.After, mode: LayoutAnchorMode.ALIGN };\r\n\r\n\t\t\ttop = layout(window.innerHeight, viewSizeHeight, verticalAnchor) + window.pageYOffset;\r\n\r\n\t\t\t// if view intersects vertically with anchor, we must avoid the anchor\r\n\t\t\tif (Range.intersects({ start: top, end: top + viewSizeHeight }, { start: verticalAnchor.offset, end: verticalAnchor.offset + verticalAnchor.size })) {\r\n\t\t\t\thorizontalAnchor.mode = LayoutAnchorMode.AVOID;\r\n\t\t\t}\r\n\r\n\t\t\tleft = layout(window.innerWidth, viewSizeWidth, horizontalAnchor);\r\n\t\t} else {\r\n\t\t\tconst horizontalAnchor: ILayoutAnchor = { offset: around.left, size: around.width, position: anchorAlignment === AnchorAlignment.LEFT ? LayoutAnchorPosition.Before : LayoutAnchorPosition.After };\r\n\t\t\tconst verticalAnchor: ILayoutAnchor = { offset: around.top, size: around.height, position: anchorPosition === AnchorPosition.BELOW ? LayoutAnchorPosition.Before : LayoutAnchorPosition.After, mode: LayoutAnchorMode.ALIGN };\r\n\r\n\t\t\tleft = layout(window.innerWidth, viewSizeWidth, horizontalAnchor);\r\n\r\n\t\t\t// if view intersects horizontally with anchor, we must avoid the anchor\r\n\t\t\tif (Range.intersects({ start: left, end: left + viewSizeWidth }, { start: horizontalAnchor.offset, end: horizontalAnchor.offset + horizontalAnchor.size })) {\r\n\t\t\t\tverticalAnchor.mode = LayoutAnchorMode.AVOID;\r\n\t\t\t}\r\n\r\n\t\t\ttop = layout(window.innerHeight, viewSizeHeight, verticalAnchor) + window.pageYOffset;\r\n\t\t}\r\n\r\n\t\tthis.view.classList.remove('top', 'bottom', 'left', 'right');\r\n\t\tthis.view.classList.add(anchorPosition === AnchorPosition.BELOW ? 'bottom' : 'top');\r\n\t\tthis.view.classList.add(anchorAlignment === AnchorAlignment.LEFT ? 'left' : 'right');\r\n\t\tthis.view.classList.toggle('fixed', this.useFixedPosition);\r\n\r\n\t\tconst containerPosition = DOM.getDomNodePagePosition(this.container!);\r\n\t\tthis.view.style.top = `${top - (this.useFixedPosition ? DOM.getDomNodePagePosition(this.view).top : containerPosition.top)}px`;\r\n\t\tthis.view.style.left = `${left - (this.useFixedPosition ? DOM.getDomNodePagePosition(this.view).left : containerPosition.left)}px`;\r\n\t\tthis.view.style.width = 'initial';\r\n\t}\r\n\r\n\thide(data?: any): void {\r\n\t\tconst delegate = this.delegate;\r\n\t\tthis.delegate = null;\r\n\r\n\t\tif (delegate?.onHide) {\r\n\t\t\tdelegate.onHide(data);\r\n\t\t}\r\n\r\n\t\tthis.toDisposeOnClean.dispose();\r\n\r\n\t\tDOM.hide(this.view);\r\n\t}\r\n\r\n\tprivate isVisible(): boolean {\r\n\t\treturn !!this.delegate;\r\n\t}\r\n\r\n\tprivate onDOMEvent(e: Event, onCapture: boolean): void {\r\n\t\tif (this.delegate) {\r\n\t\t\tif (this.delegate.onDOMEvent) {\r\n\t\t\t\tthis.delegate.onDOMEvent(e, document.activeElement);\r\n\t\t\t} else if (onCapture && !DOM.isAncestor(e.target, this.container)) {\r\n\t\t\t\tthis.hide();\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis.hide();\r\n\r\n\t\tsuper.dispose();\r\n\t}\r\n}\r\n\r\nlet SHADOW_ROOT_CSS = /* css */ `\r\n\t:host {\r\n\t\tall: initial; /* 1st rule so subsequent properties are reset. */\r\n\t}\r\n\r\n\t@font-face {\r\n\t\tfont-family: \"codicon\";\r\n\t\tsrc: url(\"./codicon.ttf?5d4d76ab2ce5108968ad644d591a16a6\") format(\"truetype\");\r\n\t}\r\n\r\n\t.codicon[class*='codicon-'] {\r\n\t\tfont: normal normal normal 16px/1 codicon;\r\n\t\tdisplay: inline-block;\r\n\t\ttext-decoration: none;\r\n\t\ttext-rendering: auto;\r\n\t\ttext-align: center;\r\n\t\t-webkit-font-smoothing: antialiased;\r\n\t\t-moz-osx-font-smoothing: grayscale;\r\n\t\tuser-select: none;\r\n\t\t-webkit-user-select: none;\r\n\t\t-ms-user-select: none;\r\n\t}\r\n\r\n\t:host {\r\n\t\tfont-family: -apple-system, BlinkMacSystemFont, \"Segoe WPC\", \"Segoe UI\", \"HelveticaNeue-Light\", system-ui, \"Ubuntu\", \"Droid Sans\", sans-serif;\r\n\t}\r\n\r\n\t:host-context(.mac) { font-family: -apple-system, BlinkMacSystemFont, sans-serif; }\r\n\t:host-context(.mac:lang(zh-Hans)) { font-family: -apple-system, BlinkMacSystemFont, \"PingFang SC\", \"Hiragino Sans GB\", sans-serif; }\r\n\t:host-context(.mac:lang(zh-Hant)) { font-family: -apple-system, BlinkMacSystemFont, \"PingFang TC\", sans-serif; }\r\n\t:host-context(.mac:lang(ja)) { font-family: -apple-system, BlinkMacSystemFont, \"Hiragino Kaku Gothic Pro\", sans-serif; }\r\n\t:host-context(.mac:lang(ko)) { font-family: -apple-system, BlinkMacSystemFont, \"Nanum Gothic\", \"Apple SD Gothic Neo\", \"AppleGothic\", sans-serif; }\r\n\r\n\t:host-context(.windows) { font-family: \"Segoe WPC\", \"Segoe UI\", sans-serif; }\r\n\t:host-context(.windows:lang(zh-Hans)) { font-family: \"Segoe WPC\", \"Segoe UI\", \"Microsoft YaHei\", sans-serif; }\r\n\t:host-context(.windows:lang(zh-Hant)) { font-family: \"Segoe WPC\", \"Segoe UI\", \"Microsoft Jhenghei\", sans-serif; }\r\n\t:host-context(.windows:lang(ja)) { font-family: \"Segoe WPC\", \"Segoe UI\", \"Yu Gothic UI\", \"Meiryo UI\", sans-serif; }\r\n\t:host-context(.windows:lang(ko)) { font-family: \"Segoe WPC\", \"Segoe UI\", \"Malgun Gothic\", \"Dotom\", sans-serif; }\r\n\r\n\t:host-context(.linux) { font-family: system-ui, \"Ubuntu\", \"Droid Sans\", sans-serif; }\r\n\t:host-context(.linux:lang(zh-Hans)) { font-family: system-ui, \"Ubuntu\", \"Droid Sans\", \"Source Han Sans SC\", \"Source Han Sans CN\", \"Source Han Sans\", sans-serif; }\r\n\t:host-context(.linux:lang(zh-Hant)) { font-family: system-ui, \"Ubuntu\", \"Droid Sans\", \"Source Han Sans TC\", \"Source Han Sans TW\", \"Source Han Sans\", sans-serif; }\r\n\t:host-context(.linux:lang(ja)) { font-family: system-ui, \"Ubuntu\", \"Droid Sans\", \"Source Han Sans J\", \"Source Han Sans JP\", \"Source Han Sans\", sans-serif; }\r\n\t:host-context(.linux:lang(ko)) { font-family: system-ui, \"Ubuntu\", \"Droid Sans\", \"Source Han Sans K\", \"Source Han Sans JR\", \"Source Han Sans\", \"UnDotum\", \"FBaekmuk Gulim\", sans-serif; }\r\n`;\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./countBadge';\r\nimport { $, append } from 'vs/base/browser/dom';\r\nimport { format } from 'vs/base/common/strings';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { mixin } from 'vs/base/common/objects';\r\nimport { IThemable } from 'vs/base/common/styler';\r\n\r\nexport interface ICountBadgeOptions extends ICountBadgetyles {\r\n\tcount?: number;\r\n\tcountFormat?: string;\r\n\ttitleFormat?: string;\r\n}\r\n\r\nexport interface ICountBadgetyles {\r\n\tbadgeBackground?: Color;\r\n\tbadgeForeground?: Color;\r\n\tbadgeBorder?: Color;\r\n}\r\n\r\nconst defaultOpts = {\r\n\tbadgeBackground: Color.fromHex('#4D4D4D'),\r\n\tbadgeForeground: Color.fromHex('#FFFFFF')\r\n};\r\n\r\nexport class CountBadge implements IThemable {\r\n\r\n\tprivate element: HTMLElement;\r\n\tprivate count: number = 0;\r\n\tprivate countFormat: string;\r\n\tprivate titleFormat: string;\r\n\r\n\tprivate badgeBackground: Color | undefined;\r\n\tprivate badgeForeground: Color | undefined;\r\n\tprivate badgeBorder: Color | undefined;\r\n\r\n\tprivate options: ICountBadgeOptions;\r\n\r\n\tconstructor(container: HTMLElement, options?: ICountBadgeOptions) {\r\n\t\tthis.options = options || Object.create(null);\r\n\t\tmixin(this.options, defaultOpts, false);\r\n\r\n\t\tthis.badgeBackground = this.options.badgeBackground;\r\n\t\tthis.badgeForeground = this.options.badgeForeground;\r\n\t\tthis.badgeBorder = this.options.badgeBorder;\r\n\r\n\t\tthis.element = append(container, $('.monaco-count-badge'));\r\n\t\tthis.countFormat = this.options.countFormat || '{0}';\r\n\t\tthis.titleFormat = this.options.titleFormat || '';\r\n\t\tthis.setCount(this.options.count || 0);\r\n\t}\r\n\r\n\tsetCount(count: number) {\r\n\t\tthis.count = count;\r\n\t\tthis.render();\r\n\t}\r\n\r\n\tsetTitleFormat(titleFormat: string) {\r\n\t\tthis.titleFormat = titleFormat;\r\n\t\tthis.render();\r\n\t}\r\n\r\n\tprivate render() {\r\n\t\tthis.element.textContent = format(this.countFormat, this.count);\r\n\t\tthis.element.title = format(this.titleFormat, this.count);\r\n\r\n\t\tthis.applyStyles();\r\n\t}\r\n\r\n\tstyle(styles: ICountBadgetyles): void {\r\n\t\tthis.badgeBackground = styles.badgeBackground;\r\n\t\tthis.badgeForeground = styles.badgeForeground;\r\n\t\tthis.badgeBorder = styles.badgeBorder;\r\n\r\n\t\tthis.applyStyles();\r\n\t}\r\n\r\n\tprivate applyStyles(): void {\r\n\t\tif (this.element) {\r\n\t\t\tconst background = this.badgeBackground ? this.badgeBackground.toString() : '';\r\n\t\t\tconst foreground = this.badgeForeground ? this.badgeForeground.toString() : '';\r\n\t\t\tconst border = this.badgeBorder ? this.badgeBorder.toString() : '';\r\n\r\n\t\t\tthis.element.style.backgroundColor = background;\r\n\t\t\tthis.element.style.color = foreground;\r\n\r\n\t\t\tthis.element.style.borderWidth = border ? '1px' : '';\r\n\t\t\tthis.element.style.borderStyle = border ? 'solid' : '';\r\n\t\t\tthis.element.style.borderColor = border;\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./mouseCursor';\r\n\r\nexport const MOUSE_CURSOR_TEXT_CSS_CLASS_NAME = `monaco-mouse-cursor-text`;\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./progressbar';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { mixin } from 'vs/base/common/objects';\r\nimport { show } from 'vs/base/browser/dom';\r\nimport { RunOnceScheduler } from 'vs/base/common/async';\r\n\r\nconst CSS_DONE = 'done';\r\nconst CSS_ACTIVE = 'active';\r\nconst CSS_INFINITE = 'infinite';\r\nconst CSS_DISCRETE = 'discrete';\r\n\r\nexport interface IProgressBarOptions extends IProgressBarStyles {\r\n}\r\n\r\nexport interface IProgressBarStyles {\r\n\tprogressBarBackground?: Color;\r\n}\r\n\r\nconst defaultOpts = {\r\n\tprogressBarBackground: Color.fromHex('#0E70C0')\r\n};\r\n\r\n/**\r\n * A progress bar with support for infinite or discrete progress.\r\n */\r\nexport class ProgressBar extends Disposable {\r\n\tprivate options: IProgressBarOptions;\r\n\tprivate workedVal: number;\r\n\tprivate element!: HTMLElement;\r\n\tprivate bit!: HTMLElement;\r\n\tprivate totalWork: number | undefined;\r\n\tprivate progressBarBackground: Color | undefined;\r\n\tprivate showDelayedScheduler: RunOnceScheduler;\r\n\r\n\tconstructor(container: HTMLElement, options?: IProgressBarOptions) {\r\n\t\tsuper();\r\n\r\n\t\tthis.options = options || Object.create(null);\r\n\t\tmixin(this.options, defaultOpts, false);\r\n\r\n\t\tthis.workedVal = 0;\r\n\r\n\t\tthis.progressBarBackground = this.options.progressBarBackground;\r\n\r\n\t\tthis._register(this.showDelayedScheduler = new RunOnceScheduler(() => show(this.element), 0));\r\n\r\n\t\tthis.create(container);\r\n\t}\r\n\r\n\tprivate create(container: HTMLElement): void {\r\n\t\tthis.element = document.createElement('div');\r\n\t\tthis.element.classList.add('monaco-progress-container');\r\n\t\tthis.element.setAttribute('role', 'progressbar');\r\n\t\tthis.element.setAttribute('aria-valuemin', '0');\r\n\t\tcontainer.appendChild(this.element);\r\n\r\n\t\tthis.bit = document.createElement('div');\r\n\t\tthis.bit.classList.add('progress-bit');\r\n\t\tthis.element.appendChild(this.bit);\r\n\r\n\t\tthis.applyStyles();\r\n\t}\r\n\r\n\tprivate off(): void {\r\n\t\tthis.bit.style.width = 'inherit';\r\n\t\tthis.bit.style.opacity = '1';\r\n\t\tthis.element.classList.remove(CSS_ACTIVE, CSS_INFINITE, CSS_DISCRETE);\r\n\r\n\t\tthis.workedVal = 0;\r\n\t\tthis.totalWork = undefined;\r\n\t}\r\n\r\n\t/**\r\n\t * Stops the progressbar from showing any progress instantly without fading out.\r\n\t */\r\n\tstop(): ProgressBar {\r\n\t\treturn this.doDone(false);\r\n\t}\r\n\r\n\tprivate doDone(delayed: boolean): ProgressBar {\r\n\t\tthis.element.classList.add(CSS_DONE);\r\n\r\n\t\t// let it grow to 100% width and hide afterwards\r\n\t\tif (!this.element.classList.contains(CSS_INFINITE)) {\r\n\t\t\tthis.bit.style.width = 'inherit';\r\n\r\n\t\t\tif (delayed) {\r\n\t\t\t\tsetTimeout(() => this.off(), 200);\r\n\t\t\t} else {\r\n\t\t\t\tthis.off();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// let it fade out and hide afterwards\r\n\t\telse {\r\n\t\t\tthis.bit.style.opacity = '0';\r\n\t\t\tif (delayed) {\r\n\t\t\t\tsetTimeout(() => this.off(), 200);\r\n\t\t\t} else {\r\n\t\t\t\tthis.off();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t}\r\n\r\n\t/**\r\n\t * Use this mode to indicate progress that has no total number of work units.\r\n\t */\r\n\tinfinite(): ProgressBar {\r\n\t\tthis.bit.style.width = '2%';\r\n\t\tthis.bit.style.opacity = '1';\r\n\r\n\t\tthis.element.classList.remove(CSS_DISCRETE, CSS_DONE);\r\n\t\tthis.element.classList.add(CSS_ACTIVE, CSS_INFINITE);\r\n\r\n\t\treturn this;\r\n\t}\r\n\r\n\tgetContainer(): HTMLElement {\r\n\t\treturn this.element;\r\n\t}\r\n\r\n\tstyle(styles: IProgressBarStyles): void {\r\n\t\tthis.progressBarBackground = styles.progressBarBackground;\r\n\r\n\t\tthis.applyStyles();\r\n\t}\r\n\r\n\tprotected applyStyles(): void {\r\n\t\tif (this.bit) {\r\n\t\t\tconst background = this.progressBarBackground ? this.progressBarBackground.toString() : '';\r\n\r\n\t\t\tthis.bit.style.backgroundColor = background;\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./sash';\r\nimport { IDisposable, dispose, Disposable, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { isMacintosh } from 'vs/base/common/platform';\r\nimport * as types from 'vs/base/common/types';\r\nimport { EventType, GestureEvent, Gesture } from 'vs/base/browser/touch';\r\nimport { StandardMouseEvent } from 'vs/base/browser/mouseEvent';\r\nimport { Event, Emitter } from 'vs/base/common/event';\r\nimport { getElementsByTagName, EventHelper, createStyleSheet, addDisposableListener, append, $ } from 'vs/base/browser/dom';\r\nimport { domEvent } from 'vs/base/browser/event';\r\n\r\nconst DEBUG = false;\r\n\r\nexport interface ISashLayoutProvider { }\r\n\r\nexport interface IVerticalSashLayoutProvider extends ISashLayoutProvider {\r\n\tgetVerticalSashLeft(sash: Sash): number;\r\n\tgetVerticalSashTop?(sash: Sash): number;\r\n\tgetVerticalSashHeight?(sash: Sash): number;\r\n}\r\n\r\nexport interface IHorizontalSashLayoutProvider extends ISashLayoutProvider {\r\n\tgetHorizontalSashTop(sash: Sash): number;\r\n\tgetHorizontalSashLeft?(sash: Sash): number;\r\n\tgetHorizontalSashWidth?(sash: Sash): number;\r\n}\r\n\r\nexport interface ISashEvent {\r\n\tstartX: number;\r\n\tcurrentX: number;\r\n\tstartY: number;\r\n\tcurrentY: number;\r\n\taltKey: boolean;\r\n}\r\n\r\nexport enum OrthogonalEdge {\r\n\tNorth = 'north',\r\n\tSouth = 'south',\r\n\tEast = 'east',\r\n\tWest = 'west'\r\n}\r\n\r\nexport interface ISashOptions {\r\n\treadonly orientation: Orientation;\r\n\treadonly orthogonalStartSash?: Sash;\r\n\treadonly orthogonalEndSash?: Sash;\r\n\treadonly size?: number;\r\n\treadonly orthogonalEdge?: OrthogonalEdge;\r\n}\r\n\r\nexport const enum Orientation {\r\n\tVERTICAL,\r\n\tHORIZONTAL\r\n}\r\n\r\nexport const enum SashState {\r\n\tDisabled,\r\n\tMinimum,\r\n\tMaximum,\r\n\tEnabled\r\n}\r\n\r\nlet globalSize = 4;\r\nconst onDidChangeGlobalSize = new Emitter();\r\n\r\nexport class Sash extends Disposable {\r\n\r\n\tprivate el: HTMLElement;\r\n\tprivate layoutProvider: ISashLayoutProvider;\r\n\tprivate hidden: boolean;\r\n\tprivate orientation!: Orientation;\r\n\tprivate size: number;\r\n\r\n\tprivate _state: SashState = SashState.Enabled;\r\n\tget state(): SashState { return this._state; }\r\n\tset state(state: SashState) {\r\n\t\tif (this._state === state) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.el.classList.toggle('disabled', state === SashState.Disabled);\r\n\t\tthis.el.classList.toggle('minimum', state === SashState.Minimum);\r\n\t\tthis.el.classList.toggle('maximum', state === SashState.Maximum);\r\n\r\n\t\tthis._state = state;\r\n\t\tthis._onDidEnablementChange.fire(state);\r\n\t}\r\n\r\n\tprivate readonly _onDidEnablementChange = this._register(new Emitter());\r\n\treadonly onDidEnablementChange: Event = this._onDidEnablementChange.event;\r\n\r\n\tprivate readonly _onDidStart = this._register(new Emitter());\r\n\treadonly onDidStart: Event = this._onDidStart.event;\r\n\r\n\tprivate readonly _onDidChange = this._register(new Emitter());\r\n\treadonly onDidChange: Event = this._onDidChange.event;\r\n\r\n\tprivate readonly _onDidReset = this._register(new Emitter());\r\n\treadonly onDidReset: Event = this._onDidReset.event;\r\n\r\n\tprivate readonly _onDidEnd = this._register(new Emitter());\r\n\treadonly onDidEnd: Event = this._onDidEnd.event;\r\n\r\n\tlinkedSash: Sash | undefined = undefined;\r\n\r\n\tprivate readonly orthogonalStartSashDisposables = this._register(new DisposableStore());\r\n\tprivate _orthogonalStartSash: Sash | undefined;\r\n\tget orthogonalStartSash(): Sash | undefined { return this._orthogonalStartSash; }\r\n\tset orthogonalStartSash(sash: Sash | undefined) {\r\n\t\tthis.orthogonalStartSashDisposables.clear();\r\n\r\n\t\tif (sash) {\r\n\t\t\tthis.orthogonalStartSashDisposables.add(sash.onDidEnablementChange(this.onOrthogonalStartSashEnablementChange, this));\r\n\t\t\tthis.onOrthogonalStartSashEnablementChange(sash.state);\r\n\t\t} else {\r\n\t\t\tthis.onOrthogonalStartSashEnablementChange(SashState.Disabled);\r\n\t\t}\r\n\r\n\t\tthis._orthogonalStartSash = sash;\r\n\t}\r\n\r\n\tprivate readonly orthogonalEndSashDisposables = this._register(new DisposableStore());\r\n\tprivate _orthogonalEndSash: Sash | undefined;\r\n\tget orthogonalEndSash(): Sash | undefined { return this._orthogonalEndSash; }\r\n\tset orthogonalEndSash(sash: Sash | undefined) {\r\n\t\tthis.orthogonalEndSashDisposables.clear();\r\n\r\n\t\tif (sash) {\r\n\t\t\tthis.orthogonalEndSashDisposables.add(sash.onDidEnablementChange(this.onOrthogonalEndSashEnablementChange, this));\r\n\t\t\tthis.onOrthogonalEndSashEnablementChange(sash.state);\r\n\t\t} else {\r\n\t\t\tthis.onOrthogonalEndSashEnablementChange(SashState.Disabled);\r\n\t\t}\r\n\r\n\t\tthis._orthogonalEndSash = sash;\r\n\t}\r\n\r\n\tconstructor(container: HTMLElement, layoutProvider: IVerticalSashLayoutProvider, options: ISashOptions);\r\n\tconstructor(container: HTMLElement, layoutProvider: IHorizontalSashLayoutProvider, options: ISashOptions);\r\n\tconstructor(container: HTMLElement, layoutProvider: ISashLayoutProvider, options: ISashOptions) {\r\n\t\tsuper();\r\n\r\n\t\tthis.el = append(container, $('.monaco-sash'));\r\n\r\n\t\tif (options.orthogonalEdge) {\r\n\t\t\tthis.el.classList.add(`orthogonal-edge-${options.orthogonalEdge}`);\r\n\t\t}\r\n\r\n\t\tif (isMacintosh) {\r\n\t\t\tthis.el.classList.add('mac');\r\n\t\t}\r\n\r\n\t\tthis._register(domEvent(this.el, 'mousedown')(this.onMouseDown, this));\r\n\t\tthis._register(domEvent(this.el, 'dblclick')(this.onMouseDoubleClick, this));\r\n\r\n\t\tthis._register(Gesture.addTarget(this.el));\r\n\t\tthis._register(domEvent(this.el, EventType.Start)(this.onTouchStart, this));\r\n\r\n\t\tif (typeof options.size === 'number') {\r\n\t\t\tthis.size = options.size;\r\n\r\n\t\t\tif (options.orientation === Orientation.VERTICAL) {\r\n\t\t\t\tthis.el.style.width = `${this.size}px`;\r\n\t\t\t} else {\r\n\t\t\t\tthis.el.style.height = `${this.size}px`;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tthis.size = globalSize;\r\n\t\t\tthis._register(onDidChangeGlobalSize.event(size => {\r\n\t\t\t\tthis.size = size;\r\n\t\t\t\tthis.layout();\r\n\t\t\t}));\r\n\t\t}\r\n\r\n\t\tthis.hidden = false;\r\n\t\tthis.layoutProvider = layoutProvider;\r\n\r\n\t\tthis.orthogonalStartSash = options.orthogonalStartSash;\r\n\t\tthis.orthogonalEndSash = options.orthogonalEndSash;\r\n\r\n\t\tthis.orientation = options.orientation || Orientation.VERTICAL;\r\n\r\n\t\tif (this.orientation === Orientation.HORIZONTAL) {\r\n\t\t\tthis.el.classList.add('horizontal');\r\n\t\t\tthis.el.classList.remove('vertical');\r\n\t\t} else {\r\n\t\t\tthis.el.classList.remove('horizontal');\r\n\t\t\tthis.el.classList.add('vertical');\r\n\t\t}\r\n\r\n\t\tthis.el.classList.toggle('debug', DEBUG);\r\n\r\n\t\tthis.layout();\r\n\t}\r\n\r\n\tprivate onMouseDown(e: MouseEvent): void {\r\n\t\tEventHelper.stop(e, false);\r\n\r\n\t\tlet isMultisashResize = false;\r\n\r\n\t\tif (!(e as any).__orthogonalSashEvent) {\r\n\t\t\tconst orthogonalSash = this.getOrthogonalSash(e);\r\n\r\n\t\t\tif (orthogonalSash) {\r\n\t\t\t\tisMultisashResize = true;\r\n\t\t\t\t(e as any).__orthogonalSashEvent = true;\r\n\t\t\t\torthogonalSash.onMouseDown(e);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (this.linkedSash && !(e as any).__linkedSashEvent) {\r\n\t\t\t(e as any).__linkedSashEvent = true;\r\n\t\t\tthis.linkedSash.onMouseDown(e);\r\n\t\t}\r\n\r\n\t\tif (!this.state) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// Select both iframes and webviews; internally Electron nests an iframe\r\n\t\t// in its component, but this isn't queryable.\r\n\t\tconst iframes = [\r\n\t\t\t...getElementsByTagName('iframe'),\r\n\t\t\t...getElementsByTagName('webview'),\r\n\t\t];\r\n\r\n\t\tfor (const iframe of iframes) {\r\n\t\t\tiframe.style.pointerEvents = 'none'; // disable mouse events on iframes as long as we drag the sash\r\n\t\t}\r\n\r\n\t\tconst mouseDownEvent = new StandardMouseEvent(e);\r\n\t\tconst startX = mouseDownEvent.posx;\r\n\t\tconst startY = mouseDownEvent.posy;\r\n\t\tconst altKey = mouseDownEvent.altKey;\r\n\t\tconst startEvent: ISashEvent = { startX, currentX: startX, startY, currentY: startY, altKey };\r\n\r\n\t\tthis.el.classList.add('active');\r\n\t\tthis._onDidStart.fire(startEvent);\r\n\r\n\t\t// fix https://github.com/microsoft/vscode/issues/21675\r\n\t\tconst style = createStyleSheet(this.el);\r\n\t\tconst updateStyle = () => {\r\n\t\t\tlet cursor = '';\r\n\r\n\t\t\tif (isMultisashResize) {\r\n\t\t\t\tcursor = 'all-scroll';\r\n\t\t\t} else if (this.orientation === Orientation.HORIZONTAL) {\r\n\t\t\t\tif (this.state === SashState.Minimum) {\r\n\t\t\t\t\tcursor = 's-resize';\r\n\t\t\t\t} else if (this.state === SashState.Maximum) {\r\n\t\t\t\t\tcursor = 'n-resize';\r\n\t\t\t\t} else {\r\n\t\t\t\t\tcursor = isMacintosh ? 'row-resize' : 'ns-resize';\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tif (this.state === SashState.Minimum) {\r\n\t\t\t\t\tcursor = 'e-resize';\r\n\t\t\t\t} else if (this.state === SashState.Maximum) {\r\n\t\t\t\t\tcursor = 'w-resize';\r\n\t\t\t\t} else {\r\n\t\t\t\t\tcursor = isMacintosh ? 'col-resize' : 'ew-resize';\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tstyle.textContent = `* { cursor: ${cursor} !important; }`;\r\n\t\t};\r\n\r\n\t\tconst disposables = new DisposableStore();\r\n\r\n\t\tupdateStyle();\r\n\r\n\t\tif (!isMultisashResize) {\r\n\t\t\tthis.onDidEnablementChange(updateStyle, null, disposables);\r\n\t\t}\r\n\r\n\t\tconst onMouseMove = (e: MouseEvent) => {\r\n\t\t\tEventHelper.stop(e, false);\r\n\t\t\tconst mouseMoveEvent = new StandardMouseEvent(e);\r\n\t\t\tconst event: ISashEvent = { startX, currentX: mouseMoveEvent.posx, startY, currentY: mouseMoveEvent.posy, altKey };\r\n\r\n\t\t\tthis._onDidChange.fire(event);\r\n\t\t};\r\n\r\n\t\tconst onMouseUp = (e: MouseEvent) => {\r\n\t\t\tEventHelper.stop(e, false);\r\n\r\n\t\t\tthis.el.removeChild(style);\r\n\r\n\t\t\tthis.el.classList.remove('active');\r\n\t\t\tthis._onDidEnd.fire();\r\n\r\n\t\t\tdisposables.dispose();\r\n\r\n\t\t\tfor (const iframe of iframes) {\r\n\t\t\t\tiframe.style.pointerEvents = 'auto';\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tdomEvent(window, 'mousemove')(onMouseMove, null, disposables);\r\n\t\tdomEvent(window, 'mouseup')(onMouseUp, null, disposables);\r\n\t}\r\n\r\n\tprivate onMouseDoubleClick(e: MouseEvent): void {\r\n\t\tconst orthogonalSash = this.getOrthogonalSash(e);\r\n\r\n\t\tif (orthogonalSash) {\r\n\t\t\torthogonalSash._onDidReset.fire();\r\n\t\t}\r\n\r\n\t\tif (this.linkedSash) {\r\n\t\t\tthis.linkedSash._onDidReset.fire();\r\n\t\t}\r\n\r\n\t\tthis._onDidReset.fire();\r\n\t}\r\n\r\n\tprivate onTouchStart(event: GestureEvent): void {\r\n\t\tEventHelper.stop(event);\r\n\r\n\t\tconst listeners: IDisposable[] = [];\r\n\r\n\t\tconst startX = event.pageX;\r\n\t\tconst startY = event.pageY;\r\n\t\tconst altKey = event.altKey;\r\n\r\n\t\tthis._onDidStart.fire({\r\n\t\t\tstartX: startX,\r\n\t\t\tcurrentX: startX,\r\n\t\t\tstartY: startY,\r\n\t\t\tcurrentY: startY,\r\n\t\t\taltKey\r\n\t\t});\r\n\r\n\t\tlisteners.push(addDisposableListener(this.el, EventType.Change, (event: GestureEvent) => {\r\n\t\t\tif (types.isNumber(event.pageX) && types.isNumber(event.pageY)) {\r\n\t\t\t\tthis._onDidChange.fire({\r\n\t\t\t\t\tstartX: startX,\r\n\t\t\t\t\tcurrentX: event.pageX,\r\n\t\t\t\t\tstartY: startY,\r\n\t\t\t\t\tcurrentY: event.pageY,\r\n\t\t\t\t\taltKey\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tlisteners.push(addDisposableListener(this.el, EventType.End, (event: GestureEvent) => {\r\n\t\t\tthis._onDidEnd.fire();\r\n\t\t\tdispose(listeners);\r\n\t\t}));\r\n\t}\r\n\r\n\tlayout(): void {\r\n\t\tif (this.orientation === Orientation.VERTICAL) {\r\n\t\t\tconst verticalProvider = (this.layoutProvider);\r\n\t\t\tthis.el.style.left = verticalProvider.getVerticalSashLeft(this) - (this.size / 2) + 'px';\r\n\r\n\t\t\tif (verticalProvider.getVerticalSashTop) {\r\n\t\t\t\tthis.el.style.top = verticalProvider.getVerticalSashTop(this) + 'px';\r\n\t\t\t}\r\n\r\n\t\t\tif (verticalProvider.getVerticalSashHeight) {\r\n\t\t\t\tthis.el.style.height = verticalProvider.getVerticalSashHeight(this) + 'px';\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tconst horizontalProvider = (this.layoutProvider);\r\n\t\t\tthis.el.style.top = horizontalProvider.getHorizontalSashTop(this) - (this.size / 2) + 'px';\r\n\r\n\t\t\tif (horizontalProvider.getHorizontalSashLeft) {\r\n\t\t\t\tthis.el.style.left = horizontalProvider.getHorizontalSashLeft(this) + 'px';\r\n\t\t\t}\r\n\r\n\t\t\tif (horizontalProvider.getHorizontalSashWidth) {\r\n\t\t\t\tthis.el.style.width = horizontalProvider.getHorizontalSashWidth(this) + 'px';\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\thide(): void {\r\n\t\tthis.hidden = true;\r\n\t\tthis.el.style.display = 'none';\r\n\t\tthis.el.setAttribute('aria-hidden', 'true');\r\n\t}\r\n\r\n\tprivate onOrthogonalStartSashEnablementChange(state: SashState): void {\r\n\t\tthis.el.classList.toggle('orthogonal-start', state !== SashState.Disabled);\r\n\t}\r\n\r\n\tprivate onOrthogonalEndSashEnablementChange(state: SashState): void {\r\n\t\tthis.el.classList.toggle('orthogonal-end', state !== SashState.Disabled);\r\n\t}\r\n\r\n\tprivate getOrthogonalSash(e: MouseEvent): Sash | undefined {\r\n\t\tif (this.orientation === Orientation.VERTICAL) {\r\n\t\t\tif (e.offsetY <= this.size) {\r\n\t\t\t\treturn this.orthogonalStartSash;\r\n\t\t\t} else if (e.offsetY >= this.el.clientHeight - this.size) {\r\n\t\t\t\treturn this.orthogonalEndSash;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tif (e.offsetX <= this.size) {\r\n\t\t\t\treturn this.orthogonalStartSash;\r\n\t\t\t} else if (e.offsetX >= this.el.clientWidth - this.size) {\r\n\t\t\t\treturn this.orthogonalEndSash;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tsuper.dispose();\r\n\t\tthis.el.remove();\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./media/scrollbars';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { IMouseEvent, StandardWheelEvent, IMouseWheelEvent } from 'vs/base/browser/mouseEvent';\r\nimport { ScrollbarHost } from 'vs/base/browser/ui/scrollbar/abstractScrollbar';\r\nimport { HorizontalScrollbar } from 'vs/base/browser/ui/scrollbar/horizontalScrollbar';\r\nimport { ScrollableElementChangeOptions, ScrollableElementCreationOptions, ScrollableElementResolvedOptions } from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';\r\nimport { VerticalScrollbar } from 'vs/base/browser/ui/scrollbar/verticalScrollbar';\r\nimport { Widget } from 'vs/base/browser/ui/widget';\r\nimport { TimeoutTimer } from 'vs/base/common/async';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { IDisposable, dispose } from 'vs/base/common/lifecycle';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport { INewScrollDimensions, INewScrollPosition, IScrollDimensions, IScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable';\r\nimport { getZoomFactor } from 'vs/base/browser/browser';\r\n\r\nconst HIDE_TIMEOUT = 500;\r\nconst SCROLL_WHEEL_SENSITIVITY = 50;\r\nconst SCROLL_WHEEL_SMOOTH_SCROLL_ENABLED = true;\r\n\r\nexport interface IOverviewRulerLayoutInfo {\r\n\tparent: HTMLElement;\r\n\tinsertBefore: HTMLElement;\r\n}\r\n\r\nclass MouseWheelClassifierItem {\r\n\tpublic timestamp: number;\r\n\tpublic deltaX: number;\r\n\tpublic deltaY: number;\r\n\tpublic score: number;\r\n\r\n\tconstructor(timestamp: number, deltaX: number, deltaY: number) {\r\n\t\tthis.timestamp = timestamp;\r\n\t\tthis.deltaX = deltaX;\r\n\t\tthis.deltaY = deltaY;\r\n\t\tthis.score = 0;\r\n\t}\r\n}\r\n\r\nexport class MouseWheelClassifier {\r\n\r\n\tpublic static readonly INSTANCE = new MouseWheelClassifier();\r\n\r\n\tprivate readonly _capacity: number;\r\n\tprivate _memory: MouseWheelClassifierItem[];\r\n\tprivate _front: number;\r\n\tprivate _rear: number;\r\n\r\n\tconstructor() {\r\n\t\tthis._capacity = 5;\r\n\t\tthis._memory = [];\r\n\t\tthis._front = -1;\r\n\t\tthis._rear = -1;\r\n\t}\r\n\r\n\tpublic isPhysicalMouseWheel(): boolean {\r\n\t\tif (this._front === -1 && this._rear === -1) {\r\n\t\t\t// no elements\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\t// 0.5 * last + 0.25 * 2nd last + 0.125 * 3rd last + ...\r\n\t\tlet remainingInfluence = 1;\r\n\t\tlet score = 0;\r\n\t\tlet iteration = 1;\r\n\r\n\t\tlet index = this._rear;\r\n\t\tdo {\r\n\t\t\tconst influence = (index === this._front ? remainingInfluence : Math.pow(2, -iteration));\r\n\t\t\tremainingInfluence -= influence;\r\n\t\t\tscore += this._memory[index].score * influence;\r\n\r\n\t\t\tif (index === this._front) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tindex = (this._capacity + index - 1) % this._capacity;\r\n\t\t\titeration++;\r\n\t\t} while (true);\r\n\r\n\t\treturn (score <= 0.5);\r\n\t}\r\n\r\n\tpublic accept(timestamp: number, deltaX: number, deltaY: number): void {\r\n\t\tconst item = new MouseWheelClassifierItem(timestamp, deltaX, deltaY);\r\n\t\titem.score = this._computeScore(item);\r\n\r\n\t\tif (this._front === -1 && this._rear === -1) {\r\n\t\t\tthis._memory[0] = item;\r\n\t\t\tthis._front = 0;\r\n\t\t\tthis._rear = 0;\r\n\t\t} else {\r\n\t\t\tthis._rear = (this._rear + 1) % this._capacity;\r\n\t\t\tif (this._rear === this._front) {\r\n\t\t\t\t// Drop oldest\r\n\t\t\t\tthis._front = (this._front + 1) % this._capacity;\r\n\t\t\t}\r\n\t\t\tthis._memory[this._rear] = item;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * A score between 0 and 1 for `item`.\r\n\t * - a score towards 0 indicates that the source appears to be a physical mouse wheel\r\n\t * - a score towards 1 indicates that the source appears to be a touchpad or magic mouse, etc.\r\n\t */\r\n\tprivate _computeScore(item: MouseWheelClassifierItem): number {\r\n\r\n\t\tif (Math.abs(item.deltaX) > 0 && Math.abs(item.deltaY) > 0) {\r\n\t\t\t// both axes exercised => definitely not a physical mouse wheel\r\n\t\t\treturn 1;\r\n\t\t}\r\n\r\n\t\tlet score: number = 0.5;\r\n\t\tconst prev = (this._front === -1 && this._rear === -1 ? null : this._memory[this._rear]);\r\n\t\tif (prev) {\r\n\t\t\t// const deltaT = item.timestamp - prev.timestamp;\r\n\t\t\t// if (deltaT < 1000 / 30) {\r\n\t\t\t// \t// sooner than X times per second => indicator that this is not a physical mouse wheel\r\n\t\t\t// \tscore += 0.25;\r\n\t\t\t// }\r\n\r\n\t\t\t// if (item.deltaX === prev.deltaX && item.deltaY === prev.deltaY) {\r\n\t\t\t// \t// equal amplitude => indicator that this is a physical mouse wheel\r\n\t\t\t// \tscore -= 0.25;\r\n\t\t\t// }\r\n\t\t}\r\n\r\n\t\tif (!this._isAlmostInt(item.deltaX) || !this._isAlmostInt(item.deltaY)) {\r\n\t\t\t// non-integer deltas => indicator that this is not a physical mouse wheel\r\n\t\t\tscore += 0.25;\r\n\t\t}\r\n\r\n\t\treturn Math.min(Math.max(score, 0), 1);\r\n\t}\r\n\r\n\tprivate _isAlmostInt(value: number): boolean {\r\n\t\tconst delta = Math.abs(Math.round(value) - value);\r\n\t\treturn (delta < 0.01);\r\n\t}\r\n}\r\n\r\nexport abstract class AbstractScrollableElement extends Widget {\r\n\r\n\tprivate readonly _options: ScrollableElementResolvedOptions;\r\n\tprotected readonly _scrollable: Scrollable;\r\n\tprivate readonly _verticalScrollbar: VerticalScrollbar;\r\n\tprivate readonly _horizontalScrollbar: HorizontalScrollbar;\r\n\tprivate readonly _domNode: HTMLElement;\r\n\r\n\tprivate readonly _leftShadowDomNode: FastDomNode | null;\r\n\tprivate readonly _topShadowDomNode: FastDomNode | null;\r\n\tprivate readonly _topLeftShadowDomNode: FastDomNode | null;\r\n\r\n\tprivate readonly _listenOnDomNode: HTMLElement;\r\n\r\n\tprivate _mouseWheelToDispose: IDisposable[];\r\n\r\n\tprivate _isDragging: boolean;\r\n\tprivate _mouseIsOver: boolean;\r\n\r\n\tprivate readonly _hideTimeout: TimeoutTimer;\r\n\tprivate _shouldRender: boolean;\r\n\r\n\tprivate _revealOnScroll: boolean;\r\n\r\n\tprivate readonly _onScroll = this._register(new Emitter());\r\n\tpublic readonly onScroll: Event = this._onScroll.event;\r\n\r\n\tprivate readonly _onWillScroll = this._register(new Emitter());\r\n\r\n\tprotected constructor(element: HTMLElement, options: ScrollableElementCreationOptions, scrollable: Scrollable) {\r\n\t\tsuper();\r\n\t\telement.style.overflow = 'hidden';\r\n\t\tthis._options = resolveOptions(options);\r\n\t\tthis._scrollable = scrollable;\r\n\r\n\t\tthis._register(this._scrollable.onScroll((e) => {\r\n\t\t\tthis._onWillScroll.fire(e);\r\n\t\t\tthis._onDidScroll(e);\r\n\t\t\tthis._onScroll.fire(e);\r\n\t\t}));\r\n\r\n\t\tconst scrollbarHost: ScrollbarHost = {\r\n\t\t\tonMouseWheel: (mouseWheelEvent: StandardWheelEvent) => this._onMouseWheel(mouseWheelEvent),\r\n\t\t\tonDragStart: () => this._onDragStart(),\r\n\t\t\tonDragEnd: () => this._onDragEnd(),\r\n\t\t};\r\n\t\tthis._verticalScrollbar = this._register(new VerticalScrollbar(this._scrollable, this._options, scrollbarHost));\r\n\t\tthis._horizontalScrollbar = this._register(new HorizontalScrollbar(this._scrollable, this._options, scrollbarHost));\r\n\r\n\t\tthis._domNode = document.createElement('div');\r\n\t\tthis._domNode.className = 'monaco-scrollable-element ' + this._options.className;\r\n\t\tthis._domNode.setAttribute('role', 'presentation');\r\n\t\tthis._domNode.style.position = 'relative';\r\n\t\tthis._domNode.style.overflow = 'hidden';\r\n\t\tthis._domNode.appendChild(element);\r\n\t\tthis._domNode.appendChild(this._horizontalScrollbar.domNode.domNode);\r\n\t\tthis._domNode.appendChild(this._verticalScrollbar.domNode.domNode);\r\n\r\n\t\tif (this._options.useShadows) {\r\n\t\t\tthis._leftShadowDomNode = createFastDomNode(document.createElement('div'));\r\n\t\t\tthis._leftShadowDomNode.setClassName('shadow');\r\n\t\t\tthis._domNode.appendChild(this._leftShadowDomNode.domNode);\r\n\r\n\t\t\tthis._topShadowDomNode = createFastDomNode(document.createElement('div'));\r\n\t\t\tthis._topShadowDomNode.setClassName('shadow');\r\n\t\t\tthis._domNode.appendChild(this._topShadowDomNode.domNode);\r\n\r\n\t\t\tthis._topLeftShadowDomNode = createFastDomNode(document.createElement('div'));\r\n\t\t\tthis._topLeftShadowDomNode.setClassName('shadow top-left-corner');\r\n\t\t\tthis._domNode.appendChild(this._topLeftShadowDomNode.domNode);\r\n\t\t} else {\r\n\t\t\tthis._leftShadowDomNode = null;\r\n\t\t\tthis._topShadowDomNode = null;\r\n\t\t\tthis._topLeftShadowDomNode = null;\r\n\t\t}\r\n\r\n\t\tthis._listenOnDomNode = this._options.listenOnDomNode || this._domNode;\r\n\r\n\t\tthis._mouseWheelToDispose = [];\r\n\t\tthis._setListeningToMouseWheel(this._options.handleMouseWheel);\r\n\r\n\t\tthis.onmouseover(this._listenOnDomNode, (e) => this._onMouseOver(e));\r\n\t\tthis.onnonbubblingmouseout(this._listenOnDomNode, (e) => this._onMouseOut(e));\r\n\r\n\t\tthis._hideTimeout = this._register(new TimeoutTimer());\r\n\t\tthis._isDragging = false;\r\n\t\tthis._mouseIsOver = false;\r\n\r\n\t\tthis._shouldRender = true;\r\n\r\n\t\tthis._revealOnScroll = true;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._mouseWheelToDispose = dispose(this._mouseWheelToDispose);\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\t/**\r\n\t * Get the generated 'scrollable' dom node\r\n\t */\r\n\tpublic getDomNode(): HTMLElement {\r\n\t\treturn this._domNode;\r\n\t}\r\n\r\n\tpublic getOverviewRulerLayoutInfo(): IOverviewRulerLayoutInfo {\r\n\t\treturn {\r\n\t\t\tparent: this._domNode,\r\n\t\t\tinsertBefore: this._verticalScrollbar.domNode.domNode,\r\n\t\t};\r\n\t}\r\n\r\n\t/**\r\n\t * Delegate a mouse down event to the vertical scrollbar.\r\n\t * This is to help with clicking somewhere else and having the scrollbar react.\r\n\t */\r\n\tpublic delegateVerticalScrollbarMouseDown(browserEvent: IMouseEvent): void {\r\n\t\tthis._verticalScrollbar.delegateMouseDown(browserEvent);\r\n\t}\r\n\r\n\tpublic getScrollDimensions(): IScrollDimensions {\r\n\t\treturn this._scrollable.getScrollDimensions();\r\n\t}\r\n\r\n\tpublic setScrollDimensions(dimensions: INewScrollDimensions): void {\r\n\t\tthis._scrollable.setScrollDimensions(dimensions, false);\r\n\t}\r\n\r\n\t/**\r\n\t * Update the class name of the scrollable element.\r\n\t */\r\n\tpublic updateClassName(newClassName: string): void {\r\n\t\tthis._options.className = newClassName;\r\n\t\t// Defaults are different on Macs\r\n\t\tif (platform.isMacintosh) {\r\n\t\t\tthis._options.className += ' mac';\r\n\t\t}\r\n\t\tthis._domNode.className = 'monaco-scrollable-element ' + this._options.className;\r\n\t}\r\n\r\n\t/**\r\n\t * Update configuration options for the scrollbar.\r\n\t * Really this is Editor.IEditorScrollbarOptions, but base shouldn't\r\n\t * depend on Editor.\r\n\t */\r\n\tpublic updateOptions(newOptions: ScrollableElementChangeOptions): void {\r\n\t\tif (typeof newOptions.handleMouseWheel !== 'undefined') {\r\n\t\t\tthis._options.handleMouseWheel = newOptions.handleMouseWheel;\r\n\t\t\tthis._setListeningToMouseWheel(this._options.handleMouseWheel);\r\n\t\t}\r\n\t\tif (typeof newOptions.mouseWheelScrollSensitivity !== 'undefined') {\r\n\t\t\tthis._options.mouseWheelScrollSensitivity = newOptions.mouseWheelScrollSensitivity;\r\n\t\t}\r\n\t\tif (typeof newOptions.fastScrollSensitivity !== 'undefined') {\r\n\t\t\tthis._options.fastScrollSensitivity = newOptions.fastScrollSensitivity;\r\n\t\t}\r\n\t\tif (typeof newOptions.scrollPredominantAxis !== 'undefined') {\r\n\t\t\tthis._options.scrollPredominantAxis = newOptions.scrollPredominantAxis;\r\n\t\t}\r\n\t\tif (typeof newOptions.horizontalScrollbarSize !== 'undefined') {\r\n\t\t\tthis._horizontalScrollbar.updateScrollbarSize(newOptions.horizontalScrollbarSize);\r\n\t\t}\r\n\r\n\t\tif (!this._options.lazyRender) {\r\n\t\t\tthis._render();\r\n\t\t}\r\n\t}\r\n\r\n\t// -------------------- mouse wheel scrolling --------------------\r\n\r\n\tprivate _setListeningToMouseWheel(shouldListen: boolean): void {\r\n\t\tconst isListening = (this._mouseWheelToDispose.length > 0);\r\n\r\n\t\tif (isListening === shouldListen) {\r\n\t\t\t// No change\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// Stop listening (if necessary)\r\n\t\tthis._mouseWheelToDispose = dispose(this._mouseWheelToDispose);\r\n\r\n\t\t// Start listening (if necessary)\r\n\t\tif (shouldListen) {\r\n\t\t\tconst onMouseWheel = (browserEvent: IMouseWheelEvent) => {\r\n\t\t\t\tthis._onMouseWheel(new StandardWheelEvent(browserEvent));\r\n\t\t\t};\r\n\r\n\t\t\tthis._mouseWheelToDispose.push(dom.addDisposableListener(this._listenOnDomNode, dom.EventType.MOUSE_WHEEL, onMouseWheel, { passive: false }));\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _onMouseWheel(e: StandardWheelEvent): void {\r\n\r\n\t\tconst classifier = MouseWheelClassifier.INSTANCE;\r\n\t\tif (SCROLL_WHEEL_SMOOTH_SCROLL_ENABLED) {\r\n\t\t\tconst osZoomFactor = window.devicePixelRatio / getZoomFactor();\r\n\t\t\tif (platform.isWindows || platform.isLinux) {\r\n\t\t\t\t// On Windows and Linux, the incoming delta events are multiplied with the OS zoom factor.\r\n\t\t\t\t// The OS zoom factor can be reverse engineered by using the device pixel ratio and the configured zoom factor into account.\r\n\t\t\t\tclassifier.accept(Date.now(), e.deltaX / osZoomFactor, e.deltaY / osZoomFactor);\r\n\t\t\t} else {\r\n\t\t\t\tclassifier.accept(Date.now(), e.deltaX, e.deltaY);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// console.log(`${Date.now()}, ${e.deltaY}, ${e.deltaX}`);\r\n\r\n\t\tlet didScroll = false;\r\n\r\n\t\tif (e.deltaY || e.deltaX) {\r\n\t\t\tlet deltaY = e.deltaY * this._options.mouseWheelScrollSensitivity;\r\n\t\t\tlet deltaX = e.deltaX * this._options.mouseWheelScrollSensitivity;\r\n\r\n\t\t\tif (this._options.scrollPredominantAxis) {\r\n\t\t\t\tif (Math.abs(deltaY) >= Math.abs(deltaX)) {\r\n\t\t\t\t\tdeltaX = 0;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tdeltaY = 0;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (this._options.flipAxes) {\r\n\t\t\t\t[deltaY, deltaX] = [deltaX, deltaY];\r\n\t\t\t}\r\n\r\n\t\t\t// Convert vertical scrolling to horizontal if shift is held, this\r\n\t\t\t// is handled at a higher level on Mac\r\n\t\t\tconst shiftConvert = !platform.isMacintosh && e.browserEvent && e.browserEvent.shiftKey;\r\n\t\t\tif ((this._options.scrollYToX || shiftConvert) && !deltaX) {\r\n\t\t\t\tdeltaX = deltaY;\r\n\t\t\t\tdeltaY = 0;\r\n\t\t\t}\r\n\r\n\t\t\tif (e.browserEvent && e.browserEvent.altKey) {\r\n\t\t\t\t// fastScrolling\r\n\t\t\t\tdeltaX = deltaX * this._options.fastScrollSensitivity;\r\n\t\t\t\tdeltaY = deltaY * this._options.fastScrollSensitivity;\r\n\t\t\t}\r\n\r\n\t\t\tconst futureScrollPosition = this._scrollable.getFutureScrollPosition();\r\n\r\n\t\t\tlet desiredScrollPosition: INewScrollPosition = {};\r\n\t\t\tif (deltaY) {\r\n\t\t\t\tconst desiredScrollTop = futureScrollPosition.scrollTop - SCROLL_WHEEL_SENSITIVITY * deltaY;\r\n\t\t\t\tthis._verticalScrollbar.writeScrollPosition(desiredScrollPosition, desiredScrollTop);\r\n\t\t\t}\r\n\t\t\tif (deltaX) {\r\n\t\t\t\tconst desiredScrollLeft = futureScrollPosition.scrollLeft - SCROLL_WHEEL_SENSITIVITY * deltaX;\r\n\t\t\t\tthis._horizontalScrollbar.writeScrollPosition(desiredScrollPosition, desiredScrollLeft);\r\n\t\t\t}\r\n\r\n\t\t\t// Check that we are scrolling towards a location which is valid\r\n\t\t\tdesiredScrollPosition = this._scrollable.validateScrollPosition(desiredScrollPosition);\r\n\r\n\t\t\tif (futureScrollPosition.scrollLeft !== desiredScrollPosition.scrollLeft || futureScrollPosition.scrollTop !== desiredScrollPosition.scrollTop) {\r\n\r\n\t\t\t\tconst canPerformSmoothScroll = (\r\n\t\t\t\t\tSCROLL_WHEEL_SMOOTH_SCROLL_ENABLED\r\n\t\t\t\t\t&& this._options.mouseWheelSmoothScroll\r\n\t\t\t\t\t&& classifier.isPhysicalMouseWheel()\r\n\t\t\t\t);\r\n\r\n\t\t\t\tif (canPerformSmoothScroll) {\r\n\t\t\t\t\tthis._scrollable.setScrollPositionSmooth(desiredScrollPosition);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis._scrollable.setScrollPositionNow(desiredScrollPosition);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tdidScroll = true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet consumeMouseWheel = didScroll;\r\n\t\tif (!consumeMouseWheel && this._options.alwaysConsumeMouseWheel) {\r\n\t\t\tconsumeMouseWheel = true;\r\n\t\t}\r\n\t\tif (!consumeMouseWheel && this._options.consumeMouseWheelIfScrollbarIsNeeded && (this._verticalScrollbar.isNeeded() || this._horizontalScrollbar.isNeeded())) {\r\n\t\t\tconsumeMouseWheel = true;\r\n\t\t}\r\n\r\n\t\tif (consumeMouseWheel) {\r\n\t\t\te.preventDefault();\r\n\t\t\te.stopPropagation();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _onDidScroll(e: ScrollEvent): void {\r\n\t\tthis._shouldRender = this._horizontalScrollbar.onDidScroll(e) || this._shouldRender;\r\n\t\tthis._shouldRender = this._verticalScrollbar.onDidScroll(e) || this._shouldRender;\r\n\r\n\t\tif (this._options.useShadows) {\r\n\t\t\tthis._shouldRender = true;\r\n\t\t}\r\n\r\n\t\tif (this._revealOnScroll) {\r\n\t\t\tthis._reveal();\r\n\t\t}\r\n\r\n\t\tif (!this._options.lazyRender) {\r\n\t\t\tthis._render();\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Render / mutate the DOM now.\r\n\t * Should be used together with the ctor option `lazyRender`.\r\n\t */\r\n\tpublic renderNow(): void {\r\n\t\tif (!this._options.lazyRender) {\r\n\t\t\tthrow new Error('Please use `lazyRender` together with `renderNow`!');\r\n\t\t}\r\n\r\n\t\tthis._render();\r\n\t}\r\n\r\n\tprivate _render(): void {\r\n\t\tif (!this._shouldRender) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._shouldRender = false;\r\n\r\n\t\tthis._horizontalScrollbar.render();\r\n\t\tthis._verticalScrollbar.render();\r\n\r\n\t\tif (this._options.useShadows) {\r\n\t\t\tconst scrollState = this._scrollable.getCurrentScrollPosition();\r\n\t\t\tconst enableTop = scrollState.scrollTop > 0;\r\n\t\t\tconst enableLeft = scrollState.scrollLeft > 0;\r\n\r\n\t\t\tthis._leftShadowDomNode!.setClassName('shadow' + (enableLeft ? ' left' : ''));\r\n\t\t\tthis._topShadowDomNode!.setClassName('shadow' + (enableTop ? ' top' : ''));\r\n\t\t\tthis._topLeftShadowDomNode!.setClassName('shadow top-left-corner' + (enableTop ? ' top' : '') + (enableLeft ? ' left' : ''));\r\n\t\t}\r\n\t}\r\n\r\n\t// -------------------- fade in / fade out --------------------\r\n\r\n\tprivate _onDragStart(): void {\r\n\t\tthis._isDragging = true;\r\n\t\tthis._reveal();\r\n\t}\r\n\r\n\tprivate _onDragEnd(): void {\r\n\t\tthis._isDragging = false;\r\n\t\tthis._hide();\r\n\t}\r\n\r\n\tprivate _onMouseOut(e: IMouseEvent): void {\r\n\t\tthis._mouseIsOver = false;\r\n\t\tthis._hide();\r\n\t}\r\n\r\n\tprivate _onMouseOver(e: IMouseEvent): void {\r\n\t\tthis._mouseIsOver = true;\r\n\t\tthis._reveal();\r\n\t}\r\n\r\n\tprivate _reveal(): void {\r\n\t\tthis._verticalScrollbar.beginReveal();\r\n\t\tthis._horizontalScrollbar.beginReveal();\r\n\t\tthis._scheduleHide();\r\n\t}\r\n\r\n\tprivate _hide(): void {\r\n\t\tif (!this._mouseIsOver && !this._isDragging) {\r\n\t\t\tthis._verticalScrollbar.beginHide();\r\n\t\t\tthis._horizontalScrollbar.beginHide();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _scheduleHide(): void {\r\n\t\tif (!this._mouseIsOver && !this._isDragging) {\r\n\t\t\tthis._hideTimeout.cancelAndSet(() => this._hide(), HIDE_TIMEOUT);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class ScrollableElement extends AbstractScrollableElement {\r\n\r\n\tconstructor(element: HTMLElement, options: ScrollableElementCreationOptions) {\r\n\t\toptions = options || {};\r\n\t\toptions.mouseWheelSmoothScroll = false;\r\n\t\tconst scrollable = new Scrollable(0, (callback) => dom.scheduleAtNextAnimationFrame(callback));\r\n\t\tsuper(element, options, scrollable);\r\n\t\tthis._register(scrollable);\r\n\t}\r\n\r\n\tpublic setScrollPosition(update: INewScrollPosition): void {\r\n\t\tthis._scrollable.setScrollPositionNow(update);\r\n\t}\r\n}\r\n\r\nexport class SmoothScrollableElement extends AbstractScrollableElement {\r\n\r\n\tconstructor(element: HTMLElement, options: ScrollableElementCreationOptions, scrollable: Scrollable) {\r\n\t\tsuper(element, options, scrollable);\r\n\t}\r\n\r\n\tpublic setScrollPosition(update: INewScrollPosition & { reuseAnimation?: boolean }): void {\r\n\t\tif (update.reuseAnimation) {\r\n\t\t\tthis._scrollable.setScrollPositionSmooth(update, update.reuseAnimation);\r\n\t\t} else {\r\n\t\t\tthis._scrollable.setScrollPositionNow(update);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getScrollPosition(): IScrollPosition {\r\n\t\treturn this._scrollable.getCurrentScrollPosition();\r\n\t}\r\n\r\n}\r\n\r\nexport class DomScrollableElement extends ScrollableElement {\r\n\r\n\tprivate _element: HTMLElement;\r\n\r\n\tconstructor(element: HTMLElement, options: ScrollableElementCreationOptions) {\r\n\t\tsuper(element, options);\r\n\t\tthis._element = element;\r\n\t\tthis.onScroll((e) => {\r\n\t\t\tif (e.scrollTopChanged) {\r\n\t\t\t\tthis._element.scrollTop = e.scrollTop;\r\n\t\t\t}\r\n\t\t\tif (e.scrollLeftChanged) {\r\n\t\t\t\tthis._element.scrollLeft = e.scrollLeft;\r\n\t\t\t}\r\n\t\t});\r\n\t\tthis.scanDomNode();\r\n\t}\r\n\r\n\tpublic scanDomNode(): void {\r\n\t\t// width, scrollLeft, scrollWidth, height, scrollTop, scrollHeight\r\n\t\tthis.setScrollDimensions({\r\n\t\t\twidth: this._element.clientWidth,\r\n\t\t\tscrollWidth: this._element.scrollWidth,\r\n\t\t\theight: this._element.clientHeight,\r\n\t\t\tscrollHeight: this._element.scrollHeight\r\n\t\t});\r\n\t\tthis.setScrollPosition({\r\n\t\t\tscrollLeft: this._element.scrollLeft,\r\n\t\t\tscrollTop: this._element.scrollTop,\r\n\t\t});\r\n\t}\r\n}\r\n\r\nfunction resolveOptions(opts: ScrollableElementCreationOptions): ScrollableElementResolvedOptions {\r\n\tconst result: ScrollableElementResolvedOptions = {\r\n\t\tlazyRender: (typeof opts.lazyRender !== 'undefined' ? opts.lazyRender : false),\r\n\t\tclassName: (typeof opts.className !== 'undefined' ? opts.className : ''),\r\n\t\tuseShadows: (typeof opts.useShadows !== 'undefined' ? opts.useShadows : true),\r\n\t\thandleMouseWheel: (typeof opts.handleMouseWheel !== 'undefined' ? opts.handleMouseWheel : true),\r\n\t\tflipAxes: (typeof opts.flipAxes !== 'undefined' ? opts.flipAxes : false),\r\n\t\tconsumeMouseWheelIfScrollbarIsNeeded: (typeof opts.consumeMouseWheelIfScrollbarIsNeeded !== 'undefined' ? opts.consumeMouseWheelIfScrollbarIsNeeded : false),\r\n\t\talwaysConsumeMouseWheel: (typeof opts.alwaysConsumeMouseWheel !== 'undefined' ? opts.alwaysConsumeMouseWheel : false),\r\n\t\tscrollYToX: (typeof opts.scrollYToX !== 'undefined' ? opts.scrollYToX : false),\r\n\t\tmouseWheelScrollSensitivity: (typeof opts.mouseWheelScrollSensitivity !== 'undefined' ? opts.mouseWheelScrollSensitivity : 1),\r\n\t\tfastScrollSensitivity: (typeof opts.fastScrollSensitivity !== 'undefined' ? opts.fastScrollSensitivity : 5),\r\n\t\tscrollPredominantAxis: (typeof opts.scrollPredominantAxis !== 'undefined' ? opts.scrollPredominantAxis : true),\r\n\t\tmouseWheelSmoothScroll: (typeof opts.mouseWheelSmoothScroll !== 'undefined' ? opts.mouseWheelSmoothScroll : true),\r\n\t\tarrowSize: (typeof opts.arrowSize !== 'undefined' ? opts.arrowSize : 11),\r\n\r\n\t\tlistenOnDomNode: (typeof opts.listenOnDomNode !== 'undefined' ? opts.listenOnDomNode : null),\r\n\r\n\t\thorizontal: (typeof opts.horizontal !== 'undefined' ? opts.horizontal : ScrollbarVisibility.Auto),\r\n\t\thorizontalScrollbarSize: (typeof opts.horizontalScrollbarSize !== 'undefined' ? opts.horizontalScrollbarSize : 10),\r\n\t\thorizontalSliderSize: (typeof opts.horizontalSliderSize !== 'undefined' ? opts.horizontalSliderSize : 0),\r\n\t\thorizontalHasArrows: (typeof opts.horizontalHasArrows !== 'undefined' ? opts.horizontalHasArrows : false),\r\n\r\n\t\tvertical: (typeof opts.vertical !== 'undefined' ? opts.vertical : ScrollbarVisibility.Auto),\r\n\t\tverticalScrollbarSize: (typeof opts.verticalScrollbarSize !== 'undefined' ? opts.verticalScrollbarSize : 10),\r\n\t\tverticalHasArrows: (typeof opts.verticalHasArrows !== 'undefined' ? opts.verticalHasArrows : false),\r\n\t\tverticalSliderSize: (typeof opts.verticalSliderSize !== 'undefined' ? opts.verticalSliderSize : 0),\r\n\r\n\t\tscrollByPage: (typeof opts.scrollByPage !== 'undefined' ? opts.scrollByPage : false)\r\n\t};\r\n\r\n\tresult.horizontalSliderSize = (typeof opts.horizontalSliderSize !== 'undefined' ? opts.horizontalSliderSize : result.horizontalScrollbarSize);\r\n\tresult.verticalSliderSize = (typeof opts.verticalSliderSize !== 'undefined' ? opts.verticalSliderSize : result.verticalScrollbarSize);\r\n\r\n\t// Defaults are different on Macs\r\n\tif (platform.isMacintosh) {\r\n\t\tresult.className += ' mac';\r\n\t}\r\n\r\n\treturn result;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./hover';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { IDisposable, Disposable } from 'vs/base/common/lifecycle';\r\nimport { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';\r\n\r\nconst $ = dom.$;\r\n\r\nexport class HoverWidget extends Disposable {\r\n\r\n\tpublic readonly containerDomNode: HTMLElement;\r\n\tpublic readonly contentsDomNode: HTMLElement;\r\n\tprivate readonly _scrollbar: DomScrollableElement;\r\n\r\n\tconstructor() {\r\n\t\tsuper();\r\n\r\n\t\tthis.containerDomNode = document.createElement('div');\r\n\t\tthis.containerDomNode.className = 'monaco-hover';\r\n\t\tthis.containerDomNode.tabIndex = 0;\r\n\t\tthis.containerDomNode.setAttribute('role', 'tooltip');\r\n\r\n\t\tthis.contentsDomNode = document.createElement('div');\r\n\t\tthis.contentsDomNode.className = 'monaco-hover-content';\r\n\r\n\t\tthis._scrollbar = this._register(new DomScrollableElement(this.contentsDomNode, {\r\n\t\t\tconsumeMouseWheelIfScrollbarIsNeeded: true\r\n\t\t}));\r\n\t\tthis.containerDomNode.appendChild(this._scrollbar.getDomNode());\r\n\t}\r\n\r\n\tpublic onContentsChanged(): void {\r\n\t\tthis._scrollbar.scanDomNode();\r\n\t}\r\n}\r\n\r\nexport function renderHoverAction(parent: HTMLElement, actionOptions: { label: string, iconClass?: string, run: (target: HTMLElement) => void, commandId: string }, keybindingLabel: string | null): IDisposable {\r\n\tconst actionContainer = dom.append(parent, $('div.action-container'));\r\n\tconst action = dom.append(actionContainer, $('a.action'));\r\n\taction.setAttribute('href', '#');\r\n\taction.setAttribute('role', 'button');\r\n\tif (actionOptions.iconClass) {\r\n\t\tdom.append(action, $(`span.icon.${actionOptions.iconClass}`));\r\n\t}\r\n\tconst label = dom.append(action, $('span'));\r\n\tlabel.textContent = keybindingLabel ? `${actionOptions.label} (${keybindingLabel})` : actionOptions.label;\r\n\treturn dom.addDisposableListener(actionContainer, dom.EventType.CLICK, e => {\r\n\t\te.stopPropagation();\r\n\t\te.preventDefault();\r\n\t\tactionOptions.run(actionContainer);\r\n\t});\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { getOrDefault } from 'vs/base/common/objects';\r\nimport { IDisposable, dispose, Disposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { Gesture, EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch';\r\nimport { Event, Emitter } from 'vs/base/common/event';\r\nimport { domEvent } from 'vs/base/browser/event';\r\nimport { SmoothScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';\r\nimport { ScrollEvent, ScrollbarVisibility, INewScrollDimensions, Scrollable } from 'vs/base/common/scrollable';\r\nimport { RangeMap, shift } from './rangeMap';\r\nimport { IListVirtualDelegate, IListRenderer, IListMouseEvent, IListTouchEvent, IListGestureEvent, IListDragEvent, IListDragAndDrop, ListDragOverEffect } from './list';\r\nimport { RowCache, IRow } from './rowCache';\r\nimport { ISpliceable } from 'vs/base/common/sequence';\r\nimport { memoize } from 'vs/base/common/decorators';\r\nimport { Range, IRange } from 'vs/base/common/range';\r\nimport { equals, distinct } from 'vs/base/common/arrays';\r\nimport { DataTransfers, StaticDND, IDragAndDropData } from 'vs/base/browser/dnd';\r\nimport { disposableTimeout, Delayer } from 'vs/base/common/async';\r\nimport { isFirefox } from 'vs/base/browser/browser';\r\nimport { $, animate, getContentHeight, getContentWidth, getTopLeftOffset, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom';\r\n\r\ninterface IItem {\r\n\treadonly id: string;\r\n\treadonly element: T;\r\n\treadonly templateId: string;\r\n\trow: IRow | null;\r\n\tsize: number;\r\n\twidth: number | undefined;\r\n\thasDynamicHeight: boolean;\r\n\tlastDynamicHeightWidth: number | undefined;\r\n\turi: string | undefined;\r\n\tdropTarget: boolean;\r\n\tdragStartDisposable: IDisposable;\r\n}\r\n\r\nexport interface IListViewDragAndDrop extends IListDragAndDrop {\r\n\tgetDragElements(element: T): T[];\r\n}\r\n\r\nexport interface IListViewAccessibilityProvider {\r\n\tgetSetSize?(element: T, index: number, listLength: number): number;\r\n\tgetPosInSet?(element: T, index: number): number;\r\n\tgetRole?(element: T): string | undefined;\r\n\tisChecked?(element: T): boolean | undefined;\r\n}\r\n\r\nexport interface IListViewOptionsUpdate {\r\n\treadonly additionalScrollHeight?: number;\r\n\treadonly smoothScrolling?: boolean;\r\n\treadonly horizontalScrolling?: boolean;\r\n}\r\n\r\nexport interface IListViewOptions extends IListViewOptionsUpdate {\r\n\treadonly dnd?: IListViewDragAndDrop;\r\n\treadonly useShadows?: boolean;\r\n\treadonly verticalScrollMode?: ScrollbarVisibility;\r\n\treadonly setRowLineHeight?: boolean;\r\n\treadonly setRowHeight?: boolean;\r\n\treadonly supportDynamicHeights?: boolean;\r\n\treadonly mouseSupport?: boolean;\r\n\treadonly accessibilityProvider?: IListViewAccessibilityProvider;\r\n\treadonly transformOptimization?: boolean;\r\n}\r\n\r\nconst DefaultOptions = {\r\n\tuseShadows: true,\r\n\tverticalScrollMode: ScrollbarVisibility.Auto,\r\n\tsetRowLineHeight: true,\r\n\tsetRowHeight: true,\r\n\tsupportDynamicHeights: false,\r\n\tdnd: {\r\n\t\tgetDragElements(e: T) { return [e]; },\r\n\t\tgetDragURI() { return null; },\r\n\t\tonDragStart(): void { },\r\n\t\tonDragOver() { return false; },\r\n\t\tdrop() { }\r\n\t},\r\n\thorizontalScrolling: false,\r\n\ttransformOptimization: true\r\n};\r\n\r\nexport class ElementsDragAndDropData implements IDragAndDropData {\r\n\r\n\treadonly elements: T[];\r\n\r\n\tconstructor(elements: T[]) {\r\n\t\tthis.elements = elements;\r\n\t}\r\n\r\n\tupdate(): void { }\r\n\r\n\tgetData(): T[] {\r\n\t\treturn this.elements;\r\n\t}\r\n}\r\n\r\nexport class ExternalElementsDragAndDropData implements IDragAndDropData {\r\n\r\n\treadonly elements: T[];\r\n\r\n\tconstructor(elements: T[]) {\r\n\t\tthis.elements = elements;\r\n\t}\r\n\r\n\tupdate(): void { }\r\n\r\n\tgetData(): T[] {\r\n\t\treturn this.elements;\r\n\t}\r\n}\r\n\r\nexport class NativeDragAndDropData implements IDragAndDropData {\r\n\r\n\treadonly types: any[];\r\n\treadonly files: any[];\r\n\r\n\tconstructor() {\r\n\t\tthis.types = [];\r\n\t\tthis.files = [];\r\n\t}\r\n\r\n\tupdate(dataTransfer: DataTransfer): void {\r\n\t\tif (dataTransfer.types) {\r\n\t\t\tthis.types.splice(0, this.types.length, ...dataTransfer.types);\r\n\t\t}\r\n\r\n\t\tif (dataTransfer.files) {\r\n\t\t\tthis.files.splice(0, this.files.length);\r\n\r\n\t\t\tfor (let i = 0; i < dataTransfer.files.length; i++) {\r\n\t\t\t\tconst file = dataTransfer.files.item(i);\r\n\r\n\t\t\t\tif (file && (file.size || file.type)) {\r\n\t\t\t\t\tthis.files.push(file);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tgetData(): any {\r\n\t\treturn {\r\n\t\t\ttypes: this.types,\r\n\t\t\tfiles: this.files\r\n\t\t};\r\n\t}\r\n}\r\n\r\nfunction equalsDragFeedback(f1: number[] | undefined, f2: number[] | undefined): boolean {\r\n\tif (Array.isArray(f1) && Array.isArray(f2)) {\r\n\t\treturn equals(f1, f2!);\r\n\t}\r\n\r\n\treturn f1 === f2;\r\n}\r\n\r\nclass ListViewAccessibilityProvider implements Required> {\r\n\r\n\treadonly getSetSize: (element: any, index: number, listLength: number) => number;\r\n\treadonly getPosInSet: (element: any, index: number) => number;\r\n\treadonly getRole: (element: T) => string | undefined;\r\n\treadonly isChecked: (element: T) => boolean | undefined;\r\n\r\n\tconstructor(accessibilityProvider?: IListViewAccessibilityProvider) {\r\n\t\tif (accessibilityProvider?.getSetSize) {\r\n\t\t\tthis.getSetSize = accessibilityProvider.getSetSize.bind(accessibilityProvider);\r\n\t\t} else {\r\n\t\t\tthis.getSetSize = (e, i, l) => l;\r\n\t\t}\r\n\r\n\t\tif (accessibilityProvider?.getPosInSet) {\r\n\t\t\tthis.getPosInSet = accessibilityProvider.getPosInSet.bind(accessibilityProvider);\r\n\t\t} else {\r\n\t\t\tthis.getPosInSet = (e, i) => i + 1;\r\n\t\t}\r\n\r\n\t\tif (accessibilityProvider?.getRole) {\r\n\t\t\tthis.getRole = accessibilityProvider.getRole.bind(accessibilityProvider);\r\n\t\t} else {\r\n\t\t\tthis.getRole = _ => 'listitem';\r\n\t\t}\r\n\r\n\t\tif (accessibilityProvider?.isChecked) {\r\n\t\t\tthis.isChecked = accessibilityProvider.isChecked.bind(accessibilityProvider);\r\n\t\t} else {\r\n\t\t\tthis.isChecked = _ => undefined;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class ListView implements ISpliceable, IDisposable {\r\n\r\n\tprivate static InstanceCount = 0;\r\n\treadonly domId = `list_id_${++ListView.InstanceCount}`;\r\n\r\n\treadonly domNode: HTMLElement;\r\n\r\n\tprivate items: IItem[];\r\n\tprivate itemId: number;\r\n\tprivate rangeMap: RangeMap;\r\n\tprivate cache: RowCache;\r\n\tprivate renderers = new Map>();\r\n\tprivate lastRenderTop: number;\r\n\tprivate lastRenderHeight: number;\r\n\tprivate renderWidth = 0;\r\n\tprivate rowsContainer: HTMLElement;\r\n\tprivate scrollable: Scrollable;\r\n\tprivate scrollableElement: SmoothScrollableElement;\r\n\tprivate _scrollHeight: number = 0;\r\n\tprivate scrollableElementUpdateDisposable: IDisposable | null = null;\r\n\tprivate scrollableElementWidthDelayer = new Delayer(50);\r\n\tprivate splicing = false;\r\n\tprivate dragOverAnimationDisposable: IDisposable | undefined;\r\n\tprivate dragOverAnimationStopDisposable: IDisposable = Disposable.None;\r\n\tprivate dragOverMouseY: number = 0;\r\n\tprivate setRowLineHeight: boolean;\r\n\tprivate setRowHeight: boolean;\r\n\tprivate supportDynamicHeights: boolean;\r\n\tprivate additionalScrollHeight: number;\r\n\tprivate accessibilityProvider: ListViewAccessibilityProvider;\r\n\tprivate scrollWidth: number | undefined;\r\n\r\n\tprivate dnd: IListViewDragAndDrop;\r\n\tprivate canDrop: boolean = false;\r\n\tprivate currentDragData: IDragAndDropData | undefined;\r\n\tprivate currentDragFeedback: number[] | undefined;\r\n\tprivate currentDragFeedbackDisposable: IDisposable = Disposable.None;\r\n\tprivate onDragLeaveTimeout: IDisposable = Disposable.None;\r\n\r\n\tprivate readonly disposables: DisposableStore = new DisposableStore();\r\n\r\n\tprivate readonly _onDidChangeContentHeight = new Emitter();\r\n\tget contentHeight(): number { return this.rangeMap.size; }\r\n\r\n\tprivate _horizontalScrolling: boolean = false;\r\n\tprivate get horizontalScrolling(): boolean { return this._horizontalScrolling; }\r\n\tprivate set horizontalScrolling(value: boolean) {\r\n\t\tif (value === this._horizontalScrolling) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (value && this.supportDynamicHeights) {\r\n\t\t\tthrow new Error('Horizontal scrolling and dynamic heights not supported simultaneously');\r\n\t\t}\r\n\r\n\t\tthis._horizontalScrolling = value;\r\n\t\tthis.domNode.classList.toggle('horizontal-scrolling', this._horizontalScrolling);\r\n\r\n\t\tif (this._horizontalScrolling) {\r\n\t\t\tfor (const item of this.items) {\r\n\t\t\t\tthis.measureItemWidth(item);\r\n\t\t\t}\r\n\r\n\t\t\tthis.updateScrollWidth();\r\n\t\t\tthis.scrollableElement.setScrollDimensions({ width: getContentWidth(this.domNode) });\r\n\t\t\tthis.rowsContainer.style.width = `${Math.max(this.scrollWidth || 0, this.renderWidth)}px`;\r\n\t\t} else {\r\n\t\t\tthis.scrollableElementWidthDelayer.cancel();\r\n\t\t\tthis.scrollableElement.setScrollDimensions({ width: this.renderWidth, scrollWidth: this.renderWidth });\r\n\t\t\tthis.rowsContainer.style.width = '';\r\n\t\t}\r\n\t}\r\n\r\n\tconstructor(\r\n\t\tcontainer: HTMLElement,\r\n\t\tprivate virtualDelegate: IListVirtualDelegate,\r\n\t\trenderers: IListRenderer[],\r\n\t\toptions: IListViewOptions = DefaultOptions as IListViewOptions\r\n\t) {\r\n\t\tif (options.horizontalScrolling && options.supportDynamicHeights) {\r\n\t\t\tthrow new Error('Horizontal scrolling and dynamic heights not supported simultaneously');\r\n\t\t}\r\n\r\n\t\tthis.items = [];\r\n\t\tthis.itemId = 0;\r\n\t\tthis.rangeMap = new RangeMap();\r\n\r\n\t\tfor (const renderer of renderers) {\r\n\t\t\tthis.renderers.set(renderer.templateId, renderer);\r\n\t\t}\r\n\r\n\t\tthis.cache = this.disposables.add(new RowCache(this.renderers));\r\n\r\n\t\tthis.lastRenderTop = 0;\r\n\t\tthis.lastRenderHeight = 0;\r\n\r\n\t\tthis.domNode = document.createElement('div');\r\n\t\tthis.domNode.className = 'monaco-list';\r\n\r\n\t\tthis.domNode.classList.add(this.domId);\r\n\t\tthis.domNode.tabIndex = 0;\r\n\r\n\t\tthis.domNode.classList.toggle('mouse-support', typeof options.mouseSupport === 'boolean' ? options.mouseSupport : true);\r\n\r\n\t\tthis._horizontalScrolling = getOrDefault(options, o => o.horizontalScrolling, DefaultOptions.horizontalScrolling);\r\n\t\tthis.domNode.classList.toggle('horizontal-scrolling', this._horizontalScrolling);\r\n\r\n\t\tthis.additionalScrollHeight = typeof options.additionalScrollHeight === 'undefined' ? 0 : options.additionalScrollHeight;\r\n\r\n\t\tthis.accessibilityProvider = new ListViewAccessibilityProvider(options.accessibilityProvider);\r\n\r\n\t\tthis.rowsContainer = document.createElement('div');\r\n\t\tthis.rowsContainer.className = 'monaco-list-rows';\r\n\r\n\t\tconst transformOptimization = getOrDefault(options, o => o.transformOptimization, DefaultOptions.transformOptimization);\r\n\t\tif (transformOptimization) {\r\n\t\t\tthis.rowsContainer.style.transform = 'translate3d(0px, 0px, 0px)';\r\n\t\t}\r\n\r\n\t\tthis.disposables.add(Gesture.addTarget(this.rowsContainer));\r\n\r\n\t\tthis.scrollable = new Scrollable(getOrDefault(options, o => o.smoothScrolling, false) ? 125 : 0, cb => scheduleAtNextAnimationFrame(cb));\r\n\t\tthis.scrollableElement = this.disposables.add(new SmoothScrollableElement(this.rowsContainer, {\r\n\t\t\thorizontal: ScrollbarVisibility.Auto,\r\n\t\t\tvertical: getOrDefault(options, o => o.verticalScrollMode, DefaultOptions.verticalScrollMode),\r\n\t\t\tuseShadows: getOrDefault(options, o => o.useShadows, DefaultOptions.useShadows),\r\n\t\t}, this.scrollable));\r\n\r\n\t\tthis.domNode.appendChild(this.scrollableElement.getDomNode());\r\n\t\tcontainer.appendChild(this.domNode);\r\n\r\n\t\tthis.scrollableElement.onScroll(this.onScroll, this, this.disposables);\r\n\t\tdomEvent(this.rowsContainer, TouchEventType.Change)(this.onTouchChange, this, this.disposables);\r\n\r\n\t\t// Prevent the monaco-scrollable-element from scrolling\r\n\t\t// https://github.com/microsoft/vscode/issues/44181\r\n\t\tdomEvent(this.scrollableElement.getDomNode(), 'scroll')\r\n\t\t\t(e => (e.target as HTMLElement).scrollTop = 0, null, this.disposables);\r\n\r\n\t\tEvent.map(domEvent(this.domNode, 'dragover'), e => this.toDragEvent(e))(this.onDragOver, this, this.disposables);\r\n\t\tEvent.map(domEvent(this.domNode, 'drop'), e => this.toDragEvent(e))(this.onDrop, this, this.disposables);\r\n\t\tdomEvent(this.domNode, 'dragleave')(this.onDragLeave, this, this.disposables);\r\n\t\tdomEvent(window, 'dragend')(this.onDragEnd, this, this.disposables);\r\n\r\n\t\tthis.setRowLineHeight = getOrDefault(options, o => o.setRowLineHeight, DefaultOptions.setRowLineHeight);\r\n\t\tthis.setRowHeight = getOrDefault(options, o => o.setRowHeight, DefaultOptions.setRowHeight);\r\n\t\tthis.supportDynamicHeights = getOrDefault(options, o => o.supportDynamicHeights, DefaultOptions.supportDynamicHeights);\r\n\t\tthis.dnd = getOrDefault, IListViewDragAndDrop>(options, o => o.dnd, DefaultOptions.dnd);\r\n\r\n\t\tthis.layout();\r\n\t}\r\n\r\n\tupdateOptions(options: IListViewOptionsUpdate) {\r\n\t\tif (options.additionalScrollHeight !== undefined) {\r\n\t\t\tthis.additionalScrollHeight = options.additionalScrollHeight;\r\n\t\t}\r\n\r\n\t\tif (options.smoothScrolling !== undefined) {\r\n\t\t\tthis.scrollable.setSmoothScrollDuration(options.smoothScrolling ? 125 : 0);\r\n\t\t}\r\n\r\n\t\tif (options.horizontalScrolling !== undefined) {\r\n\t\t\tthis.horizontalScrolling = options.horizontalScrolling;\r\n\t\t}\r\n\t}\r\n\r\n\tsplice(start: number, deleteCount: number, elements: T[] = []): T[] {\r\n\t\tif (this.splicing) {\r\n\t\t\tthrow new Error('Can\\'t run recursive splices.');\r\n\t\t}\r\n\r\n\t\tthis.splicing = true;\r\n\r\n\t\ttry {\r\n\t\t\treturn this._splice(start, deleteCount, elements);\r\n\t\t} finally {\r\n\t\t\tthis.splicing = false;\r\n\t\t\tthis._onDidChangeContentHeight.fire(this.contentHeight);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _splice(start: number, deleteCount: number, elements: T[] = []): T[] {\r\n\t\tconst previousRenderRange = this.getRenderRange(this.lastRenderTop, this.lastRenderHeight);\r\n\t\tconst deleteRange = { start, end: start + deleteCount };\r\n\t\tconst removeRange = Range.intersect(previousRenderRange, deleteRange);\r\n\r\n\t\t// try to reuse rows, avoid removing them from DOM\r\n\t\tconst rowsToDispose = new Map();\r\n\t\tfor (let i = removeRange.start; i < removeRange.end; i++) {\r\n\t\t\tconst item = this.items[i];\r\n\t\t\titem.dragStartDisposable.dispose();\r\n\r\n\t\t\tif (item.row) {\r\n\t\t\t\tlet rows = rowsToDispose.get(item.templateId);\r\n\r\n\t\t\t\tif (!rows) {\r\n\t\t\t\t\trows = [];\r\n\t\t\t\t\trowsToDispose.set(item.templateId, rows);\r\n\t\t\t\t}\r\n\r\n\t\t\t\trows.push([item.row, item.element, i, item.size]);\r\n\t\t\t}\r\n\r\n\t\t\titem.row = null;\r\n\t\t}\r\n\r\n\t\tconst previousRestRange: IRange = { start: start + deleteCount, end: this.items.length };\r\n\t\tconst previousRenderedRestRange = Range.intersect(previousRestRange, previousRenderRange);\r\n\t\tconst previousUnrenderedRestRanges = Range.relativeComplement(previousRestRange, previousRenderRange);\r\n\r\n\t\tconst inserted = elements.map>(element => ({\r\n\t\t\tid: String(this.itemId++),\r\n\t\t\telement,\r\n\t\t\ttemplateId: this.virtualDelegate.getTemplateId(element),\r\n\t\t\tsize: this.virtualDelegate.getHeight(element),\r\n\t\t\twidth: undefined,\r\n\t\t\thasDynamicHeight: !!this.virtualDelegate.hasDynamicHeight && this.virtualDelegate.hasDynamicHeight(element),\r\n\t\t\tlastDynamicHeightWidth: undefined,\r\n\t\t\trow: null,\r\n\t\t\turi: undefined,\r\n\t\t\tdropTarget: false,\r\n\t\t\tdragStartDisposable: Disposable.None\r\n\t\t}));\r\n\r\n\t\tlet deleted: IItem[];\r\n\r\n\t\t// TODO@joao: improve this optimization to catch even more cases\r\n\t\tif (start === 0 && deleteCount >= this.items.length) {\r\n\t\t\tthis.rangeMap = new RangeMap();\r\n\t\t\tthis.rangeMap.splice(0, 0, inserted);\r\n\t\t\tthis.items = inserted;\r\n\t\t\tdeleted = [];\r\n\t\t} else {\r\n\t\t\tthis.rangeMap.splice(start, deleteCount, inserted);\r\n\t\t\tdeleted = this.items.splice(start, deleteCount, ...inserted);\r\n\t\t}\r\n\r\n\t\tconst delta = elements.length - deleteCount;\r\n\t\tconst renderRange = this.getRenderRange(this.lastRenderTop, this.lastRenderHeight);\r\n\t\tconst renderedRestRange = shift(previousRenderedRestRange, delta);\r\n\t\tconst updateRange = Range.intersect(renderRange, renderedRestRange);\r\n\r\n\t\tfor (let i = updateRange.start; i < updateRange.end; i++) {\r\n\t\t\tthis.updateItemInDOM(this.items[i], i);\r\n\t\t}\r\n\r\n\t\tconst removeRanges = Range.relativeComplement(renderedRestRange, renderRange);\r\n\r\n\t\tfor (const range of removeRanges) {\r\n\t\t\tfor (let i = range.start; i < range.end; i++) {\r\n\t\t\t\tthis.removeItemFromDOM(i);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst unrenderedRestRanges = previousUnrenderedRestRanges.map(r => shift(r, delta));\r\n\t\tconst elementsRange = { start, end: start + elements.length };\r\n\t\tconst insertRanges = [elementsRange, ...unrenderedRestRanges].map(r => Range.intersect(renderRange, r));\r\n\t\tconst beforeElement = this.getNextToLastElement(insertRanges);\r\n\r\n\t\tfor (const range of insertRanges) {\r\n\t\t\tfor (let i = range.start; i < range.end; i++) {\r\n\t\t\t\tconst item = this.items[i];\r\n\t\t\t\tconst rows = rowsToDispose.get(item.templateId);\r\n\t\t\t\tconst rowData = rows?.pop();\r\n\r\n\t\t\t\tif (!rowData) {\r\n\t\t\t\t\tthis.insertItemInDOM(i, beforeElement);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tconst [row, element, index, size] = rowData;\r\n\t\t\t\t\tconst renderer = this.renderers.get(item.templateId);\r\n\r\n\t\t\t\t\tif (renderer && renderer.disposeElement) {\r\n\t\t\t\t\t\trenderer.disposeElement(element, index, row.templateData, size);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tthis.insertItemInDOM(i, beforeElement, row);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tfor (const [templateId, rows] of rowsToDispose) {\r\n\t\t\tfor (const [row, element, index, size] of rows) {\r\n\t\t\t\tconst renderer = this.renderers.get(templateId);\r\n\r\n\t\t\t\tif (renderer && renderer.disposeElement) {\r\n\t\t\t\t\trenderer.disposeElement(element, index, row.templateData, size);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis.cache.release(row);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis.eventuallyUpdateScrollDimensions();\r\n\r\n\t\tif (this.supportDynamicHeights) {\r\n\t\t\tthis._rerender(this.scrollTop, this.renderHeight);\r\n\t\t}\r\n\r\n\t\treturn deleted.map(i => i.element);\r\n\t}\r\n\r\n\tprivate eventuallyUpdateScrollDimensions(): void {\r\n\t\tthis._scrollHeight = this.contentHeight;\r\n\t\tthis.rowsContainer.style.height = `${this._scrollHeight}px`;\r\n\r\n\t\tif (!this.scrollableElementUpdateDisposable) {\r\n\t\t\tthis.scrollableElementUpdateDisposable = scheduleAtNextAnimationFrame(() => {\r\n\t\t\t\tthis.scrollableElement.setScrollDimensions({ scrollHeight: this.scrollHeight });\r\n\t\t\t\tthis.updateScrollWidth();\r\n\t\t\t\tthis.scrollableElementUpdateDisposable = null;\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tprivate eventuallyUpdateScrollWidth(): void {\r\n\t\tif (!this.horizontalScrolling) {\r\n\t\t\tthis.scrollableElementWidthDelayer.cancel();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.scrollableElementWidthDelayer.trigger(() => this.updateScrollWidth());\r\n\t}\r\n\r\n\tprivate updateScrollWidth(): void {\r\n\t\tif (!this.horizontalScrolling) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet scrollWidth = 0;\r\n\r\n\t\tfor (const item of this.items) {\r\n\t\t\tif (typeof item.width !== 'undefined') {\r\n\t\t\t\tscrollWidth = Math.max(scrollWidth, item.width);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis.scrollWidth = scrollWidth;\r\n\t\tthis.scrollableElement.setScrollDimensions({ scrollWidth: scrollWidth === 0 ? 0 : (scrollWidth + 10) });\r\n\t}\r\n\r\n\trerender(): void {\r\n\t\tif (!this.supportDynamicHeights) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tfor (const item of this.items) {\r\n\t\t\titem.lastDynamicHeightWidth = undefined;\r\n\t\t}\r\n\r\n\t\tthis._rerender(this.lastRenderTop, this.lastRenderHeight);\r\n\t}\r\n\r\n\tget length(): number {\r\n\t\treturn this.items.length;\r\n\t}\r\n\r\n\tget renderHeight(): number {\r\n\t\tconst scrollDimensions = this.scrollableElement.getScrollDimensions();\r\n\t\treturn scrollDimensions.height;\r\n\t}\r\n\r\n\telement(index: number): T {\r\n\t\treturn this.items[index].element;\r\n\t}\r\n\r\n\tdomElement(index: number): HTMLElement | null {\r\n\t\tconst row = this.items[index].row;\r\n\t\treturn row && row.domNode;\r\n\t}\r\n\r\n\telementHeight(index: number): number {\r\n\t\treturn this.items[index].size;\r\n\t}\r\n\r\n\telementTop(index: number): number {\r\n\t\treturn this.rangeMap.positionAt(index);\r\n\t}\r\n\r\n\tindexAt(position: number): number {\r\n\t\treturn this.rangeMap.indexAt(position);\r\n\t}\r\n\r\n\tindexAfter(position: number): number {\r\n\t\treturn this.rangeMap.indexAfter(position);\r\n\t}\r\n\r\n\tlayout(height?: number, width?: number): void {\r\n\t\tlet scrollDimensions: INewScrollDimensions = {\r\n\t\t\theight: typeof height === 'number' ? height : getContentHeight(this.domNode)\r\n\t\t};\r\n\r\n\t\tif (this.scrollableElementUpdateDisposable) {\r\n\t\t\tthis.scrollableElementUpdateDisposable.dispose();\r\n\t\t\tthis.scrollableElementUpdateDisposable = null;\r\n\t\t\tscrollDimensions.scrollHeight = this.scrollHeight;\r\n\t\t}\r\n\r\n\t\tthis.scrollableElement.setScrollDimensions(scrollDimensions);\r\n\r\n\t\tif (typeof width !== 'undefined') {\r\n\t\t\tthis.renderWidth = width;\r\n\r\n\t\t\tif (this.supportDynamicHeights) {\r\n\t\t\t\tthis._rerender(this.scrollTop, this.renderHeight);\r\n\t\t\t}\r\n\r\n\t\t\tif (this.horizontalScrolling) {\r\n\t\t\t\tthis.scrollableElement.setScrollDimensions({\r\n\t\t\t\t\twidth: typeof width === 'number' ? width : getContentWidth(this.domNode)\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t// Render\r\n\r\n\tprivate render(previousRenderRange: IRange, renderTop: number, renderHeight: number, renderLeft: number | undefined, scrollWidth: number | undefined, updateItemsInDOM: boolean = false): void {\r\n\t\tconst renderRange = this.getRenderRange(renderTop, renderHeight);\r\n\r\n\t\tconst rangesToInsert = Range.relativeComplement(renderRange, previousRenderRange);\r\n\t\tconst rangesToRemove = Range.relativeComplement(previousRenderRange, renderRange);\r\n\t\tconst beforeElement = this.getNextToLastElement(rangesToInsert);\r\n\r\n\t\tif (updateItemsInDOM) {\r\n\t\t\tconst rangesToUpdate = Range.intersect(previousRenderRange, renderRange);\r\n\r\n\t\t\tfor (let i = rangesToUpdate.start; i < rangesToUpdate.end; i++) {\r\n\t\t\t\tthis.updateItemInDOM(this.items[i], i);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tfor (const range of rangesToInsert) {\r\n\t\t\tfor (let i = range.start; i < range.end; i++) {\r\n\t\t\t\tthis.insertItemInDOM(i, beforeElement);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tfor (const range of rangesToRemove) {\r\n\t\t\tfor (let i = range.start; i < range.end; i++) {\r\n\t\t\t\tthis.removeItemFromDOM(i);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (renderLeft !== undefined) {\r\n\t\t\tthis.rowsContainer.style.left = `-${renderLeft}px`;\r\n\t\t}\r\n\r\n\t\tthis.rowsContainer.style.top = `-${renderTop}px`;\r\n\r\n\t\tif (this.horizontalScrolling && scrollWidth !== undefined) {\r\n\t\t\tthis.rowsContainer.style.width = `${Math.max(scrollWidth, this.renderWidth)}px`;\r\n\t\t}\r\n\r\n\t\tthis.lastRenderTop = renderTop;\r\n\t\tthis.lastRenderHeight = renderHeight;\r\n\t}\r\n\r\n\t// DOM operations\r\n\r\n\tprivate insertItemInDOM(index: number, beforeElement: HTMLElement | null, row?: IRow): void {\r\n\t\tconst item = this.items[index];\r\n\r\n\t\tif (!item.row) {\r\n\t\t\titem.row = row ?? this.cache.alloc(item.templateId);\r\n\t\t}\r\n\r\n\t\tconst role = this.accessibilityProvider.getRole(item.element) || 'listitem';\r\n\t\titem.row.domNode.setAttribute('role', role);\r\n\r\n\t\tconst checked = this.accessibilityProvider.isChecked(item.element);\r\n\t\tif (typeof checked !== 'undefined') {\r\n\t\t\titem.row.domNode.setAttribute('aria-checked', String(!!checked));\r\n\t\t}\r\n\r\n\t\tif (!item.row.domNode.parentElement) {\r\n\t\t\tif (beforeElement) {\r\n\t\t\t\tthis.rowsContainer.insertBefore(item.row.domNode, beforeElement);\r\n\t\t\t} else {\r\n\t\t\t\tthis.rowsContainer.appendChild(item.row.domNode);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis.updateItemInDOM(item, index);\r\n\r\n\t\tconst renderer = this.renderers.get(item.templateId);\r\n\r\n\t\tif (!renderer) {\r\n\t\t\tthrow new Error(`No renderer found for template id ${item.templateId}`);\r\n\t\t}\r\n\r\n\t\tif (renderer) {\r\n\t\t\trenderer.renderElement(item.element, index, item.row.templateData, item.size);\r\n\t\t}\r\n\r\n\t\tconst uri = this.dnd.getDragURI(item.element);\r\n\t\titem.dragStartDisposable.dispose();\r\n\t\titem.row.domNode.draggable = !!uri;\r\n\r\n\t\tif (uri) {\r\n\t\t\tconst onDragStart = domEvent(item.row.domNode, 'dragstart');\r\n\t\t\titem.dragStartDisposable = onDragStart(event => this.onDragStart(item.element, uri, event));\r\n\t\t}\r\n\r\n\t\tif (this.horizontalScrolling) {\r\n\t\t\tthis.measureItemWidth(item);\r\n\t\t\tthis.eventuallyUpdateScrollWidth();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate measureItemWidth(item: IItem): void {\r\n\t\tif (!item.row || !item.row.domNode) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\titem.row.domNode.style.width = isFirefox ? '-moz-fit-content' : 'fit-content';\r\n\t\titem.width = getContentWidth(item.row.domNode);\r\n\t\tconst style = window.getComputedStyle(item.row.domNode);\r\n\r\n\t\tif (style.paddingLeft) {\r\n\t\t\titem.width += parseFloat(style.paddingLeft);\r\n\t\t}\r\n\r\n\t\tif (style.paddingRight) {\r\n\t\t\titem.width += parseFloat(style.paddingRight);\r\n\t\t}\r\n\r\n\t\titem.row.domNode.style.width = '';\r\n\t}\r\n\r\n\tprivate updateItemInDOM(item: IItem, index: number): void {\r\n\t\titem.row!.domNode.style.top = `${this.elementTop(index)}px`;\r\n\r\n\t\tif (this.setRowHeight) {\r\n\t\t\titem.row!.domNode.style.height = `${item.size}px`;\r\n\t\t}\r\n\r\n\t\tif (this.setRowLineHeight) {\r\n\t\t\titem.row!.domNode.style.lineHeight = `${item.size}px`;\r\n\t\t}\r\n\r\n\t\titem.row!.domNode.setAttribute('data-index', `${index}`);\r\n\t\titem.row!.domNode.setAttribute('data-last-element', index === this.length - 1 ? 'true' : 'false');\r\n\t\titem.row!.domNode.setAttribute('aria-setsize', String(this.accessibilityProvider.getSetSize(item.element, index, this.length)));\r\n\t\titem.row!.domNode.setAttribute('aria-posinset', String(this.accessibilityProvider.getPosInSet(item.element, index)));\r\n\t\titem.row!.domNode.setAttribute('id', this.getElementDomId(index));\r\n\r\n\t\titem.row!.domNode.classList.toggle('drop-target', item.dropTarget);\r\n\t}\r\n\r\n\tprivate removeItemFromDOM(index: number): void {\r\n\t\tconst item = this.items[index];\r\n\t\titem.dragStartDisposable.dispose();\r\n\r\n\t\tif (item.row) {\r\n\t\t\tconst renderer = this.renderers.get(item.templateId);\r\n\r\n\t\t\tif (renderer && renderer.disposeElement) {\r\n\t\t\t\trenderer.disposeElement(item.element, index, item.row.templateData, item.size);\r\n\t\t\t}\r\n\r\n\t\t\tthis.cache.release(item.row);\r\n\t\t\titem.row = null;\r\n\t\t}\r\n\r\n\t\tif (this.horizontalScrolling) {\r\n\t\t\tthis.eventuallyUpdateScrollWidth();\r\n\t\t}\r\n\t}\r\n\r\n\tgetScrollTop(): number {\r\n\t\tconst scrollPosition = this.scrollableElement.getScrollPosition();\r\n\t\treturn scrollPosition.scrollTop;\r\n\t}\r\n\r\n\tsetScrollTop(scrollTop: number, reuseAnimation?: boolean): void {\r\n\t\tif (this.scrollableElementUpdateDisposable) {\r\n\t\t\tthis.scrollableElementUpdateDisposable.dispose();\r\n\t\t\tthis.scrollableElementUpdateDisposable = null;\r\n\t\t\tthis.scrollableElement.setScrollDimensions({ scrollHeight: this.scrollHeight });\r\n\t\t}\r\n\r\n\t\tthis.scrollableElement.setScrollPosition({ scrollTop, reuseAnimation });\r\n\t}\r\n\r\n\r\n\tget scrollTop(): number {\r\n\t\treturn this.getScrollTop();\r\n\t}\r\n\r\n\tset scrollTop(scrollTop: number) {\r\n\t\tthis.setScrollTop(scrollTop);\r\n\t}\r\n\r\n\tget scrollHeight(): number {\r\n\t\treturn this._scrollHeight + (this.horizontalScrolling ? 10 : 0) + this.additionalScrollHeight;\r\n\t}\r\n\r\n\t// Events\r\n\r\n\t@memoize get onMouseClick(): Event> { return Event.map(domEvent(this.domNode, 'click'), e => this.toMouseEvent(e)); }\r\n\t@memoize get onMouseDblClick(): Event> { return Event.map(domEvent(this.domNode, 'dblclick'), e => this.toMouseEvent(e)); }\r\n\t@memoize get onMouseMiddleClick(): Event> { return Event.filter(Event.map(domEvent(this.domNode, 'auxclick'), e => this.toMouseEvent(e as MouseEvent)), e => e.browserEvent.button === 1); }\r\n\t@memoize get onMouseDown(): Event> { return Event.map(domEvent(this.domNode, 'mousedown'), e => this.toMouseEvent(e)); }\r\n\t@memoize get onContextMenu(): Event> { return Event.map(domEvent(this.domNode, 'contextmenu'), e => this.toMouseEvent(e)); }\r\n\t@memoize get onTouchStart(): Event> { return Event.map(domEvent(this.domNode, 'touchstart'), e => this.toTouchEvent(e)); }\r\n\t@memoize get onTap(): Event> { return Event.map(domEvent(this.rowsContainer, TouchEventType.Tap), e => this.toGestureEvent(e)); }\r\n\r\n\tprivate toMouseEvent(browserEvent: MouseEvent): IListMouseEvent {\r\n\t\tconst index = this.getItemIndexFromEventTarget(browserEvent.target || null);\r\n\t\tconst item = typeof index === 'undefined' ? undefined : this.items[index];\r\n\t\tconst element = item && item.element;\r\n\t\treturn { browserEvent, index, element };\r\n\t}\r\n\r\n\tprivate toTouchEvent(browserEvent: TouchEvent): IListTouchEvent {\r\n\t\tconst index = this.getItemIndexFromEventTarget(browserEvent.target || null);\r\n\t\tconst item = typeof index === 'undefined' ? undefined : this.items[index];\r\n\t\tconst element = item && item.element;\r\n\t\treturn { browserEvent, index, element };\r\n\t}\r\n\r\n\tprivate toGestureEvent(browserEvent: GestureEvent): IListGestureEvent {\r\n\t\tconst index = this.getItemIndexFromEventTarget(browserEvent.initialTarget || null);\r\n\t\tconst item = typeof index === 'undefined' ? undefined : this.items[index];\r\n\t\tconst element = item && item.element;\r\n\t\treturn { browserEvent, index, element };\r\n\t}\r\n\r\n\tprivate toDragEvent(browserEvent: DragEvent): IListDragEvent {\r\n\t\tconst index = this.getItemIndexFromEventTarget(browserEvent.target || null);\r\n\t\tconst item = typeof index === 'undefined' ? undefined : this.items[index];\r\n\t\tconst element = item && item.element;\r\n\t\treturn { browserEvent, index, element };\r\n\t}\r\n\r\n\tprivate onScroll(e: ScrollEvent): void {\r\n\t\ttry {\r\n\t\t\tconst previousRenderRange = this.getRenderRange(this.lastRenderTop, this.lastRenderHeight);\r\n\t\t\tthis.render(previousRenderRange, e.scrollTop, e.height, e.scrollLeft, e.scrollWidth);\r\n\r\n\t\t\tif (this.supportDynamicHeights) {\r\n\t\t\t\tthis._rerender(e.scrollTop, e.height, e.inSmoothScrolling);\r\n\t\t\t}\r\n\t\t} catch (err) {\r\n\t\t\tconsole.error('Got bad scroll event:', e);\r\n\t\t\tthrow err;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate onTouchChange(event: GestureEvent): void {\r\n\t\tevent.preventDefault();\r\n\t\tevent.stopPropagation();\r\n\r\n\t\tthis.scrollTop -= event.translationY;\r\n\t}\r\n\r\n\t// DND\r\n\r\n\tprivate onDragStart(element: T, uri: string, event: DragEvent): void {\r\n\t\tif (!event.dataTransfer) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst elements = this.dnd.getDragElements(element);\r\n\r\n\t\tevent.dataTransfer.effectAllowed = 'copyMove';\r\n\t\tevent.dataTransfer.setData(DataTransfers.RESOURCES, JSON.stringify([uri]));\r\n\r\n\t\tif (event.dataTransfer.setDragImage) {\r\n\t\t\tlet label: string | undefined;\r\n\r\n\t\t\tif (this.dnd.getDragLabel) {\r\n\t\t\t\tlabel = this.dnd.getDragLabel(elements, event);\r\n\t\t\t}\r\n\r\n\t\t\tif (typeof label === 'undefined') {\r\n\t\t\t\tlabel = String(elements.length);\r\n\t\t\t}\r\n\r\n\t\t\tconst dragImage = $('.monaco-drag-image');\r\n\t\t\tdragImage.textContent = label;\r\n\t\t\tdocument.body.appendChild(dragImage);\r\n\t\t\tevent.dataTransfer.setDragImage(dragImage, -10, -10);\r\n\t\t\tsetTimeout(() => document.body.removeChild(dragImage), 0);\r\n\t\t}\r\n\r\n\t\tthis.currentDragData = new ElementsDragAndDropData(elements);\r\n\t\tStaticDND.CurrentDragAndDropData = new ExternalElementsDragAndDropData(elements);\r\n\r\n\t\tif (this.dnd.onDragStart) {\r\n\t\t\tthis.dnd.onDragStart(this.currentDragData, event);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate onDragOver(event: IListDragEvent): boolean {\r\n\t\tevent.browserEvent.preventDefault(); // needed so that the drop event fires (https://stackoverflow.com/questions/21339924/drop-event-not-firing-in-chrome)\r\n\r\n\t\tthis.onDragLeaveTimeout.dispose();\r\n\r\n\t\tif (StaticDND.CurrentDragAndDropData && StaticDND.CurrentDragAndDropData.getData() === 'vscode-ui') {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tthis.setupDragAndDropScrollTopAnimation(event.browserEvent);\r\n\r\n\t\tif (!event.browserEvent.dataTransfer) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\t// Drag over from outside\r\n\t\tif (!this.currentDragData) {\r\n\t\t\tif (StaticDND.CurrentDragAndDropData) {\r\n\t\t\t\t// Drag over from another list\r\n\t\t\t\tthis.currentDragData = StaticDND.CurrentDragAndDropData;\r\n\r\n\t\t\t} else {\r\n\t\t\t\t// Drag over from the desktop\r\n\t\t\t\tif (!event.browserEvent.dataTransfer.types) {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis.currentDragData = new NativeDragAndDropData();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst result = this.dnd.onDragOver(this.currentDragData, event.element, event.index, event.browserEvent);\r\n\t\tthis.canDrop = typeof result === 'boolean' ? result : result.accept;\r\n\r\n\t\tif (!this.canDrop) {\r\n\t\t\tthis.currentDragFeedback = undefined;\r\n\t\t\tthis.currentDragFeedbackDisposable.dispose();\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tevent.browserEvent.dataTransfer.dropEffect = (typeof result !== 'boolean' && result.effect === ListDragOverEffect.Copy) ? 'copy' : 'move';\r\n\r\n\t\tlet feedback: number[];\r\n\r\n\t\tif (typeof result !== 'boolean' && result.feedback) {\r\n\t\t\tfeedback = result.feedback;\r\n\t\t} else {\r\n\t\t\tif (typeof event.index === 'undefined') {\r\n\t\t\t\tfeedback = [-1];\r\n\t\t\t} else {\r\n\t\t\t\tfeedback = [event.index];\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// sanitize feedback list\r\n\t\tfeedback = distinct(feedback).filter(i => i >= -1 && i < this.length).sort((a, b) => a - b);\r\n\t\tfeedback = feedback[0] === -1 ? [-1] : feedback;\r\n\r\n\t\tif (equalsDragFeedback(this.currentDragFeedback, feedback)) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tthis.currentDragFeedback = feedback;\r\n\t\tthis.currentDragFeedbackDisposable.dispose();\r\n\r\n\t\tif (feedback[0] === -1) { // entire list feedback\r\n\t\t\tthis.domNode.classList.add('drop-target');\r\n\t\t\tthis.rowsContainer.classList.add('drop-target');\r\n\t\t\tthis.currentDragFeedbackDisposable = toDisposable(() => {\r\n\t\t\t\tthis.domNode.classList.remove('drop-target');\r\n\t\t\t\tthis.rowsContainer.classList.remove('drop-target');\r\n\t\t\t});\r\n\t\t} else {\r\n\t\t\tfor (const index of feedback) {\r\n\t\t\t\tconst item = this.items[index]!;\r\n\t\t\t\titem.dropTarget = true;\r\n\r\n\t\t\t\tif (item.row) {\r\n\t\t\t\t\titem.row.domNode.classList.add('drop-target');\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tthis.currentDragFeedbackDisposable = toDisposable(() => {\r\n\t\t\t\tfor (const index of feedback) {\r\n\t\t\t\t\tconst item = this.items[index]!;\r\n\t\t\t\t\titem.dropTarget = false;\r\n\r\n\t\t\t\t\tif (item.row) {\r\n\t\t\t\t\t\titem.row.domNode.classList.remove('drop-target');\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tprivate onDragLeave(): void {\r\n\t\tthis.onDragLeaveTimeout.dispose();\r\n\t\tthis.onDragLeaveTimeout = disposableTimeout(() => this.clearDragOverFeedback(), 100);\r\n\t}\r\n\r\n\tprivate onDrop(event: IListDragEvent): void {\r\n\t\tif (!this.canDrop) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst dragData = this.currentDragData;\r\n\t\tthis.teardownDragAndDropScrollTopAnimation();\r\n\t\tthis.clearDragOverFeedback();\r\n\t\tthis.currentDragData = undefined;\r\n\t\tStaticDND.CurrentDragAndDropData = undefined;\r\n\r\n\t\tif (!dragData || !event.browserEvent.dataTransfer) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tevent.browserEvent.preventDefault();\r\n\t\tdragData.update(event.browserEvent.dataTransfer);\r\n\t\tthis.dnd.drop(dragData, event.element, event.index, event.browserEvent);\r\n\t}\r\n\r\n\tprivate onDragEnd(event: DragEvent): void {\r\n\t\tthis.canDrop = false;\r\n\t\tthis.teardownDragAndDropScrollTopAnimation();\r\n\t\tthis.clearDragOverFeedback();\r\n\t\tthis.currentDragData = undefined;\r\n\t\tStaticDND.CurrentDragAndDropData = undefined;\r\n\r\n\t\tif (this.dnd.onDragEnd) {\r\n\t\t\tthis.dnd.onDragEnd(event);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate clearDragOverFeedback(): void {\r\n\t\tthis.currentDragFeedback = undefined;\r\n\t\tthis.currentDragFeedbackDisposable.dispose();\r\n\t\tthis.currentDragFeedbackDisposable = Disposable.None;\r\n\t}\r\n\r\n\t// DND scroll top animation\r\n\r\n\tprivate setupDragAndDropScrollTopAnimation(event: DragEvent): void {\r\n\t\tif (!this.dragOverAnimationDisposable) {\r\n\t\t\tconst viewTop = getTopLeftOffset(this.domNode).top;\r\n\t\t\tthis.dragOverAnimationDisposable = animate(this.animateDragAndDropScrollTop.bind(this, viewTop));\r\n\t\t}\r\n\r\n\t\tthis.dragOverAnimationStopDisposable.dispose();\r\n\t\tthis.dragOverAnimationStopDisposable = disposableTimeout(() => {\r\n\t\t\tif (this.dragOverAnimationDisposable) {\r\n\t\t\t\tthis.dragOverAnimationDisposable.dispose();\r\n\t\t\t\tthis.dragOverAnimationDisposable = undefined;\r\n\t\t\t}\r\n\t\t}, 1000);\r\n\r\n\t\tthis.dragOverMouseY = event.pageY;\r\n\t}\r\n\r\n\tprivate animateDragAndDropScrollTop(viewTop: number): void {\r\n\t\tif (this.dragOverMouseY === undefined) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst diff = this.dragOverMouseY - viewTop;\r\n\t\tconst upperLimit = this.renderHeight - 35;\r\n\r\n\t\tif (diff < 35) {\r\n\t\t\tthis.scrollTop += Math.max(-14, Math.floor(0.3 * (diff - 35)));\r\n\t\t} else if (diff > upperLimit) {\r\n\t\t\tthis.scrollTop += Math.min(14, Math.floor(0.3 * (diff - upperLimit)));\r\n\t\t}\r\n\t}\r\n\r\n\tprivate teardownDragAndDropScrollTopAnimation(): void {\r\n\t\tthis.dragOverAnimationStopDisposable.dispose();\r\n\r\n\t\tif (this.dragOverAnimationDisposable) {\r\n\t\t\tthis.dragOverAnimationDisposable.dispose();\r\n\t\t\tthis.dragOverAnimationDisposable = undefined;\r\n\t\t}\r\n\t}\r\n\r\n\t// Util\r\n\r\n\tprivate getItemIndexFromEventTarget(target: EventTarget | null): number | undefined {\r\n\t\tconst scrollableElement = this.scrollableElement.getDomNode();\r\n\t\tlet element: HTMLElement | null = target as (HTMLElement | null);\r\n\r\n\t\twhile (element instanceof HTMLElement && element !== this.rowsContainer && scrollableElement.contains(element)) {\r\n\t\t\tconst rawIndex = element.getAttribute('data-index');\r\n\r\n\t\t\tif (rawIndex) {\r\n\t\t\t\tconst index = Number(rawIndex);\r\n\r\n\t\t\t\tif (!isNaN(index)) {\r\n\t\t\t\t\treturn index;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\telement = element.parentElement;\r\n\t\t}\r\n\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tprivate getRenderRange(renderTop: number, renderHeight: number): IRange {\r\n\t\treturn {\r\n\t\t\tstart: this.rangeMap.indexAt(renderTop),\r\n\t\t\tend: this.rangeMap.indexAfter(renderTop + renderHeight - 1)\r\n\t\t};\r\n\t}\r\n\r\n\t/**\r\n\t * Given a stable rendered state, checks every rendered element whether it needs\r\n\t * to be probed for dynamic height. Adjusts scroll height and top if necessary.\r\n\t */\r\n\tprivate _rerender(renderTop: number, renderHeight: number, inSmoothScrolling?: boolean): void {\r\n\t\tconst previousRenderRange = this.getRenderRange(renderTop, renderHeight);\r\n\r\n\t\t// Let's remember the second element's position, this helps in scrolling up\r\n\t\t// and preserving a linear upwards scroll movement\r\n\t\tlet anchorElementIndex: number | undefined;\r\n\t\tlet anchorElementTopDelta: number | undefined;\r\n\r\n\t\tif (renderTop === this.elementTop(previousRenderRange.start)) {\r\n\t\t\tanchorElementIndex = previousRenderRange.start;\r\n\t\t\tanchorElementTopDelta = 0;\r\n\t\t} else if (previousRenderRange.end - previousRenderRange.start > 1) {\r\n\t\t\tanchorElementIndex = previousRenderRange.start + 1;\r\n\t\t\tanchorElementTopDelta = this.elementTop(anchorElementIndex) - renderTop;\r\n\t\t}\r\n\r\n\t\tlet heightDiff = 0;\r\n\r\n\t\twhile (true) {\r\n\t\t\tconst renderRange = this.getRenderRange(renderTop, renderHeight);\r\n\r\n\t\t\tlet didChange = false;\r\n\r\n\t\t\tfor (let i = renderRange.start; i < renderRange.end; i++) {\r\n\t\t\t\tconst diff = this.probeDynamicHeight(i);\r\n\r\n\t\t\t\tif (diff !== 0) {\r\n\t\t\t\t\tthis.rangeMap.splice(i, 1, [this.items[i]]);\r\n\t\t\t\t}\r\n\r\n\t\t\t\theightDiff += diff;\r\n\t\t\t\tdidChange = didChange || diff !== 0;\r\n\t\t\t}\r\n\r\n\t\t\tif (!didChange) {\r\n\t\t\t\tif (heightDiff !== 0) {\r\n\t\t\t\t\tthis.eventuallyUpdateScrollDimensions();\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst unrenderRanges = Range.relativeComplement(previousRenderRange, renderRange);\r\n\r\n\t\t\t\tfor (const range of unrenderRanges) {\r\n\t\t\t\t\tfor (let i = range.start; i < range.end; i++) {\r\n\t\t\t\t\t\tif (this.items[i].row) {\r\n\t\t\t\t\t\t\tthis.removeItemFromDOM(i);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst renderRanges = Range.relativeComplement(renderRange, previousRenderRange);\r\n\r\n\t\t\t\tfor (const range of renderRanges) {\r\n\t\t\t\t\tfor (let i = range.start; i < range.end; i++) {\r\n\t\t\t\t\t\tconst afterIndex = i + 1;\r\n\t\t\t\t\t\tconst beforeRow = afterIndex < this.items.length ? this.items[afterIndex].row : null;\r\n\t\t\t\t\t\tconst beforeElement = beforeRow ? beforeRow.domNode : null;\r\n\t\t\t\t\t\tthis.insertItemInDOM(i, beforeElement);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfor (let i = renderRange.start; i < renderRange.end; i++) {\r\n\t\t\t\t\tif (this.items[i].row) {\r\n\t\t\t\t\t\tthis.updateItemInDOM(this.items[i], i);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (typeof anchorElementIndex === 'number') {\r\n\t\t\t\t\t// To compute a destination scroll top, we need to take into account the current smooth scrolling\r\n\t\t\t\t\t// animation, and then reuse it with a new target (to avoid prolonging the scroll)\r\n\t\t\t\t\t// See https://github.com/microsoft/vscode/issues/104144\r\n\t\t\t\t\t// See https://github.com/microsoft/vscode/pull/104284\r\n\t\t\t\t\t// See https://github.com/microsoft/vscode/issues/107704\r\n\t\t\t\t\tconst deltaScrollTop = this.scrollable.getFutureScrollPosition().scrollTop - renderTop;\r\n\t\t\t\t\tconst newScrollTop = this.elementTop(anchorElementIndex) - anchorElementTopDelta! + deltaScrollTop;\r\n\t\t\t\t\tthis.setScrollTop(newScrollTop, inSmoothScrolling);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis._onDidChangeContentHeight.fire(this.contentHeight);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate probeDynamicHeight(index: number): number {\r\n\t\tconst item = this.items[index];\r\n\r\n\t\tif (!item.hasDynamicHeight || item.lastDynamicHeightWidth === this.renderWidth) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tif (!!this.virtualDelegate.hasDynamicHeight && !this.virtualDelegate.hasDynamicHeight(item.element)) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tconst size = item.size;\r\n\r\n\t\tif (!this.setRowHeight && item.row) {\r\n\t\t\tlet newSize = item.row.domNode.offsetHeight;\r\n\t\t\titem.size = newSize;\r\n\t\t\titem.lastDynamicHeightWidth = this.renderWidth;\r\n\t\t\treturn newSize - size;\r\n\t\t}\r\n\r\n\t\tconst row = this.cache.alloc(item.templateId);\r\n\r\n\t\trow.domNode.style.height = '';\r\n\t\tthis.rowsContainer.appendChild(row.domNode);\r\n\r\n\t\tconst renderer = this.renderers.get(item.templateId);\r\n\t\tif (renderer) {\r\n\t\t\trenderer.renderElement(item.element, index, row.templateData, undefined);\r\n\r\n\t\t\tif (renderer.disposeElement) {\r\n\t\t\t\trenderer.disposeElement(item.element, index, row.templateData, undefined);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\titem.size = row.domNode.offsetHeight;\r\n\r\n\t\tif (this.virtualDelegate.setDynamicHeight) {\r\n\t\t\tthis.virtualDelegate.setDynamicHeight(item.element, item.size);\r\n\t\t}\r\n\r\n\t\titem.lastDynamicHeightWidth = this.renderWidth;\r\n\t\tthis.rowsContainer.removeChild(row.domNode);\r\n\t\tthis.cache.release(row);\r\n\r\n\t\treturn item.size - size;\r\n\t}\r\n\r\n\tprivate getNextToLastElement(ranges: IRange[]): HTMLElement | null {\r\n\t\tconst lastRange = ranges[ranges.length - 1];\r\n\r\n\t\tif (!lastRange) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst nextToLastItem = this.items[lastRange.end];\r\n\r\n\t\tif (!nextToLastItem) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (!nextToLastItem.row) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\treturn nextToLastItem.row.domNode;\r\n\t}\r\n\r\n\tgetElementDomId(index: number): string {\r\n\t\treturn `${this.domId}_${index}`;\r\n\t}\r\n\r\n\t// Dispose\r\n\r\n\tdispose() {\r\n\t\tif (this.items) {\r\n\t\t\tfor (const item of this.items) {\r\n\t\t\t\tif (item.row) {\r\n\t\t\t\t\tconst renderer = this.renderers.get(item.row.templateId);\r\n\t\t\t\t\tif (renderer) {\r\n\t\t\t\t\t\tif (renderer.disposeElement) {\r\n\t\t\t\t\t\t\trenderer.disposeElement(item.element, -1, item.row.templateData, undefined);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\trenderer.disposeTemplate(item.row.templateData);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tthis.items = [];\r\n\t\t}\r\n\r\n\t\tif (this.domNode && this.domNode.parentNode) {\r\n\t\t\tthis.domNode.parentNode.removeChild(this.domNode);\r\n\t\t}\r\n\r\n\t\tdispose(this.disposables);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./list';\r\nimport { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { isNumber } from 'vs/base/common/types';\r\nimport { range, binarySearch } from 'vs/base/common/arrays';\r\nimport { memoize } from 'vs/base/common/decorators';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport { Gesture } from 'vs/base/browser/touch';\r\nimport { KeyCode } from 'vs/base/common/keyCodes';\r\nimport { StandardKeyboardEvent, IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { Event, Emitter, EventBufferer } from 'vs/base/common/event';\r\nimport { domEvent } from 'vs/base/browser/event';\r\nimport { IListVirtualDelegate, IListRenderer, IListEvent, IListContextMenuEvent, IListMouseEvent, IListTouchEvent, IListGestureEvent, IIdentityProvider, IKeyboardNavigationLabelProvider, IListDragAndDrop, IListDragOverReaction, ListError, IKeyboardNavigationDelegate } from './list';\r\nimport { ListView, IListViewOptions, IListViewDragAndDrop, IListViewAccessibilityProvider, IListViewOptionsUpdate } from './listView';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { mixin } from 'vs/base/common/objects';\r\nimport { ISpliceable } from 'vs/base/common/sequence';\r\nimport { CombinedSpliceable } from 'vs/base/browser/ui/list/splice';\r\nimport { clamp } from 'vs/base/common/numbers';\r\nimport { matchesPrefix } from 'vs/base/common/filters';\r\nimport { IDragAndDropData } from 'vs/base/browser/dnd';\r\nimport { alert } from 'vs/base/browser/ui/aria/aria';\r\nimport { IThemable } from 'vs/base/common/styler';\r\nimport { createStyleSheet } from 'vs/base/browser/dom';\r\n\r\ninterface ITraitChangeEvent {\r\n\tindexes: number[];\r\n\tbrowserEvent?: UIEvent;\r\n}\r\n\r\ntype ITraitTemplateData = HTMLElement;\r\n\r\ninterface IRenderedContainer {\r\n\ttemplateData: ITraitTemplateData;\r\n\tindex: number;\r\n}\r\n\r\nclass TraitRenderer implements IListRenderer\r\n{\r\n\tprivate renderedElements: IRenderedContainer[] = [];\r\n\r\n\tconstructor(private trait: Trait) { }\r\n\r\n\tget templateId(): string {\r\n\t\treturn `template:${this.trait.trait}`;\r\n\t}\r\n\r\n\trenderTemplate(container: HTMLElement): ITraitTemplateData {\r\n\t\treturn container;\r\n\t}\r\n\r\n\trenderElement(element: T, index: number, templateData: ITraitTemplateData): void {\r\n\t\tconst renderedElementIndex = this.renderedElements.findIndex(el => el.templateData === templateData);\r\n\r\n\t\tif (renderedElementIndex >= 0) {\r\n\t\t\tconst rendered = this.renderedElements[renderedElementIndex];\r\n\t\t\tthis.trait.unrender(templateData);\r\n\t\t\trendered.index = index;\r\n\t\t} else {\r\n\t\t\tconst rendered = { index, templateData };\r\n\t\t\tthis.renderedElements.push(rendered);\r\n\t\t}\r\n\r\n\t\tthis.trait.renderIndex(index, templateData);\r\n\t}\r\n\r\n\tsplice(start: number, deleteCount: number, insertCount: number): void {\r\n\t\tconst rendered: IRenderedContainer[] = [];\r\n\r\n\t\tfor (const renderedElement of this.renderedElements) {\r\n\r\n\t\t\tif (renderedElement.index < start) {\r\n\t\t\t\trendered.push(renderedElement);\r\n\t\t\t} else if (renderedElement.index >= start + deleteCount) {\r\n\t\t\t\trendered.push({\r\n\t\t\t\t\tindex: renderedElement.index + insertCount - deleteCount,\r\n\t\t\t\t\ttemplateData: renderedElement.templateData\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis.renderedElements = rendered;\r\n\t}\r\n\r\n\trenderIndexes(indexes: number[]): void {\r\n\t\tfor (const { index, templateData } of this.renderedElements) {\r\n\t\t\tif (indexes.indexOf(index) > -1) {\r\n\t\t\t\tthis.trait.renderIndex(index, templateData);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tdisposeTemplate(templateData: ITraitTemplateData): void {\r\n\t\tconst index = this.renderedElements.findIndex(el => el.templateData === templateData);\r\n\r\n\t\tif (index < 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.renderedElements.splice(index, 1);\r\n\t}\r\n}\r\n\r\nclass Trait implements ISpliceable, IDisposable {\r\n\r\n\tprivate indexes: number[] = [];\r\n\tprivate sortedIndexes: number[] = [];\r\n\r\n\tprivate readonly _onChange = new Emitter();\r\n\treadonly onChange: Event = this._onChange.event;\r\n\r\n\tget trait(): string { return this._trait; }\r\n\r\n\t@memoize\r\n\tget renderer(): TraitRenderer {\r\n\t\treturn new TraitRenderer(this);\r\n\t}\r\n\r\n\tconstructor(private _trait: string) { }\r\n\r\n\tsplice(start: number, deleteCount: number, elements: boolean[]): void {\r\n\t\tconst diff = elements.length - deleteCount;\r\n\t\tconst end = start + deleteCount;\r\n\t\tconst indexes = [\r\n\t\t\t...this.sortedIndexes.filter(i => i < start),\r\n\t\t\t...elements.map((hasTrait, i) => hasTrait ? i + start : -1).filter(i => i !== -1),\r\n\t\t\t...this.sortedIndexes.filter(i => i >= end).map(i => i + diff)\r\n\t\t];\r\n\r\n\t\tthis.renderer.splice(start, deleteCount, elements.length);\r\n\t\tthis._set(indexes, indexes);\r\n\t}\r\n\r\n\trenderIndex(index: number, container: HTMLElement): void {\r\n\t\tcontainer.classList.toggle(this._trait, this.contains(index));\r\n\t}\r\n\r\n\tunrender(container: HTMLElement): void {\r\n\t\tcontainer.classList.remove(this._trait);\r\n\t}\r\n\r\n\t/**\r\n\t * Sets the indexes which should have this trait.\r\n\t *\r\n\t * @param indexes Indexes which should have this trait.\r\n\t * @return The old indexes which had this trait.\r\n\t */\r\n\tset(indexes: number[], browserEvent?: UIEvent): number[] {\r\n\t\treturn this._set(indexes, [...indexes].sort(numericSort), browserEvent);\r\n\t}\r\n\r\n\tprivate _set(indexes: number[], sortedIndexes: number[], browserEvent?: UIEvent): number[] {\r\n\t\tconst result = this.indexes;\r\n\t\tconst sortedResult = this.sortedIndexes;\r\n\r\n\t\tthis.indexes = indexes;\r\n\t\tthis.sortedIndexes = sortedIndexes;\r\n\r\n\t\tconst toRender = disjunction(sortedResult, indexes);\r\n\t\tthis.renderer.renderIndexes(toRender);\r\n\r\n\t\tthis._onChange.fire({ indexes, browserEvent });\r\n\t\treturn result;\r\n\t}\r\n\r\n\tget(): number[] {\r\n\t\treturn this.indexes;\r\n\t}\r\n\r\n\tcontains(index: number): boolean {\r\n\t\treturn binarySearch(this.sortedIndexes, index, numericSort) >= 0;\r\n\t}\r\n\r\n\tdispose() {\r\n\t\tdispose(this._onChange);\r\n\t}\r\n}\r\n\r\nclass SelectionTrait extends Trait {\r\n\r\n\tconstructor(private setAriaSelected: boolean) {\r\n\t\tsuper('selected');\r\n\t}\r\n\r\n\trenderIndex(index: number, container: HTMLElement): void {\r\n\t\tsuper.renderIndex(index, container);\r\n\r\n\t\tif (this.setAriaSelected) {\r\n\t\t\tif (this.contains(index)) {\r\n\t\t\t\tcontainer.setAttribute('aria-selected', 'true');\r\n\t\t\t} else {\r\n\t\t\t\tcontainer.setAttribute('aria-selected', 'false');\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\n/**\r\n * The TraitSpliceable is used as a util class to be able\r\n * to preserve traits across splice calls, given an identity\r\n * provider.\r\n */\r\nclass TraitSpliceable implements ISpliceable {\r\n\r\n\tconstructor(\r\n\t\tprivate trait: Trait,\r\n\t\tprivate view: ListView,\r\n\t\tprivate identityProvider?: IIdentityProvider\r\n\t) { }\r\n\r\n\tsplice(start: number, deleteCount: number, elements: T[]): void {\r\n\t\tif (!this.identityProvider) {\r\n\t\t\treturn this.trait.splice(start, deleteCount, elements.map(() => false));\r\n\t\t}\r\n\r\n\t\tconst pastElementsWithTrait = this.trait.get().map(i => this.identityProvider!.getId(this.view.element(i)).toString());\r\n\t\tconst elementsWithTrait = elements.map(e => pastElementsWithTrait.indexOf(this.identityProvider!.getId(e).toString()) > -1);\r\n\r\n\t\tthis.trait.splice(start, deleteCount, elementsWithTrait);\r\n\t}\r\n}\r\n\r\nexport function isInputElement(e: HTMLElement): boolean {\r\n\treturn e.tagName === 'INPUT' || e.tagName === 'TEXTAREA';\r\n}\r\n\r\nexport function isMonacoEditor(e: HTMLElement): boolean {\r\n\tif (e.classList.contains('monaco-editor')) {\r\n\t\treturn true;\r\n\t}\r\n\r\n\tif (e.classList.contains('monaco-list')) {\r\n\t\treturn false;\r\n\t}\r\n\r\n\tif (!e.parentElement) {\r\n\t\treturn false;\r\n\t}\r\n\r\n\treturn isMonacoEditor(e.parentElement);\r\n}\r\n\r\nclass KeyboardController implements IDisposable {\r\n\r\n\tprivate readonly disposables = new DisposableStore();\r\n\r\n\tconstructor(\r\n\t\tprivate list: List,\r\n\t\tprivate view: ListView,\r\n\t\toptions: IListOptions\r\n\t) {\r\n\t\tconst multipleSelectionSupport = options.multipleSelectionSupport !== false;\r\n\r\n\t\tconst onKeyDown = Event.chain(domEvent(view.domNode, 'keydown'))\r\n\t\t\t.filter(e => !isInputElement(e.target as HTMLElement))\r\n\t\t\t.map(e => new StandardKeyboardEvent(e));\r\n\r\n\t\tonKeyDown.filter(e => e.keyCode === KeyCode.Enter).on(this.onEnter, this, this.disposables);\r\n\t\tonKeyDown.filter(e => e.keyCode === KeyCode.UpArrow).on(this.onUpArrow, this, this.disposables);\r\n\t\tonKeyDown.filter(e => e.keyCode === KeyCode.DownArrow).on(this.onDownArrow, this, this.disposables);\r\n\t\tonKeyDown.filter(e => e.keyCode === KeyCode.PageUp).on(this.onPageUpArrow, this, this.disposables);\r\n\t\tonKeyDown.filter(e => e.keyCode === KeyCode.PageDown).on(this.onPageDownArrow, this, this.disposables);\r\n\t\tonKeyDown.filter(e => e.keyCode === KeyCode.Escape).on(this.onEscape, this, this.disposables);\r\n\r\n\t\tif (multipleSelectionSupport) {\r\n\t\t\tonKeyDown.filter(e => (platform.isMacintosh ? e.metaKey : e.ctrlKey) && e.keyCode === KeyCode.KEY_A).on(this.onCtrlA, this, this.disposables);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate onEnter(e: StandardKeyboardEvent): void {\r\n\t\te.preventDefault();\r\n\t\te.stopPropagation();\r\n\t\tthis.list.setSelection(this.list.getFocus(), e.browserEvent);\r\n\t}\r\n\r\n\tprivate onUpArrow(e: StandardKeyboardEvent): void {\r\n\t\te.preventDefault();\r\n\t\te.stopPropagation();\r\n\t\tthis.list.focusPrevious(1, false, e.browserEvent);\r\n\t\tthis.list.reveal(this.list.getFocus()[0]);\r\n\t\tthis.view.domNode.focus();\r\n\t}\r\n\r\n\tprivate onDownArrow(e: StandardKeyboardEvent): void {\r\n\t\te.preventDefault();\r\n\t\te.stopPropagation();\r\n\t\tthis.list.focusNext(1, false, e.browserEvent);\r\n\t\tthis.list.reveal(this.list.getFocus()[0]);\r\n\t\tthis.view.domNode.focus();\r\n\t}\r\n\r\n\tprivate onPageUpArrow(e: StandardKeyboardEvent): void {\r\n\t\te.preventDefault();\r\n\t\te.stopPropagation();\r\n\t\tthis.list.focusPreviousPage(e.browserEvent);\r\n\t\tthis.list.reveal(this.list.getFocus()[0]);\r\n\t\tthis.view.domNode.focus();\r\n\t}\r\n\r\n\tprivate onPageDownArrow(e: StandardKeyboardEvent): void {\r\n\t\te.preventDefault();\r\n\t\te.stopPropagation();\r\n\t\tthis.list.focusNextPage(e.browserEvent);\r\n\t\tthis.list.reveal(this.list.getFocus()[0]);\r\n\t\tthis.view.domNode.focus();\r\n\t}\r\n\r\n\tprivate onCtrlA(e: StandardKeyboardEvent): void {\r\n\t\te.preventDefault();\r\n\t\te.stopPropagation();\r\n\t\tthis.list.setSelection(range(this.list.length), e.browserEvent);\r\n\t\tthis.view.domNode.focus();\r\n\t}\r\n\r\n\tprivate onEscape(e: StandardKeyboardEvent): void {\r\n\t\tif (this.list.getSelection().length) {\r\n\t\t\te.preventDefault();\r\n\t\t\te.stopPropagation();\r\n\t\t\tthis.list.setSelection([], e.browserEvent);\r\n\t\t\tthis.view.domNode.focus();\r\n\t\t}\r\n\t}\r\n\r\n\tdispose() {\r\n\t\tthis.disposables.dispose();\r\n\t}\r\n}\r\n\r\nenum TypeLabelControllerState {\r\n\tIdle,\r\n\tTyping\r\n}\r\n\r\nexport const DefaultKeyboardNavigationDelegate = new class implements IKeyboardNavigationDelegate {\r\n\tmightProducePrintableCharacter(event: IKeyboardEvent): boolean {\r\n\t\tif (event.ctrlKey || event.metaKey || event.altKey) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\treturn (event.keyCode >= KeyCode.KEY_A && event.keyCode <= KeyCode.KEY_Z)\r\n\t\t\t|| (event.keyCode >= KeyCode.KEY_0 && event.keyCode <= KeyCode.KEY_9)\r\n\t\t\t|| (event.keyCode >= KeyCode.NUMPAD_0 && event.keyCode <= KeyCode.NUMPAD_9)\r\n\t\t\t|| (event.keyCode >= KeyCode.US_SEMICOLON && event.keyCode <= KeyCode.US_QUOTE);\r\n\t}\r\n};\r\n\r\nclass TypeLabelController implements IDisposable {\r\n\r\n\tprivate enabled = false;\r\n\tprivate state: TypeLabelControllerState = TypeLabelControllerState.Idle;\r\n\r\n\tprivate automaticKeyboardNavigation = true;\r\n\tprivate triggered = false;\r\n\tprivate previouslyFocused = -1;\r\n\r\n\tprivate readonly enabledDisposables = new DisposableStore();\r\n\tprivate readonly disposables = new DisposableStore();\r\n\r\n\tconstructor(\r\n\t\tprivate list: List,\r\n\t\tprivate view: ListView,\r\n\t\tprivate keyboardNavigationLabelProvider: IKeyboardNavigationLabelProvider,\r\n\t\tprivate delegate: IKeyboardNavigationDelegate\r\n\t) {\r\n\t\tthis.updateOptions(list.options);\r\n\t}\r\n\r\n\tupdateOptions(options: IListOptions): void {\r\n\t\tconst enableKeyboardNavigation = typeof options.enableKeyboardNavigation === 'undefined' ? true : !!options.enableKeyboardNavigation;\r\n\r\n\t\tif (enableKeyboardNavigation) {\r\n\t\t\tthis.enable();\r\n\t\t} else {\r\n\t\t\tthis.disable();\r\n\t\t}\r\n\r\n\t\tif (typeof options.automaticKeyboardNavigation !== 'undefined') {\r\n\t\t\tthis.automaticKeyboardNavigation = options.automaticKeyboardNavigation;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate enable(): void {\r\n\t\tif (this.enabled) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst onChar = Event.chain(domEvent(this.view.domNode, 'keydown'))\r\n\t\t\t.filter(e => !isInputElement(e.target as HTMLElement))\r\n\t\t\t.filter(() => this.automaticKeyboardNavigation || this.triggered)\r\n\t\t\t.map(event => new StandardKeyboardEvent(event))\r\n\t\t\t.filter(e => this.delegate.mightProducePrintableCharacter(e))\r\n\t\t\t.forEach(e => { e.stopPropagation(); e.preventDefault(); })\r\n\t\t\t.map(event => event.browserEvent.key)\r\n\t\t\t.event;\r\n\r\n\t\tconst onClear = Event.debounce(onChar, () => null, 800);\r\n\t\tconst onInput = Event.reduce(Event.any(onChar, onClear), (r, i) => i === null ? null : ((r || '') + i));\r\n\r\n\t\tonInput(this.onInput, this, this.enabledDisposables);\r\n\t\tonClear(this.onClear, this, this.enabledDisposables);\r\n\r\n\t\tthis.enabled = true;\r\n\t\tthis.triggered = false;\r\n\t}\r\n\r\n\tprivate disable(): void {\r\n\t\tif (!this.enabled) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.enabledDisposables.clear();\r\n\t\tthis.enabled = false;\r\n\t\tthis.triggered = false;\r\n\t}\r\n\r\n\tprivate onClear(): void {\r\n\t\tconst focus = this.list.getFocus();\r\n\t\tif (focus.length > 0 && focus[0] === this.previouslyFocused) {\r\n\t\t\t// List: re-anounce element on typing end since typed keys will interupt aria label of focused element\r\n\t\t\t// Do not announce if there was a focus change at the end to prevent duplication https://github.com/microsoft/vscode/issues/95961\r\n\t\t\tconst ariaLabel = this.list.options.accessibilityProvider?.getAriaLabel(this.list.element(focus[0]));\r\n\t\t\tif (ariaLabel) {\r\n\t\t\t\talert(ariaLabel);\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis.previouslyFocused = -1;\r\n\t}\r\n\r\n\tprivate onInput(word: string | null): void {\r\n\t\tif (!word) {\r\n\t\t\tthis.state = TypeLabelControllerState.Idle;\r\n\t\t\tthis.triggered = false;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst focus = this.list.getFocus();\r\n\t\tconst start = focus.length > 0 ? focus[0] : 0;\r\n\t\tconst delta = this.state === TypeLabelControllerState.Idle ? 1 : 0;\r\n\t\tthis.state = TypeLabelControllerState.Typing;\r\n\r\n\t\tfor (let i = 0; i < this.list.length; i++) {\r\n\t\t\tconst index = (start + i + delta) % this.list.length;\r\n\t\t\tconst label = this.keyboardNavigationLabelProvider.getKeyboardNavigationLabel(this.view.element(index));\r\n\t\t\tconst labelStr = label && label.toString();\r\n\r\n\t\t\tif (typeof labelStr === 'undefined' || matchesPrefix(word, labelStr)) {\r\n\t\t\t\tthis.previouslyFocused = start;\r\n\t\t\t\tthis.list.setFocus([index]);\r\n\t\t\t\tthis.list.reveal(index);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tdispose() {\r\n\t\tthis.disable();\r\n\t\tthis.enabledDisposables.dispose();\r\n\t\tthis.disposables.dispose();\r\n\t}\r\n}\r\n\r\nclass DOMFocusController implements IDisposable {\r\n\r\n\tprivate readonly disposables = new DisposableStore();\r\n\r\n\tconstructor(\r\n\t\tprivate list: List,\r\n\t\tprivate view: ListView\r\n\t) {\r\n\t\tconst onKeyDown = Event.chain(domEvent(view.domNode, 'keydown'))\r\n\t\t\t.filter(e => !isInputElement(e.target as HTMLElement))\r\n\t\t\t.map(e => new StandardKeyboardEvent(e));\r\n\r\n\t\tonKeyDown.filter(e => e.keyCode === KeyCode.Tab && !e.ctrlKey && !e.metaKey && !e.shiftKey && !e.altKey)\r\n\t\t\t.on(this.onTab, this, this.disposables);\r\n\t}\r\n\r\n\tprivate onTab(e: StandardKeyboardEvent): void {\r\n\t\tif (e.target !== this.view.domNode) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst focus = this.list.getFocus();\r\n\r\n\t\tif (focus.length === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst focusedDomElement = this.view.domElement(focus[0]);\r\n\r\n\t\tif (!focusedDomElement) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst tabIndexElement = focusedDomElement.querySelector('[tabIndex]');\r\n\r\n\t\tif (!tabIndexElement || !(tabIndexElement instanceof HTMLElement) || tabIndexElement.tabIndex === -1) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst style = window.getComputedStyle(tabIndexElement);\r\n\t\tif (style.visibility === 'hidden' || style.display === 'none') {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\te.preventDefault();\r\n\t\te.stopPropagation();\r\n\t\ttabIndexElement.focus();\r\n\t}\r\n\r\n\tdispose() {\r\n\t\tthis.disposables.dispose();\r\n\t}\r\n}\r\n\r\nexport function isSelectionSingleChangeEvent(event: IListMouseEvent | IListTouchEvent): boolean {\r\n\treturn platform.isMacintosh ? event.browserEvent.metaKey : event.browserEvent.ctrlKey;\r\n}\r\n\r\nexport function isSelectionRangeChangeEvent(event: IListMouseEvent | IListTouchEvent): boolean {\r\n\treturn event.browserEvent.shiftKey;\r\n}\r\n\r\nfunction isMouseRightClick(event: UIEvent): boolean {\r\n\treturn event instanceof MouseEvent && event.button === 2;\r\n}\r\n\r\nconst DefaultMultipleSelectionController = {\r\n\tisSelectionSingleChangeEvent,\r\n\tisSelectionRangeChangeEvent\r\n};\r\n\r\nexport class MouseController implements IDisposable {\r\n\r\n\tprivate multipleSelectionSupport: boolean;\r\n\treadonly multipleSelectionController: IMultipleSelectionController | undefined;\r\n\tprivate mouseSupport: boolean;\r\n\tprivate readonly disposables = new DisposableStore();\r\n\r\n\tprivate _onPointer = new Emitter>();\r\n\treadonly onPointer: Event> = this._onPointer.event;\r\n\r\n\tconstructor(protected list: List) {\r\n\t\tthis.multipleSelectionSupport = !(list.options.multipleSelectionSupport === false);\r\n\r\n\t\tif (this.multipleSelectionSupport) {\r\n\t\t\tthis.multipleSelectionController = list.options.multipleSelectionController || DefaultMultipleSelectionController;\r\n\t\t}\r\n\r\n\t\tthis.mouseSupport = typeof list.options.mouseSupport === 'undefined' || !!list.options.mouseSupport;\r\n\r\n\t\tif (this.mouseSupport) {\r\n\t\t\tlist.onMouseDown(this.onMouseDown, this, this.disposables);\r\n\t\t\tlist.onContextMenu(this.onContextMenu, this, this.disposables);\r\n\t\t\tlist.onMouseDblClick(this.onDoubleClick, this, this.disposables);\r\n\t\t\tlist.onTouchStart(this.onMouseDown, this, this.disposables);\r\n\t\t\tthis.disposables.add(Gesture.addTarget(list.getHTMLElement()));\r\n\t\t}\r\n\r\n\t\tEvent.any(list.onMouseClick, list.onMouseMiddleClick, list.onTap)(this.onViewPointer, this, this.disposables);\r\n\t}\r\n\r\n\tprotected isSelectionSingleChangeEvent(event: IListMouseEvent | IListTouchEvent): boolean {\r\n\t\tif (this.multipleSelectionController) {\r\n\t\t\treturn this.multipleSelectionController.isSelectionSingleChangeEvent(event);\r\n\t\t}\r\n\r\n\t\treturn platform.isMacintosh ? event.browserEvent.metaKey : event.browserEvent.ctrlKey;\r\n\t}\r\n\r\n\tprotected isSelectionRangeChangeEvent(event: IListMouseEvent | IListTouchEvent): boolean {\r\n\t\tif (this.multipleSelectionController) {\r\n\t\t\treturn this.multipleSelectionController.isSelectionRangeChangeEvent(event);\r\n\t\t}\r\n\r\n\t\treturn event.browserEvent.shiftKey;\r\n\t}\r\n\r\n\tprivate isSelectionChangeEvent(event: IListMouseEvent | IListTouchEvent): boolean {\r\n\t\treturn this.isSelectionSingleChangeEvent(event) || this.isSelectionRangeChangeEvent(event);\r\n\t}\r\n\r\n\tprivate onMouseDown(e: IListMouseEvent | IListTouchEvent): void {\r\n\t\tif (isMonacoEditor(e.browserEvent.target as HTMLElement)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (document.activeElement !== e.browserEvent.target) {\r\n\t\t\tthis.list.domFocus();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate onContextMenu(e: IListContextMenuEvent): void {\r\n\t\tif (isMonacoEditor(e.browserEvent.target as HTMLElement)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst focus = typeof e.index === 'undefined' ? [] : [e.index];\r\n\t\tthis.list.setFocus(focus, e.browserEvent);\r\n\t}\r\n\r\n\tprotected onViewPointer(e: IListMouseEvent): void {\r\n\t\tif (!this.mouseSupport) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (isInputElement(e.browserEvent.target as HTMLElement) || isMonacoEditor(e.browserEvent.target as HTMLElement)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet reference = this.list.getFocus()[0];\r\n\t\tconst selection = this.list.getSelection();\r\n\t\treference = reference === undefined ? selection[0] : reference;\r\n\r\n\t\tconst focus = e.index;\r\n\r\n\t\tif (typeof focus === 'undefined') {\r\n\t\t\tthis.list.setFocus([], e.browserEvent);\r\n\t\t\tthis.list.setSelection([], e.browserEvent);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this.multipleSelectionSupport && this.isSelectionRangeChangeEvent(e)) {\r\n\t\t\treturn this.changeSelection(e, reference);\r\n\t\t}\r\n\r\n\t\tif (this.multipleSelectionSupport && this.isSelectionChangeEvent(e)) {\r\n\t\t\treturn this.changeSelection(e, reference);\r\n\t\t}\r\n\r\n\t\tthis.list.setFocus([focus], e.browserEvent);\r\n\r\n\t\tif (!isMouseRightClick(e.browserEvent)) {\r\n\t\t\tthis.list.setSelection([focus], e.browserEvent);\r\n\t\t}\r\n\r\n\t\tthis._onPointer.fire(e);\r\n\t}\r\n\r\n\tprotected onDoubleClick(e: IListMouseEvent): void {\r\n\t\tif (isInputElement(e.browserEvent.target as HTMLElement) || isMonacoEditor(e.browserEvent.target as HTMLElement)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this.multipleSelectionSupport && this.isSelectionChangeEvent(e)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst focus = this.list.getFocus();\r\n\t\tthis.list.setSelection(focus, e.browserEvent);\r\n\t}\r\n\r\n\tprivate changeSelection(e: IListMouseEvent | IListTouchEvent, reference: number | undefined): void {\r\n\t\tconst focus = e.index!;\r\n\r\n\t\tif (this.isSelectionRangeChangeEvent(e) && reference !== undefined) {\r\n\t\t\tconst min = Math.min(reference, focus);\r\n\t\t\tconst max = Math.max(reference, focus);\r\n\t\t\tconst rangeSelection = range(min, max + 1);\r\n\t\t\tconst selection = this.list.getSelection();\r\n\t\t\tconst contiguousRange = getContiguousRangeContaining(disjunction(selection, [reference]), reference);\r\n\r\n\t\t\tif (contiguousRange.length === 0) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst newSelection = disjunction(rangeSelection, relativeComplement(selection, contiguousRange));\r\n\t\t\tthis.list.setSelection(newSelection, e.browserEvent);\r\n\r\n\t\t} else if (this.isSelectionSingleChangeEvent(e)) {\r\n\t\t\tconst selection = this.list.getSelection();\r\n\t\t\tconst newSelection = selection.filter(i => i !== focus);\r\n\r\n\t\t\tthis.list.setFocus([focus]);\r\n\r\n\t\t\tif (selection.length === newSelection.length) {\r\n\t\t\t\tthis.list.setSelection([...newSelection, focus], e.browserEvent);\r\n\t\t\t} else {\r\n\t\t\t\tthis.list.setSelection(newSelection, e.browserEvent);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tdispose() {\r\n\t\tthis.disposables.dispose();\r\n\t}\r\n}\r\n\r\nexport interface IMultipleSelectionController {\r\n\tisSelectionSingleChangeEvent(event: IListMouseEvent | IListTouchEvent): boolean;\r\n\tisSelectionRangeChangeEvent(event: IListMouseEvent | IListTouchEvent): boolean;\r\n}\r\n\r\nexport interface IStyleController {\r\n\tstyle(styles: IListStyles): void;\r\n}\r\n\r\nexport interface IListAccessibilityProvider extends IListViewAccessibilityProvider {\r\n\tgetAriaLabel(element: T): string | null;\r\n\tgetWidgetAriaLabel(): string;\r\n\tgetWidgetRole?(): string;\r\n\tgetAriaLevel?(element: T): number | undefined;\r\n\tonDidChangeActiveDescendant?: Event;\r\n\tgetActiveDescendantId?(element: T): string | undefined;\r\n}\r\n\r\nexport class DefaultStyleController implements IStyleController {\r\n\r\n\tconstructor(private styleElement: HTMLStyleElement, private selectorSuffix: string) { }\r\n\r\n\tstyle(styles: IListStyles): void {\r\n\t\tconst suffix = this.selectorSuffix && `.${this.selectorSuffix}`;\r\n\t\tconst content: string[] = [];\r\n\r\n\t\tif (styles.listBackground) {\r\n\t\t\tif (styles.listBackground.isOpaque()) {\r\n\t\t\t\tcontent.push(`.monaco-list${suffix} .monaco-list-rows { background: ${styles.listBackground}; }`);\r\n\t\t\t} else if (!platform.isMacintosh) { // subpixel AA doesn't exist in macOS\r\n\t\t\t\tconsole.warn(`List with id '${this.selectorSuffix}' was styled with a non-opaque background color. This will break sub-pixel antialiasing.`);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (styles.listFocusBackground) {\r\n\t\t\tcontent.push(`.monaco-list${suffix}:focus .monaco-list-row.focused { background-color: ${styles.listFocusBackground}; }`);\r\n\t\t\tcontent.push(`.monaco-list${suffix}:focus .monaco-list-row.focused:hover { background-color: ${styles.listFocusBackground}; }`); // overwrite :hover style in this case!\r\n\t\t}\r\n\r\n\t\tif (styles.listFocusForeground) {\r\n\t\t\tcontent.push(`.monaco-list${suffix}:focus .monaco-list-row.focused { color: ${styles.listFocusForeground}; }`);\r\n\t\t}\r\n\r\n\t\tif (styles.listActiveSelectionBackground) {\r\n\t\t\tcontent.push(`.monaco-list${suffix}:focus .monaco-list-row.selected { background-color: ${styles.listActiveSelectionBackground}; }`);\r\n\t\t\tcontent.push(`.monaco-list${suffix}:focus .monaco-list-row.selected:hover { background-color: ${styles.listActiveSelectionBackground}; }`); // overwrite :hover style in this case!\r\n\t\t}\r\n\r\n\t\tif (styles.listActiveSelectionForeground) {\r\n\t\t\tcontent.push(`.monaco-list${suffix}:focus .monaco-list-row.selected { color: ${styles.listActiveSelectionForeground}; }`);\r\n\t\t}\r\n\r\n\t\tif (styles.listFocusAndSelectionBackground) {\r\n\t\t\tcontent.push(`\r\n\t\t\t\t.monaco-drag-image,\r\n\t\t\t\t.monaco-list${suffix}:focus .monaco-list-row.selected.focused { background-color: ${styles.listFocusAndSelectionBackground}; }\r\n\t\t\t`);\r\n\t\t}\r\n\r\n\t\tif (styles.listFocusAndSelectionForeground) {\r\n\t\t\tcontent.push(`\r\n\t\t\t\t.monaco-drag-image,\r\n\t\t\t\t.monaco-list${suffix}:focus .monaco-list-row.selected.focused { color: ${styles.listFocusAndSelectionForeground}; }\r\n\t\t\t`);\r\n\t\t}\r\n\r\n\t\tif (styles.listInactiveFocusBackground) {\r\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-list-row.focused { background-color: ${styles.listInactiveFocusBackground}; }`);\r\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-list-row.focused:hover { background-color: ${styles.listInactiveFocusBackground}; }`); // overwrite :hover style in this case!\r\n\t\t}\r\n\r\n\t\tif (styles.listInactiveSelectionBackground) {\r\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-list-row.selected { background-color: ${styles.listInactiveSelectionBackground}; }`);\r\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-list-row.selected:hover { background-color: ${styles.listInactiveSelectionBackground}; }`); // overwrite :hover style in this case!\r\n\t\t}\r\n\r\n\t\tif (styles.listInactiveSelectionForeground) {\r\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-list-row.selected { color: ${styles.listInactiveSelectionForeground}; }`);\r\n\t\t}\r\n\r\n\t\tif (styles.listHoverBackground) {\r\n\t\t\tcontent.push(`.monaco-list${suffix}:not(.drop-target) .monaco-list-row:hover:not(.selected):not(.focused) { background-color: ${styles.listHoverBackground}; }`);\r\n\t\t}\r\n\r\n\t\tif (styles.listHoverForeground) {\r\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-list-row:hover:not(.selected):not(.focused) { color: ${styles.listHoverForeground}; }`);\r\n\t\t}\r\n\r\n\t\tif (styles.listSelectionOutline) {\r\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-list-row.selected { outline: 1px dotted ${styles.listSelectionOutline}; outline-offset: -1px; }`);\r\n\t\t}\r\n\r\n\t\tif (styles.listFocusOutline) {\r\n\t\t\tcontent.push(`\r\n\t\t\t\t.monaco-drag-image,\r\n\t\t\t\t.monaco-list${suffix}:focus .monaco-list-row.focused { outline: 1px solid ${styles.listFocusOutline}; outline-offset: -1px; }\r\n\t\t\t`);\r\n\t\t}\r\n\r\n\t\tif (styles.listInactiveFocusOutline) {\r\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-list-row.focused { outline: 1px dotted ${styles.listInactiveFocusOutline}; outline-offset: -1px; }`);\r\n\t\t}\r\n\r\n\t\tif (styles.listHoverOutline) {\r\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-list-row:hover { outline: 1px dashed ${styles.listHoverOutline}; outline-offset: -1px; }`);\r\n\t\t}\r\n\r\n\t\tif (styles.listDropBackground) {\r\n\t\t\tcontent.push(`\r\n\t\t\t\t.monaco-list${suffix}.drop-target,\r\n\t\t\t\t.monaco-list${suffix} .monaco-list-rows.drop-target,\r\n\t\t\t\t.monaco-list${suffix} .monaco-list-row.drop-target { background-color: ${styles.listDropBackground} !important; color: inherit !important; }\r\n\t\t\t`);\r\n\t\t}\r\n\r\n\t\tif (styles.listFilterWidgetBackground) {\r\n\t\t\tcontent.push(`.monaco-list-type-filter { background-color: ${styles.listFilterWidgetBackground} }`);\r\n\t\t}\r\n\r\n\t\tif (styles.listFilterWidgetOutline) {\r\n\t\t\tcontent.push(`.monaco-list-type-filter { border: 1px solid ${styles.listFilterWidgetOutline}; }`);\r\n\t\t}\r\n\r\n\t\tif (styles.listFilterWidgetNoMatchesOutline) {\r\n\t\t\tcontent.push(`.monaco-list-type-filter.no-matches { border: 1px solid ${styles.listFilterWidgetNoMatchesOutline}; }`);\r\n\t\t}\r\n\r\n\t\tif (styles.listMatchesShadow) {\r\n\t\t\tcontent.push(`.monaco-list-type-filter { box-shadow: 1px 1px 1px ${styles.listMatchesShadow}; }`);\r\n\t\t}\r\n\r\n\t\tthis.styleElement.textContent = content.join('\\n');\r\n\t}\r\n}\r\n\r\nexport interface IListOptions {\r\n\treadonly identityProvider?: IIdentityProvider;\r\n\treadonly dnd?: IListDragAndDrop;\r\n\treadonly enableKeyboardNavigation?: boolean;\r\n\treadonly automaticKeyboardNavigation?: boolean;\r\n\treadonly keyboardNavigationLabelProvider?: IKeyboardNavigationLabelProvider;\r\n\treadonly keyboardNavigationDelegate?: IKeyboardNavigationDelegate;\r\n\treadonly keyboardSupport?: boolean;\r\n\treadonly multipleSelectionSupport?: boolean;\r\n\treadonly multipleSelectionController?: IMultipleSelectionController;\r\n\treadonly styleController?: (suffix: string) => IStyleController;\r\n\treadonly accessibilityProvider?: IListAccessibilityProvider;\r\n\r\n\t// list view options\r\n\treadonly useShadows?: boolean;\r\n\treadonly setRowLineHeight?: boolean;\r\n\treadonly mouseSupport?: boolean;\r\n\treadonly horizontalScrolling?: boolean;\r\n\treadonly smoothScrolling?: boolean;\r\n}\r\n\r\nexport interface IListStyles {\r\n\tlistBackground?: Color;\r\n\tlistFocusBackground?: Color;\r\n\tlistFocusForeground?: Color;\r\n\tlistActiveSelectionBackground?: Color;\r\n\tlistActiveSelectionForeground?: Color;\r\n\tlistFocusAndSelectionBackground?: Color;\r\n\tlistFocusAndSelectionForeground?: Color;\r\n\tlistInactiveSelectionBackground?: Color;\r\n\tlistInactiveSelectionForeground?: Color;\r\n\tlistInactiveFocusBackground?: Color;\r\n\tlistHoverBackground?: Color;\r\n\tlistHoverForeground?: Color;\r\n\tlistDropBackground?: Color;\r\n\tlistFocusOutline?: Color;\r\n\tlistInactiveFocusOutline?: Color;\r\n\tlistSelectionOutline?: Color;\r\n\tlistHoverOutline?: Color;\r\n\tlistFilterWidgetBackground?: Color;\r\n\tlistFilterWidgetOutline?: Color;\r\n\tlistFilterWidgetNoMatchesOutline?: Color;\r\n\tlistMatchesShadow?: Color;\r\n\ttreeIndentGuidesStroke?: Color;\r\n}\r\n\r\nconst defaultStyles: IListStyles = {\r\n\tlistFocusBackground: Color.fromHex('#7FB0D0'),\r\n\tlistActiveSelectionBackground: Color.fromHex('#0E639C'),\r\n\tlistActiveSelectionForeground: Color.fromHex('#FFFFFF'),\r\n\tlistFocusAndSelectionBackground: Color.fromHex('#094771'),\r\n\tlistFocusAndSelectionForeground: Color.fromHex('#FFFFFF'),\r\n\tlistInactiveSelectionBackground: Color.fromHex('#3F3F46'),\r\n\tlistHoverBackground: Color.fromHex('#2A2D2E'),\r\n\tlistDropBackground: Color.fromHex('#383B3D'),\r\n\ttreeIndentGuidesStroke: Color.fromHex('#a9a9a9')\r\n};\r\n\r\nconst DefaultOptions: IListOptions = {\r\n\tkeyboardSupport: true,\r\n\tmouseSupport: true,\r\n\tmultipleSelectionSupport: true,\r\n\tdnd: {\r\n\t\tgetDragURI() { return null; },\r\n\t\tonDragStart(): void { },\r\n\t\tonDragOver() { return false; },\r\n\t\tdrop() { }\r\n\t}\r\n};\r\n\r\n// TODO@Joao: move these utils into a SortedArray class\r\n\r\nfunction getContiguousRangeContaining(range: number[], value: number): number[] {\r\n\tconst index = range.indexOf(value);\r\n\r\n\tif (index === -1) {\r\n\t\treturn [];\r\n\t}\r\n\r\n\tconst result: number[] = [];\r\n\tlet i = index - 1;\r\n\twhile (i >= 0 && range[i] === value - (index - i)) {\r\n\t\tresult.push(range[i--]);\r\n\t}\r\n\r\n\tresult.reverse();\r\n\ti = index;\r\n\twhile (i < range.length && range[i] === value + (i - index)) {\r\n\t\tresult.push(range[i++]);\r\n\t}\r\n\r\n\treturn result;\r\n}\r\n\r\n/**\r\n * Given two sorted collections of numbers, returns the intersection\r\n * between them (OR).\r\n */\r\nfunction disjunction(one: number[], other: number[]): number[] {\r\n\tconst result: number[] = [];\r\n\tlet i = 0, j = 0;\r\n\r\n\twhile (i < one.length || j < other.length) {\r\n\t\tif (i >= one.length) {\r\n\t\t\tresult.push(other[j++]);\r\n\t\t} else if (j >= other.length) {\r\n\t\t\tresult.push(one[i++]);\r\n\t\t} else if (one[i] === other[j]) {\r\n\t\t\tresult.push(one[i]);\r\n\t\t\ti++;\r\n\t\t\tj++;\r\n\t\t\tcontinue;\r\n\t\t} else if (one[i] < other[j]) {\r\n\t\t\tresult.push(one[i++]);\r\n\t\t} else {\r\n\t\t\tresult.push(other[j++]);\r\n\t\t}\r\n\t}\r\n\r\n\treturn result;\r\n}\r\n\r\n/**\r\n * Given two sorted collections of numbers, returns the relative\r\n * complement between them (XOR).\r\n */\r\nfunction relativeComplement(one: number[], other: number[]): number[] {\r\n\tconst result: number[] = [];\r\n\tlet i = 0, j = 0;\r\n\r\n\twhile (i < one.length || j < other.length) {\r\n\t\tif (i >= one.length) {\r\n\t\t\tresult.push(other[j++]);\r\n\t\t} else if (j >= other.length) {\r\n\t\t\tresult.push(one[i++]);\r\n\t\t} else if (one[i] === other[j]) {\r\n\t\t\ti++;\r\n\t\t\tj++;\r\n\t\t\tcontinue;\r\n\t\t} else if (one[i] < other[j]) {\r\n\t\t\tresult.push(one[i++]);\r\n\t\t} else {\r\n\t\t\tj++;\r\n\t\t}\r\n\t}\r\n\r\n\treturn result;\r\n}\r\n\r\nconst numericSort = (a: number, b: number) => a - b;\r\n\r\nclass PipelineRenderer implements IListRenderer {\r\n\r\n\tconstructor(\r\n\t\tprivate _templateId: string,\r\n\t\tprivate renderers: IListRenderer[]\r\n\t) { }\r\n\r\n\tget templateId(): string {\r\n\t\treturn this._templateId;\r\n\t}\r\n\r\n\trenderTemplate(container: HTMLElement): any[] {\r\n\t\treturn this.renderers.map(r => r.renderTemplate(container));\r\n\t}\r\n\r\n\trenderElement(element: T, index: number, templateData: any[], height: number | undefined): void {\r\n\t\tlet i = 0;\r\n\r\n\t\tfor (const renderer of this.renderers) {\r\n\t\t\trenderer.renderElement(element, index, templateData[i++], height);\r\n\t\t}\r\n\t}\r\n\r\n\tdisposeElement(element: T, index: number, templateData: any[], height: number | undefined): void {\r\n\t\tlet i = 0;\r\n\r\n\t\tfor (const renderer of this.renderers) {\r\n\t\t\tif (renderer.disposeElement) {\r\n\t\t\t\trenderer.disposeElement(element, index, templateData[i], height);\r\n\t\t\t}\r\n\r\n\t\t\ti += 1;\r\n\t\t}\r\n\t}\r\n\r\n\tdisposeTemplate(templateData: any[]): void {\r\n\t\tlet i = 0;\r\n\r\n\t\tfor (const renderer of this.renderers) {\r\n\t\t\trenderer.disposeTemplate(templateData[i++]);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass AccessibiltyRenderer implements IListRenderer {\r\n\r\n\ttemplateId: string = 'a18n';\r\n\r\n\tconstructor(private accessibilityProvider: IListAccessibilityProvider) { }\r\n\r\n\trenderTemplate(container: HTMLElement): HTMLElement {\r\n\t\treturn container;\r\n\t}\r\n\r\n\trenderElement(element: T, index: number, container: HTMLElement): void {\r\n\t\tconst ariaLabel = this.accessibilityProvider.getAriaLabel(element);\r\n\r\n\t\tif (ariaLabel) {\r\n\t\t\tcontainer.setAttribute('aria-label', ariaLabel);\r\n\t\t} else {\r\n\t\t\tcontainer.removeAttribute('aria-label');\r\n\t\t}\r\n\r\n\t\tconst ariaLevel = this.accessibilityProvider.getAriaLevel && this.accessibilityProvider.getAriaLevel(element);\r\n\r\n\t\tif (typeof ariaLevel === 'number') {\r\n\t\t\tcontainer.setAttribute('aria-level', `${ariaLevel}`);\r\n\t\t} else {\r\n\t\t\tcontainer.removeAttribute('aria-level');\r\n\t\t}\r\n\t}\r\n\r\n\tdisposeTemplate(templateData: any): void {\r\n\t\t// noop\r\n\t}\r\n}\r\n\r\nclass ListViewDragAndDrop implements IListViewDragAndDrop {\r\n\r\n\tconstructor(private list: List, private dnd: IListDragAndDrop) { }\r\n\r\n\tgetDragElements(element: T): T[] {\r\n\t\tconst selection = this.list.getSelectedElements();\r\n\t\tconst elements = selection.indexOf(element) > -1 ? selection : [element];\r\n\t\treturn elements;\r\n\t}\r\n\r\n\tgetDragURI(element: T): string | null {\r\n\t\treturn this.dnd.getDragURI(element);\r\n\t}\r\n\r\n\tgetDragLabel?(elements: T[], originalEvent: DragEvent): string | undefined {\r\n\t\tif (this.dnd.getDragLabel) {\r\n\t\t\treturn this.dnd.getDragLabel(elements, originalEvent);\r\n\t\t}\r\n\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tonDragStart(data: IDragAndDropData, originalEvent: DragEvent): void {\r\n\t\tif (this.dnd.onDragStart) {\r\n\t\t\tthis.dnd.onDragStart(data, originalEvent);\r\n\t\t}\r\n\t}\r\n\r\n\tonDragOver(data: IDragAndDropData, targetElement: T, targetIndex: number, originalEvent: DragEvent): boolean | IListDragOverReaction {\r\n\t\treturn this.dnd.onDragOver(data, targetElement, targetIndex, originalEvent);\r\n\t}\r\n\r\n\tonDragEnd(originalEvent: DragEvent): void {\r\n\t\tif (this.dnd.onDragEnd) {\r\n\t\t\tthis.dnd.onDragEnd(originalEvent);\r\n\t\t}\r\n\t}\r\n\r\n\tdrop(data: IDragAndDropData, targetElement: T, targetIndex: number, originalEvent: DragEvent): void {\r\n\t\tthis.dnd.drop(data, targetElement, targetIndex, originalEvent);\r\n\t}\r\n}\r\n\r\nexport interface IListOptionsUpdate extends IListViewOptionsUpdate {\r\n\treadonly enableKeyboardNavigation?: boolean;\r\n\treadonly automaticKeyboardNavigation?: boolean;\r\n}\r\n\r\nexport class List implements ISpliceable, IThemable, IDisposable {\r\n\r\n\tprivate focus: Trait;\r\n\tprivate selection: Trait;\r\n\tprivate eventBufferer = new EventBufferer();\r\n\tprotected view: ListView;\r\n\tprivate spliceable: ISpliceable;\r\n\tprivate styleController: IStyleController;\r\n\tprivate typeLabelController?: TypeLabelController;\r\n\tprivate accessibilityProvider?: IListAccessibilityProvider;\r\n\tprivate mouseController: MouseController;\r\n\tprivate _ariaLabel: string = '';\r\n\r\n\tprotected readonly disposables = new DisposableStore();\r\n\r\n\t@memoize get onDidChangeFocus(): Event> {\r\n\t\treturn Event.map(this.eventBufferer.wrapEvent(this.focus.onChange), e => this.toListEvent(e));\r\n\t}\r\n\r\n\t@memoize get onDidChangeSelection(): Event> {\r\n\t\treturn Event.map(this.eventBufferer.wrapEvent(this.selection.onChange), e => this.toListEvent(e));\r\n\t}\r\n\r\n\tget domId(): string { return this.view.domId; }\r\n\tget onMouseClick(): Event> { return this.view.onMouseClick; }\r\n\tget onMouseDblClick(): Event> { return this.view.onMouseDblClick; }\r\n\tget onMouseMiddleClick(): Event> { return this.view.onMouseMiddleClick; }\r\n\tget onPointer(): Event> { return this.mouseController.onPointer; }\r\n\tget onMouseDown(): Event> { return this.view.onMouseDown; }\r\n\tget onTouchStart(): Event> { return this.view.onTouchStart; }\r\n\tget onTap(): Event> { return this.view.onTap; }\r\n\r\n\tprivate didJustPressContextMenuKey: boolean = false;\r\n\t@memoize get onContextMenu(): Event> {\r\n\t\tconst fromKeydown = Event.chain(domEvent(this.view.domNode, 'keydown'))\r\n\t\t\t.map(e => new StandardKeyboardEvent(e))\r\n\t\t\t.filter(e => this.didJustPressContextMenuKey = e.keyCode === KeyCode.ContextMenu || (e.shiftKey && e.keyCode === KeyCode.F10))\r\n\t\t\t.filter(e => { e.preventDefault(); e.stopPropagation(); return false; })\r\n\t\t\t.event as Event;\r\n\r\n\t\tconst fromKeyup = Event.chain(domEvent(this.view.domNode, 'keyup'))\r\n\t\t\t.filter(() => {\r\n\t\t\t\tconst didJustPressContextMenuKey = this.didJustPressContextMenuKey;\r\n\t\t\t\tthis.didJustPressContextMenuKey = false;\r\n\t\t\t\treturn didJustPressContextMenuKey;\r\n\t\t\t})\r\n\t\t\t.filter(() => this.getFocus().length > 0 && !!this.view.domElement(this.getFocus()[0]))\r\n\t\t\t.map(browserEvent => {\r\n\t\t\t\tconst index = this.getFocus()[0];\r\n\t\t\t\tconst element = this.view.element(index);\r\n\t\t\t\tconst anchor = this.view.domElement(index) as HTMLElement;\r\n\t\t\t\treturn { index, element, anchor, browserEvent };\r\n\t\t\t})\r\n\t\t\t.event;\r\n\r\n\t\tconst fromMouse = Event.chain(this.view.onContextMenu)\r\n\t\t\t.filter(() => !this.didJustPressContextMenuKey)\r\n\t\t\t.map(({ element, index, browserEvent }) => ({ element, index, anchor: { x: browserEvent.clientX + 1, y: browserEvent.clientY }, browserEvent }))\r\n\t\t\t.event;\r\n\r\n\t\treturn Event.any>(fromKeydown, fromKeyup, fromMouse);\r\n\t}\r\n\r\n\tget onKeyDown(): Event { return domEvent(this.view.domNode, 'keydown'); }\r\n\r\n\treadonly onDidFocus: Event;\r\n\treadonly onDidBlur: Event;\r\n\r\n\tprivate readonly _onDidDispose = new Emitter();\r\n\treadonly onDidDispose: Event = this._onDidDispose.event;\r\n\r\n\tconstructor(\r\n\t\tprivate user: string,\r\n\t\tcontainer: HTMLElement,\r\n\t\tvirtualDelegate: IListVirtualDelegate,\r\n\t\trenderers: IListRenderer[],\r\n\t\tprivate _options: IListOptions = DefaultOptions\r\n\t) {\r\n\t\tconst role = this._options.accessibilityProvider && this._options.accessibilityProvider.getWidgetRole ? this._options.accessibilityProvider?.getWidgetRole() : 'list';\r\n\t\tthis.selection = new SelectionTrait(role !== 'listbox');\r\n\t\tthis.focus = new Trait('focused');\r\n\r\n\t\tmixin(_options, defaultStyles, false);\r\n\r\n\t\tconst baseRenderers: IListRenderer[] = [this.focus.renderer, this.selection.renderer];\r\n\r\n\t\tthis.accessibilityProvider = _options.accessibilityProvider;\r\n\r\n\t\tif (this.accessibilityProvider) {\r\n\t\t\tbaseRenderers.push(new AccessibiltyRenderer(this.accessibilityProvider));\r\n\r\n\t\t\tif (this.accessibilityProvider.onDidChangeActiveDescendant) {\r\n\t\t\t\tthis.accessibilityProvider.onDidChangeActiveDescendant(this.onDidChangeActiveDescendant, this, this.disposables);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\trenderers = renderers.map(r => new PipelineRenderer(r.templateId, [...baseRenderers, r]));\r\n\r\n\t\tconst viewOptions: IListViewOptions = {\r\n\t\t\t..._options,\r\n\t\t\tdnd: _options.dnd && new ListViewDragAndDrop(this, _options.dnd)\r\n\t\t};\r\n\r\n\t\tthis.view = new ListView(container, virtualDelegate, renderers, viewOptions);\r\n\t\tthis.view.domNode.setAttribute('role', role);\r\n\r\n\t\tif (_options.styleController) {\r\n\t\t\tthis.styleController = _options.styleController(this.view.domId);\r\n\t\t} else {\r\n\t\t\tconst styleElement = createStyleSheet(this.view.domNode);\r\n\t\t\tthis.styleController = new DefaultStyleController(styleElement, this.view.domId);\r\n\t\t}\r\n\r\n\t\tthis.spliceable = new CombinedSpliceable([\r\n\t\t\tnew TraitSpliceable(this.focus, this.view, _options.identityProvider),\r\n\t\t\tnew TraitSpliceable(this.selection, this.view, _options.identityProvider),\r\n\t\t\tthis.view\r\n\t\t]);\r\n\r\n\t\tthis.disposables.add(this.focus);\r\n\t\tthis.disposables.add(this.selection);\r\n\t\tthis.disposables.add(this.view);\r\n\t\tthis.disposables.add(this._onDidDispose);\r\n\r\n\t\tthis.onDidFocus = Event.map(domEvent(this.view.domNode, 'focus', true), () => null!);\r\n\t\tthis.onDidBlur = Event.map(domEvent(this.view.domNode, 'blur', true), () => null!);\r\n\r\n\t\tthis.disposables.add(new DOMFocusController(this, this.view));\r\n\r\n\t\tif (typeof _options.keyboardSupport !== 'boolean' || _options.keyboardSupport) {\r\n\t\t\tconst controller = new KeyboardController(this, this.view, _options);\r\n\t\t\tthis.disposables.add(controller);\r\n\t\t}\r\n\r\n\t\tif (_options.keyboardNavigationLabelProvider) {\r\n\t\t\tconst delegate = _options.keyboardNavigationDelegate || DefaultKeyboardNavigationDelegate;\r\n\t\t\tthis.typeLabelController = new TypeLabelController(this, this.view, _options.keyboardNavigationLabelProvider, delegate);\r\n\t\t\tthis.disposables.add(this.typeLabelController);\r\n\t\t}\r\n\r\n\t\tthis.mouseController = this.createMouseController(_options);\r\n\t\tthis.disposables.add(this.mouseController);\r\n\r\n\t\tthis.onDidChangeFocus(this._onFocusChange, this, this.disposables);\r\n\t\tthis.onDidChangeSelection(this._onSelectionChange, this, this.disposables);\r\n\r\n\t\tif (this.accessibilityProvider) {\r\n\t\t\tthis.ariaLabel = this.accessibilityProvider.getWidgetAriaLabel();\r\n\t\t}\r\n\t\tif (_options.multipleSelectionSupport) {\r\n\t\t\tthis.view.domNode.setAttribute('aria-multiselectable', 'true');\r\n\t\t}\r\n\t}\r\n\r\n\tprotected createMouseController(options: IListOptions): MouseController {\r\n\t\treturn new MouseController(this);\r\n\t}\r\n\r\n\tupdateOptions(optionsUpdate: IListOptionsUpdate = {}): void {\r\n\t\tthis._options = { ...this._options, ...optionsUpdate };\r\n\r\n\t\tif (this.typeLabelController) {\r\n\t\t\tthis.typeLabelController.updateOptions(this._options);\r\n\t\t}\r\n\r\n\t\tthis.view.updateOptions(optionsUpdate);\r\n\t}\r\n\r\n\tget options(): IListOptions {\r\n\t\treturn this._options;\r\n\t}\r\n\r\n\tsplice(start: number, deleteCount: number, elements: T[] = []): void {\r\n\t\tif (start < 0 || start > this.view.length) {\r\n\t\t\tthrow new ListError(this.user, `Invalid start index: ${start}`);\r\n\t\t}\r\n\r\n\t\tif (deleteCount < 0) {\r\n\t\t\tthrow new ListError(this.user, `Invalid delete count: ${deleteCount}`);\r\n\t\t}\r\n\r\n\t\tif (deleteCount === 0 && elements.length === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.eventBufferer.bufferEvents(() => this.spliceable.splice(start, deleteCount, elements));\r\n\t}\r\n\r\n\trerender(): void {\r\n\t\tthis.view.rerender();\r\n\t}\r\n\r\n\telement(index: number): T {\r\n\t\treturn this.view.element(index);\r\n\t}\r\n\r\n\tget length(): number {\r\n\t\treturn this.view.length;\r\n\t}\r\n\r\n\tget contentHeight(): number {\r\n\t\treturn this.view.contentHeight;\r\n\t}\r\n\r\n\tget scrollTop(): number {\r\n\t\treturn this.view.getScrollTop();\r\n\t}\r\n\r\n\tset scrollTop(scrollTop: number) {\r\n\t\tthis.view.setScrollTop(scrollTop);\r\n\t}\r\n\r\n\tget ariaLabel(): string {\r\n\t\treturn this._ariaLabel;\r\n\t}\r\n\r\n\tset ariaLabel(value: string) {\r\n\t\tthis._ariaLabel = value;\r\n\t\tthis.view.domNode.setAttribute('aria-label', value);\r\n\t}\r\n\r\n\tdomFocus(): void {\r\n\t\tthis.view.domNode.focus();\r\n\t}\r\n\r\n\tlayout(height?: number, width?: number): void {\r\n\t\tthis.view.layout(height, width);\r\n\t}\r\n\r\n\tsetSelection(indexes: number[], browserEvent?: UIEvent): void {\r\n\t\tfor (const index of indexes) {\r\n\t\t\tif (index < 0 || index >= this.length) {\r\n\t\t\t\tthrow new ListError(this.user, `Invalid index ${index}`);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis.selection.set(indexes, browserEvent);\r\n\t}\r\n\r\n\tgetSelection(): number[] {\r\n\t\treturn this.selection.get();\r\n\t}\r\n\r\n\tgetSelectedElements(): T[] {\r\n\t\treturn this.getSelection().map(i => this.view.element(i));\r\n\t}\r\n\r\n\tsetFocus(indexes: number[], browserEvent?: UIEvent): void {\r\n\t\tfor (const index of indexes) {\r\n\t\t\tif (index < 0 || index >= this.length) {\r\n\t\t\t\tthrow new ListError(this.user, `Invalid index ${index}`);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis.focus.set(indexes, browserEvent);\r\n\t}\r\n\r\n\tfocusNext(n = 1, loop = false, browserEvent?: UIEvent, filter?: (element: T) => boolean): void {\r\n\t\tif (this.length === 0) { return; }\r\n\r\n\t\tconst focus = this.focus.get();\r\n\t\tconst index = this.findNextIndex(focus.length > 0 ? focus[0] + n : 0, loop, filter);\r\n\r\n\t\tif (index > -1) {\r\n\t\t\tthis.setFocus([index], browserEvent);\r\n\t\t}\r\n\t}\r\n\r\n\tfocusPrevious(n = 1, loop = false, browserEvent?: UIEvent, filter?: (element: T) => boolean): void {\r\n\t\tif (this.length === 0) { return; }\r\n\r\n\t\tconst focus = this.focus.get();\r\n\t\tconst index = this.findPreviousIndex(focus.length > 0 ? focus[0] - n : 0, loop, filter);\r\n\r\n\t\tif (index > -1) {\r\n\t\t\tthis.setFocus([index], browserEvent);\r\n\t\t}\r\n\t}\r\n\r\n\tfocusNextPage(browserEvent?: UIEvent, filter?: (element: T) => boolean): void {\r\n\t\tlet lastPageIndex = this.view.indexAt(this.view.getScrollTop() + this.view.renderHeight);\r\n\t\tlastPageIndex = lastPageIndex === 0 ? 0 : lastPageIndex - 1;\r\n\t\tconst lastPageElement = this.view.element(lastPageIndex);\r\n\t\tconst currentlyFocusedElement = this.getFocusedElements()[0];\r\n\r\n\t\tif (currentlyFocusedElement !== lastPageElement) {\r\n\t\t\tconst lastGoodPageIndex = this.findPreviousIndex(lastPageIndex, false, filter);\r\n\r\n\t\t\tif (lastGoodPageIndex > -1 && currentlyFocusedElement !== this.view.element(lastGoodPageIndex)) {\r\n\t\t\t\tthis.setFocus([lastGoodPageIndex], browserEvent);\r\n\t\t\t} else {\r\n\t\t\t\tthis.setFocus([lastPageIndex], browserEvent);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tconst previousScrollTop = this.view.getScrollTop();\r\n\t\t\tthis.view.setScrollTop(previousScrollTop + this.view.renderHeight - this.view.elementHeight(lastPageIndex));\r\n\r\n\t\t\tif (this.view.getScrollTop() !== previousScrollTop) {\r\n\t\t\t\tthis.setFocus([]);\r\n\r\n\t\t\t\t// Let the scroll event listener run\r\n\t\t\t\tsetTimeout(() => this.focusNextPage(browserEvent, filter), 0);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tfocusPreviousPage(browserEvent?: UIEvent, filter?: (element: T) => boolean): void {\r\n\t\tlet firstPageIndex: number;\r\n\t\tconst scrollTop = this.view.getScrollTop();\r\n\r\n\t\tif (scrollTop === 0) {\r\n\t\t\tfirstPageIndex = this.view.indexAt(scrollTop);\r\n\t\t} else {\r\n\t\t\tfirstPageIndex = this.view.indexAfter(scrollTop - 1);\r\n\t\t}\r\n\r\n\t\tconst firstPageElement = this.view.element(firstPageIndex);\r\n\t\tconst currentlyFocusedElement = this.getFocusedElements()[0];\r\n\r\n\t\tif (currentlyFocusedElement !== firstPageElement) {\r\n\t\t\tconst firstGoodPageIndex = this.findNextIndex(firstPageIndex, false, filter);\r\n\r\n\t\t\tif (firstGoodPageIndex > -1 && currentlyFocusedElement !== this.view.element(firstGoodPageIndex)) {\r\n\t\t\t\tthis.setFocus([firstGoodPageIndex], browserEvent);\r\n\t\t\t} else {\r\n\t\t\t\tthis.setFocus([firstPageIndex], browserEvent);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tconst previousScrollTop = scrollTop;\r\n\t\t\tthis.view.setScrollTop(scrollTop - this.view.renderHeight);\r\n\r\n\t\t\tif (this.view.getScrollTop() !== previousScrollTop) {\r\n\t\t\t\tthis.setFocus([]);\r\n\r\n\t\t\t\t// Let the scroll event listener run\r\n\t\t\t\tsetTimeout(() => this.focusPreviousPage(browserEvent, filter), 0);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tfocusLast(browserEvent?: UIEvent, filter?: (element: T) => boolean): void {\r\n\t\tif (this.length === 0) { return; }\r\n\r\n\t\tconst index = this.findPreviousIndex(this.length - 1, false, filter);\r\n\r\n\t\tif (index > -1) {\r\n\t\t\tthis.setFocus([index], browserEvent);\r\n\t\t}\r\n\t}\r\n\r\n\tfocusFirst(browserEvent?: UIEvent, filter?: (element: T) => boolean): void {\r\n\t\tthis.focusNth(0, browserEvent, filter);\r\n\t}\r\n\r\n\tfocusNth(n: number, browserEvent?: UIEvent, filter?: (element: T) => boolean): void {\r\n\t\tif (this.length === 0) { return; }\r\n\r\n\t\tconst index = this.findNextIndex(n, false, filter);\r\n\r\n\t\tif (index > -1) {\r\n\t\t\tthis.setFocus([index], browserEvent);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate findNextIndex(index: number, loop = false, filter?: (element: T) => boolean): number {\r\n\t\tfor (let i = 0; i < this.length; i++) {\r\n\t\t\tif (index >= this.length && !loop) {\r\n\t\t\t\treturn -1;\r\n\t\t\t}\r\n\r\n\t\t\tindex = index % this.length;\r\n\r\n\t\t\tif (!filter || filter(this.element(index))) {\r\n\t\t\t\treturn index;\r\n\t\t\t}\r\n\r\n\t\t\tindex++;\r\n\t\t}\r\n\r\n\t\treturn -1;\r\n\t}\r\n\r\n\tprivate findPreviousIndex(index: number, loop = false, filter?: (element: T) => boolean): number {\r\n\t\tfor (let i = 0; i < this.length; i++) {\r\n\t\t\tif (index < 0 && !loop) {\r\n\t\t\t\treturn -1;\r\n\t\t\t}\r\n\r\n\t\t\tindex = (this.length + (index % this.length)) % this.length;\r\n\r\n\t\t\tif (!filter || filter(this.element(index))) {\r\n\t\t\t\treturn index;\r\n\t\t\t}\r\n\r\n\t\t\tindex--;\r\n\t\t}\r\n\r\n\t\treturn -1;\r\n\t}\r\n\r\n\tgetFocus(): number[] {\r\n\t\treturn this.focus.get();\r\n\t}\r\n\r\n\tgetFocusedElements(): T[] {\r\n\t\treturn this.getFocus().map(i => this.view.element(i));\r\n\t}\r\n\r\n\treveal(index: number, relativeTop?: number): void {\r\n\t\tif (index < 0 || index >= this.length) {\r\n\t\t\tthrow new ListError(this.user, `Invalid index ${index}`);\r\n\t\t}\r\n\r\n\t\tconst scrollTop = this.view.getScrollTop();\r\n\t\tconst elementTop = this.view.elementTop(index);\r\n\t\tconst elementHeight = this.view.elementHeight(index);\r\n\r\n\t\tif (isNumber(relativeTop)) {\r\n\t\t\t// y = mx + b\r\n\t\t\tconst m = elementHeight - this.view.renderHeight;\r\n\t\t\tthis.view.setScrollTop(m * clamp(relativeTop, 0, 1) + elementTop);\r\n\t\t} else {\r\n\t\t\tconst viewItemBottom = elementTop + elementHeight;\r\n\t\t\tconst wrapperBottom = scrollTop + this.view.renderHeight;\r\n\r\n\t\t\tif (elementTop < scrollTop && viewItemBottom >= wrapperBottom) {\r\n\t\t\t\t// The element is already overflowing the viewport, no-op\r\n\t\t\t} else if (elementTop < scrollTop) {\r\n\t\t\t\tthis.view.setScrollTop(elementTop);\r\n\t\t\t} else if (viewItemBottom >= wrapperBottom) {\r\n\t\t\t\tthis.view.setScrollTop(viewItemBottom - this.view.renderHeight);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the relative position of an element rendered in the list.\r\n\t * Returns `null` if the element isn't *entirely* in the visible viewport.\r\n\t */\r\n\tgetRelativeTop(index: number): number | null {\r\n\t\tif (index < 0 || index >= this.length) {\r\n\t\t\tthrow new ListError(this.user, `Invalid index ${index}`);\r\n\t\t}\r\n\r\n\t\tconst scrollTop = this.view.getScrollTop();\r\n\t\tconst elementTop = this.view.elementTop(index);\r\n\t\tconst elementHeight = this.view.elementHeight(index);\r\n\r\n\t\tif (elementTop < scrollTop || elementTop + elementHeight > scrollTop + this.view.renderHeight) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\t// y = mx + b\r\n\t\tconst m = elementHeight - this.view.renderHeight;\r\n\t\treturn Math.abs((scrollTop - elementTop) / m);\r\n\t}\r\n\r\n\tgetHTMLElement(): HTMLElement {\r\n\t\treturn this.view.domNode;\r\n\t}\r\n\r\n\tstyle(styles: IListStyles): void {\r\n\t\tthis.styleController.style(styles);\r\n\t}\r\n\r\n\tprivate toListEvent({ indexes, browserEvent }: ITraitChangeEvent) {\r\n\t\treturn { indexes, elements: indexes.map(i => this.view.element(i)), browserEvent };\r\n\t}\r\n\r\n\tprivate _onFocusChange(): void {\r\n\t\tconst focus = this.focus.get();\r\n\t\tthis.view.domNode.classList.toggle('element-focused', focus.length > 0);\r\n\t\tthis.onDidChangeActiveDescendant();\r\n\t}\r\n\r\n\tprivate onDidChangeActiveDescendant(): void {\r\n\t\tconst focus = this.focus.get();\r\n\r\n\t\tif (focus.length > 0) {\r\n\t\t\tlet id: string | undefined;\r\n\r\n\t\t\tif (this.accessibilityProvider?.getActiveDescendantId) {\r\n\t\t\t\tid = this.accessibilityProvider.getActiveDescendantId(this.view.element(focus[0]));\r\n\t\t\t}\r\n\r\n\t\t\tthis.view.domNode.setAttribute('aria-activedescendant', id || this.view.getElementDomId(focus[0]));\r\n\t\t} else {\r\n\t\t\tthis.view.domNode.removeAttribute('aria-activedescendant');\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _onSelectionChange(): void {\r\n\t\tconst selection = this.selection.get();\r\n\r\n\t\tthis.view.domNode.classList.toggle('selection-none', selection.length === 0);\r\n\t\tthis.view.domNode.classList.toggle('selection-single', selection.length === 1);\r\n\t\tthis.view.domNode.classList.toggle('selection-multiple', selection.length > 1);\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._onDidDispose.fire();\r\n\t\tthis.disposables.dispose();\r\n\r\n\t\tthis._onDidDispose.dispose();\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./list';\r\nimport { IDisposable, Disposable } from 'vs/base/common/lifecycle';\r\nimport { range } from 'vs/base/common/arrays';\r\nimport { IListVirtualDelegate, IListRenderer, IListEvent, IListMouseEvent } from './list';\r\nimport { List, IListStyles, IListOptions, IListAccessibilityProvider, IListOptionsUpdate } from './listWidget';\r\nimport { IPagedModel } from 'vs/base/common/paging';\r\nimport { Event } from 'vs/base/common/event';\r\nimport { CancellationTokenSource } from 'vs/base/common/cancellation';\r\nimport { IThemable } from 'vs/base/common/styler';\r\n\r\nexport interface IPagedRenderer extends IListRenderer {\r\n\trenderPlaceholder(index: number, templateData: TTemplateData): void;\r\n}\r\n\r\nexport interface ITemplateData {\r\n\tdata?: T;\r\n\tdisposable?: IDisposable;\r\n}\r\n\r\nclass PagedRenderer implements IListRenderer> {\r\n\r\n\tget templateId(): string { return this.renderer.templateId; }\r\n\r\n\tconstructor(\r\n\t\tprivate renderer: IPagedRenderer,\r\n\t\tprivate modelProvider: () => IPagedModel\r\n\t) { }\r\n\r\n\trenderTemplate(container: HTMLElement): ITemplateData {\r\n\t\tconst data = this.renderer.renderTemplate(container);\r\n\t\treturn { data, disposable: Disposable.None };\r\n\t}\r\n\r\n\trenderElement(index: number, _: number, data: ITemplateData, height: number | undefined): void {\r\n\t\tif (data.disposable) {\r\n\t\t\tdata.disposable.dispose();\r\n\t\t}\r\n\r\n\t\tif (!data.data) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst model = this.modelProvider();\r\n\r\n\t\tif (model.isResolved(index)) {\r\n\t\t\treturn this.renderer.renderElement(model.get(index), index, data.data, height);\r\n\t\t}\r\n\r\n\t\tconst cts = new CancellationTokenSource();\r\n\t\tconst promise = model.resolve(index, cts.token);\r\n\t\tdata.disposable = { dispose: () => cts.cancel() };\r\n\r\n\t\tthis.renderer.renderPlaceholder(index, data.data);\r\n\t\tpromise.then(entry => this.renderer.renderElement(entry, index, data.data!, height));\r\n\t}\r\n\r\n\tdisposeTemplate(data: ITemplateData): void {\r\n\t\tif (data.disposable) {\r\n\t\t\tdata.disposable.dispose();\r\n\t\t\tdata.disposable = undefined;\r\n\t\t}\r\n\t\tif (data.data) {\r\n\t\t\tthis.renderer.disposeTemplate(data.data);\r\n\t\t\tdata.data = undefined;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass PagedAccessibilityProvider implements IListAccessibilityProvider {\r\n\r\n\tconstructor(\r\n\t\tprivate modelProvider: () => IPagedModel,\r\n\t\tprivate accessibilityProvider: IListAccessibilityProvider\r\n\t) { }\r\n\r\n\tgetWidgetAriaLabel(): string {\r\n\t\treturn this.accessibilityProvider.getWidgetAriaLabel();\r\n\t}\r\n\r\n\tgetAriaLabel(index: number): string | null {\r\n\t\tconst model = this.modelProvider();\r\n\r\n\t\tif (!model.isResolved(index)) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\treturn this.accessibilityProvider.getAriaLabel(model.get(index));\r\n\t}\r\n}\r\n\r\nexport interface IPagedListOptions {\r\n\treadonly keyboardSupport?: boolean;\r\n\treadonly multipleSelectionSupport?: boolean;\r\n\treadonly accessibilityProvider?: IListAccessibilityProvider;\r\n\treadonly horizontalScrolling?: boolean;\r\n}\r\n\r\nfunction fromPagedListOptions(modelProvider: () => IPagedModel, options: IPagedListOptions): IListOptions {\r\n\treturn {\r\n\t\t...options,\r\n\t\taccessibilityProvider: options.accessibilityProvider && new PagedAccessibilityProvider(modelProvider, options.accessibilityProvider)\r\n\t};\r\n}\r\n\r\nexport class PagedList implements IThemable, IDisposable {\r\n\r\n\tprivate list: List;\r\n\tprivate _model!: IPagedModel;\r\n\r\n\tconstructor(\r\n\t\tuser: string,\r\n\t\tcontainer: HTMLElement,\r\n\t\tvirtualDelegate: IListVirtualDelegate,\r\n\t\trenderers: IPagedRenderer[],\r\n\t\toptions: IPagedListOptions = {}\r\n\t) {\r\n\t\tconst modelProvider = () => this.model;\r\n\t\tconst pagedRenderers = renderers.map(r => new PagedRenderer>(r, modelProvider));\r\n\t\tthis.list = new List(user, container, virtualDelegate, pagedRenderers, fromPagedListOptions(modelProvider, options));\r\n\t}\r\n\r\n\tupdateOptions(options: IListOptionsUpdate) {\r\n\t\tthis.list.updateOptions(options);\r\n\t}\r\n\r\n\tgetHTMLElement(): HTMLElement {\r\n\t\treturn this.list.getHTMLElement();\r\n\t}\r\n\r\n\tget onDidFocus(): Event {\r\n\t\treturn this.list.onDidFocus;\r\n\t}\r\n\r\n\tget onDidDispose(): Event {\r\n\t\treturn this.list.onDidDispose;\r\n\t}\r\n\r\n\tget onMouseDblClick(): Event> {\r\n\t\treturn Event.map(this.list.onMouseDblClick, ({ element, index, browserEvent }) => ({ element: element === undefined ? undefined : this._model.get(element), index, browserEvent }));\r\n\t}\r\n\r\n\tget onPointer(): Event> {\r\n\t\treturn Event.map(this.list.onPointer, ({ element, index, browserEvent }) => ({ element: element === undefined ? undefined : this._model.get(element), index, browserEvent }));\r\n\t}\r\n\r\n\tget onDidChangeFocus(): Event> {\r\n\t\treturn Event.map(this.list.onDidChangeFocus, ({ elements, indexes, browserEvent }) => ({ elements: elements.map(e => this._model.get(e)), indexes, browserEvent }));\r\n\t}\r\n\r\n\tget onDidChangeSelection(): Event> {\r\n\t\treturn Event.map(this.list.onDidChangeSelection, ({ elements, indexes, browserEvent }) => ({ elements: elements.map(e => this._model.get(e)), indexes, browserEvent }));\r\n\t}\r\n\r\n\tget model(): IPagedModel {\r\n\t\treturn this._model;\r\n\t}\r\n\r\n\tset model(model: IPagedModel) {\r\n\t\tthis._model = model;\r\n\t\tthis.list.splice(0, this.list.length, range(model.length));\r\n\t}\r\n\r\n\tgetFocus(): number[] {\r\n\t\treturn this.list.getFocus();\r\n\t}\r\n\r\n\tsetSelection(indexes: number[], browserEvent?: UIEvent): void {\r\n\t\tthis.list.setSelection(indexes, browserEvent);\r\n\t}\r\n\r\n\tstyle(styles: IListStyles): void {\r\n\t\tthis.list.style(styles);\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis.list.dispose();\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./splitview';\r\nimport { IDisposable, toDisposable, Disposable, combinedDisposable } from 'vs/base/common/lifecycle';\r\nimport { Event, Emitter } from 'vs/base/common/event';\r\nimport * as types from 'vs/base/common/types';\r\nimport { clamp } from 'vs/base/common/numbers';\r\nimport { range, pushToStart, pushToEnd } from 'vs/base/common/arrays';\r\nimport { Sash, Orientation, ISashEvent as IBaseSashEvent, SashState } from 'vs/base/browser/ui/sash/sash';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { domEvent } from 'vs/base/browser/event';\r\nimport { $, append, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom';\r\nimport { SmoothScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';\r\nimport { Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable';\r\nexport { Orientation } from 'vs/base/browser/ui/sash/sash';\r\n\r\nexport interface ISplitViewStyles {\r\n\tseparatorBorder: Color;\r\n}\r\n\r\nconst defaultStyles: ISplitViewStyles = {\r\n\tseparatorBorder: Color.transparent\r\n};\r\n\r\nexport interface ISplitViewOptions {\r\n\treadonly orientation?: Orientation; // default Orientation.VERTICAL\r\n\treadonly styles?: ISplitViewStyles;\r\n\treadonly inverseAltBehavior?: boolean;\r\n\treadonly proportionalLayout?: boolean; // default true,\r\n\treadonly descriptor?: ISplitViewDescriptor;\r\n}\r\n\r\n/**\r\n * Only used when `proportionalLayout` is false.\r\n */\r\nexport const enum LayoutPriority {\r\n\tNormal,\r\n\tLow,\r\n\tHigh\r\n}\r\n\r\nexport interface IView {\r\n\treadonly element: HTMLElement;\r\n\treadonly minimumSize: number;\r\n\treadonly maximumSize: number;\r\n\treadonly onDidChange: Event;\r\n\treadonly priority?: LayoutPriority;\r\n\treadonly snap?: boolean;\r\n\tlayout(size: number, offset: number, context: TLayoutContext | undefined): void;\r\n\tsetVisible?(visible: boolean): void;\r\n}\r\n\r\ninterface ISashEvent {\r\n\treadonly sash: Sash;\r\n\treadonly start: number;\r\n\treadonly current: number;\r\n\treadonly alt: boolean;\r\n}\r\n\r\ntype ViewItemSize = number | { cachedVisibleSize: number };\r\n\r\nabstract class ViewItem {\r\n\r\n\tprivate _size: number;\r\n\tset size(size: number) {\r\n\t\tthis._size = size;\r\n\t}\r\n\r\n\tget size(): number {\r\n\t\treturn this._size;\r\n\t}\r\n\r\n\tprivate _cachedVisibleSize: number | undefined = undefined;\r\n\r\n\tget visible(): boolean {\r\n\t\treturn typeof this._cachedVisibleSize === 'undefined';\r\n\t}\r\n\r\n\tsetVisible(visible: boolean, size?: number): void {\r\n\t\tif (visible === this.visible) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (visible) {\r\n\t\t\tthis.size = clamp(this._cachedVisibleSize!, this.viewMinimumSize, this.viewMaximumSize);\r\n\t\t\tthis._cachedVisibleSize = undefined;\r\n\t\t} else {\r\n\t\t\tthis._cachedVisibleSize = typeof size === 'number' ? size : this.size;\r\n\t\t\tthis.size = 0;\r\n\t\t}\r\n\r\n\t\tthis.container.classList.toggle('visible', visible);\r\n\r\n\t\tif (this.view.setVisible) {\r\n\t\t\tthis.view.setVisible(visible);\r\n\t\t}\r\n\t}\r\n\r\n\tget minimumSize(): number { return this.visible ? this.view.minimumSize : 0; }\r\n\tget viewMinimumSize(): number { return this.view.minimumSize; }\r\n\r\n\tget maximumSize(): number { return this.visible ? this.view.maximumSize : 0; }\r\n\tget viewMaximumSize(): number { return this.view.maximumSize; }\r\n\r\n\tget priority(): LayoutPriority | undefined { return this.view.priority; }\r\n\tget snap(): boolean { return !!this.view.snap; }\r\n\r\n\tset enabled(enabled: boolean) {\r\n\t\tthis.container.style.pointerEvents = enabled ? '' : 'none';\r\n\t}\r\n\r\n\tconstructor(\r\n\t\tprotected container: HTMLElement,\r\n\t\tprivate view: IView,\r\n\t\tsize: ViewItemSize,\r\n\t\tprivate disposable: IDisposable\r\n\t) {\r\n\t\tif (typeof size === 'number') {\r\n\t\t\tthis._size = size;\r\n\t\t\tthis._cachedVisibleSize = undefined;\r\n\t\t\tcontainer.classList.add('visible');\r\n\t\t} else {\r\n\t\t\tthis._size = 0;\r\n\t\t\tthis._cachedVisibleSize = size.cachedVisibleSize;\r\n\t\t}\r\n\t}\r\n\r\n\tlayout(offset: number, layoutContext: TLayoutContext | undefined): void {\r\n\t\tthis.layoutContainer(offset);\r\n\t\tthis.view.layout(this.size, offset, layoutContext);\r\n\t}\r\n\r\n\tabstract layoutContainer(offset: number): void;\r\n\r\n\tdispose(): IView {\r\n\t\tthis.disposable.dispose();\r\n\t\treturn this.view;\r\n\t}\r\n}\r\n\r\nclass VerticalViewItem extends ViewItem {\r\n\r\n\tlayoutContainer(offset: number): void {\r\n\t\tthis.container.style.top = `${offset}px`;\r\n\t\tthis.container.style.height = `${this.size}px`;\r\n\t}\r\n}\r\n\r\nclass HorizontalViewItem extends ViewItem {\r\n\r\n\tlayoutContainer(offset: number): void {\r\n\t\tthis.container.style.left = `${offset}px`;\r\n\t\tthis.container.style.width = `${this.size}px`;\r\n\t}\r\n}\r\n\r\ninterface ISashItem {\r\n\tsash: Sash;\r\n\tdisposable: IDisposable;\r\n}\r\n\r\ninterface ISashDragSnapState {\r\n\treadonly index: number;\r\n\treadonly limitDelta: number;\r\n\treadonly size: number;\r\n}\r\n\r\ninterface ISashDragState {\r\n\tindex: number;\r\n\tstart: number;\r\n\tcurrent: number;\r\n\tsizes: number[];\r\n\tminDelta: number;\r\n\tmaxDelta: number;\r\n\talt: boolean;\r\n\tsnapBefore: ISashDragSnapState | undefined;\r\n\tsnapAfter: ISashDragSnapState | undefined;\r\n\tdisposable: IDisposable;\r\n}\r\n\r\nenum State {\r\n\tIdle,\r\n\tBusy\r\n}\r\n\r\nexport type DistributeSizing = { type: 'distribute' };\r\nexport type SplitSizing = { type: 'split', index: number };\r\nexport type InvisibleSizing = { type: 'invisible', cachedVisibleSize: number };\r\nexport type Sizing = DistributeSizing | SplitSizing | InvisibleSizing;\r\n\r\nexport namespace Sizing {\r\n\texport const Distribute: DistributeSizing = { type: 'distribute' };\r\n\texport function Split(index: number): SplitSizing { return { type: 'split', index }; }\r\n\texport function Invisible(cachedVisibleSize: number): InvisibleSizing { return { type: 'invisible', cachedVisibleSize }; }\r\n}\r\n\r\nexport interface ISplitViewDescriptor {\r\n\tsize: number;\r\n\tviews: {\r\n\t\tvisible?: boolean;\r\n\t\tsize: number;\r\n\t\tview: IView;\r\n\t}[];\r\n}\r\n\r\nexport class SplitView extends Disposable {\r\n\r\n\treadonly orientation: Orientation;\r\n\treadonly el: HTMLElement;\r\n\tprivate sashContainer: HTMLElement;\r\n\tprivate viewContainer: HTMLElement;\r\n\tprivate scrollable: Scrollable;\r\n\tprivate scrollableElement: SmoothScrollableElement;\r\n\tprivate size = 0;\r\n\tprivate layoutContext: TLayoutContext | undefined;\r\n\tprivate contentSize = 0;\r\n\tprivate proportions: undefined | number[] = undefined;\r\n\tprivate viewItems: ViewItem[] = [];\r\n\tprivate sashItems: ISashItem[] = [];\r\n\tprivate sashDragState: ISashDragState | undefined;\r\n\tprivate state: State = State.Idle;\r\n\tprivate inverseAltBehavior: boolean;\r\n\tprivate proportionalLayout: boolean;\r\n\r\n\tprivate _onDidSashChange = this._register(new Emitter());\r\n\treadonly onDidSashChange = this._onDidSashChange.event;\r\n\r\n\tprivate _onDidSashReset = this._register(new Emitter());\r\n\r\n\tprivate _orthogonalStartSash: Sash | undefined;\r\n\tget orthogonalStartSash(): Sash | undefined { return this._orthogonalStartSash; }\r\n\tset orthogonalStartSash(sash: Sash | undefined) {\r\n\t\tfor (const sashItem of this.sashItems) {\r\n\t\t\tsashItem.sash.orthogonalStartSash = sash;\r\n\t\t}\r\n\r\n\t\tthis._orthogonalStartSash = sash;\r\n\t}\r\n\r\n\tprivate _orthogonalEndSash: Sash | undefined;\r\n\tget orthogonalEndSash(): Sash | undefined { return this._orthogonalEndSash; }\r\n\tset orthogonalEndSash(sash: Sash | undefined) {\r\n\t\tfor (const sashItem of this.sashItems) {\r\n\t\t\tsashItem.sash.orthogonalEndSash = sash;\r\n\t\t}\r\n\r\n\t\tthis._orthogonalEndSash = sash;\r\n\t}\r\n\r\n\tprivate _startSnappingEnabled = true;\r\n\tget startSnappingEnabled(): boolean { return this._startSnappingEnabled; }\r\n\tset startSnappingEnabled(startSnappingEnabled: boolean) {\r\n\t\tif (this._startSnappingEnabled === startSnappingEnabled) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._startSnappingEnabled = startSnappingEnabled;\r\n\t\tthis.updateSashEnablement();\r\n\t}\r\n\r\n\tprivate _endSnappingEnabled = true;\r\n\tget endSnappingEnabled(): boolean { return this._endSnappingEnabled; }\r\n\tset endSnappingEnabled(endSnappingEnabled: boolean) {\r\n\t\tif (this._endSnappingEnabled === endSnappingEnabled) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._endSnappingEnabled = endSnappingEnabled;\r\n\t\tthis.updateSashEnablement();\r\n\t}\r\n\r\n\tconstructor(container: HTMLElement, options: ISplitViewOptions = {}) {\r\n\t\tsuper();\r\n\r\n\t\tthis.orientation = types.isUndefined(options.orientation) ? Orientation.VERTICAL : options.orientation;\r\n\t\tthis.inverseAltBehavior = !!options.inverseAltBehavior;\r\n\t\tthis.proportionalLayout = types.isUndefined(options.proportionalLayout) ? true : !!options.proportionalLayout;\r\n\r\n\t\tthis.el = document.createElement('div');\r\n\t\tthis.el.classList.add('monaco-split-view2');\r\n\t\tthis.el.classList.add(this.orientation === Orientation.VERTICAL ? 'vertical' : 'horizontal');\r\n\t\tcontainer.appendChild(this.el);\r\n\r\n\t\tthis.sashContainer = append(this.el, $('.sash-container'));\r\n\t\tthis.viewContainer = $('.split-view-container');\r\n\r\n\t\tthis.scrollable = new Scrollable(125, scheduleAtNextAnimationFrame);\r\n\t\tthis.scrollableElement = this._register(new SmoothScrollableElement(this.viewContainer, {\r\n\t\t\tvertical: this.orientation === Orientation.VERTICAL ? ScrollbarVisibility.Auto : ScrollbarVisibility.Hidden,\r\n\t\t\thorizontal: this.orientation === Orientation.HORIZONTAL ? ScrollbarVisibility.Auto : ScrollbarVisibility.Hidden\r\n\t\t}, this.scrollable));\r\n\r\n\t\tthis._register(this.scrollableElement.onScroll(e => {\r\n\t\t\tthis.viewContainer.scrollTop = e.scrollTop;\r\n\t\t\tthis.viewContainer.scrollLeft = e.scrollLeft;\r\n\t\t}));\r\n\r\n\t\tappend(this.el, this.scrollableElement.getDomNode());\r\n\r\n\t\tthis.style(options.styles || defaultStyles);\r\n\r\n\t\t// We have an existing set of view, add them now\r\n\t\tif (options.descriptor) {\r\n\t\t\tthis.size = options.descriptor.size;\r\n\t\t\toptions.descriptor.views.forEach((viewDescriptor, index) => {\r\n\t\t\t\tconst sizing = types.isUndefined(viewDescriptor.visible) || viewDescriptor.visible ? viewDescriptor.size : { type: 'invisible', cachedVisibleSize: viewDescriptor.size } as InvisibleSizing;\r\n\r\n\t\t\t\tconst view = viewDescriptor.view;\r\n\t\t\t\tthis.doAddView(view, sizing, index, true);\r\n\t\t\t});\r\n\r\n\t\t\t// Initialize content size and proportions for first layout\r\n\t\t\tthis.contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);\r\n\t\t\tthis.saveProportions();\r\n\t\t}\r\n\t}\r\n\r\n\tstyle(styles: ISplitViewStyles): void {\r\n\t\tif (styles.separatorBorder.isTransparent()) {\r\n\t\t\tthis.el.classList.remove('separator-border');\r\n\t\t\tthis.el.style.removeProperty('--separator-border');\r\n\t\t} else {\r\n\t\t\tthis.el.classList.add('separator-border');\r\n\t\t\tthis.el.style.setProperty('--separator-border', styles.separatorBorder.toString());\r\n\t\t}\r\n\t}\r\n\r\n\taddView(view: IView, size: number | Sizing, index = this.viewItems.length, skipLayout?: boolean): void {\r\n\t\tthis.doAddView(view, size, index, skipLayout);\r\n\t}\r\n\r\n\tlayout(size: number, layoutContext?: TLayoutContext): void {\r\n\t\tconst previousSize = Math.max(this.size, this.contentSize);\r\n\t\tthis.size = size;\r\n\t\tthis.layoutContext = layoutContext;\r\n\r\n\t\tif (!this.proportions) {\r\n\t\t\tconst indexes = range(this.viewItems.length);\r\n\t\t\tconst lowPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.Low);\r\n\t\t\tconst highPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.High);\r\n\r\n\t\t\tthis.resize(this.viewItems.length - 1, size - previousSize, undefined, lowPriorityIndexes, highPriorityIndexes);\r\n\t\t} else {\r\n\t\t\tfor (let i = 0; i < this.viewItems.length; i++) {\r\n\t\t\t\tconst item = this.viewItems[i];\r\n\t\t\t\titem.size = clamp(Math.round(this.proportions[i] * size), item.minimumSize, item.maximumSize);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis.distributeEmptySpace();\r\n\t\tthis.layoutViews();\r\n\t}\r\n\r\n\tprivate saveProportions(): void {\r\n\t\tif (this.proportionalLayout && this.contentSize > 0) {\r\n\t\t\tthis.proportions = this.viewItems.map(i => i.size / this.contentSize);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate onSashStart({ sash, start, alt }: ISashEvent): void {\r\n\t\tfor (const item of this.viewItems) {\r\n\t\t\titem.enabled = false;\r\n\t\t}\r\n\r\n\t\tconst index = this.sashItems.findIndex(item => item.sash === sash);\r\n\r\n\t\t// This way, we can press Alt while we resize a sash, macOS style!\r\n\t\tconst disposable = combinedDisposable(\r\n\t\t\tdomEvent(document.body, 'keydown')(e => resetSashDragState(this.sashDragState!.current, e.altKey)),\r\n\t\t\tdomEvent(document.body, 'keyup')(() => resetSashDragState(this.sashDragState!.current, false))\r\n\t\t);\r\n\r\n\t\tconst resetSashDragState = (start: number, alt: boolean) => {\r\n\t\t\tconst sizes = this.viewItems.map(i => i.size);\r\n\t\t\tlet minDelta = Number.NEGATIVE_INFINITY;\r\n\t\t\tlet maxDelta = Number.POSITIVE_INFINITY;\r\n\r\n\t\t\tif (this.inverseAltBehavior) {\r\n\t\t\t\talt = !alt;\r\n\t\t\t}\r\n\r\n\t\t\tif (alt) {\r\n\t\t\t\t// When we're using the last sash with Alt, we're resizing\r\n\t\t\t\t// the view to the left/up, instead of right/down as usual\r\n\t\t\t\t// Thus, we must do the inverse of the usual\r\n\t\t\t\tconst isLastSash = index === this.sashItems.length - 1;\r\n\r\n\t\t\t\tif (isLastSash) {\r\n\t\t\t\t\tconst viewItem = this.viewItems[index];\r\n\t\t\t\t\tminDelta = (viewItem.minimumSize - viewItem.size) / 2;\r\n\t\t\t\t\tmaxDelta = (viewItem.maximumSize - viewItem.size) / 2;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tconst viewItem = this.viewItems[index + 1];\r\n\t\t\t\t\tminDelta = (viewItem.size - viewItem.maximumSize) / 2;\r\n\t\t\t\t\tmaxDelta = (viewItem.size - viewItem.minimumSize) / 2;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tlet snapBefore: ISashDragSnapState | undefined;\r\n\t\t\tlet snapAfter: ISashDragSnapState | undefined;\r\n\r\n\t\t\tif (!alt) {\r\n\t\t\t\tconst upIndexes = range(index, -1);\r\n\t\t\t\tconst downIndexes = range(index + 1, this.viewItems.length);\r\n\t\t\t\tconst minDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].minimumSize - sizes[i]), 0);\r\n\t\t\t\tconst maxDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].viewMaximumSize - sizes[i]), 0);\r\n\t\t\t\tconst maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].minimumSize), 0);\r\n\t\t\t\tconst minDeltaDown = downIndexes.length === 0 ? Number.NEGATIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].viewMaximumSize), 0);\r\n\t\t\t\tconst minDelta = Math.max(minDeltaUp, minDeltaDown);\r\n\t\t\t\tconst maxDelta = Math.min(maxDeltaDown, maxDeltaUp);\r\n\t\t\t\tconst snapBeforeIndex = this.findFirstSnapIndex(upIndexes);\r\n\t\t\t\tconst snapAfterIndex = this.findFirstSnapIndex(downIndexes);\r\n\r\n\t\t\t\tif (typeof snapBeforeIndex === 'number') {\r\n\t\t\t\t\tconst viewItem = this.viewItems[snapBeforeIndex];\r\n\t\t\t\t\tconst halfSize = Math.floor(viewItem.viewMinimumSize / 2);\r\n\r\n\t\t\t\t\tsnapBefore = {\r\n\t\t\t\t\t\tindex: snapBeforeIndex,\r\n\t\t\t\t\t\tlimitDelta: viewItem.visible ? minDelta - halfSize : minDelta + halfSize,\r\n\t\t\t\t\t\tsize: viewItem.size\r\n\t\t\t\t\t};\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (typeof snapAfterIndex === 'number') {\r\n\t\t\t\t\tconst viewItem = this.viewItems[snapAfterIndex];\r\n\t\t\t\t\tconst halfSize = Math.floor(viewItem.viewMinimumSize / 2);\r\n\r\n\t\t\t\t\tsnapAfter = {\r\n\t\t\t\t\t\tindex: snapAfterIndex,\r\n\t\t\t\t\t\tlimitDelta: viewItem.visible ? maxDelta + halfSize : maxDelta - halfSize,\r\n\t\t\t\t\t\tsize: viewItem.size\r\n\t\t\t\t\t};\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tthis.sashDragState = { start, current: start, index, sizes, minDelta, maxDelta, alt, snapBefore, snapAfter, disposable };\r\n\t\t};\r\n\r\n\t\tresetSashDragState(start, alt);\r\n\t}\r\n\r\n\tprivate onSashChange({ current }: ISashEvent): void {\r\n\t\tconst { index, start, sizes, alt, minDelta, maxDelta, snapBefore, snapAfter } = this.sashDragState!;\r\n\t\tthis.sashDragState!.current = current;\r\n\r\n\t\tconst delta = current - start;\r\n\t\tconst newDelta = this.resize(index, delta, sizes, undefined, undefined, minDelta, maxDelta, snapBefore, snapAfter);\r\n\r\n\t\tif (alt) {\r\n\t\t\tconst isLastSash = index === this.sashItems.length - 1;\r\n\t\t\tconst newSizes = this.viewItems.map(i => i.size);\r\n\t\t\tconst viewItemIndex = isLastSash ? index : index + 1;\r\n\t\t\tconst viewItem = this.viewItems[viewItemIndex];\r\n\t\t\tconst newMinDelta = viewItem.size - viewItem.maximumSize;\r\n\t\t\tconst newMaxDelta = viewItem.size - viewItem.minimumSize;\r\n\t\t\tconst resizeIndex = isLastSash ? index - 1 : index + 1;\r\n\r\n\t\t\tthis.resize(resizeIndex, -newDelta, newSizes, undefined, undefined, newMinDelta, newMaxDelta);\r\n\t\t}\r\n\r\n\t\tthis.distributeEmptySpace();\r\n\t\tthis.layoutViews();\r\n\t}\r\n\r\n\tprivate onSashEnd(index: number): void {\r\n\t\tthis._onDidSashChange.fire(index);\r\n\t\tthis.sashDragState!.disposable.dispose();\r\n\t\tthis.saveProportions();\r\n\r\n\t\tfor (const item of this.viewItems) {\r\n\t\t\titem.enabled = true;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate onViewChange(item: ViewItem, size: number | undefined): void {\r\n\t\tconst index = this.viewItems.indexOf(item);\r\n\r\n\t\tif (index < 0 || index >= this.viewItems.length) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tsize = typeof size === 'number' ? size : item.size;\r\n\t\tsize = clamp(size, item.minimumSize, item.maximumSize);\r\n\r\n\t\tif (this.inverseAltBehavior && index > 0) {\r\n\t\t\t// In this case, we want the view to grow or shrink both sides equally\r\n\t\t\t// so we just resize the \"left\" side by half and let `resize` do the clamping magic\r\n\t\t\tthis.resize(index - 1, Math.floor((item.size - size) / 2));\r\n\t\t\tthis.distributeEmptySpace();\r\n\t\t\tthis.layoutViews();\r\n\t\t} else {\r\n\t\t\titem.size = size;\r\n\t\t\tthis.relayout([index], undefined);\r\n\t\t}\r\n\t}\r\n\r\n\tresizeView(index: number, size: number): void {\r\n\t\tif (this.state !== State.Idle) {\r\n\t\t\tthrow new Error('Cant modify splitview');\r\n\t\t}\r\n\r\n\t\tthis.state = State.Busy;\r\n\r\n\t\tif (index < 0 || index >= this.viewItems.length) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst indexes = range(this.viewItems.length).filter(i => i !== index);\r\n\t\tconst lowPriorityIndexes = [...indexes.filter(i => this.viewItems[i].priority === LayoutPriority.Low), index];\r\n\t\tconst highPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.High);\r\n\r\n\t\tconst item = this.viewItems[index];\r\n\t\tsize = Math.round(size);\r\n\t\tsize = clamp(size, item.minimumSize, Math.min(item.maximumSize, this.size));\r\n\r\n\t\titem.size = size;\r\n\t\tthis.relayout(lowPriorityIndexes, highPriorityIndexes);\r\n\t\tthis.state = State.Idle;\r\n\t}\r\n\r\n\tdistributeViewSizes(): void {\r\n\t\tconst flexibleViewItems: ViewItem[] = [];\r\n\t\tlet flexibleSize = 0;\r\n\r\n\t\tfor (const item of this.viewItems) {\r\n\t\t\tif (item.maximumSize - item.minimumSize > 0) {\r\n\t\t\t\tflexibleViewItems.push(item);\r\n\t\t\t\tflexibleSize += item.size;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst size = Math.floor(flexibleSize / flexibleViewItems.length);\r\n\r\n\t\tfor (const item of flexibleViewItems) {\r\n\t\t\titem.size = clamp(size, item.minimumSize, item.maximumSize);\r\n\t\t}\r\n\r\n\t\tconst indexes = range(this.viewItems.length);\r\n\t\tconst lowPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.Low);\r\n\t\tconst highPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.High);\r\n\r\n\t\tthis.relayout(lowPriorityIndexes, highPriorityIndexes);\r\n\t}\r\n\r\n\tgetViewSize(index: number): number {\r\n\t\tif (index < 0 || index >= this.viewItems.length) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\r\n\t\treturn this.viewItems[index].size;\r\n\t}\r\n\r\n\tprivate doAddView(view: IView, size: number | Sizing, index = this.viewItems.length, skipLayout?: boolean): void {\r\n\t\tif (this.state !== State.Idle) {\r\n\t\t\tthrow new Error('Cant modify splitview');\r\n\t\t}\r\n\r\n\t\tthis.state = State.Busy;\r\n\r\n\t\t// Add view\r\n\t\tconst container = $('.split-view-view');\r\n\r\n\t\tif (index === this.viewItems.length) {\r\n\t\t\tthis.viewContainer.appendChild(container);\r\n\t\t} else {\r\n\t\t\tthis.viewContainer.insertBefore(container, this.viewContainer.children.item(index));\r\n\t\t}\r\n\r\n\t\tconst onChangeDisposable = view.onDidChange(size => this.onViewChange(item, size));\r\n\t\tconst containerDisposable = toDisposable(() => this.viewContainer.removeChild(container));\r\n\t\tconst disposable = combinedDisposable(onChangeDisposable, containerDisposable);\r\n\r\n\t\tlet viewSize: ViewItemSize;\r\n\r\n\t\tif (typeof size === 'number') {\r\n\t\t\tviewSize = size;\r\n\t\t} else if (size.type === 'split') {\r\n\t\t\tviewSize = this.getViewSize(size.index) / 2;\r\n\t\t} else if (size.type === 'invisible') {\r\n\t\t\tviewSize = { cachedVisibleSize: size.cachedVisibleSize };\r\n\t\t} else {\r\n\t\t\tviewSize = view.minimumSize;\r\n\t\t}\r\n\r\n\t\tconst item = this.orientation === Orientation.VERTICAL\r\n\t\t\t? new VerticalViewItem(container, view, viewSize, disposable)\r\n\t\t\t: new HorizontalViewItem(container, view, viewSize, disposable);\r\n\r\n\t\tthis.viewItems.splice(index, 0, item);\r\n\r\n\t\t// Add sash\r\n\t\tif (this.viewItems.length > 1) {\r\n\t\t\tconst sash = this.orientation === Orientation.VERTICAL\r\n\t\t\t\t? new Sash(this.sashContainer, { getHorizontalSashTop: (sash: Sash) => this.getSashPosition(sash) }, {\r\n\t\t\t\t\torientation: Orientation.HORIZONTAL,\r\n\t\t\t\t\torthogonalStartSash: this.orthogonalStartSash,\r\n\t\t\t\t\torthogonalEndSash: this.orthogonalEndSash\r\n\t\t\t\t})\r\n\t\t\t\t: new Sash(this.sashContainer, { getVerticalSashLeft: (sash: Sash) => this.getSashPosition(sash) }, {\r\n\t\t\t\t\torientation: Orientation.VERTICAL,\r\n\t\t\t\t\torthogonalStartSash: this.orthogonalStartSash,\r\n\t\t\t\t\torthogonalEndSash: this.orthogonalEndSash\r\n\t\t\t\t});\r\n\r\n\t\t\tconst sashEventMapper = this.orientation === Orientation.VERTICAL\r\n\t\t\t\t? (e: IBaseSashEvent) => ({ sash, start: e.startY, current: e.currentY, alt: e.altKey })\r\n\t\t\t\t: (e: IBaseSashEvent) => ({ sash, start: e.startX, current: e.currentX, alt: e.altKey });\r\n\r\n\t\t\tconst onStart = Event.map(sash.onDidStart, sashEventMapper);\r\n\t\t\tconst onStartDisposable = onStart(this.onSashStart, this);\r\n\t\t\tconst onChange = Event.map(sash.onDidChange, sashEventMapper);\r\n\t\t\tconst onChangeDisposable = onChange(this.onSashChange, this);\r\n\t\t\tconst onEnd = Event.map(sash.onDidEnd, () => this.sashItems.findIndex(item => item.sash === sash));\r\n\t\t\tconst onEndDisposable = onEnd(this.onSashEnd, this);\r\n\r\n\t\t\tconst onDidResetDisposable = sash.onDidReset(() => {\r\n\t\t\t\tconst index = this.sashItems.findIndex(item => item.sash === sash);\r\n\t\t\t\tconst upIndexes = range(index, -1);\r\n\t\t\t\tconst downIndexes = range(index + 1, this.viewItems.length);\r\n\t\t\t\tconst snapBeforeIndex = this.findFirstSnapIndex(upIndexes);\r\n\t\t\t\tconst snapAfterIndex = this.findFirstSnapIndex(downIndexes);\r\n\r\n\t\t\t\tif (typeof snapBeforeIndex === 'number' && !this.viewItems[snapBeforeIndex].visible) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (typeof snapAfterIndex === 'number' && !this.viewItems[snapAfterIndex].visible) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis._onDidSashReset.fire(index);\r\n\t\t\t});\r\n\r\n\t\t\tconst disposable = combinedDisposable(onStartDisposable, onChangeDisposable, onEndDisposable, onDidResetDisposable, sash);\r\n\t\t\tconst sashItem: ISashItem = { sash, disposable };\r\n\r\n\t\t\tthis.sashItems.splice(index - 1, 0, sashItem);\r\n\t\t}\r\n\r\n\t\tcontainer.appendChild(view.element);\r\n\r\n\t\tlet highPriorityIndexes: number[] | undefined;\r\n\r\n\t\tif (typeof size !== 'number' && size.type === 'split') {\r\n\t\t\thighPriorityIndexes = [size.index];\r\n\t\t}\r\n\r\n\t\tif (!skipLayout) {\r\n\t\t\tthis.relayout([index], highPriorityIndexes);\r\n\t\t}\r\n\r\n\t\tthis.state = State.Idle;\r\n\r\n\t\tif (!skipLayout && typeof size !== 'number' && size.type === 'distribute') {\r\n\t\t\tthis.distributeViewSizes();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate relayout(lowPriorityIndexes?: number[], highPriorityIndexes?: number[]): void {\r\n\t\tconst contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);\r\n\r\n\t\tthis.resize(this.viewItems.length - 1, this.size - contentSize, undefined, lowPriorityIndexes, highPriorityIndexes);\r\n\t\tthis.distributeEmptySpace();\r\n\t\tthis.layoutViews();\r\n\t\tthis.saveProportions();\r\n\t}\r\n\r\n\tprivate resize(\r\n\t\tindex: number,\r\n\t\tdelta: number,\r\n\t\tsizes = this.viewItems.map(i => i.size),\r\n\t\tlowPriorityIndexes?: number[],\r\n\t\thighPriorityIndexes?: number[],\r\n\t\toverloadMinDelta: number = Number.NEGATIVE_INFINITY,\r\n\t\toverloadMaxDelta: number = Number.POSITIVE_INFINITY,\r\n\t\tsnapBefore?: ISashDragSnapState,\r\n\t\tsnapAfter?: ISashDragSnapState\r\n\t): number {\r\n\t\tif (index < 0 || index >= this.viewItems.length) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tconst upIndexes = range(index, -1);\r\n\t\tconst downIndexes = range(index + 1, this.viewItems.length);\r\n\r\n\t\tif (highPriorityIndexes) {\r\n\t\t\tfor (const index of highPriorityIndexes) {\r\n\t\t\t\tpushToStart(upIndexes, index);\r\n\t\t\t\tpushToStart(downIndexes, index);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (lowPriorityIndexes) {\r\n\t\t\tfor (const index of lowPriorityIndexes) {\r\n\t\t\t\tpushToEnd(upIndexes, index);\r\n\t\t\t\tpushToEnd(downIndexes, index);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst upItems = upIndexes.map(i => this.viewItems[i]);\r\n\t\tconst upSizes = upIndexes.map(i => sizes[i]);\r\n\r\n\t\tconst downItems = downIndexes.map(i => this.viewItems[i]);\r\n\t\tconst downSizes = downIndexes.map(i => sizes[i]);\r\n\r\n\t\tconst minDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].minimumSize - sizes[i]), 0);\r\n\t\tconst maxDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].maximumSize - sizes[i]), 0);\r\n\t\tconst maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].minimumSize), 0);\r\n\t\tconst minDeltaDown = downIndexes.length === 0 ? Number.NEGATIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].maximumSize), 0);\r\n\t\tconst minDelta = Math.max(minDeltaUp, minDeltaDown, overloadMinDelta);\r\n\t\tconst maxDelta = Math.min(maxDeltaDown, maxDeltaUp, overloadMaxDelta);\r\n\r\n\t\tlet snapped = false;\r\n\r\n\t\tif (snapBefore) {\r\n\t\t\tconst snapView = this.viewItems[snapBefore.index];\r\n\t\t\tconst visible = delta >= snapBefore.limitDelta;\r\n\t\t\tsnapped = visible !== snapView.visible;\r\n\t\t\tsnapView.setVisible(visible, snapBefore.size);\r\n\t\t}\r\n\r\n\t\tif (!snapped && snapAfter) {\r\n\t\t\tconst snapView = this.viewItems[snapAfter.index];\r\n\t\t\tconst visible = delta < snapAfter.limitDelta;\r\n\t\t\tsnapped = visible !== snapView.visible;\r\n\t\t\tsnapView.setVisible(visible, snapAfter.size);\r\n\t\t}\r\n\r\n\t\tif (snapped) {\r\n\t\t\treturn this.resize(index, delta, sizes, lowPriorityIndexes, highPriorityIndexes, overloadMinDelta, overloadMaxDelta);\r\n\t\t}\r\n\r\n\t\tdelta = clamp(delta, minDelta, maxDelta);\r\n\r\n\t\tfor (let i = 0, deltaUp = delta; i < upItems.length; i++) {\r\n\t\t\tconst item = upItems[i];\r\n\t\t\tconst size = clamp(upSizes[i] + deltaUp, item.minimumSize, item.maximumSize);\r\n\t\t\tconst viewDelta = size - upSizes[i];\r\n\r\n\t\t\tdeltaUp -= viewDelta;\r\n\t\t\titem.size = size;\r\n\t\t}\r\n\r\n\t\tfor (let i = 0, deltaDown = delta; i < downItems.length; i++) {\r\n\t\t\tconst item = downItems[i];\r\n\t\t\tconst size = clamp(downSizes[i] - deltaDown, item.minimumSize, item.maximumSize);\r\n\t\t\tconst viewDelta = size - downSizes[i];\r\n\r\n\t\t\tdeltaDown += viewDelta;\r\n\t\t\titem.size = size;\r\n\t\t}\r\n\r\n\t\treturn delta;\r\n\t}\r\n\r\n\tprivate distributeEmptySpace(lowPriorityIndex?: number): void {\r\n\t\tconst contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);\r\n\t\tlet emptyDelta = this.size - contentSize;\r\n\r\n\t\tconst indexes = range(this.viewItems.length - 1, -1);\r\n\t\tconst lowPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.Low);\r\n\t\tconst highPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.High);\r\n\r\n\t\tfor (const index of highPriorityIndexes) {\r\n\t\t\tpushToStart(indexes, index);\r\n\t\t}\r\n\r\n\t\tfor (const index of lowPriorityIndexes) {\r\n\t\t\tpushToEnd(indexes, index);\r\n\t\t}\r\n\r\n\t\tif (typeof lowPriorityIndex === 'number') {\r\n\t\t\tpushToEnd(indexes, lowPriorityIndex);\r\n\t\t}\r\n\r\n\t\tfor (let i = 0; emptyDelta !== 0 && i < indexes.length; i++) {\r\n\t\t\tconst item = this.viewItems[indexes[i]];\r\n\t\t\tconst size = clamp(item.size + emptyDelta, item.minimumSize, item.maximumSize);\r\n\t\t\tconst viewDelta = size - item.size;\r\n\r\n\t\t\temptyDelta -= viewDelta;\r\n\t\t\titem.size = size;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate layoutViews(): void {\r\n\t\t// Save new content size\r\n\t\tthis.contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);\r\n\r\n\t\t// Layout views\r\n\t\tlet offset = 0;\r\n\r\n\t\tfor (const viewItem of this.viewItems) {\r\n\t\t\tviewItem.layout(offset, this.layoutContext);\r\n\t\t\toffset += viewItem.size;\r\n\t\t}\r\n\r\n\t\t// Layout sashes\r\n\t\tthis.sashItems.forEach(item => item.sash.layout());\r\n\t\tthis.updateSashEnablement();\r\n\t\tthis.updateScrollableElement();\r\n\t}\r\n\r\n\tprivate updateScrollableElement(): void {\r\n\t\tif (this.orientation === Orientation.VERTICAL) {\r\n\t\t\tthis.scrollableElement.setScrollDimensions({\r\n\t\t\t\theight: this.size,\r\n\t\t\t\tscrollHeight: this.contentSize\r\n\t\t\t});\r\n\t\t} else {\r\n\t\t\tthis.scrollableElement.setScrollDimensions({\r\n\t\t\t\twidth: this.size,\r\n\t\t\t\tscrollWidth: this.contentSize\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tprivate updateSashEnablement(): void {\r\n\t\tlet previous = false;\r\n\t\tconst collapsesDown = this.viewItems.map(i => previous = (i.size - i.minimumSize > 0) || previous);\r\n\r\n\t\tprevious = false;\r\n\t\tconst expandsDown = this.viewItems.map(i => previous = (i.maximumSize - i.size > 0) || previous);\r\n\r\n\t\tconst reverseViews = [...this.viewItems].reverse();\r\n\t\tprevious = false;\r\n\t\tconst collapsesUp = reverseViews.map(i => previous = (i.size - i.minimumSize > 0) || previous).reverse();\r\n\r\n\t\tprevious = false;\r\n\t\tconst expandsUp = reverseViews.map(i => previous = (i.maximumSize - i.size > 0) || previous).reverse();\r\n\r\n\t\tlet position = 0;\r\n\t\tfor (let index = 0; index < this.sashItems.length; index++) {\r\n\t\t\tconst { sash } = this.sashItems[index];\r\n\t\t\tconst viewItem = this.viewItems[index];\r\n\t\t\tposition += viewItem.size;\r\n\r\n\t\t\tconst min = !(collapsesDown[index] && expandsUp[index + 1]);\r\n\t\t\tconst max = !(expandsDown[index] && collapsesUp[index + 1]);\r\n\r\n\t\t\tif (min && max) {\r\n\t\t\t\tconst upIndexes = range(index, -1);\r\n\t\t\t\tconst downIndexes = range(index + 1, this.viewItems.length);\r\n\t\t\t\tconst snapBeforeIndex = this.findFirstSnapIndex(upIndexes);\r\n\t\t\t\tconst snapAfterIndex = this.findFirstSnapIndex(downIndexes);\r\n\r\n\t\t\t\tconst snappedBefore = typeof snapBeforeIndex === 'number' && !this.viewItems[snapBeforeIndex].visible;\r\n\t\t\t\tconst snappedAfter = typeof snapAfterIndex === 'number' && !this.viewItems[snapAfterIndex].visible;\r\n\r\n\t\t\t\tif (snappedBefore && collapsesUp[index] && (position > 0 || this.startSnappingEnabled)) {\r\n\t\t\t\t\tsash.state = SashState.Minimum;\r\n\t\t\t\t} else if (snappedAfter && collapsesDown[index] && (position < this.contentSize || this.endSnappingEnabled)) {\r\n\t\t\t\t\tsash.state = SashState.Maximum;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tsash.state = SashState.Disabled;\r\n\t\t\t\t}\r\n\t\t\t} else if (min && !max) {\r\n\t\t\t\tsash.state = SashState.Minimum;\r\n\t\t\t} else if (!min && max) {\r\n\t\t\t\tsash.state = SashState.Maximum;\r\n\t\t\t} else {\r\n\t\t\t\tsash.state = SashState.Enabled;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate getSashPosition(sash: Sash): number {\r\n\t\tlet position = 0;\r\n\r\n\t\tfor (let i = 0; i < this.sashItems.length; i++) {\r\n\t\t\tposition += this.viewItems[i].size;\r\n\r\n\t\t\tif (this.sashItems[i].sash === sash) {\r\n\t\t\t\treturn position;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn 0;\r\n\t}\r\n\r\n\tprivate findFirstSnapIndex(indexes: number[]): number | undefined {\r\n\t\t// visible views first\r\n\t\tfor (const index of indexes) {\r\n\t\t\tconst viewItem = this.viewItems[index];\r\n\r\n\t\t\tif (!viewItem.visible) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (viewItem.snap) {\r\n\t\t\t\treturn index;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// then, hidden views\r\n\t\tfor (const index of indexes) {\r\n\t\t\tconst viewItem = this.viewItems[index];\r\n\r\n\t\t\tif (viewItem.visible && viewItem.maximumSize - viewItem.minimumSize > 0) {\r\n\t\t\t\treturn undefined;\r\n\t\t\t}\r\n\r\n\t\t\tif (!viewItem.visible && viewItem.snap) {\r\n\t\t\t\treturn index;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tsuper.dispose();\r\n\r\n\t\tthis.viewItems.forEach(i => i.dispose());\r\n\t\tthis.viewItems = [];\r\n\r\n\t\tthis.sashItems.forEach(i => i.disposable.dispose());\r\n\t\tthis.sashItems = [];\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./media/quickInput';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { IdGenerator } from 'vs/base/common/idGenerator';\r\n\r\nconst iconPathToClass: Record = {};\r\nconst iconClassGenerator = new IdGenerator('quick-input-button-icon-');\r\n\r\nexport function getIconClass(iconPath: { dark: URI; light?: URI; } | undefined): string | undefined {\r\n\tif (!iconPath) {\r\n\t\treturn undefined;\r\n\t}\r\n\tlet iconClass: string;\r\n\r\n\tconst key = iconPath.dark.toString();\r\n\tif (iconPathToClass[key]) {\r\n\t\ticonClass = iconPathToClass[key];\r\n\t} else {\r\n\t\ticonClass = iconClassGenerator.nextId();\r\n\t\tdom.createCSSRule(`.${iconClass}`, `background-image: ${dom.asCSSUrl(iconPath.light || iconPath.dark)}`);\r\n\t\tdom.createCSSRule(`.vs-dark .${iconClass}, .hc-black .${iconClass}`, `background-image: ${dom.asCSSUrl(iconPath.dark)}`);\r\n\t\ticonPathToClass[key] = iconClass;\r\n\t}\r\n\r\n\treturn iconClass;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { BareFontInfo } from 'vs/editor/common/config/fontInfo';\r\n\r\nexport const enum CharWidthRequestType {\r\n\tRegular = 0,\r\n\tItalic = 1,\r\n\tBold = 2\r\n}\r\n\r\nexport class CharWidthRequest {\r\n\r\n\tpublic readonly chr: string;\r\n\tpublic readonly type: CharWidthRequestType;\r\n\tpublic width: number;\r\n\r\n\tconstructor(chr: string, type: CharWidthRequestType) {\r\n\t\tthis.chr = chr;\r\n\t\tthis.type = type;\r\n\t\tthis.width = 0;\r\n\t}\r\n\r\n\tpublic fulfill(width: number) {\r\n\t\tthis.width = width;\r\n\t}\r\n}\r\n\r\nclass DomCharWidthReader {\r\n\r\n\tprivate readonly _bareFontInfo: BareFontInfo;\r\n\tprivate readonly _requests: CharWidthRequest[];\r\n\r\n\tprivate _container: HTMLElement | null;\r\n\tprivate _testElements: HTMLSpanElement[] | null;\r\n\r\n\tconstructor(bareFontInfo: BareFontInfo, requests: CharWidthRequest[]) {\r\n\t\tthis._bareFontInfo = bareFontInfo;\r\n\t\tthis._requests = requests;\r\n\r\n\t\tthis._container = null;\r\n\t\tthis._testElements = null;\r\n\t}\r\n\r\n\tpublic read(): void {\r\n\t\t// Create a test container with all these test elements\r\n\t\tthis._createDomElements();\r\n\r\n\t\t// Add the container to the DOM\r\n\t\tdocument.body.appendChild(this._container!);\r\n\r\n\t\t// Read character widths\r\n\t\tthis._readFromDomElements();\r\n\r\n\t\t// Remove the container from the DOM\r\n\t\tdocument.body.removeChild(this._container!);\r\n\r\n\t\tthis._container = null;\r\n\t\tthis._testElements = null;\r\n\t}\r\n\r\n\tprivate _createDomElements(): void {\r\n\t\tconst container = document.createElement('div');\r\n\t\tcontainer.style.position = 'absolute';\r\n\t\tcontainer.style.top = '-50000px';\r\n\t\tcontainer.style.width = '50000px';\r\n\r\n\t\tconst regularDomNode = document.createElement('div');\r\n\t\tregularDomNode.style.fontFamily = this._bareFontInfo.getMassagedFontFamily();\r\n\t\tregularDomNode.style.fontWeight = this._bareFontInfo.fontWeight;\r\n\t\tregularDomNode.style.fontSize = this._bareFontInfo.fontSize + 'px';\r\n\t\tregularDomNode.style.fontFeatureSettings = this._bareFontInfo.fontFeatureSettings;\r\n\t\tregularDomNode.style.lineHeight = this._bareFontInfo.lineHeight + 'px';\r\n\t\tregularDomNode.style.letterSpacing = this._bareFontInfo.letterSpacing + 'px';\r\n\t\tcontainer.appendChild(regularDomNode);\r\n\r\n\t\tconst boldDomNode = document.createElement('div');\r\n\t\tboldDomNode.style.fontFamily = this._bareFontInfo.getMassagedFontFamily();\r\n\t\tboldDomNode.style.fontWeight = 'bold';\r\n\t\tboldDomNode.style.fontSize = this._bareFontInfo.fontSize + 'px';\r\n\t\tboldDomNode.style.fontFeatureSettings = this._bareFontInfo.fontFeatureSettings;\r\n\t\tboldDomNode.style.lineHeight = this._bareFontInfo.lineHeight + 'px';\r\n\t\tboldDomNode.style.letterSpacing = this._bareFontInfo.letterSpacing + 'px';\r\n\t\tcontainer.appendChild(boldDomNode);\r\n\r\n\t\tconst italicDomNode = document.createElement('div');\r\n\t\titalicDomNode.style.fontFamily = this._bareFontInfo.getMassagedFontFamily();\r\n\t\titalicDomNode.style.fontWeight = this._bareFontInfo.fontWeight;\r\n\t\titalicDomNode.style.fontSize = this._bareFontInfo.fontSize + 'px';\r\n\t\titalicDomNode.style.fontFeatureSettings = this._bareFontInfo.fontFeatureSettings;\r\n\t\titalicDomNode.style.lineHeight = this._bareFontInfo.lineHeight + 'px';\r\n\t\titalicDomNode.style.letterSpacing = this._bareFontInfo.letterSpacing + 'px';\r\n\t\titalicDomNode.style.fontStyle = 'italic';\r\n\t\tcontainer.appendChild(italicDomNode);\r\n\r\n\t\tconst testElements: HTMLSpanElement[] = [];\r\n\t\tfor (const request of this._requests) {\r\n\r\n\t\t\tlet parent: HTMLElement;\r\n\t\t\tif (request.type === CharWidthRequestType.Regular) {\r\n\t\t\t\tparent = regularDomNode;\r\n\t\t\t}\r\n\t\t\tif (request.type === CharWidthRequestType.Bold) {\r\n\t\t\t\tparent = boldDomNode;\r\n\t\t\t}\r\n\t\t\tif (request.type === CharWidthRequestType.Italic) {\r\n\t\t\t\tparent = italicDomNode;\r\n\t\t\t}\r\n\r\n\t\t\tparent!.appendChild(document.createElement('br'));\r\n\r\n\t\t\tconst testElement = document.createElement('span');\r\n\t\t\tDomCharWidthReader._render(testElement, request);\r\n\t\t\tparent!.appendChild(testElement);\r\n\r\n\t\t\ttestElements.push(testElement);\r\n\t\t}\r\n\r\n\t\tthis._container = container;\r\n\t\tthis._testElements = testElements;\r\n\t}\r\n\r\n\tprivate static _render(testElement: HTMLElement, request: CharWidthRequest): void {\r\n\t\tif (request.chr === ' ') {\r\n\t\t\tlet htmlString = '\\u00a0';\r\n\t\t\t// Repeat character 256 (2^8) times\r\n\t\t\tfor (let i = 0; i < 8; i++) {\r\n\t\t\t\thtmlString += htmlString;\r\n\t\t\t}\r\n\t\t\ttestElement.innerText = htmlString;\r\n\t\t} else {\r\n\t\t\tlet testString = request.chr;\r\n\t\t\t// Repeat character 256 (2^8) times\r\n\t\t\tfor (let i = 0; i < 8; i++) {\r\n\t\t\t\ttestString += testString;\r\n\t\t\t}\r\n\t\t\ttestElement.textContent = testString;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _readFromDomElements(): void {\r\n\t\tfor (let i = 0, len = this._requests.length; i < len; i++) {\r\n\t\t\tconst request = this._requests[i];\r\n\t\t\tconst testElement = this._testElements![i];\r\n\r\n\t\t\trequest.fulfill(testElement.offsetWidth / 256);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport function readCharWidths(bareFontInfo: BareFontInfo, requests: CharWidthRequest[]): void {\r\n\tconst reader = new DomCharWidthReader(bareFontInfo, requests);\r\n\treader.read();\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { IDimension } from 'vs/editor/common/editorCommon';\r\n\r\ninterface ResizeObserver {\r\n\tobserve(target: Element): void;\r\n\tdisconnect(): void;\r\n}\r\n\r\ninterface ResizeObserverEntry {\r\n\treadonly contentRect: DOMRectReadOnly;\r\n}\r\n\r\ntype ResizeObserverCallback = (entries: ReadonlyArray, observer: ResizeObserver) => void;\r\n\r\ndeclare const ResizeObserver: {\r\n\tprototype: ResizeObserver;\r\n\tnew(callback: ResizeObserverCallback): ResizeObserver;\r\n};\r\n\r\n\r\nexport class ElementSizeObserver extends Disposable {\r\n\r\n\tprivate readonly referenceDomElement: HTMLElement | null;\r\n\tprivate readonly changeCallback: () => void;\r\n\tprivate width: number;\r\n\tprivate height: number;\r\n\tprivate resizeObserver: ResizeObserver | null;\r\n\tprivate measureReferenceDomElementToken: number;\r\n\r\n\tconstructor(referenceDomElement: HTMLElement | null, dimension: IDimension | undefined, changeCallback: () => void) {\r\n\t\tsuper();\r\n\t\tthis.referenceDomElement = referenceDomElement;\r\n\t\tthis.changeCallback = changeCallback;\r\n\t\tthis.width = -1;\r\n\t\tthis.height = -1;\r\n\t\tthis.resizeObserver = null;\r\n\t\tthis.measureReferenceDomElementToken = -1;\r\n\t\tthis.measureReferenceDomElement(false, dimension);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis.stopObserving();\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tpublic getWidth(): number {\r\n\t\treturn this.width;\r\n\t}\r\n\r\n\tpublic getHeight(): number {\r\n\t\treturn this.height;\r\n\t}\r\n\r\n\tpublic startObserving(): void {\r\n\t\tif (typeof ResizeObserver !== 'undefined') {\r\n\t\t\tif (!this.resizeObserver && this.referenceDomElement) {\r\n\t\t\t\tthis.resizeObserver = new ResizeObserver((entries) => {\r\n\t\t\t\t\tif (entries && entries[0] && entries[0].contentRect) {\r\n\t\t\t\t\t\tthis.observe({ width: entries[0].contentRect.width, height: entries[0].contentRect.height });\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tthis.observe();\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t\tthis.resizeObserver.observe(this.referenceDomElement);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tif (this.measureReferenceDomElementToken === -1) {\r\n\t\t\t\t// setInterval type defaults to NodeJS.Timeout instead of number, so specify it as a number\r\n\t\t\t\tthis.measureReferenceDomElementToken = setInterval(() => this.observe(), 100);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic stopObserving(): void {\r\n\t\tif (this.resizeObserver) {\r\n\t\t\tthis.resizeObserver.disconnect();\r\n\t\t\tthis.resizeObserver = null;\r\n\t\t}\r\n\t\tif (this.measureReferenceDomElementToken !== -1) {\r\n\t\t\tclearInterval(this.measureReferenceDomElementToken);\r\n\t\t\tthis.measureReferenceDomElementToken = -1;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic observe(dimension?: IDimension): void {\r\n\t\tthis.measureReferenceDomElement(true, dimension);\r\n\t}\r\n\r\n\tprivate measureReferenceDomElement(callChangeCallback: boolean, dimension?: IDimension): void {\r\n\t\tlet observedWidth = 0;\r\n\t\tlet observedHeight = 0;\r\n\t\tif (dimension) {\r\n\t\t\tobservedWidth = dimension.width;\r\n\t\t\tobservedHeight = dimension.height;\r\n\t\t} else if (this.referenceDomElement) {\r\n\t\t\tobservedWidth = this.referenceDomElement.clientWidth;\r\n\t\t\tobservedHeight = this.referenceDomElement.clientHeight;\r\n\t\t}\r\n\t\tobservedWidth = Math.max(5, observedWidth);\r\n\t\tobservedHeight = Math.max(5, observedHeight);\r\n\t\tif (this.width !== observedWidth || this.height !== observedHeight) {\r\n\t\t\tthis.width = observedWidth;\r\n\t\t\tthis.height = observedHeight;\r\n\t\t\tif (callChangeCallback) {\r\n\t\t\t\tthis.changeCallback();\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { GlobalMouseMoveMonitor } from 'vs/base/browser/globalMouseMoveMonitor';\r\nimport { StandardMouseEvent } from 'vs/base/browser/mouseEvent';\r\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\r\n\r\n/**\r\n * Coordinates relative to the whole document (e.g. mouse event's pageX and pageY)\r\n */\r\nexport class PageCoordinates {\r\n\t_pageCoordinatesBrand: void;\r\n\r\n\tconstructor(\r\n\t\tpublic readonly x: number,\r\n\t\tpublic readonly y: number\r\n\t) { }\r\n\r\n\tpublic toClientCoordinates(): ClientCoordinates {\r\n\t\treturn new ClientCoordinates(this.x - dom.StandardWindow.scrollX, this.y - dom.StandardWindow.scrollY);\r\n\t}\r\n}\r\n\r\n/**\r\n * Coordinates within the application's client area (i.e. origin is document's scroll position).\r\n *\r\n * For example, clicking in the top-left corner of the client area will\r\n * always result in a mouse event with a client.x value of 0, regardless\r\n * of whether the page is scrolled horizontally.\r\n */\r\nexport class ClientCoordinates {\r\n\t_clientCoordinatesBrand: void;\r\n\r\n\tconstructor(\r\n\t\tpublic readonly clientX: number,\r\n\t\tpublic readonly clientY: number\r\n\t) { }\r\n\r\n\tpublic toPageCoordinates(): PageCoordinates {\r\n\t\treturn new PageCoordinates(this.clientX + dom.StandardWindow.scrollX, this.clientY + dom.StandardWindow.scrollY);\r\n\t}\r\n}\r\n\r\n/**\r\n * The position of the editor in the page.\r\n */\r\nexport class EditorPagePosition {\r\n\t_editorPagePositionBrand: void;\r\n\r\n\tconstructor(\r\n\t\tpublic readonly x: number,\r\n\t\tpublic readonly y: number,\r\n\t\tpublic readonly width: number,\r\n\t\tpublic readonly height: number\r\n\t) { }\r\n}\r\n\r\nexport function createEditorPagePosition(editorViewDomNode: HTMLElement): EditorPagePosition {\r\n\tconst editorPos = dom.getDomNodePagePosition(editorViewDomNode);\r\n\treturn new EditorPagePosition(editorPos.left, editorPos.top, editorPos.width, editorPos.height);\r\n}\r\n\r\nexport class EditorMouseEvent extends StandardMouseEvent {\r\n\t_editorMouseEventBrand: void;\r\n\r\n\t/**\r\n\t * Coordinates relative to the whole document.\r\n\t */\r\n\tpublic readonly pos: PageCoordinates;\r\n\r\n\t/**\r\n\t * Editor's coordinates relative to the whole document.\r\n\t */\r\n\tpublic readonly editorPos: EditorPagePosition;\r\n\r\n\tconstructor(e: MouseEvent, editorViewDomNode: HTMLElement) {\r\n\t\tsuper(e);\r\n\t\tthis.pos = new PageCoordinates(this.posx, this.posy);\r\n\t\tthis.editorPos = createEditorPagePosition(editorViewDomNode);\r\n\t}\r\n}\r\n\r\nexport interface EditorMouseEventMerger {\r\n\t(lastEvent: EditorMouseEvent | null, currentEvent: EditorMouseEvent): EditorMouseEvent;\r\n}\r\n\r\nexport class EditorMouseEventFactory {\r\n\r\n\tprivate readonly _editorViewDomNode: HTMLElement;\r\n\r\n\tconstructor(editorViewDomNode: HTMLElement) {\r\n\t\tthis._editorViewDomNode = editorViewDomNode;\r\n\t}\r\n\r\n\tprivate _create(e: MouseEvent): EditorMouseEvent {\r\n\t\treturn new EditorMouseEvent(e, this._editorViewDomNode);\r\n\t}\r\n\r\n\tpublic onContextMenu(target: HTMLElement, callback: (e: EditorMouseEvent) => void): IDisposable {\r\n\t\treturn dom.addDisposableListener(target, 'contextmenu', (e: MouseEvent) => {\r\n\t\t\tcallback(this._create(e));\r\n\t\t});\r\n\t}\r\n\r\n\tpublic onMouseUp(target: HTMLElement, callback: (e: EditorMouseEvent) => void): IDisposable {\r\n\t\treturn dom.addDisposableListener(target, 'mouseup', (e: MouseEvent) => {\r\n\t\t\tcallback(this._create(e));\r\n\t\t});\r\n\t}\r\n\r\n\tpublic onMouseDown(target: HTMLElement, callback: (e: EditorMouseEvent) => void): IDisposable {\r\n\t\treturn dom.addDisposableListener(target, 'mousedown', (e: MouseEvent) => {\r\n\t\t\tcallback(this._create(e));\r\n\t\t});\r\n\t}\r\n\r\n\tpublic onMouseLeave(target: HTMLElement, callback: (e: EditorMouseEvent) => void): IDisposable {\r\n\t\treturn dom.addDisposableNonBubblingMouseOutListener(target, (e: MouseEvent) => {\r\n\t\t\tcallback(this._create(e));\r\n\t\t});\r\n\t}\r\n\r\n\tpublic onMouseMoveThrottled(target: HTMLElement, callback: (e: EditorMouseEvent) => void, merger: EditorMouseEventMerger, minimumTimeMs: number): IDisposable {\r\n\t\tconst myMerger: dom.IEventMerger = (lastEvent: EditorMouseEvent | null, currentEvent: MouseEvent): EditorMouseEvent => {\r\n\t\t\treturn merger(lastEvent, this._create(currentEvent));\r\n\t\t};\r\n\t\treturn dom.addDisposableThrottledListener(target, 'mousemove', callback, myMerger, minimumTimeMs);\r\n\t}\r\n}\r\n\r\nexport class EditorPointerEventFactory {\r\n\r\n\tprivate readonly _editorViewDomNode: HTMLElement;\r\n\r\n\tconstructor(editorViewDomNode: HTMLElement) {\r\n\t\tthis._editorViewDomNode = editorViewDomNode;\r\n\t}\r\n\r\n\tprivate _create(e: MouseEvent): EditorMouseEvent {\r\n\t\treturn new EditorMouseEvent(e, this._editorViewDomNode);\r\n\t}\r\n\r\n\tpublic onPointerUp(target: HTMLElement, callback: (e: EditorMouseEvent) => void): IDisposable {\r\n\t\treturn dom.addDisposableListener(target, 'pointerup', (e: MouseEvent) => {\r\n\t\t\tcallback(this._create(e));\r\n\t\t});\r\n\t}\r\n\r\n\tpublic onPointerDown(target: HTMLElement, callback: (e: EditorMouseEvent) => void): IDisposable {\r\n\t\treturn dom.addDisposableListener(target, 'pointerdown', (e: MouseEvent) => {\r\n\t\t\tcallback(this._create(e));\r\n\t\t});\r\n\t}\r\n\r\n\tpublic onPointerLeave(target: HTMLElement, callback: (e: EditorMouseEvent) => void): IDisposable {\r\n\t\treturn dom.addDisposableNonBubblingPointerOutListener(target, (e: MouseEvent) => {\r\n\t\t\tcallback(this._create(e));\r\n\t\t});\r\n\t}\r\n\r\n\tpublic onPointerMoveThrottled(target: HTMLElement, callback: (e: EditorMouseEvent) => void, merger: EditorMouseEventMerger, minimumTimeMs: number): IDisposable {\r\n\t\tconst myMerger: dom.IEventMerger = (lastEvent: EditorMouseEvent | null, currentEvent: MouseEvent): EditorMouseEvent => {\r\n\t\t\treturn merger(lastEvent, this._create(currentEvent));\r\n\t\t};\r\n\t\treturn dom.addDisposableThrottledListener(target, 'pointermove', callback, myMerger, minimumTimeMs);\r\n\t}\r\n}\r\n\r\nexport class GlobalEditorMouseMoveMonitor extends Disposable {\r\n\r\n\tprivate readonly _editorViewDomNode: HTMLElement;\r\n\tprivate readonly _globalMouseMoveMonitor: GlobalMouseMoveMonitor;\r\n\tprivate _keydownListener: IDisposable | null;\r\n\r\n\tconstructor(editorViewDomNode: HTMLElement) {\r\n\t\tsuper();\r\n\t\tthis._editorViewDomNode = editorViewDomNode;\r\n\t\tthis._globalMouseMoveMonitor = this._register(new GlobalMouseMoveMonitor());\r\n\t\tthis._keydownListener = null;\r\n\t}\r\n\r\n\tpublic startMonitoring(\r\n\t\tinitialElement: HTMLElement,\r\n\t\tinitialButtons: number,\r\n\t\tmerger: EditorMouseEventMerger,\r\n\t\tmouseMoveCallback: (e: EditorMouseEvent) => void,\r\n\t\tonStopCallback: (browserEvent?: MouseEvent | KeyboardEvent) => void\r\n\t): void {\r\n\r\n\t\t// Add a <> keydown event listener that will cancel the monitoring\r\n\t\t// if something other than a modifier key is pressed\r\n\t\tthis._keydownListener = dom.addStandardDisposableListener(document, 'keydown', (e) => {\r\n\t\t\tconst kb = e.toKeybinding();\r\n\t\t\tif (kb.isModifierKey()) {\r\n\t\t\t\t// Allow modifier keys\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tthis._globalMouseMoveMonitor.stopMonitoring(true, e.browserEvent);\r\n\t\t}, true);\r\n\r\n\t\tconst myMerger: dom.IEventMerger = (lastEvent: EditorMouseEvent | null, currentEvent: MouseEvent): EditorMouseEvent => {\r\n\t\t\treturn merger(lastEvent, new EditorMouseEvent(currentEvent, this._editorViewDomNode));\r\n\t\t};\r\n\r\n\t\tthis._globalMouseMoveMonitor.startMonitoring(initialElement, initialButtons, myMerger, mouseMoveCallback, (e) => {\r\n\t\t\tthis._keydownListener!.dispose();\r\n\t\t\tonStopCallback(e);\r\n\t\t});\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\r\nimport { IDecorationRenderOptions } from 'vs/editor/common/editorCommon';\r\nimport { IModelDecorationOptions } from 'vs/editor/common/model';\r\nimport { IResourceEditorInput } from 'vs/platform/editor/common/editor';\r\nimport { URI } from 'vs/base/common/uri';\r\n\r\nexport abstract class AbstractCodeEditorService extends Disposable implements ICodeEditorService {\r\n\r\n\tdeclare readonly _serviceBrand: undefined;\r\n\r\n\tprivate readonly _onCodeEditorAdd: Emitter = this._register(new Emitter());\r\n\tpublic readonly onCodeEditorAdd: Event = this._onCodeEditorAdd.event;\r\n\r\n\tprivate readonly _onCodeEditorRemove: Emitter = this._register(new Emitter());\r\n\tpublic readonly onCodeEditorRemove: Event = this._onCodeEditorRemove.event;\r\n\r\n\tprivate readonly _onDiffEditorAdd: Emitter = this._register(new Emitter());\r\n\r\n\tprivate readonly _onDiffEditorRemove: Emitter = this._register(new Emitter());\r\n\r\n\tprotected readonly _onDecorationTypeRegistered: Emitter = this._register(new Emitter());\r\n\r\n\tprivate readonly _codeEditors: { [editorId: string]: ICodeEditor; };\r\n\tprivate readonly _diffEditors: { [editorId: string]: IDiffEditor; };\r\n\r\n\tconstructor() {\r\n\t\tsuper();\r\n\t\tthis._codeEditors = Object.create(null);\r\n\t\tthis._diffEditors = Object.create(null);\r\n\t}\r\n\r\n\taddCodeEditor(editor: ICodeEditor): void {\r\n\t\tthis._codeEditors[editor.getId()] = editor;\r\n\t\tthis._onCodeEditorAdd.fire(editor);\r\n\t}\r\n\r\n\tremoveCodeEditor(editor: ICodeEditor): void {\r\n\t\tif (delete this._codeEditors[editor.getId()]) {\r\n\t\t\tthis._onCodeEditorRemove.fire(editor);\r\n\t\t}\r\n\t}\r\n\r\n\tlistCodeEditors(): ICodeEditor[] {\r\n\t\treturn Object.keys(this._codeEditors).map(id => this._codeEditors[id]);\r\n\t}\r\n\r\n\taddDiffEditor(editor: IDiffEditor): void {\r\n\t\tthis._diffEditors[editor.getId()] = editor;\r\n\t\tthis._onDiffEditorAdd.fire(editor);\r\n\t}\r\n\r\n\tremoveDiffEditor(editor: IDiffEditor): void {\r\n\t\tif (delete this._diffEditors[editor.getId()]) {\r\n\t\t\tthis._onDiffEditorRemove.fire(editor);\r\n\t\t}\r\n\t}\r\n\r\n\tlistDiffEditors(): IDiffEditor[] {\r\n\t\treturn Object.keys(this._diffEditors).map(id => this._diffEditors[id]);\r\n\t}\r\n\r\n\tgetFocusedCodeEditor(): ICodeEditor | null {\r\n\t\tlet editorWithWidgetFocus: ICodeEditor | null = null;\r\n\r\n\t\tconst editors = this.listCodeEditors();\r\n\t\tfor (const editor of editors) {\r\n\r\n\t\t\tif (editor.hasTextFocus()) {\r\n\t\t\t\t// bingo!\r\n\t\t\t\treturn editor;\r\n\t\t\t}\r\n\r\n\t\t\tif (editor.hasWidgetFocus()) {\r\n\t\t\t\teditorWithWidgetFocus = editor;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn editorWithWidgetFocus;\r\n\t}\r\n\r\n\tabstract registerDecorationType(key: string, options: IDecorationRenderOptions, parentTypeKey?: string, editor?: ICodeEditor): void;\r\n\tabstract removeDecorationType(key: string): void;\r\n\tabstract resolveDecorationOptions(decorationTypeKey: string | undefined, writable: boolean): IModelDecorationOptions;\r\n\tprivate readonly _modelProperties = new Map>();\r\n\r\n\tpublic setModelProperty(resource: URI, key: string, value: any): void {\r\n\t\tconst key1 = resource.toString();\r\n\t\tlet dest: Map;\r\n\t\tif (this._modelProperties.has(key1)) {\r\n\t\t\tdest = this._modelProperties.get(key1)!;\r\n\t\t} else {\r\n\t\t\tdest = new Map();\r\n\t\t\tthis._modelProperties.set(key1, dest);\r\n\t\t}\r\n\r\n\t\tdest.set(key, value);\r\n\t}\r\n\r\n\tpublic getModelProperty(resource: URI, key: string): any {\r\n\t\tconst key1 = resource.toString();\r\n\t\tif (this._modelProperties.has(key1)) {\r\n\t\t\tconst innerMap = this._modelProperties.get(key1)!;\r\n\t\t\treturn innerMap.get(key);\r\n\t\t}\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tabstract getActiveCodeEditor(): ICodeEditor | null;\r\n\tabstract openCodeEditor(input: IResourceEditorInput, source: ICodeEditor | null, sideBySide?: boolean): Promise;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nexport const enum Constants {\r\n\tSTART_CH_CODE = 32, // Space\r\n\tEND_CH_CODE = 126, // Tilde (~)\r\n\tUNKNOWN_CODE = 65533, // UTF placeholder code\r\n\tCHAR_COUNT = END_CH_CODE - START_CH_CODE + 2,\r\n\r\n\tSAMPLED_CHAR_HEIGHT = 16,\r\n\tSAMPLED_CHAR_WIDTH = 10,\r\n\r\n\tBASE_CHAR_HEIGHT = 2,\r\n\tBASE_CHAR_WIDTH = 1,\r\n\r\n\tRGBA_CHANNELS_CNT = 4,\r\n\tRGBA_SAMPLED_ROW_WIDTH = RGBA_CHANNELS_CNT * CHAR_COUNT * SAMPLED_CHAR_WIDTH\r\n}\r\n\r\nexport const allCharCodes: ReadonlyArray = (() => {\r\n\tconst v: number[] = [];\r\n\tfor (let i = Constants.START_CH_CODE; i <= Constants.END_CH_CODE; i++) {\r\n\t\tv.push(i);\r\n\t}\r\n\r\n\tv.push(Constants.UNKNOWN_CODE);\r\n\treturn v;\r\n})();\r\n\r\nexport const getCharIndex = (chCode: number, fontScale: number) => {\r\n\tchCode -= Constants.START_CH_CODE;\r\n\tif (chCode < 0 || chCode > Constants.CHAR_COUNT) {\r\n\t\tif (fontScale <= 2) {\r\n\t\t\t// for smaller scales, we can get away with using any ASCII character...\r\n\t\t\treturn (chCode + Constants.CHAR_COUNT) % Constants.CHAR_COUNT;\r\n\t\t}\r\n\t\treturn Constants.CHAR_COUNT - 1; // unknown symbol\r\n\t}\r\n\r\n\treturn chCode;\r\n};\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { RGBA8 } from 'vs/editor/common/core/rgba';\r\nimport { Constants, getCharIndex } from './minimapCharSheet';\r\nimport { toUint8 } from 'vs/base/common/uint';\r\n\r\nexport class MinimapCharRenderer {\r\n\t_minimapCharRendererBrand: void;\r\n\r\n\tprivate readonly charDataNormal: Uint8ClampedArray;\r\n\tprivate readonly charDataLight: Uint8ClampedArray;\r\n\r\n\tconstructor(charData: Uint8ClampedArray, public readonly scale: number) {\r\n\t\tthis.charDataNormal = MinimapCharRenderer.soften(charData, 12 / 15);\r\n\t\tthis.charDataLight = MinimapCharRenderer.soften(charData, 50 / 60);\r\n\t}\r\n\r\n\tprivate static soften(input: Uint8ClampedArray, ratio: number): Uint8ClampedArray {\r\n\t\tlet result = new Uint8ClampedArray(input.length);\r\n\t\tfor (let i = 0, len = input.length; i < len; i++) {\r\n\t\t\tresult[i] = toUint8(input[i] * ratio);\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic renderChar(\r\n\t\ttarget: ImageData,\r\n\t\tdx: number,\r\n\t\tdy: number,\r\n\t\tchCode: number,\r\n\t\tcolor: RGBA8,\r\n\t\tbackgroundColor: RGBA8,\r\n\t\tfontScale: number,\r\n\t\tuseLighterFont: boolean,\r\n\t\tforce1pxHeight: boolean\r\n\t): void {\r\n\t\tconst charWidth = Constants.BASE_CHAR_WIDTH * this.scale;\r\n\t\tconst charHeight = Constants.BASE_CHAR_HEIGHT * this.scale;\r\n\t\tconst renderHeight = (force1pxHeight ? 1 : charHeight);\r\n\t\tif (dx + charWidth > target.width || dy + renderHeight > target.height) {\r\n\t\t\tconsole.warn('bad render request outside image data');\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst charData = useLighterFont ? this.charDataLight : this.charDataNormal;\r\n\t\tconst charIndex = getCharIndex(chCode, fontScale);\r\n\r\n\t\tconst destWidth = target.width * Constants.RGBA_CHANNELS_CNT;\r\n\r\n\t\tconst backgroundR = backgroundColor.r;\r\n\t\tconst backgroundG = backgroundColor.g;\r\n\t\tconst backgroundB = backgroundColor.b;\r\n\r\n\t\tconst deltaR = color.r - backgroundR;\r\n\t\tconst deltaG = color.g - backgroundG;\r\n\t\tconst deltaB = color.b - backgroundB;\r\n\r\n\t\tconst dest = target.data;\r\n\t\tlet sourceOffset = charIndex * charWidth * charHeight;\r\n\r\n\t\tlet row = dy * destWidth + dx * Constants.RGBA_CHANNELS_CNT;\r\n\t\tfor (let y = 0; y < renderHeight; y++) {\r\n\t\t\tlet column = row;\r\n\t\t\tfor (let x = 0; x < charWidth; x++) {\r\n\t\t\t\tconst c = charData[sourceOffset++] / 255;\r\n\t\t\t\tdest[column++] = backgroundR + deltaR * c;\r\n\t\t\t\tdest[column++] = backgroundG + deltaG * c;\r\n\t\t\t\tdest[column++] = backgroundB + deltaB * c;\r\n\t\t\t\tcolumn++;\r\n\t\t\t}\r\n\r\n\t\t\trow += destWidth;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic blockRenderChar(\r\n\t\ttarget: ImageData,\r\n\t\tdx: number,\r\n\t\tdy: number,\r\n\t\tcolor: RGBA8,\r\n\t\tbackgroundColor: RGBA8,\r\n\t\tuseLighterFont: boolean,\r\n\t\tforce1pxHeight: boolean\r\n\t): void {\r\n\t\tconst charWidth = Constants.BASE_CHAR_WIDTH * this.scale;\r\n\t\tconst charHeight = Constants.BASE_CHAR_HEIGHT * this.scale;\r\n\t\tconst renderHeight = (force1pxHeight ? 1 : charHeight);\r\n\t\tif (dx + charWidth > target.width || dy + renderHeight > target.height) {\r\n\t\t\tconsole.warn('bad render request outside image data');\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst destWidth = target.width * Constants.RGBA_CHANNELS_CNT;\r\n\r\n\t\tconst c = 0.5;\r\n\r\n\t\tconst backgroundR = backgroundColor.r;\r\n\t\tconst backgroundG = backgroundColor.g;\r\n\t\tconst backgroundB = backgroundColor.b;\r\n\r\n\t\tconst deltaR = color.r - backgroundR;\r\n\t\tconst deltaG = color.g - backgroundG;\r\n\t\tconst deltaB = color.b - backgroundB;\r\n\r\n\t\tconst colorR = backgroundR + deltaR * c;\r\n\t\tconst colorG = backgroundG + deltaG * c;\r\n\t\tconst colorB = backgroundB + deltaB * c;\r\n\r\n\t\tconst dest = target.data;\r\n\r\n\t\tlet row = dy * destWidth + dx * Constants.RGBA_CHANNELS_CNT;\r\n\t\tfor (let y = 0; y < renderHeight; y++) {\r\n\t\t\tlet column = row;\r\n\t\t\tfor (let x = 0; x < charWidth; x++) {\r\n\t\t\t\tdest[column++] = colorR;\r\n\t\t\t\tdest[column++] = colorG;\r\n\t\t\t\tdest[column++] = colorB;\r\n\t\t\t\tcolumn++;\r\n\t\t\t}\r\n\r\n\t\t\trow += destWidth;\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { once } from 'vs/base/common/functional';\r\n\r\nconst charTable: { [hex: string]: number } = {\r\n\t'0': 0,\r\n\t'1': 1,\r\n\t'2': 2,\r\n\t'3': 3,\r\n\t'4': 4,\r\n\t'5': 5,\r\n\t'6': 6,\r\n\t'7': 7,\r\n\t'8': 8,\r\n\t'9': 9,\r\n\tA: 10,\r\n\tB: 11,\r\n\tC: 12,\r\n\tD: 13,\r\n\tE: 14,\r\n\tF: 15\r\n};\r\n\r\nconst decodeData = (str: string) => {\r\n\tconst output = new Uint8ClampedArray(str.length / 2);\r\n\tfor (let i = 0; i < str.length; i += 2) {\r\n\t\toutput[i >> 1] = (charTable[str[i]] << 4) | (charTable[str[i + 1]] & 0xF);\r\n\t}\r\n\r\n\treturn output;\r\n};\r\n\r\n/*\r\nconst encodeData = (data: Uint8ClampedArray, length: string) => {\r\n\tconst chars = '0123456789ABCDEF';\r\n\tlet output = '';\r\n\tfor (let i = 0; i < data.length; i++) {\r\n\t\toutput += chars[data[i] >> 4] + chars[data[i] & 0xf];\r\n\t}\r\n\treturn output;\r\n};\r\n*/\r\n\r\n/**\r\n * Map of minimap scales to prebaked sample data at those scales. We don't\r\n * sample much larger data, because then font family becomes visible, which\r\n * is use-configurable.\r\n */\r\nexport const prebakedMiniMaps: { [scale: number]: () => Uint8ClampedArray } = {\r\n\t1: once(() =>\r\n\t\tdecodeData(\r\n\t\t\t'0000511D6300CF609C709645A78432005642574171487021003C451900274D35D762755E8B629C5BA856AF57BA649530C167D1512A272A3F6038604460398526BCA2A968DB6F8957C768BE5FBE2FB467CF5D8D5B795DC7625B5DFF50DE64C466DB2FC47CD860A65E9A2EB96CB54CE06DA763AB2EA26860524D3763536601005116008177A8705E53AB738E6A982F88BAA35B5F5B626D9C636B449B737E5B7B678598869A662F6B5B8542706C704C80736A607578685B70594A49715A4522E792'\r\n\t\t)\r\n\t),\r\n\t2: once(() =>\r\n\t\tdecodeData(\r\n\t\t\t'000000000000000055394F383D2800008B8B1F210002000081B1CBCBCC820000847AAF6B9AAF2119BE08B8881AD60000A44FD07DCCF107015338130C00000000385972265F390B406E2437634B4B48031B12B8A0847000001E15B29A402F0000000000004B33460B00007A752C2A0000000000004D3900000084394B82013400ABA5CFC7AD9C0302A45A3E5A98AB000089A43382D97900008BA54AA087A70A0248A6A7AE6DBE0000BF6F94987EA40A01A06DCFA7A7A9030496C32F77891D0000A99FB1A0AFA80603B29AB9CA75930D010C0948354D3900000C0948354F37460D0028BE673D8400000000AF9D7B6E00002B007AA8933400007AA642675C2700007984CFB9C3985B768772A8A6B7B20000CAAECAAFC4B700009F94A6009F840009D09F9BA4CA9C0000CC8FC76DC87F0000C991C472A2000000A894A48CA7B501079BA2C9C69BA20000B19A5D3FA89000005CA6009DA2960901B0A7F0669FB200009D009E00B7890000DAD0F5D092820000D294D4C48BD10000B5A7A4A3B1A50402CAB6CBA6A2000000B5A7A4A3B1A8044FCDADD19D9CB00000B7778F7B8AAE0803C9AB5D3F5D3F00009EA09EA0BAB006039EA0989A8C7900009B9EF4D6B7C00000A9A7816CACA80000ABAC84705D3F000096DA635CDC8C00006F486F266F263D4784006124097B00374F6D2D6D2D6D4A3A95872322000000030000000000008D8939130000000000002E22A5C9CBC70600AB25C0B5C9B400061A2DB04CA67001082AA6BEBEBFC606002321DACBC19E03087AA08B6768380000282FBAC0B8CA7A88AD25BBA5A29900004C396C5894A6000040485A6E356E9442A32CD17EADA70000B4237923628600003E2DE9C1D7B500002F25BBA5A2990000231DB6AFB4A804023025C0B5CAB588062B2CBDBEC0C706882435A75CA20000002326BD6A82A908048B4B9A5A668000002423A09CB4BB060025259C9D8A7900001C1FCAB2C7C700002A2A9387ABA200002626A4A47D6E9D14333163A0C87500004B6F9C2D643A257049364936493647358A34438355497F1A0000A24C1D590000D38DFFBDD4CD3126'\r\n\t\t)\r\n\t)\r\n};\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { MinimapCharRenderer } from 'vs/editor/browser/viewParts/minimap/minimapCharRenderer';\r\nimport { allCharCodes } from 'vs/editor/browser/viewParts/minimap/minimapCharSheet';\r\nimport { prebakedMiniMaps } from 'vs/editor/browser/viewParts/minimap/minimapPreBaked';\r\nimport { Constants } from './minimapCharSheet';\r\nimport { toUint8 } from 'vs/base/common/uint';\r\n\r\n/**\r\n * Creates character renderers. It takes a 'scale' that determines how large\r\n * characters should be drawn. Using this, it draws data into a canvas and\r\n * then downsamples the characters as necessary for the current display.\r\n * This makes rendering more efficient, rather than drawing a full (tiny)\r\n * font, or downsampling in real-time.\r\n */\r\nexport class MinimapCharRendererFactory {\r\n\tprivate static lastCreated?: MinimapCharRenderer;\r\n\tprivate static lastFontFamily?: string;\r\n\r\n\t/**\r\n\t * Creates a new character renderer factory with the given scale.\r\n\t */\r\n\tpublic static create(scale: number, fontFamily: string) {\r\n\t\t// renderers are immutable. By default we'll 'create' a new minimap\r\n\t\t// character renderer whenever we switch editors, no need to do extra work.\r\n\t\tif (this.lastCreated && scale === this.lastCreated.scale && fontFamily === this.lastFontFamily) {\r\n\t\t\treturn this.lastCreated;\r\n\t\t}\r\n\r\n\t\tlet factory: MinimapCharRenderer;\r\n\t\tif (prebakedMiniMaps[scale]) {\r\n\t\t\tfactory = new MinimapCharRenderer(prebakedMiniMaps[scale](), scale);\r\n\t\t} else {\r\n\t\t\tfactory = MinimapCharRendererFactory.createFromSampleData(\r\n\t\t\t\tMinimapCharRendererFactory.createSampleData(fontFamily).data,\r\n\t\t\t\tscale\r\n\t\t\t);\r\n\t\t}\r\n\r\n\t\tthis.lastFontFamily = fontFamily;\r\n\t\tthis.lastCreated = factory;\r\n\t\treturn factory;\r\n\t}\r\n\r\n\t/**\r\n\t * Creates the font sample data, writing to a canvas.\r\n\t */\r\n\tpublic static createSampleData(fontFamily: string): ImageData {\r\n\t\tconst canvas = document.createElement('canvas');\r\n\t\tconst ctx = canvas.getContext('2d')!;\r\n\r\n\t\tcanvas.style.height = `${Constants.SAMPLED_CHAR_HEIGHT}px`;\r\n\t\tcanvas.height = Constants.SAMPLED_CHAR_HEIGHT;\r\n\t\tcanvas.width = Constants.CHAR_COUNT * Constants.SAMPLED_CHAR_WIDTH;\r\n\t\tcanvas.style.width = Constants.CHAR_COUNT * Constants.SAMPLED_CHAR_WIDTH + 'px';\r\n\r\n\t\tctx.fillStyle = '#ffffff';\r\n\t\tctx.font = `bold ${Constants.SAMPLED_CHAR_HEIGHT}px ${fontFamily}`;\r\n\t\tctx.textBaseline = 'middle';\r\n\r\n\t\tlet x = 0;\r\n\t\tfor (const code of allCharCodes) {\r\n\t\t\tctx.fillText(String.fromCharCode(code), x, Constants.SAMPLED_CHAR_HEIGHT / 2);\r\n\t\t\tx += Constants.SAMPLED_CHAR_WIDTH;\r\n\t\t}\r\n\r\n\t\treturn ctx.getImageData(0, 0, Constants.CHAR_COUNT * Constants.SAMPLED_CHAR_WIDTH, Constants.SAMPLED_CHAR_HEIGHT);\r\n\t}\r\n\r\n\t/**\r\n\t * Creates a character renderer from the canvas sample data.\r\n\t */\r\n\tpublic static createFromSampleData(source: Uint8ClampedArray, scale: number): MinimapCharRenderer {\r\n\t\tconst expectedLength =\r\n\t\t\tConstants.SAMPLED_CHAR_HEIGHT * Constants.SAMPLED_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT * Constants.CHAR_COUNT;\r\n\t\tif (source.length !== expectedLength) {\r\n\t\t\tthrow new Error('Unexpected source in MinimapCharRenderer');\r\n\t\t}\r\n\r\n\t\tlet charData = MinimapCharRendererFactory._downsample(source, scale);\r\n\t\treturn new MinimapCharRenderer(charData, scale);\r\n\t}\r\n\r\n\tprivate static _downsampleChar(\r\n\t\tsource: Uint8ClampedArray,\r\n\t\tsourceOffset: number,\r\n\t\tdest: Uint8ClampedArray,\r\n\t\tdestOffset: number,\r\n\t\tscale: number\r\n\t): number {\r\n\t\tconst width = Constants.BASE_CHAR_WIDTH * scale;\r\n\t\tconst height = Constants.BASE_CHAR_HEIGHT * scale;\r\n\r\n\t\tlet targetIndex = destOffset;\r\n\t\tlet brightest = 0;\r\n\r\n\t\t// This is essentially an ad-hoc rescaling algorithm. Standard approaches\r\n\t\t// like bicubic interpolation are awesome for scaling between image sizes,\r\n\t\t// but don't work so well when scaling to very small pixel values, we end\r\n\t\t// up with blurry, indistinct forms.\r\n\t\t//\r\n\t\t// The approach taken here is simply mapping each source pixel to the target\r\n\t\t// pixels, and taking the weighted values for all pixels in each, and then\r\n\t\t// averaging them out. Finally we apply an intensity boost in _downsample,\r\n\t\t// since when scaling to the smallest pixel sizes there's more black space\r\n\t\t// which causes characters to be much less distinct.\r\n\t\tfor (let y = 0; y < height; y++) {\r\n\t\t\t// 1. For this destination pixel, get the source pixels we're sampling\r\n\t\t\t// from (x1, y1) to the next pixel (x2, y2)\r\n\t\t\tconst sourceY1 = (y / height) * Constants.SAMPLED_CHAR_HEIGHT;\r\n\t\t\tconst sourceY2 = ((y + 1) / height) * Constants.SAMPLED_CHAR_HEIGHT;\r\n\r\n\t\t\tfor (let x = 0; x < width; x++) {\r\n\t\t\t\tconst sourceX1 = (x / width) * Constants.SAMPLED_CHAR_WIDTH;\r\n\t\t\t\tconst sourceX2 = ((x + 1) / width) * Constants.SAMPLED_CHAR_WIDTH;\r\n\r\n\t\t\t\t// 2. Sample all of them, summing them up and weighting them. Similar\r\n\t\t\t\t// to bilinear interpolation.\r\n\t\t\t\tlet value = 0;\r\n\t\t\t\tlet samples = 0;\r\n\t\t\t\tfor (let sy = sourceY1; sy < sourceY2; sy++) {\r\n\t\t\t\t\tconst sourceRow = sourceOffset + Math.floor(sy) * Constants.RGBA_SAMPLED_ROW_WIDTH;\r\n\t\t\t\t\tconst yBalance = 1 - (sy - Math.floor(sy));\r\n\t\t\t\t\tfor (let sx = sourceX1; sx < sourceX2; sx++) {\r\n\t\t\t\t\t\tconst xBalance = 1 - (sx - Math.floor(sx));\r\n\t\t\t\t\t\tconst sourceIndex = sourceRow + Math.floor(sx) * Constants.RGBA_CHANNELS_CNT;\r\n\r\n\t\t\t\t\t\tconst weight = xBalance * yBalance;\r\n\t\t\t\t\t\tsamples += weight;\r\n\t\t\t\t\t\tvalue += ((source[sourceIndex] * source[sourceIndex + 3]) / 255) * weight;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst final = value / samples;\r\n\t\t\t\tbrightest = Math.max(brightest, final);\r\n\t\t\t\tdest[targetIndex++] = toUint8(final);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn brightest;\r\n\t}\r\n\r\n\tprivate static _downsample(data: Uint8ClampedArray, scale: number): Uint8ClampedArray {\r\n\t\tconst pixelsPerCharacter = Constants.BASE_CHAR_HEIGHT * scale * Constants.BASE_CHAR_WIDTH * scale;\r\n\t\tconst resultLen = pixelsPerCharacter * Constants.CHAR_COUNT;\r\n\t\tconst result = new Uint8ClampedArray(resultLen);\r\n\r\n\t\tlet resultOffset = 0;\r\n\t\tlet sourceOffset = 0;\r\n\t\tlet brightest = 0;\r\n\t\tfor (let charIndex = 0; charIndex < Constants.CHAR_COUNT; charIndex++) {\r\n\t\t\tbrightest = Math.max(brightest, this._downsampleChar(data, sourceOffset, result, resultOffset, scale));\r\n\t\t\tresultOffset += pixelsPerCharacter;\r\n\t\t\tsourceOffset += Constants.SAMPLED_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT;\r\n\t\t}\r\n\r\n\t\tif (brightest > 0) {\r\n\t\t\tconst adjust = 255 / brightest;\r\n\t\t\tfor (let i = 0; i < resultLen; i++) {\r\n\t\t\t\tresult[i] *= adjust;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\n\r\nexport interface IEditorZoom {\r\n\tonDidChangeZoomLevel: Event;\r\n\tgetZoomLevel(): number;\r\n\tsetZoomLevel(zoomLevel: number): void;\r\n}\r\n\r\nexport const EditorZoom: IEditorZoom = new class implements IEditorZoom {\r\n\r\n\tprivate _zoomLevel: number = 0;\r\n\r\n\tprivate readonly _onDidChangeZoomLevel = new Emitter();\r\n\tpublic readonly onDidChangeZoomLevel: Event = this._onDidChangeZoomLevel.event;\r\n\r\n\tpublic getZoomLevel(): number {\r\n\t\treturn this._zoomLevel;\r\n\t}\r\n\r\n\tpublic setZoomLevel(zoomLevel: number): void {\r\n\t\tzoomLevel = Math.min(Math.max(-5, zoomLevel), 20);\r\n\t\tif (this._zoomLevel === zoomLevel) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._zoomLevel = zoomLevel;\r\n\t\tthis._onDidChangeZoomLevel.fire(this._zoomLevel);\r\n\t}\r\n};\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as platform from 'vs/base/common/platform';\r\nimport { ValidatedEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { EditorZoom } from 'vs/editor/common/config/editorZoom';\r\n\r\n/**\r\n * Determined from empirical observations.\r\n * @internal\r\n */\r\nconst GOLDEN_LINE_HEIGHT_RATIO = platform.isMacintosh ? 1.5 : 1.35;\r\n\r\n/**\r\n * @internal\r\n */\r\nconst MINIMUM_LINE_HEIGHT = 8;\r\n\r\nexport class BareFontInfo {\r\n\treadonly _bareFontInfoBrand: void;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tpublic static createFromValidatedSettings(options: ValidatedEditorOptions, zoomLevel: number, pixelRatio: number, ignoreEditorZoom: boolean): BareFontInfo {\r\n\t\tconst fontFamily = options.get(EditorOption.fontFamily);\r\n\t\tconst fontWeight = options.get(EditorOption.fontWeight);\r\n\t\tconst fontSize = options.get(EditorOption.fontSize);\r\n\t\tconst fontFeatureSettings = options.get(EditorOption.fontLigatures);\r\n\t\tconst lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tconst letterSpacing = options.get(EditorOption.letterSpacing);\r\n\t\treturn BareFontInfo._create(fontFamily, fontWeight, fontSize, fontFeatureSettings, lineHeight, letterSpacing, zoomLevel, pixelRatio, ignoreEditorZoom);\r\n\t}\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tprivate static _create(fontFamily: string, fontWeight: string, fontSize: number, fontFeatureSettings: string, lineHeight: number, letterSpacing: number, zoomLevel: number, pixelRatio: number, ignoreEditorZoom: boolean): BareFontInfo {\r\n\t\tif (lineHeight === 0) {\r\n\t\t\tlineHeight = Math.round(GOLDEN_LINE_HEIGHT_RATIO * fontSize);\r\n\t\t} else if (lineHeight < MINIMUM_LINE_HEIGHT) {\r\n\t\t\tlineHeight = MINIMUM_LINE_HEIGHT;\r\n\t\t}\r\n\r\n\t\tconst editorZoomLevelMultiplier = 1 + (ignoreEditorZoom ? 0 : EditorZoom.getZoomLevel() * 0.1);\r\n\t\tfontSize *= editorZoomLevelMultiplier;\r\n\t\tlineHeight *= editorZoomLevelMultiplier;\r\n\r\n\t\treturn new BareFontInfo({\r\n\t\t\tzoomLevel: zoomLevel,\r\n\t\t\tpixelRatio: pixelRatio,\r\n\t\t\tfontFamily: fontFamily,\r\n\t\t\tfontWeight: fontWeight,\r\n\t\t\tfontSize: fontSize,\r\n\t\t\tfontFeatureSettings: fontFeatureSettings,\r\n\t\t\tlineHeight: lineHeight,\r\n\t\t\tletterSpacing: letterSpacing\r\n\t\t});\r\n\t}\r\n\r\n\treadonly zoomLevel: number;\r\n\treadonly pixelRatio: number;\r\n\treadonly fontFamily: string;\r\n\treadonly fontWeight: string;\r\n\treadonly fontSize: number;\r\n\treadonly fontFeatureSettings: string;\r\n\treadonly lineHeight: number;\r\n\treadonly letterSpacing: number;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tprotected constructor(opts: {\r\n\t\tzoomLevel: number;\r\n\t\tpixelRatio: number;\r\n\t\tfontFamily: string;\r\n\t\tfontWeight: string;\r\n\t\tfontSize: number;\r\n\t\tfontFeatureSettings: string;\r\n\t\tlineHeight: number;\r\n\t\tletterSpacing: number;\r\n\t}) {\r\n\t\tthis.zoomLevel = opts.zoomLevel;\r\n\t\tthis.pixelRatio = opts.pixelRatio;\r\n\t\tthis.fontFamily = String(opts.fontFamily);\r\n\t\tthis.fontWeight = String(opts.fontWeight);\r\n\t\tthis.fontSize = opts.fontSize;\r\n\t\tthis.fontFeatureSettings = opts.fontFeatureSettings;\r\n\t\tthis.lineHeight = opts.lineHeight | 0;\r\n\t\tthis.letterSpacing = opts.letterSpacing;\r\n\t}\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tpublic getId(): string {\r\n\t\treturn this.zoomLevel + '-' + this.pixelRatio + '-' + this.fontFamily + '-' + this.fontWeight + '-' + this.fontSize + '-' + this.fontFeatureSettings + '-' + this.lineHeight + '-' + this.letterSpacing;\r\n\t}\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tpublic getMassagedFontFamily(): string {\r\n\t\tif (/[,\"']/.test(this.fontFamily)) {\r\n\t\t\t// Looks like the font family might be already escaped\r\n\t\t\treturn this.fontFamily;\r\n\t\t}\r\n\t\tif (/[+ ]/.test(this.fontFamily)) {\r\n\t\t\t// Wrap a font family using + or with quotes\r\n\t\t\treturn `\"${this.fontFamily}\"`;\r\n\t\t}\r\n\r\n\t\treturn this.fontFamily;\r\n\t}\r\n}\r\n\r\n// change this whenever `FontInfo` members are changed\r\nexport const SERIALIZED_FONT_INFO_VERSION = 1;\r\n\r\nexport class FontInfo extends BareFontInfo {\r\n\treadonly _editorStylingBrand: void;\r\n\r\n\treadonly version: number = SERIALIZED_FONT_INFO_VERSION;\r\n\treadonly isTrusted: boolean;\r\n\treadonly isMonospace: boolean;\r\n\treadonly typicalHalfwidthCharacterWidth: number;\r\n\treadonly typicalFullwidthCharacterWidth: number;\r\n\treadonly canUseHalfwidthRightwardsArrow: boolean;\r\n\treadonly spaceWidth: number;\r\n\treadonly middotWidth: number;\r\n\treadonly wsmiddotWidth: number;\r\n\treadonly maxDigitWidth: number;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tconstructor(opts: {\r\n\t\tzoomLevel: number;\r\n\t\tpixelRatio: number;\r\n\t\tfontFamily: string;\r\n\t\tfontWeight: string;\r\n\t\tfontSize: number;\r\n\t\tfontFeatureSettings: string;\r\n\t\tlineHeight: number;\r\n\t\tletterSpacing: number;\r\n\t\tisMonospace: boolean;\r\n\t\ttypicalHalfwidthCharacterWidth: number;\r\n\t\ttypicalFullwidthCharacterWidth: number;\r\n\t\tcanUseHalfwidthRightwardsArrow: boolean;\r\n\t\tspaceWidth: number;\r\n\t\tmiddotWidth: number;\r\n\t\twsmiddotWidth: number;\r\n\t\tmaxDigitWidth: number;\r\n\t}, isTrusted: boolean) {\r\n\t\tsuper(opts);\r\n\t\tthis.isTrusted = isTrusted;\r\n\t\tthis.isMonospace = opts.isMonospace;\r\n\t\tthis.typicalHalfwidthCharacterWidth = opts.typicalHalfwidthCharacterWidth;\r\n\t\tthis.typicalFullwidthCharacterWidth = opts.typicalFullwidthCharacterWidth;\r\n\t\tthis.canUseHalfwidthRightwardsArrow = opts.canUseHalfwidthRightwardsArrow;\r\n\t\tthis.spaceWidth = opts.spaceWidth;\r\n\t\tthis.middotWidth = opts.middotWidth;\r\n\t\tthis.wsmiddotWidth = opts.wsmiddotWidth;\r\n\t\tthis.maxDigitWidth = opts.maxDigitWidth;\r\n\t}\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tpublic equals(other: FontInfo): boolean {\r\n\t\treturn (\r\n\t\t\tthis.fontFamily === other.fontFamily\r\n\t\t\t&& this.fontWeight === other.fontWeight\r\n\t\t\t&& this.fontSize === other.fontSize\r\n\t\t\t&& this.fontFeatureSettings === other.fontFeatureSettings\r\n\t\t\t&& this.lineHeight === other.lineHeight\r\n\t\t\t&& this.letterSpacing === other.letterSpacing\r\n\t\t\t&& this.typicalHalfwidthCharacterWidth === other.typicalHalfwidthCharacterWidth\r\n\t\t\t&& this.typicalFullwidthCharacterWidth === other.typicalFullwidthCharacterWidth\r\n\t\t\t&& this.canUseHalfwidthRightwardsArrow === other.canUseHalfwidthRightwardsArrow\r\n\t\t\t&& this.spaceWidth === other.spaceWidth\r\n\t\t\t&& this.middotWidth === other.middotWidth\r\n\t\t\t&& this.wsmiddotWidth === other.wsmiddotWidth\r\n\t\t\t&& this.maxDigitWidth === other.maxDigitWidth\r\n\t\t);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { toUint8 } from 'vs/base/common/uint';\r\n\r\n/**\r\n * A fast character classifier that uses a compact array for ASCII values.\r\n */\r\nexport class CharacterClassifier {\r\n\t/**\r\n\t * Maintain a compact (fully initialized ASCII map for quickly classifying ASCII characters - used more often in code).\r\n\t */\r\n\tprotected _asciiMap: Uint8Array;\r\n\r\n\t/**\r\n\t * The entire map (sparse array).\r\n\t */\r\n\tprotected _map: Map;\r\n\r\n\tprotected _defaultValue: number;\r\n\r\n\tconstructor(_defaultValue: T) {\r\n\t\tlet defaultValue = toUint8(_defaultValue);\r\n\r\n\t\tthis._defaultValue = defaultValue;\r\n\t\tthis._asciiMap = CharacterClassifier._createAsciiMap(defaultValue);\r\n\t\tthis._map = new Map();\r\n\t}\r\n\r\n\tprivate static _createAsciiMap(defaultValue: number): Uint8Array {\r\n\t\tlet asciiMap: Uint8Array = new Uint8Array(256);\r\n\t\tfor (let i = 0; i < 256; i++) {\r\n\t\t\tasciiMap[i] = defaultValue;\r\n\t\t}\r\n\t\treturn asciiMap;\r\n\t}\r\n\r\n\tpublic set(charCode: number, _value: T): void {\r\n\t\tlet value = toUint8(_value);\r\n\r\n\t\tif (charCode >= 0 && charCode < 256) {\r\n\t\t\tthis._asciiMap[charCode] = value;\r\n\t\t} else {\r\n\t\t\tthis._map.set(charCode, value);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic get(charCode: number): T {\r\n\t\tif (charCode >= 0 && charCode < 256) {\r\n\t\t\treturn this._asciiMap[charCode];\r\n\t\t} else {\r\n\t\t\treturn (this._map.get(charCode) || this._defaultValue);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nconst enum Boolean {\r\n\tFalse = 0,\r\n\tTrue = 1\r\n}\r\n\r\nexport class CharacterSet {\r\n\r\n\tprivate readonly _actual: CharacterClassifier;\r\n\r\n\tconstructor() {\r\n\t\tthis._actual = new CharacterClassifier(Boolean.False);\r\n\t}\r\n\r\n\tpublic add(charCode: number): void {\r\n\t\tthis._actual.set(charCode, Boolean.True);\r\n\t}\r\n\r\n\tpublic has(charCode: number): boolean {\r\n\t\treturn (this._actual.get(charCode) === Boolean.True);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport { CharacterClassifier } from 'vs/editor/common/core/characterClassifier';\r\n\r\nexport const enum WordCharacterClass {\r\n\tRegular = 0,\r\n\tWhitespace = 1,\r\n\tWordSeparator = 2\r\n}\r\n\r\nexport class WordCharacterClassifier extends CharacterClassifier {\r\n\r\n\tconstructor(wordSeparators: string) {\r\n\t\tsuper(WordCharacterClass.Regular);\r\n\r\n\t\tfor (let i = 0, len = wordSeparators.length; i < len; i++) {\r\n\t\t\tthis.set(wordSeparators.charCodeAt(i), WordCharacterClass.WordSeparator);\r\n\t\t}\r\n\r\n\t\tthis.set(CharCode.Space, WordCharacterClass.Whitespace);\r\n\t\tthis.set(CharCode.Tab, WordCharacterClass.Whitespace);\r\n\t}\r\n\r\n}\r\n\r\nfunction once(computeFn: (input: string) => R): (input: string) => R {\r\n\tlet cache: { [key: string]: R; } = {}; // TODO@Alex unbounded cache\r\n\treturn (input: string): R => {\r\n\t\tif (!cache.hasOwnProperty(input)) {\r\n\t\t\tcache[input] = computeFn(input);\r\n\t\t}\r\n\t\treturn cache[input];\r\n\t};\r\n}\r\n\r\nexport const getMapForWordSeparators = once(\r\n\t(input) => new WordCharacterClassifier(input)\r\n);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\n/**\r\n * A position in the editor. This interface is suitable for serialization.\r\n */\r\nexport interface IPosition {\r\n\t/**\r\n\t * line number (starts at 1)\r\n\t */\r\n\treadonly lineNumber: number;\r\n\t/**\r\n\t * column (the first character in a line is between column 1 and column 2)\r\n\t */\r\n\treadonly column: number;\r\n}\r\n\r\n/**\r\n * A position in the editor.\r\n */\r\nexport class Position {\r\n\t/**\r\n\t * line number (starts at 1)\r\n\t */\r\n\tpublic readonly lineNumber: number;\r\n\t/**\r\n\t * column (the first character in a line is between column 1 and column 2)\r\n\t */\r\n\tpublic readonly column: number;\r\n\r\n\tconstructor(lineNumber: number, column: number) {\r\n\t\tthis.lineNumber = lineNumber;\r\n\t\tthis.column = column;\r\n\t}\r\n\r\n\t/**\r\n\t * Create a new position from this position.\r\n\t *\r\n\t * @param newLineNumber new line number\r\n\t * @param newColumn new column\r\n\t */\r\n\twith(newLineNumber: number = this.lineNumber, newColumn: number = this.column): Position {\r\n\t\tif (newLineNumber === this.lineNumber && newColumn === this.column) {\r\n\t\t\treturn this;\r\n\t\t} else {\r\n\t\t\treturn new Position(newLineNumber, newColumn);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Derive a new position from this position.\r\n\t *\r\n\t * @param deltaLineNumber line number delta\r\n\t * @param deltaColumn column delta\r\n\t */\r\n\tdelta(deltaLineNumber: number = 0, deltaColumn: number = 0): Position {\r\n\t\treturn this.with(this.lineNumber + deltaLineNumber, this.column + deltaColumn);\r\n\t}\r\n\r\n\t/**\r\n\t * Test if this position equals other position\r\n\t */\r\n\tpublic equals(other: IPosition): boolean {\r\n\t\treturn Position.equals(this, other);\r\n\t}\r\n\r\n\t/**\r\n\t * Test if position `a` equals position `b`\r\n\t */\r\n\tpublic static equals(a: IPosition | null, b: IPosition | null): boolean {\r\n\t\tif (!a && !b) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn (\r\n\t\t\t!!a &&\r\n\t\t\t!!b &&\r\n\t\t\ta.lineNumber === b.lineNumber &&\r\n\t\t\ta.column === b.column\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * Test if this position is before other position.\r\n\t * If the two positions are equal, the result will be false.\r\n\t */\r\n\tpublic isBefore(other: IPosition): boolean {\r\n\t\treturn Position.isBefore(this, other);\r\n\t}\r\n\r\n\t/**\r\n\t * Test if position `a` is before position `b`.\r\n\t * If the two positions are equal, the result will be false.\r\n\t */\r\n\tpublic static isBefore(a: IPosition, b: IPosition): boolean {\r\n\t\tif (a.lineNumber < b.lineNumber) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (b.lineNumber < a.lineNumber) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn a.column < b.column;\r\n\t}\r\n\r\n\t/**\r\n\t * Test if this position is before other position.\r\n\t * If the two positions are equal, the result will be true.\r\n\t */\r\n\tpublic isBeforeOrEqual(other: IPosition): boolean {\r\n\t\treturn Position.isBeforeOrEqual(this, other);\r\n\t}\r\n\r\n\t/**\r\n\t * Test if position `a` is before position `b`.\r\n\t * If the two positions are equal, the result will be true.\r\n\t */\r\n\tpublic static isBeforeOrEqual(a: IPosition, b: IPosition): boolean {\r\n\t\tif (a.lineNumber < b.lineNumber) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (b.lineNumber < a.lineNumber) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn a.column <= b.column;\r\n\t}\r\n\r\n\t/**\r\n\t * A function that compares positions, useful for sorting\r\n\t */\r\n\tpublic static compare(a: IPosition, b: IPosition): number {\r\n\t\tlet aLineNumber = a.lineNumber | 0;\r\n\t\tlet bLineNumber = b.lineNumber | 0;\r\n\r\n\t\tif (aLineNumber === bLineNumber) {\r\n\t\t\tlet aColumn = a.column | 0;\r\n\t\t\tlet bColumn = b.column | 0;\r\n\t\t\treturn aColumn - bColumn;\r\n\t\t}\r\n\r\n\t\treturn aLineNumber - bLineNumber;\r\n\t}\r\n\r\n\t/**\r\n\t * Clone this position.\r\n\t */\r\n\tpublic clone(): Position {\r\n\t\treturn new Position(this.lineNumber, this.column);\r\n\t}\r\n\r\n\t/**\r\n\t * Convert to a human-readable representation.\r\n\t */\r\n\tpublic toString(): string {\r\n\t\treturn '(' + this.lineNumber + ',' + this.column + ')';\r\n\t}\r\n\r\n\t// ---\r\n\r\n\t/**\r\n\t * Create a `Position` from an `IPosition`.\r\n\t */\r\n\tpublic static lift(pos: IPosition): Position {\r\n\t\treturn new Position(pos.lineNumber, pos.column);\r\n\t}\r\n\r\n\t/**\r\n\t * Test if `obj` is an `IPosition`.\r\n\t */\r\n\tpublic static isIPosition(obj: any): obj is IPosition {\r\n\t\treturn (\r\n\t\t\tobj\r\n\t\t\t&& (typeof obj.lineNumber === 'number')\r\n\t\t\t&& (typeof obj.column === 'number')\r\n\t\t);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IPosition, Position } from 'vs/editor/common/core/position';\r\n\r\n/**\r\n * A range in the editor. This interface is suitable for serialization.\r\n */\r\nexport interface IRange {\r\n\t/**\r\n\t * Line number on which the range starts (starts at 1).\r\n\t */\r\n\treadonly startLineNumber: number;\r\n\t/**\r\n\t * Column on which the range starts in line `startLineNumber` (starts at 1).\r\n\t */\r\n\treadonly startColumn: number;\r\n\t/**\r\n\t * Line number on which the range ends.\r\n\t */\r\n\treadonly endLineNumber: number;\r\n\t/**\r\n\t * Column on which the range ends in line `endLineNumber`.\r\n\t */\r\n\treadonly endColumn: number;\r\n}\r\n\r\n/**\r\n * A range in the editor. (startLineNumber,startColumn) is <= (endLineNumber,endColumn)\r\n */\r\nexport class Range {\r\n\r\n\t/**\r\n\t * Line number on which the range starts (starts at 1).\r\n\t */\r\n\tpublic readonly startLineNumber: number;\r\n\t/**\r\n\t * Column on which the range starts in line `startLineNumber` (starts at 1).\r\n\t */\r\n\tpublic readonly startColumn: number;\r\n\t/**\r\n\t * Line number on which the range ends.\r\n\t */\r\n\tpublic readonly endLineNumber: number;\r\n\t/**\r\n\t * Column on which the range ends in line `endLineNumber`.\r\n\t */\r\n\tpublic readonly endColumn: number;\r\n\r\n\tconstructor(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number) {\r\n\t\tif ((startLineNumber > endLineNumber) || (startLineNumber === endLineNumber && startColumn > endColumn)) {\r\n\t\t\tthis.startLineNumber = endLineNumber;\r\n\t\t\tthis.startColumn = endColumn;\r\n\t\t\tthis.endLineNumber = startLineNumber;\r\n\t\t\tthis.endColumn = startColumn;\r\n\t\t} else {\r\n\t\t\tthis.startLineNumber = startLineNumber;\r\n\t\t\tthis.startColumn = startColumn;\r\n\t\t\tthis.endLineNumber = endLineNumber;\r\n\t\t\tthis.endColumn = endColumn;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Test if this range is empty.\r\n\t */\r\n\tpublic isEmpty(): boolean {\r\n\t\treturn Range.isEmpty(this);\r\n\t}\r\n\r\n\t/**\r\n\t * Test if `range` is empty.\r\n\t */\r\n\tpublic static isEmpty(range: IRange): boolean {\r\n\t\treturn (range.startLineNumber === range.endLineNumber && range.startColumn === range.endColumn);\r\n\t}\r\n\r\n\t/**\r\n\t * Test if position is in this range. If the position is at the edges, will return true.\r\n\t */\r\n\tpublic containsPosition(position: IPosition): boolean {\r\n\t\treturn Range.containsPosition(this, position);\r\n\t}\r\n\r\n\t/**\r\n\t * Test if `position` is in `range`. If the position is at the edges, will return true.\r\n\t */\r\n\tpublic static containsPosition(range: IRange, position: IPosition): boolean {\r\n\t\tif (position.lineNumber < range.startLineNumber || position.lineNumber > range.endLineNumber) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (position.lineNumber === range.startLineNumber && position.column < range.startColumn) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (position.lineNumber === range.endLineNumber && position.column > range.endColumn) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t * Test if range is in this range. If the range is equal to this range, will return true.\r\n\t */\r\n\tpublic containsRange(range: IRange): boolean {\r\n\t\treturn Range.containsRange(this, range);\r\n\t}\r\n\r\n\t/**\r\n\t * Test if `otherRange` is in `range`. If the ranges are equal, will return true.\r\n\t */\r\n\tpublic static containsRange(range: IRange, otherRange: IRange): boolean {\r\n\t\tif (otherRange.startLineNumber < range.startLineNumber || otherRange.endLineNumber < range.startLineNumber) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (otherRange.startLineNumber > range.endLineNumber || otherRange.endLineNumber > range.endLineNumber) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (otherRange.startLineNumber === range.startLineNumber && otherRange.startColumn < range.startColumn) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (otherRange.endLineNumber === range.endLineNumber && otherRange.endColumn > range.endColumn) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t * Test if `range` is strictly in this range. `range` must start after and end before this range for the result to be true.\r\n\t */\r\n\tpublic strictContainsRange(range: IRange): boolean {\r\n\t\treturn Range.strictContainsRange(this, range);\r\n\t}\r\n\r\n\t/**\r\n\t * Test if `otherRange` is strinctly in `range` (must start after, and end before). If the ranges are equal, will return false.\r\n\t */\r\n\tpublic static strictContainsRange(range: IRange, otherRange: IRange): boolean {\r\n\t\tif (otherRange.startLineNumber < range.startLineNumber || otherRange.endLineNumber < range.startLineNumber) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (otherRange.startLineNumber > range.endLineNumber || otherRange.endLineNumber > range.endLineNumber) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (otherRange.startLineNumber === range.startLineNumber && otherRange.startColumn <= range.startColumn) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (otherRange.endLineNumber === range.endLineNumber && otherRange.endColumn >= range.endColumn) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t * A reunion of the two ranges.\r\n\t * The smallest position will be used as the start point, and the largest one as the end point.\r\n\t */\r\n\tpublic plusRange(range: IRange): Range {\r\n\t\treturn Range.plusRange(this, range);\r\n\t}\r\n\r\n\t/**\r\n\t * A reunion of the two ranges.\r\n\t * The smallest position will be used as the start point, and the largest one as the end point.\r\n\t */\r\n\tpublic static plusRange(a: IRange, b: IRange): Range {\r\n\t\tlet startLineNumber: number;\r\n\t\tlet startColumn: number;\r\n\t\tlet endLineNumber: number;\r\n\t\tlet endColumn: number;\r\n\r\n\t\tif (b.startLineNumber < a.startLineNumber) {\r\n\t\t\tstartLineNumber = b.startLineNumber;\r\n\t\t\tstartColumn = b.startColumn;\r\n\t\t} else if (b.startLineNumber === a.startLineNumber) {\r\n\t\t\tstartLineNumber = b.startLineNumber;\r\n\t\t\tstartColumn = Math.min(b.startColumn, a.startColumn);\r\n\t\t} else {\r\n\t\t\tstartLineNumber = a.startLineNumber;\r\n\t\t\tstartColumn = a.startColumn;\r\n\t\t}\r\n\r\n\t\tif (b.endLineNumber > a.endLineNumber) {\r\n\t\t\tendLineNumber = b.endLineNumber;\r\n\t\t\tendColumn = b.endColumn;\r\n\t\t} else if (b.endLineNumber === a.endLineNumber) {\r\n\t\t\tendLineNumber = b.endLineNumber;\r\n\t\t\tendColumn = Math.max(b.endColumn, a.endColumn);\r\n\t\t} else {\r\n\t\t\tendLineNumber = a.endLineNumber;\r\n\t\t\tendColumn = a.endColumn;\r\n\t\t}\r\n\r\n\t\treturn new Range(startLineNumber, startColumn, endLineNumber, endColumn);\r\n\t}\r\n\r\n\t/**\r\n\t * A intersection of the two ranges.\r\n\t */\r\n\tpublic intersectRanges(range: IRange): Range | null {\r\n\t\treturn Range.intersectRanges(this, range);\r\n\t}\r\n\r\n\t/**\r\n\t * A intersection of the two ranges.\r\n\t */\r\n\tpublic static intersectRanges(a: IRange, b: IRange): Range | null {\r\n\t\tlet resultStartLineNumber = a.startLineNumber;\r\n\t\tlet resultStartColumn = a.startColumn;\r\n\t\tlet resultEndLineNumber = a.endLineNumber;\r\n\t\tlet resultEndColumn = a.endColumn;\r\n\t\tlet otherStartLineNumber = b.startLineNumber;\r\n\t\tlet otherStartColumn = b.startColumn;\r\n\t\tlet otherEndLineNumber = b.endLineNumber;\r\n\t\tlet otherEndColumn = b.endColumn;\r\n\r\n\t\tif (resultStartLineNumber < otherStartLineNumber) {\r\n\t\t\tresultStartLineNumber = otherStartLineNumber;\r\n\t\t\tresultStartColumn = otherStartColumn;\r\n\t\t} else if (resultStartLineNumber === otherStartLineNumber) {\r\n\t\t\tresultStartColumn = Math.max(resultStartColumn, otherStartColumn);\r\n\t\t}\r\n\r\n\t\tif (resultEndLineNumber > otherEndLineNumber) {\r\n\t\t\tresultEndLineNumber = otherEndLineNumber;\r\n\t\t\tresultEndColumn = otherEndColumn;\r\n\t\t} else if (resultEndLineNumber === otherEndLineNumber) {\r\n\t\t\tresultEndColumn = Math.min(resultEndColumn, otherEndColumn);\r\n\t\t}\r\n\r\n\t\t// Check if selection is now empty\r\n\t\tif (resultStartLineNumber > resultEndLineNumber) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tif (resultStartLineNumber === resultEndLineNumber && resultStartColumn > resultEndColumn) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn new Range(resultStartLineNumber, resultStartColumn, resultEndLineNumber, resultEndColumn);\r\n\t}\r\n\r\n\t/**\r\n\t * Test if this range equals other.\r\n\t */\r\n\tpublic equalsRange(other: IRange | null): boolean {\r\n\t\treturn Range.equalsRange(this, other);\r\n\t}\r\n\r\n\t/**\r\n\t * Test if range `a` equals `b`.\r\n\t */\r\n\tpublic static equalsRange(a: IRange | null, b: IRange | null): boolean {\r\n\t\treturn (\r\n\t\t\t!!a &&\r\n\t\t\t!!b &&\r\n\t\t\ta.startLineNumber === b.startLineNumber &&\r\n\t\t\ta.startColumn === b.startColumn &&\r\n\t\t\ta.endLineNumber === b.endLineNumber &&\r\n\t\t\ta.endColumn === b.endColumn\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * Return the end position (which will be after or equal to the start position)\r\n\t */\r\n\tpublic getEndPosition(): Position {\r\n\t\treturn Range.getEndPosition(this);\r\n\t}\r\n\r\n\t/**\r\n\t * Return the end position (which will be after or equal to the start position)\r\n\t */\r\n\tpublic static getEndPosition(range: IRange): Position {\r\n\t\treturn new Position(range.endLineNumber, range.endColumn);\r\n\t}\r\n\r\n\t/**\r\n\t * Return the start position (which will be before or equal to the end position)\r\n\t */\r\n\tpublic getStartPosition(): Position {\r\n\t\treturn Range.getStartPosition(this);\r\n\t}\r\n\r\n\t/**\r\n\t * Return the start position (which will be before or equal to the end position)\r\n\t */\r\n\tpublic static getStartPosition(range: IRange): Position {\r\n\t\treturn new Position(range.startLineNumber, range.startColumn);\r\n\t}\r\n\r\n\t/**\r\n\t * Transform to a user presentable string representation.\r\n\t */\r\n\tpublic toString(): string {\r\n\t\treturn '[' + this.startLineNumber + ',' + this.startColumn + ' -> ' + this.endLineNumber + ',' + this.endColumn + ']';\r\n\t}\r\n\r\n\t/**\r\n\t * Create a new range using this range's start position, and using endLineNumber and endColumn as the end position.\r\n\t */\r\n\tpublic setEndPosition(endLineNumber: number, endColumn: number): Range {\r\n\t\treturn new Range(this.startLineNumber, this.startColumn, endLineNumber, endColumn);\r\n\t}\r\n\r\n\t/**\r\n\t * Create a new range using this range's end position, and using startLineNumber and startColumn as the start position.\r\n\t */\r\n\tpublic setStartPosition(startLineNumber: number, startColumn: number): Range {\r\n\t\treturn new Range(startLineNumber, startColumn, this.endLineNumber, this.endColumn);\r\n\t}\r\n\r\n\t/**\r\n\t * Create a new empty range using this range's start position.\r\n\t */\r\n\tpublic collapseToStart(): Range {\r\n\t\treturn Range.collapseToStart(this);\r\n\t}\r\n\r\n\t/**\r\n\t * Create a new empty range using this range's start position.\r\n\t */\r\n\tpublic static collapseToStart(range: IRange): Range {\r\n\t\treturn new Range(range.startLineNumber, range.startColumn, range.startLineNumber, range.startColumn);\r\n\t}\r\n\r\n\t// ---\r\n\r\n\tpublic static fromPositions(start: IPosition, end: IPosition = start): Range {\r\n\t\treturn new Range(start.lineNumber, start.column, end.lineNumber, end.column);\r\n\t}\r\n\r\n\t/**\r\n\t * Create a `Range` from an `IRange`.\r\n\t */\r\n\tpublic static lift(range: undefined | null): null;\r\n\tpublic static lift(range: IRange): Range;\r\n\tpublic static lift(range: IRange | undefined | null): Range | null {\r\n\t\tif (!range) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn new Range(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);\r\n\t}\r\n\r\n\t/**\r\n\t * Test if `obj` is an `IRange`.\r\n\t */\r\n\tpublic static isIRange(obj: any): obj is IRange {\r\n\t\treturn (\r\n\t\t\tobj\r\n\t\t\t&& (typeof obj.startLineNumber === 'number')\r\n\t\t\t&& (typeof obj.startColumn === 'number')\r\n\t\t\t&& (typeof obj.endLineNumber === 'number')\r\n\t\t\t&& (typeof obj.endColumn === 'number')\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * Test if the two ranges are touching in any way.\r\n\t */\r\n\tpublic static areIntersectingOrTouching(a: IRange, b: IRange): boolean {\r\n\t\t// Check if `a` is before `b`\r\n\t\tif (a.endLineNumber < b.startLineNumber || (a.endLineNumber === b.startLineNumber && a.endColumn < b.startColumn)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\t// Check if `b` is before `a`\r\n\t\tif (b.endLineNumber < a.startLineNumber || (b.endLineNumber === a.startLineNumber && b.endColumn < a.startColumn)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\t// These ranges must intersect\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t * Test if the two ranges are intersecting. If the ranges are touching it returns true.\r\n\t */\r\n\tpublic static areIntersecting(a: IRange, b: IRange): boolean {\r\n\t\t// Check if `a` is before `b`\r\n\t\tif (a.endLineNumber < b.startLineNumber || (a.endLineNumber === b.startLineNumber && a.endColumn <= b.startColumn)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\t// Check if `b` is before `a`\r\n\t\tif (b.endLineNumber < a.startLineNumber || (b.endLineNumber === a.startLineNumber && b.endColumn <= a.startColumn)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\t// These ranges must intersect\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t * A function that compares ranges, useful for sorting ranges\r\n\t * It will first compare ranges on the startPosition and then on the endPosition\r\n\t */\r\n\tpublic static compareRangesUsingStarts(a: IRange | null | undefined, b: IRange | null | undefined): number {\r\n\t\tif (a && b) {\r\n\t\t\tconst aStartLineNumber = a.startLineNumber | 0;\r\n\t\t\tconst bStartLineNumber = b.startLineNumber | 0;\r\n\r\n\t\t\tif (aStartLineNumber === bStartLineNumber) {\r\n\t\t\t\tconst aStartColumn = a.startColumn | 0;\r\n\t\t\t\tconst bStartColumn = b.startColumn | 0;\r\n\r\n\t\t\t\tif (aStartColumn === bStartColumn) {\r\n\t\t\t\t\tconst aEndLineNumber = a.endLineNumber | 0;\r\n\t\t\t\t\tconst bEndLineNumber = b.endLineNumber | 0;\r\n\r\n\t\t\t\t\tif (aEndLineNumber === bEndLineNumber) {\r\n\t\t\t\t\t\tconst aEndColumn = a.endColumn | 0;\r\n\t\t\t\t\t\tconst bEndColumn = b.endColumn | 0;\r\n\t\t\t\t\t\treturn aEndColumn - bEndColumn;\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn aEndLineNumber - bEndLineNumber;\r\n\t\t\t\t}\r\n\t\t\t\treturn aStartColumn - bStartColumn;\r\n\t\t\t}\r\n\t\t\treturn aStartLineNumber - bStartLineNumber;\r\n\t\t}\r\n\t\tconst aExists = (a ? 1 : 0);\r\n\t\tconst bExists = (b ? 1 : 0);\r\n\t\treturn aExists - bExists;\r\n\t}\r\n\r\n\t/**\r\n\t * A function that compares ranges, useful for sorting ranges\r\n\t * It will first compare ranges on the endPosition and then on the startPosition\r\n\t */\r\n\tpublic static compareRangesUsingEnds(a: IRange, b: IRange): number {\r\n\t\tif (a.endLineNumber === b.endLineNumber) {\r\n\t\t\tif (a.endColumn === b.endColumn) {\r\n\t\t\t\tif (a.startLineNumber === b.startLineNumber) {\r\n\t\t\t\t\treturn a.startColumn - b.startColumn;\r\n\t\t\t\t}\r\n\t\t\t\treturn a.startLineNumber - b.startLineNumber;\r\n\t\t\t}\r\n\t\t\treturn a.endColumn - b.endColumn;\r\n\t\t}\r\n\t\treturn a.endLineNumber - b.endLineNumber;\r\n\t}\r\n\r\n\t/**\r\n\t * Test if the range spans multiple lines.\r\n\t */\r\n\tpublic static spansMultipleLines(range: IRange): boolean {\r\n\t\treturn range.endLineNumber > range.startLineNumber;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { EndOfLinePreference } from 'vs/editor/common/model';\r\n\r\nexport const _debugComposition = false;\r\n\r\nexport interface ITextAreaWrapper {\r\n\tgetValue(): string;\r\n\tsetValue(reason: string, value: string): void;\r\n\r\n\tgetSelectionStart(): number;\r\n\tgetSelectionEnd(): number;\r\n\tsetSelectionRange(reason: string, selectionStart: number, selectionEnd: number): void;\r\n}\r\n\r\nexport interface ISimpleModel {\r\n\tgetLineCount(): number;\r\n\tgetLineMaxColumn(lineNumber: number): number;\r\n\tgetValueInRange(range: Range, eol: EndOfLinePreference): string;\r\n}\r\n\r\nexport interface ITypeData {\r\n\ttext: string;\r\n\treplaceCharCnt: number;\r\n}\r\n\r\nexport class TextAreaState {\r\n\r\n\tpublic static readonly EMPTY = new TextAreaState('', 0, 0, null, null);\r\n\r\n\tpublic readonly value: string;\r\n\tpublic readonly selectionStart: number;\r\n\tpublic readonly selectionEnd: number;\r\n\tpublic readonly selectionStartPosition: Position | null;\r\n\tpublic readonly selectionEndPosition: Position | null;\r\n\r\n\tconstructor(value: string, selectionStart: number, selectionEnd: number, selectionStartPosition: Position | null, selectionEndPosition: Position | null) {\r\n\t\tthis.value = value;\r\n\t\tthis.selectionStart = selectionStart;\r\n\t\tthis.selectionEnd = selectionEnd;\r\n\t\tthis.selectionStartPosition = selectionStartPosition;\r\n\t\tthis.selectionEndPosition = selectionEndPosition;\r\n\t}\r\n\r\n\tpublic toString(): string {\r\n\t\treturn '[ <' + this.value + '>, selectionStart: ' + this.selectionStart + ', selectionEnd: ' + this.selectionEnd + ']';\r\n\t}\r\n\r\n\tpublic static readFromTextArea(textArea: ITextAreaWrapper): TextAreaState {\r\n\t\treturn new TextAreaState(textArea.getValue(), textArea.getSelectionStart(), textArea.getSelectionEnd(), null, null);\r\n\t}\r\n\r\n\tpublic collapseSelection(): TextAreaState {\r\n\t\treturn new TextAreaState(this.value, this.value.length, this.value.length, null, null);\r\n\t}\r\n\r\n\tpublic writeToTextArea(reason: string, textArea: ITextAreaWrapper, select: boolean): void {\r\n\t\tif (_debugComposition) {\r\n\t\t\tconsole.log('writeToTextArea ' + reason + ': ' + this.toString());\r\n\t\t}\r\n\t\ttextArea.setValue(reason, this.value);\r\n\t\tif (select) {\r\n\t\t\ttextArea.setSelectionRange(reason, this.selectionStart, this.selectionEnd);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic deduceEditorPosition(offset: number): [Position | null, number, number] {\r\n\t\tif (offset <= this.selectionStart) {\r\n\t\t\tconst str = this.value.substring(offset, this.selectionStart);\r\n\t\t\treturn this._finishDeduceEditorPosition(this.selectionStartPosition, str, -1);\r\n\t\t}\r\n\t\tif (offset >= this.selectionEnd) {\r\n\t\t\tconst str = this.value.substring(this.selectionEnd, offset);\r\n\t\t\treturn this._finishDeduceEditorPosition(this.selectionEndPosition, str, 1);\r\n\t\t}\r\n\t\tconst str1 = this.value.substring(this.selectionStart, offset);\r\n\t\tif (str1.indexOf(String.fromCharCode(8230)) === -1) {\r\n\t\t\treturn this._finishDeduceEditorPosition(this.selectionStartPosition, str1, 1);\r\n\t\t}\r\n\t\tconst str2 = this.value.substring(offset, this.selectionEnd);\r\n\t\treturn this._finishDeduceEditorPosition(this.selectionEndPosition, str2, -1);\r\n\t}\r\n\r\n\tprivate _finishDeduceEditorPosition(anchor: Position | null, deltaText: string, signum: number): [Position | null, number, number] {\r\n\t\tlet lineFeedCnt = 0;\r\n\t\tlet lastLineFeedIndex = -1;\r\n\t\twhile ((lastLineFeedIndex = deltaText.indexOf('\\n', lastLineFeedIndex + 1)) !== -1) {\r\n\t\t\tlineFeedCnt++;\r\n\t\t}\r\n\t\treturn [anchor, signum * deltaText.length, lineFeedCnt];\r\n\t}\r\n\r\n\tpublic static selectedText(text: string): TextAreaState {\r\n\t\treturn new TextAreaState(text, 0, text.length, null, null);\r\n\t}\r\n\r\n\tpublic static deduceInput(previousState: TextAreaState, currentState: TextAreaState, couldBeEmojiInput: boolean): ITypeData {\r\n\t\tif (!previousState) {\r\n\t\t\t// This is the EMPTY state\r\n\t\t\treturn {\r\n\t\t\t\ttext: '',\r\n\t\t\t\treplaceCharCnt: 0\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tif (_debugComposition) {\r\n\t\t\tconsole.log('------------------------deduceInput');\r\n\t\t\tconsole.log('PREVIOUS STATE: ' + previousState.toString());\r\n\t\t\tconsole.log('CURRENT STATE: ' + currentState.toString());\r\n\t\t}\r\n\r\n\t\tlet previousValue = previousState.value;\r\n\t\tlet previousSelectionStart = previousState.selectionStart;\r\n\t\tlet previousSelectionEnd = previousState.selectionEnd;\r\n\t\tlet currentValue = currentState.value;\r\n\t\tlet currentSelectionStart = currentState.selectionStart;\r\n\t\tlet currentSelectionEnd = currentState.selectionEnd;\r\n\r\n\t\t// Strip the previous suffix from the value (without interfering with the current selection)\r\n\t\tconst previousSuffix = previousValue.substring(previousSelectionEnd);\r\n\t\tconst currentSuffix = currentValue.substring(currentSelectionEnd);\r\n\t\tconst suffixLength = strings.commonSuffixLength(previousSuffix, currentSuffix);\r\n\t\tcurrentValue = currentValue.substring(0, currentValue.length - suffixLength);\r\n\t\tpreviousValue = previousValue.substring(0, previousValue.length - suffixLength);\r\n\r\n\t\tconst previousPrefix = previousValue.substring(0, previousSelectionStart);\r\n\t\tconst currentPrefix = currentValue.substring(0, currentSelectionStart);\r\n\t\tconst prefixLength = strings.commonPrefixLength(previousPrefix, currentPrefix);\r\n\t\tcurrentValue = currentValue.substring(prefixLength);\r\n\t\tpreviousValue = previousValue.substring(prefixLength);\r\n\t\tcurrentSelectionStart -= prefixLength;\r\n\t\tpreviousSelectionStart -= prefixLength;\r\n\t\tcurrentSelectionEnd -= prefixLength;\r\n\t\tpreviousSelectionEnd -= prefixLength;\r\n\r\n\t\tif (_debugComposition) {\r\n\t\t\tconsole.log('AFTER DIFFING PREVIOUS STATE: <' + previousValue + '>, selectionStart: ' + previousSelectionStart + ', selectionEnd: ' + previousSelectionEnd);\r\n\t\t\tconsole.log('AFTER DIFFING CURRENT STATE: <' + currentValue + '>, selectionStart: ' + currentSelectionStart + ', selectionEnd: ' + currentSelectionEnd);\r\n\t\t}\r\n\r\n\t\tif (couldBeEmojiInput && currentSelectionStart === currentSelectionEnd && previousValue.length > 0) {\r\n\t\t\t// on OSX, emojis from the emoji picker are inserted at random locations\r\n\t\t\t// the only hints we can use is that the selection is immediately after the inserted emoji\r\n\t\t\t// and that none of the old text has been deleted\r\n\r\n\t\t\tlet potentialEmojiInput: string | null = null;\r\n\r\n\t\t\tif (currentSelectionStart === currentValue.length) {\r\n\t\t\t\t// emoji potentially inserted \"somewhere\" after the previous selection => it should appear at the end of `currentValue`\r\n\t\t\t\tif (currentValue.startsWith(previousValue)) {\r\n\t\t\t\t\t// only if all of the old text is accounted for\r\n\t\t\t\t\tpotentialEmojiInput = currentValue.substring(previousValue.length);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\t// emoji potentially inserted \"somewhere\" before the previous selection => it should appear at the start of `currentValue`\r\n\t\t\t\tif (currentValue.endsWith(previousValue)) {\r\n\t\t\t\t\t// only if all of the old text is accounted for\r\n\t\t\t\t\tpotentialEmojiInput = currentValue.substring(0, currentValue.length - previousValue.length);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (potentialEmojiInput !== null && potentialEmojiInput.length > 0) {\r\n\t\t\t\t// now we check that this is indeed an emoji\r\n\t\t\t\t// emojis can grow quite long, so a length check is of no help\r\n\t\t\t\t// e.g. 1F3F4 E0067 E0062 E0065 E006E E0067 E007F ; fully-qualified # 🏴󠁧󠁢󠁥󠁮󠁧󠁿 England\r\n\r\n\t\t\t\t// Oftentimes, emojis use Variation Selector-16 (U+FE0F), so that is a good hint\r\n\t\t\t\t// http://emojipedia.org/variation-selector-16/\r\n\t\t\t\t// > An invisible codepoint which specifies that the preceding character\r\n\t\t\t\t// > should be displayed with emoji presentation. Only required if the\r\n\t\t\t\t// > preceding character defaults to text presentation.\r\n\t\t\t\tif (/\\uFE0F/.test(potentialEmojiInput) || strings.containsEmoji(potentialEmojiInput)) {\r\n\t\t\t\t\treturn {\r\n\t\t\t\t\t\ttext: potentialEmojiInput,\r\n\t\t\t\t\t\treplaceCharCnt: 0\r\n\t\t\t\t\t};\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (currentSelectionStart === currentSelectionEnd) {\r\n\t\t\t// composition accept case (noticed in FF + Japanese)\r\n\t\t\t// [blahblah] => blahblah|\r\n\t\t\tif (\r\n\t\t\t\tpreviousValue === currentValue\r\n\t\t\t\t&& previousSelectionStart === 0\r\n\t\t\t\t&& previousSelectionEnd === previousValue.length\r\n\t\t\t\t&& currentSelectionStart === currentValue.length\r\n\t\t\t\t&& currentValue.indexOf('\\n') === -1\r\n\t\t\t) {\r\n\t\t\t\tif (strings.containsFullWidthCharacter(currentValue)) {\r\n\t\t\t\t\treturn {\r\n\t\t\t\t\t\ttext: '',\r\n\t\t\t\t\t\treplaceCharCnt: 0\r\n\t\t\t\t\t};\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// no current selection\r\n\t\t\tconst replacePreviousCharacters = (previousPrefix.length - prefixLength);\r\n\t\t\tif (_debugComposition) {\r\n\t\t\t\tconsole.log('REMOVE PREVIOUS: ' + (previousPrefix.length - prefixLength) + ' chars');\r\n\t\t\t}\r\n\r\n\t\t\treturn {\r\n\t\t\t\ttext: currentValue,\r\n\t\t\t\treplaceCharCnt: replacePreviousCharacters\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\t// there is a current selection => composition case\r\n\t\tconst replacePreviousCharacters = previousSelectionEnd - previousSelectionStart;\r\n\t\treturn {\r\n\t\t\ttext: currentValue,\r\n\t\t\treplaceCharCnt: replacePreviousCharacters\r\n\t\t};\r\n\t}\r\n}\r\n\r\nexport class PagedScreenReaderStrategy {\r\n\tprivate static _getPageOfLine(lineNumber: number, linesPerPage: number): number {\r\n\t\treturn Math.floor((lineNumber - 1) / linesPerPage);\r\n\t}\r\n\r\n\tprivate static _getRangeForPage(page: number, linesPerPage: number): Range {\r\n\t\tconst offset = page * linesPerPage;\r\n\t\tconst startLineNumber = offset + 1;\r\n\t\tconst endLineNumber = offset + linesPerPage;\r\n\t\treturn new Range(startLineNumber, 1, endLineNumber + 1, 1);\r\n\t}\r\n\r\n\tpublic static fromEditorSelection(previousState: TextAreaState, model: ISimpleModel, selection: Range, linesPerPage: number, trimLongText: boolean): TextAreaState {\r\n\r\n\t\tconst selectionStartPage = PagedScreenReaderStrategy._getPageOfLine(selection.startLineNumber, linesPerPage);\r\n\t\tconst selectionStartPageRange = PagedScreenReaderStrategy._getRangeForPage(selectionStartPage, linesPerPage);\r\n\r\n\t\tconst selectionEndPage = PagedScreenReaderStrategy._getPageOfLine(selection.endLineNumber, linesPerPage);\r\n\t\tconst selectionEndPageRange = PagedScreenReaderStrategy._getRangeForPage(selectionEndPage, linesPerPage);\r\n\r\n\t\tconst pretextRange = selectionStartPageRange.intersectRanges(new Range(1, 1, selection.startLineNumber, selection.startColumn))!;\r\n\t\tlet pretext = model.getValueInRange(pretextRange, EndOfLinePreference.LF);\r\n\r\n\t\tconst lastLine = model.getLineCount();\r\n\t\tconst lastLineMaxColumn = model.getLineMaxColumn(lastLine);\r\n\t\tconst posttextRange = selectionEndPageRange.intersectRanges(new Range(selection.endLineNumber, selection.endColumn, lastLine, lastLineMaxColumn))!;\r\n\t\tlet posttext = model.getValueInRange(posttextRange, EndOfLinePreference.LF);\r\n\r\n\r\n\t\tlet text: string;\r\n\t\tif (selectionStartPage === selectionEndPage || selectionStartPage + 1 === selectionEndPage) {\r\n\t\t\t// take full selection\r\n\t\t\ttext = model.getValueInRange(selection, EndOfLinePreference.LF);\r\n\t\t} else {\r\n\t\t\tconst selectionRange1 = selectionStartPageRange.intersectRanges(selection)!;\r\n\t\t\tconst selectionRange2 = selectionEndPageRange.intersectRanges(selection)!;\r\n\t\t\ttext = (\r\n\t\t\t\tmodel.getValueInRange(selectionRange1, EndOfLinePreference.LF)\r\n\t\t\t\t+ String.fromCharCode(8230)\r\n\t\t\t\t+ model.getValueInRange(selectionRange2, EndOfLinePreference.LF)\r\n\t\t\t);\r\n\t\t}\r\n\r\n\t\t// Chromium handles very poorly text even of a few thousand chars\r\n\t\t// Cut text to avoid stalling the entire UI\r\n\t\tif (trimLongText) {\r\n\t\t\tconst LIMIT_CHARS = 500;\r\n\t\t\tif (pretext.length > LIMIT_CHARS) {\r\n\t\t\t\tpretext = pretext.substring(pretext.length - LIMIT_CHARS, pretext.length);\r\n\t\t\t}\r\n\t\t\tif (posttext.length > LIMIT_CHARS) {\r\n\t\t\t\tposttext = posttext.substring(0, LIMIT_CHARS);\r\n\t\t\t}\r\n\t\t\tif (text.length > 2 * LIMIT_CHARS) {\r\n\t\t\t\ttext = text.substring(0, LIMIT_CHARS) + String.fromCharCode(8230) + text.substring(text.length - LIMIT_CHARS, text.length);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn new TextAreaState(pretext + text + posttext, pretext.length, pretext.length + text.length, new Position(selection.startLineNumber, selection.startColumn), new Position(selection.endLineNumber, selection.endColumn));\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as assert from 'vs/base/common/assert';\r\nimport { Emitter } from 'vs/base/common/event';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport * as objects from 'vs/base/common/objects';\r\nimport { IDiffEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { ILineChange, ScrollType } from 'vs/editor/common/editorCommon';\r\n\r\n\r\ninterface IDiffRange {\r\n\trhs: boolean;\r\n\trange: Range;\r\n}\r\n\r\nexport interface Options {\r\n\tfollowsCaret?: boolean;\r\n\tignoreCharChanges?: boolean;\r\n\talwaysRevealFirst?: boolean;\r\n}\r\n\r\nconst defaultOptions: Options = {\r\n\tfollowsCaret: true,\r\n\tignoreCharChanges: true,\r\n\talwaysRevealFirst: true\r\n};\r\n\r\nexport interface IDiffNavigator {\r\n\tcanNavigate(): boolean;\r\n\tnext(): void;\r\n\tprevious(): void;\r\n\tdispose(): void;\r\n}\r\n\r\n/**\r\n * Create a new diff navigator for the provided diff editor.\r\n */\r\nexport class DiffNavigator extends Disposable implements IDiffNavigator {\r\n\r\n\tprivate readonly _editor: IDiffEditor;\r\n\tprivate readonly _options: Options;\r\n\tprivate readonly _onDidUpdate = this._register(new Emitter());\r\n\r\n\tprivate disposed: boolean;\r\n\tprivate revealFirst: boolean;\r\n\tprivate nextIdx: number;\r\n\tprivate ranges: IDiffRange[];\r\n\tprivate ignoreSelectionChange: boolean;\r\n\r\n\tconstructor(editor: IDiffEditor, options: Options = {}) {\r\n\t\tsuper();\r\n\t\tthis._editor = editor;\r\n\t\tthis._options = objects.mixin(options, defaultOptions, false);\r\n\r\n\t\tthis.disposed = false;\r\n\r\n\t\tthis.nextIdx = -1;\r\n\t\tthis.ranges = [];\r\n\t\tthis.ignoreSelectionChange = false;\r\n\t\tthis.revealFirst = Boolean(this._options.alwaysRevealFirst);\r\n\r\n\t\t// hook up to diff editor for diff, disposal, and caret move\r\n\t\tthis._register(this._editor.onDidDispose(() => this.dispose()));\r\n\t\tthis._register(this._editor.onDidUpdateDiff(() => this._onDiffUpdated()));\r\n\r\n\t\tif (this._options.followsCaret) {\r\n\t\t\tthis._register(this._editor.getModifiedEditor().onDidChangeCursorPosition((e: ICursorPositionChangedEvent) => {\r\n\t\t\t\tif (this.ignoreSelectionChange) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\tthis.nextIdx = -1;\r\n\t\t\t}));\r\n\t\t}\r\n\t\tif (this._options.alwaysRevealFirst) {\r\n\t\t\tthis._register(this._editor.getModifiedEditor().onDidChangeModel((e) => {\r\n\t\t\t\tthis.revealFirst = true;\r\n\t\t\t}));\r\n\t\t}\r\n\r\n\t\t// init things\r\n\t\tthis._init();\r\n\t}\r\n\r\n\tprivate _init(): void {\r\n\t\tlet changes = this._editor.getLineChanges();\r\n\t\tif (!changes) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _onDiffUpdated(): void {\r\n\t\tthis._init();\r\n\r\n\t\tthis._compute(this._editor.getLineChanges());\r\n\t\tif (this.revealFirst) {\r\n\t\t\t// Only reveal first on first non-null changes\r\n\t\t\tif (this._editor.getLineChanges() !== null) {\r\n\t\t\t\tthis.revealFirst = false;\r\n\t\t\t\tthis.nextIdx = -1;\r\n\t\t\t\tthis.next(ScrollType.Immediate);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _compute(lineChanges: ILineChange[] | null): void {\r\n\r\n\t\t// new ranges\r\n\t\tthis.ranges = [];\r\n\r\n\t\tif (lineChanges) {\r\n\t\t\t// create ranges from changes\r\n\t\t\tlineChanges.forEach((lineChange) => {\r\n\r\n\t\t\t\tif (!this._options.ignoreCharChanges && lineChange.charChanges) {\r\n\r\n\t\t\t\t\tlineChange.charChanges.forEach((charChange) => {\r\n\t\t\t\t\t\tthis.ranges.push({\r\n\t\t\t\t\t\t\trhs: true,\r\n\t\t\t\t\t\t\trange: new Range(\r\n\t\t\t\t\t\t\t\tcharChange.modifiedStartLineNumber,\r\n\t\t\t\t\t\t\t\tcharChange.modifiedStartColumn,\r\n\t\t\t\t\t\t\t\tcharChange.modifiedEndLineNumber,\r\n\t\t\t\t\t\t\t\tcharChange.modifiedEndColumn)\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t});\r\n\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis.ranges.push({\r\n\t\t\t\t\t\trhs: true,\r\n\t\t\t\t\t\trange: new Range(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedStartLineNumber, 1)\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\t// sort\r\n\t\tthis.ranges.sort((left, right) => {\r\n\t\t\tif (left.range.getStartPosition().isBeforeOrEqual(right.range.getStartPosition())) {\r\n\t\t\t\treturn -1;\r\n\t\t\t} else if (right.range.getStartPosition().isBeforeOrEqual(left.range.getStartPosition())) {\r\n\t\t\t\treturn 1;\r\n\t\t\t} else {\r\n\t\t\t\treturn 0;\r\n\t\t\t}\r\n\t\t});\r\n\t\tthis._onDidUpdate.fire(this);\r\n\t}\r\n\r\n\tprivate _initIdx(fwd: boolean): void {\r\n\t\tlet found = false;\r\n\t\tlet position = this._editor.getPosition();\r\n\t\tif (!position) {\r\n\t\t\tthis.nextIdx = 0;\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tfor (let i = 0, len = this.ranges.length; i < len && !found; i++) {\r\n\t\t\tlet range = this.ranges[i].range;\r\n\t\t\tif (position.isBeforeOrEqual(range.getStartPosition())) {\r\n\t\t\t\tthis.nextIdx = i + (fwd ? 0 : -1);\r\n\t\t\t\tfound = true;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (!found) {\r\n\t\t\t// after the last change\r\n\t\t\tthis.nextIdx = fwd ? 0 : this.ranges.length - 1;\r\n\t\t}\r\n\t\tif (this.nextIdx < 0) {\r\n\t\t\tthis.nextIdx = this.ranges.length - 1;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _move(fwd: boolean, scrollType: ScrollType): void {\r\n\t\tassert.ok(!this.disposed, 'Illegal State - diff navigator has been disposed');\r\n\r\n\t\tif (!this.canNavigate()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this.nextIdx === -1) {\r\n\t\t\tthis._initIdx(fwd);\r\n\r\n\t\t} else if (fwd) {\r\n\t\t\tthis.nextIdx += 1;\r\n\t\t\tif (this.nextIdx >= this.ranges.length) {\r\n\t\t\t\tthis.nextIdx = 0;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tthis.nextIdx -= 1;\r\n\t\t\tif (this.nextIdx < 0) {\r\n\t\t\t\tthis.nextIdx = this.ranges.length - 1;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet info = this.ranges[this.nextIdx];\r\n\t\tthis.ignoreSelectionChange = true;\r\n\t\ttry {\r\n\t\t\tlet pos = info.range.getStartPosition();\r\n\t\t\tthis._editor.setPosition(pos);\r\n\t\t\tthis._editor.revealPositionInCenter(pos, scrollType);\r\n\t\t} finally {\r\n\t\t\tthis.ignoreSelectionChange = false;\r\n\t\t}\r\n\t}\r\n\r\n\tcanNavigate(): boolean {\r\n\t\treturn this.ranges && this.ranges.length > 0;\r\n\t}\r\n\r\n\tnext(scrollType: ScrollType = ScrollType.Smooth): void {\r\n\t\tthis._move(true, scrollType);\r\n\t}\r\n\r\n\tprevious(scrollType: ScrollType = ScrollType.Smooth): void {\r\n\t\tthis._move(false, scrollType);\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tsuper.dispose();\r\n\t\tthis.ranges = [];\r\n\t\tthis.disposed = true;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { IIdentifiedSingleEditOperation } from 'vs/editor/common/model';\r\n\r\nexport class EditOperation {\r\n\r\n\tpublic static insert(position: Position, text: string): IIdentifiedSingleEditOperation {\r\n\t\treturn {\r\n\t\t\trange: new Range(position.lineNumber, position.column, position.lineNumber, position.column),\r\n\t\t\ttext: text,\r\n\t\t\tforceMoveMarkers: true\r\n\t\t};\r\n\t}\r\n\r\n\tpublic static delete(range: Range): IIdentifiedSingleEditOperation {\r\n\t\treturn {\r\n\t\t\trange: range,\r\n\t\t\ttext: null\r\n\t\t};\r\n\t}\r\n\r\n\tpublic static replace(range: Range, text: string | null): IIdentifiedSingleEditOperation {\r\n\t\treturn {\r\n\t\t\trange: range,\r\n\t\t\ttext: text\r\n\t\t};\r\n\t}\r\n\r\n\tpublic static replaceMove(range: Range, text: string | null): IIdentifiedSingleEditOperation {\r\n\t\treturn {\r\n\t\t\trange: range,\r\n\t\t\ttext: text,\r\n\t\t\tforceMoveMarkers: true\r\n\t\t};\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { EditOperation } from 'vs/editor/common/core/editOperation';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { ICommand, ICursorStateComputerData, IEditOperationBuilder } from 'vs/editor/common/editorCommon';\r\nimport { IIdentifiedSingleEditOperation, ITextModel } from 'vs/editor/common/model';\r\n\r\nexport class TrimTrailingWhitespaceCommand implements ICommand {\r\n\r\n\tprivate readonly _selection: Selection;\r\n\tprivate _selectionId: string | null;\r\n\tprivate readonly _cursors: Position[];\r\n\r\n\tconstructor(selection: Selection, cursors: Position[]) {\r\n\t\tthis._selection = selection;\r\n\t\tthis._cursors = cursors;\r\n\t\tthis._selectionId = null;\r\n\t}\r\n\r\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\r\n\t\tlet ops = trimTrailingWhitespace(model, this._cursors);\r\n\t\tfor (let i = 0, len = ops.length; i < len; i++) {\r\n\t\t\tlet op = ops[i];\r\n\r\n\t\t\tbuilder.addEditOperation(op.range, op.text);\r\n\t\t}\r\n\r\n\t\tthis._selectionId = builder.trackSelection(this._selection);\r\n\t}\r\n\r\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\r\n\t\treturn helper.getTrackedSelection(this._selectionId!);\r\n\t}\r\n}\r\n\r\n/**\r\n * Generate commands for trimming trailing whitespace on a model and ignore lines on which cursors are sitting.\r\n */\r\nexport function trimTrailingWhitespace(model: ITextModel, cursors: Position[]): IIdentifiedSingleEditOperation[] {\r\n\t// Sort cursors ascending\r\n\tcursors.sort((a, b) => {\r\n\t\tif (a.lineNumber === b.lineNumber) {\r\n\t\t\treturn a.column - b.column;\r\n\t\t}\r\n\t\treturn a.lineNumber - b.lineNumber;\r\n\t});\r\n\r\n\t// Reduce multiple cursors on the same line and only keep the last one on the line\r\n\tfor (let i = cursors.length - 2; i >= 0; i--) {\r\n\t\tif (cursors[i].lineNumber === cursors[i + 1].lineNumber) {\r\n\t\t\t// Remove cursor at `i`\r\n\t\t\tcursors.splice(i, 1);\r\n\t\t}\r\n\t}\r\n\r\n\tlet r: IIdentifiedSingleEditOperation[] = [];\r\n\tlet rLen = 0;\r\n\tlet cursorIndex = 0;\r\n\tlet cursorLen = cursors.length;\r\n\r\n\tfor (let lineNumber = 1, lineCount = model.getLineCount(); lineNumber <= lineCount; lineNumber++) {\r\n\t\tlet lineContent = model.getLineContent(lineNumber);\r\n\t\tlet maxLineColumn = lineContent.length + 1;\r\n\t\tlet minEditColumn = 0;\r\n\r\n\t\tif (cursorIndex < cursorLen && cursors[cursorIndex].lineNumber === lineNumber) {\r\n\t\t\tminEditColumn = cursors[cursorIndex].column;\r\n\t\t\tcursorIndex++;\r\n\t\t\tif (minEditColumn === maxLineColumn) {\r\n\t\t\t\t// The cursor is at the end of the line => no edits for sure on this line\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (lineContent.length === 0) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tlet lastNonWhitespaceIndex = strings.lastNonWhitespaceIndex(lineContent);\r\n\r\n\t\tlet fromColumn = 0;\r\n\t\tif (lastNonWhitespaceIndex === -1) {\r\n\t\t\t// Entire line is whitespace\r\n\t\t\tfromColumn = 1;\r\n\t\t} else if (lastNonWhitespaceIndex !== lineContent.length - 1) {\r\n\t\t\t// There is trailing whitespace\r\n\t\t\tfromColumn = lastNonWhitespaceIndex + 2;\r\n\t\t} else {\r\n\t\t\t// There is no trailing whitespace\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tfromColumn = Math.max(minEditColumn, fromColumn);\r\n\t\tr[rLen++] = EditOperation.delete(new Range(\r\n\t\t\tlineNumber, fromColumn,\r\n\t\t\tlineNumber, maxLineColumn\r\n\t\t));\r\n\t}\r\n\r\n\treturn r;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\n/**\r\n * A very VM friendly rgba datastructure.\r\n * Please don't touch unless you take a look at the IR.\r\n */\r\nexport class RGBA8 {\r\n\t_rgba8Brand: void;\r\n\r\n\tstatic readonly Empty = new RGBA8(0, 0, 0, 0);\r\n\r\n\t/**\r\n\t * Red: integer in [0-255]\r\n\t */\r\n\tpublic readonly r: number;\r\n\t/**\r\n\t * Green: integer in [0-255]\r\n\t */\r\n\tpublic readonly g: number;\r\n\t/**\r\n\t * Blue: integer in [0-255]\r\n\t */\r\n\tpublic readonly b: number;\r\n\t/**\r\n\t * Alpha: integer in [0-255]\r\n\t */\r\n\tpublic readonly a: number;\r\n\r\n\tconstructor(r: number, g: number, b: number, a: number) {\r\n\t\tthis.r = RGBA8._clamp(r);\r\n\t\tthis.g = RGBA8._clamp(g);\r\n\t\tthis.b = RGBA8._clamp(b);\r\n\t\tthis.a = RGBA8._clamp(a);\r\n\t}\r\n\r\n\tpublic equals(other: RGBA8): boolean {\r\n\t\treturn (\r\n\t\t\tthis.r === other.r\r\n\t\t\t&& this.g === other.g\r\n\t\t\t&& this.b === other.b\r\n\t\t\t&& this.a === other.a\r\n\t\t);\r\n\t}\r\n\r\n\tprivate static _clamp(c: number): number {\r\n\t\tif (c < 0) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t\tif (c > 255) {\r\n\t\t\treturn 255;\r\n\t\t}\r\n\t\treturn c | 0;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IPosition, Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\n\r\n/**\r\n * A selection in the editor.\r\n * The selection is a range that has an orientation.\r\n */\r\nexport interface ISelection {\r\n\t/**\r\n\t * The line number on which the selection has started.\r\n\t */\r\n\treadonly selectionStartLineNumber: number;\r\n\t/**\r\n\t * The column on `selectionStartLineNumber` where the selection has started.\r\n\t */\r\n\treadonly selectionStartColumn: number;\r\n\t/**\r\n\t * The line number on which the selection has ended.\r\n\t */\r\n\treadonly positionLineNumber: number;\r\n\t/**\r\n\t * The column on `positionLineNumber` where the selection has ended.\r\n\t */\r\n\treadonly positionColumn: number;\r\n}\r\n\r\n/**\r\n * The direction of a selection.\r\n */\r\nexport const enum SelectionDirection {\r\n\t/**\r\n\t * The selection starts above where it ends.\r\n\t */\r\n\tLTR,\r\n\t/**\r\n\t * The selection starts below where it ends.\r\n\t */\r\n\tRTL\r\n}\r\n\r\n/**\r\n * A selection in the editor.\r\n * The selection is a range that has an orientation.\r\n */\r\nexport class Selection extends Range {\r\n\t/**\r\n\t * The line number on which the selection has started.\r\n\t */\r\n\tpublic readonly selectionStartLineNumber: number;\r\n\t/**\r\n\t * The column on `selectionStartLineNumber` where the selection has started.\r\n\t */\r\n\tpublic readonly selectionStartColumn: number;\r\n\t/**\r\n\t * The line number on which the selection has ended.\r\n\t */\r\n\tpublic readonly positionLineNumber: number;\r\n\t/**\r\n\t * The column on `positionLineNumber` where the selection has ended.\r\n\t */\r\n\tpublic readonly positionColumn: number;\r\n\r\n\tconstructor(selectionStartLineNumber: number, selectionStartColumn: number, positionLineNumber: number, positionColumn: number) {\r\n\t\tsuper(selectionStartLineNumber, selectionStartColumn, positionLineNumber, positionColumn);\r\n\t\tthis.selectionStartLineNumber = selectionStartLineNumber;\r\n\t\tthis.selectionStartColumn = selectionStartColumn;\r\n\t\tthis.positionLineNumber = positionLineNumber;\r\n\t\tthis.positionColumn = positionColumn;\r\n\t}\r\n\r\n\t/**\r\n\t * Transform to a human-readable representation.\r\n\t */\r\n\tpublic toString(): string {\r\n\t\treturn '[' + this.selectionStartLineNumber + ',' + this.selectionStartColumn + ' -> ' + this.positionLineNumber + ',' + this.positionColumn + ']';\r\n\t}\r\n\r\n\t/**\r\n\t * Test if equals other selection.\r\n\t */\r\n\tpublic equalsSelection(other: ISelection): boolean {\r\n\t\treturn (\r\n\t\t\tSelection.selectionsEqual(this, other)\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * Test if the two selections are equal.\r\n\t */\r\n\tpublic static selectionsEqual(a: ISelection, b: ISelection): boolean {\r\n\t\treturn (\r\n\t\t\ta.selectionStartLineNumber === b.selectionStartLineNumber &&\r\n\t\t\ta.selectionStartColumn === b.selectionStartColumn &&\r\n\t\t\ta.positionLineNumber === b.positionLineNumber &&\r\n\t\t\ta.positionColumn === b.positionColumn\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * Get directions (LTR or RTL).\r\n\t */\r\n\tpublic getDirection(): SelectionDirection {\r\n\t\tif (this.selectionStartLineNumber === this.startLineNumber && this.selectionStartColumn === this.startColumn) {\r\n\t\t\treturn SelectionDirection.LTR;\r\n\t\t}\r\n\t\treturn SelectionDirection.RTL;\r\n\t}\r\n\r\n\t/**\r\n\t * Create a new selection with a different `positionLineNumber` and `positionColumn`.\r\n\t */\r\n\tpublic setEndPosition(endLineNumber: number, endColumn: number): Selection {\r\n\t\tif (this.getDirection() === SelectionDirection.LTR) {\r\n\t\t\treturn new Selection(this.startLineNumber, this.startColumn, endLineNumber, endColumn);\r\n\t\t}\r\n\t\treturn new Selection(endLineNumber, endColumn, this.startLineNumber, this.startColumn);\r\n\t}\r\n\r\n\t/**\r\n\t * Get the position at `positionLineNumber` and `positionColumn`.\r\n\t */\r\n\tpublic getPosition(): Position {\r\n\t\treturn new Position(this.positionLineNumber, this.positionColumn);\r\n\t}\r\n\r\n\t/**\r\n\t * Create a new selection with a different `selectionStartLineNumber` and `selectionStartColumn`.\r\n\t */\r\n\tpublic setStartPosition(startLineNumber: number, startColumn: number): Selection {\r\n\t\tif (this.getDirection() === SelectionDirection.LTR) {\r\n\t\t\treturn new Selection(startLineNumber, startColumn, this.endLineNumber, this.endColumn);\r\n\t\t}\r\n\t\treturn new Selection(this.endLineNumber, this.endColumn, startLineNumber, startColumn);\r\n\t}\r\n\r\n\t// ----\r\n\r\n\t/**\r\n\t * Create a `Selection` from one or two positions\r\n\t */\r\n\tpublic static fromPositions(start: IPosition, end: IPosition = start): Selection {\r\n\t\treturn new Selection(start.lineNumber, start.column, end.lineNumber, end.column);\r\n\t}\r\n\r\n\t/**\r\n\t * Create a `Selection` from an `ISelection`.\r\n\t */\r\n\tpublic static liftSelection(sel: ISelection): Selection {\r\n\t\treturn new Selection(sel.selectionStartLineNumber, sel.selectionStartColumn, sel.positionLineNumber, sel.positionColumn);\r\n\t}\r\n\r\n\t/**\r\n\t * `a` equals `b`.\r\n\t */\r\n\tpublic static selectionsArrEqual(a: ISelection[], b: ISelection[]): boolean {\r\n\t\tif (a && !b || !a && b) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (!a && !b) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (a.length !== b.length) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tfor (let i = 0, len = a.length; i < len; i++) {\r\n\t\t\tif (!this.selectionsEqual(a[i], b[i])) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t * Test if `obj` is an `ISelection`.\r\n\t */\r\n\tpublic static isISelection(obj: any): obj is ISelection {\r\n\t\treturn (\r\n\t\t\tobj\r\n\t\t\t&& (typeof obj.selectionStartLineNumber === 'number')\r\n\t\t\t&& (typeof obj.selectionStartColumn === 'number')\r\n\t\t\t&& (typeof obj.positionLineNumber === 'number')\r\n\t\t\t&& (typeof obj.positionColumn === 'number')\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * Create with a direction.\r\n\t */\r\n\tpublic static createWithDirection(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, direction: SelectionDirection): Selection {\r\n\r\n\t\tif (direction === SelectionDirection.LTR) {\r\n\t\t\treturn new Selection(startLineNumber, startColumn, endLineNumber, endColumn);\r\n\t\t}\r\n\r\n\t\treturn new Selection(endLineNumber, endColumn, startLineNumber, startColumn);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as browser from 'vs/base/browser/browser';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { FastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { RunOnceScheduler } from 'vs/base/common/async';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { KeyCode } from 'vs/base/common/keyCodes';\r\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { ITextAreaWrapper, ITypeData, TextAreaState, _debugComposition } from 'vs/editor/browser/controller/textAreaState';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { BrowserFeatures } from 'vs/base/browser/canIUse';\r\n\r\nexport interface ICompositionData {\r\n\tdata: string;\r\n}\r\n\r\nexport const CopyOptions = {\r\n\tforceCopyWithSyntaxHighlighting: false\r\n};\r\n\r\nconst enum ReadFromTextArea {\r\n\tType,\r\n\tPaste\r\n}\r\n\r\nexport interface IPasteData {\r\n\ttext: string;\r\n\tmetadata: ClipboardStoredMetadata | null;\r\n}\r\n\r\nexport interface ClipboardDataToCopy {\r\n\tisFromEmptySelection: boolean;\r\n\tmulticursorText: string[] | null | undefined;\r\n\ttext: string;\r\n\thtml: string | null | undefined;\r\n\tmode: string | null;\r\n}\r\n\r\nexport interface ClipboardStoredMetadata {\r\n\tversion: 1;\r\n\tisFromEmptySelection: boolean | undefined;\r\n\tmulticursorText: string[] | null | undefined;\r\n\tmode: string | null;\r\n}\r\n\r\nexport interface ITextAreaInputHost {\r\n\tgetDataToCopy(html: boolean): ClipboardDataToCopy;\r\n\tgetScreenReaderContent(currentState: TextAreaState): TextAreaState;\r\n\tdeduceModelPosition(viewAnchorPosition: Position, deltaOffset: number, lineFeedCnt: number): Position;\r\n}\r\n\r\ninterface CompositionEvent extends UIEvent {\r\n\treadonly data: string;\r\n\treadonly locale: string;\r\n}\r\n\r\ninterface InMemoryClipboardMetadata {\r\n\tlastCopiedValue: string;\r\n\tdata: ClipboardStoredMetadata;\r\n}\r\n\r\n/**\r\n * Every time we write to the clipboard, we record a bit of extra metadata here.\r\n * Every time we read from the cipboard, if the text matches our last written text,\r\n * we can fetch the previous metadata.\r\n */\r\nexport class InMemoryClipboardMetadataManager {\r\n\tpublic static readonly INSTANCE = new InMemoryClipboardMetadataManager();\r\n\r\n\tprivate _lastState: InMemoryClipboardMetadata | null;\r\n\r\n\tconstructor() {\r\n\t\tthis._lastState = null;\r\n\t}\r\n\r\n\tpublic set(lastCopiedValue: string, data: ClipboardStoredMetadata): void {\r\n\t\tthis._lastState = { lastCopiedValue, data };\r\n\t}\r\n\r\n\tpublic get(pastedText: string): ClipboardStoredMetadata | null {\r\n\t\tif (this._lastState && this._lastState.lastCopiedValue === pastedText) {\r\n\t\t\t// match!\r\n\t\t\treturn this._lastState.data;\r\n\t\t}\r\n\t\tthis._lastState = null;\r\n\t\treturn null;\r\n\t}\r\n}\r\n\r\nexport interface ICompositionStartEvent {\r\n\tmoveOneCharacterLeft: boolean;\r\n}\r\n\r\n/**\r\n * Writes screen reader content to the textarea and is able to analyze its input events to generate:\r\n * - onCut\r\n * - onPaste\r\n * - onType\r\n *\r\n * Composition events are generated for presentation purposes (composition input is reflected in onType).\r\n */\r\nexport class TextAreaInput extends Disposable {\r\n\r\n\tprivate _onFocus = this._register(new Emitter());\r\n\tpublic readonly onFocus: Event = this._onFocus.event;\r\n\r\n\tprivate _onBlur = this._register(new Emitter());\r\n\tpublic readonly onBlur: Event = this._onBlur.event;\r\n\r\n\tprivate _onKeyDown = this._register(new Emitter());\r\n\tpublic readonly onKeyDown: Event = this._onKeyDown.event;\r\n\r\n\tprivate _onKeyUp = this._register(new Emitter());\r\n\tpublic readonly onKeyUp: Event = this._onKeyUp.event;\r\n\r\n\tprivate _onCut = this._register(new Emitter());\r\n\tpublic readonly onCut: Event = this._onCut.event;\r\n\r\n\tprivate _onPaste = this._register(new Emitter());\r\n\tpublic readonly onPaste: Event = this._onPaste.event;\r\n\r\n\tprivate _onType = this._register(new Emitter());\r\n\tpublic readonly onType: Event = this._onType.event;\r\n\r\n\tprivate _onCompositionStart = this._register(new Emitter());\r\n\tpublic readonly onCompositionStart: Event = this._onCompositionStart.event;\r\n\r\n\tprivate _onCompositionUpdate = this._register(new Emitter());\r\n\tpublic readonly onCompositionUpdate: Event = this._onCompositionUpdate.event;\r\n\r\n\tprivate _onCompositionEnd = this._register(new Emitter());\r\n\tpublic readonly onCompositionEnd: Event = this._onCompositionEnd.event;\r\n\r\n\tprivate _onSelectionChangeRequest = this._register(new Emitter());\r\n\tpublic readonly onSelectionChangeRequest: Event = this._onSelectionChangeRequest.event;\r\n\r\n\t// ---\r\n\r\n\tprivate readonly _host: ITextAreaInputHost;\r\n\tprivate readonly _textArea: TextAreaWrapper;\r\n\tprivate readonly _asyncTriggerCut: RunOnceScheduler;\r\n\tprivate readonly _asyncFocusGainWriteScreenReaderContent: RunOnceScheduler;\r\n\r\n\tprivate _textAreaState: TextAreaState;\r\n\tprivate _selectionChangeListener: IDisposable | null;\r\n\r\n\tprivate _hasFocus: boolean;\r\n\tprivate _isDoingComposition: boolean;\r\n\tprivate _nextCommand: ReadFromTextArea;\r\n\r\n\tconstructor(host: ITextAreaInputHost, private textArea: FastDomNode) {\r\n\t\tsuper();\r\n\t\tthis._host = host;\r\n\t\tthis._textArea = this._register(new TextAreaWrapper(textArea));\r\n\t\tthis._asyncTriggerCut = this._register(new RunOnceScheduler(() => this._onCut.fire(), 0));\r\n\t\tthis._asyncFocusGainWriteScreenReaderContent = this._register(new RunOnceScheduler(() => this.writeScreenReaderContent('asyncFocusGain'), 0));\r\n\r\n\t\tthis._textAreaState = TextAreaState.EMPTY;\r\n\t\tthis._selectionChangeListener = null;\r\n\t\tthis.writeScreenReaderContent('ctor');\r\n\r\n\t\tthis._hasFocus = false;\r\n\t\tthis._isDoingComposition = false;\r\n\t\tthis._nextCommand = ReadFromTextArea.Type;\r\n\r\n\t\tlet lastKeyDown: IKeyboardEvent | null = null;\r\n\r\n\t\tthis._register(dom.addStandardDisposableListener(textArea.domNode, 'keydown', (e: IKeyboardEvent) => {\r\n\t\t\tif (e.keyCode === KeyCode.KEY_IN_COMPOSITION\r\n\t\t\t\t|| (this._isDoingComposition && e.keyCode === KeyCode.Backspace)) {\r\n\t\t\t\t// Stop propagation for keyDown events if the IME is processing key input\r\n\t\t\t\te.stopPropagation();\r\n\t\t\t}\r\n\r\n\t\t\tif (e.equals(KeyCode.Escape)) {\r\n\t\t\t\t// Prevent default always for `Esc`, otherwise it will generate a keypress\r\n\t\t\t\t// See https://msdn.microsoft.com/en-us/library/ie/ms536939(v=vs.85).aspx\r\n\t\t\t\te.preventDefault();\r\n\t\t\t}\r\n\r\n\t\t\tlastKeyDown = e;\r\n\t\t\tthis._onKeyDown.fire(e);\r\n\t\t}));\r\n\r\n\t\tthis._register(dom.addStandardDisposableListener(textArea.domNode, 'keyup', (e: IKeyboardEvent) => {\r\n\t\t\tthis._onKeyUp.fire(e);\r\n\t\t}));\r\n\r\n\t\tthis._register(dom.addDisposableListener(textArea.domNode, 'compositionstart', (e: CompositionEvent) => {\r\n\t\t\tif (_debugComposition) {\r\n\t\t\t\tconsole.log(`[compositionstart]`, e);\r\n\t\t\t}\r\n\r\n\t\t\tif (this._isDoingComposition) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tthis._isDoingComposition = true;\r\n\r\n\t\t\tlet moveOneCharacterLeft = false;\r\n\t\t\tif (\r\n\t\t\t\tplatform.isMacintosh\r\n\t\t\t\t&& lastKeyDown\r\n\t\t\t\t&& lastKeyDown.equals(KeyCode.KEY_IN_COMPOSITION)\r\n\t\t\t\t&& this._textAreaState.selectionStart === this._textAreaState.selectionEnd\r\n\t\t\t\t&& this._textAreaState.selectionStart > 0\r\n\t\t\t\t&& this._textAreaState.value.substr(this._textAreaState.selectionStart - 1, 1) === e.data\r\n\t\t\t) {\r\n\t\t\t\t// Handling long press case on macOS + arrow key => pretend the character was selected\r\n\t\t\t\tif (lastKeyDown.code === 'ArrowRight' || lastKeyDown.code === 'ArrowLeft') {\r\n\t\t\t\t\tif (_debugComposition) {\r\n\t\t\t\t\t\tconsole.log(`[compositionstart] Handling long press case on macOS + arrow key`, e);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tmoveOneCharacterLeft = true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (moveOneCharacterLeft) {\r\n\t\t\t\tthis._textAreaState = new TextAreaState(\r\n\t\t\t\t\tthis._textAreaState.value,\r\n\t\t\t\t\tthis._textAreaState.selectionStart - 1,\r\n\t\t\t\t\tthis._textAreaState.selectionEnd,\r\n\t\t\t\t\tthis._textAreaState.selectionStartPosition ? new Position(this._textAreaState.selectionStartPosition.lineNumber, this._textAreaState.selectionStartPosition.column - 1) : null,\r\n\t\t\t\t\tthis._textAreaState.selectionEndPosition\r\n\t\t\t\t);\r\n\t\t\t} else {\r\n\t\t\t\tthis._setAndWriteTextAreaState('compositionstart', TextAreaState.EMPTY);\r\n\t\t\t}\r\n\r\n\t\t\tthis._onCompositionStart.fire({ moveOneCharacterLeft });\r\n\t\t}));\r\n\r\n\t\t/**\r\n\t\t * Deduce the typed input from a text area's value and the last observed state.\r\n\t\t */\r\n\t\tconst deduceInputFromTextAreaValue = (couldBeEmojiInput: boolean): [TextAreaState, ITypeData] => {\r\n\t\t\tconst oldState = this._textAreaState;\r\n\t\t\tconst newState = TextAreaState.readFromTextArea(this._textArea);\r\n\t\t\treturn [newState, TextAreaState.deduceInput(oldState, newState, couldBeEmojiInput)];\r\n\t\t};\r\n\r\n\t\t/**\r\n\t\t * Deduce the composition input from a string.\r\n\t\t */\r\n\t\tconst deduceComposition = (text: string): [TextAreaState, ITypeData] => {\r\n\t\t\tconst oldState = this._textAreaState;\r\n\t\t\tconst newState = TextAreaState.selectedText(text);\r\n\t\t\tconst typeInput: ITypeData = {\r\n\t\t\t\ttext: newState.value,\r\n\t\t\t\treplaceCharCnt: oldState.selectionEnd - oldState.selectionStart\r\n\t\t\t};\r\n\t\t\treturn [newState, typeInput];\r\n\t\t};\r\n\r\n\t\tthis._register(dom.addDisposableListener(textArea.domNode, 'compositionupdate', (e: CompositionEvent) => {\r\n\t\t\tif (_debugComposition) {\r\n\t\t\t\tconsole.log(`[compositionupdate]`, e);\r\n\t\t\t}\r\n\t\t\tconst [newState, typeInput] = deduceComposition(e.data || '');\r\n\t\t\tthis._textAreaState = newState;\r\n\t\t\tthis._onType.fire(typeInput);\r\n\t\t\tthis._onCompositionUpdate.fire(e);\r\n\t\t}));\r\n\r\n\t\tthis._register(dom.addDisposableListener(textArea.domNode, 'compositionend', (e: CompositionEvent) => {\r\n\t\t\tif (_debugComposition) {\r\n\t\t\t\tconsole.log(`[compositionend]`, e);\r\n\t\t\t}\r\n\t\t\t// https://github.com/microsoft/monaco-editor/issues/1663\r\n\t\t\t// On iOS 13.2, Chinese system IME randomly trigger an additional compositionend event with empty data\r\n\t\t\tif (!this._isDoingComposition) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst [newState, typeInput] = deduceComposition(e.data || '');\r\n\t\t\tthis._textAreaState = newState;\r\n\t\t\tthis._onType.fire(typeInput);\r\n\r\n\t\t\t// isChrome: the textarea is not updated correctly when composition ends\r\n\t\t\t// isFirefox: the textarea is not updated correctly after inserting emojis\r\n\t\t\t// => we cannot assume the text at the end consists only of the composited text\r\n\t\t\tif (browser.isChrome || browser.isFirefox) {\r\n\t\t\t\tthis._textAreaState = TextAreaState.readFromTextArea(this._textArea);\r\n\t\t\t}\r\n\r\n\t\t\tif (!this._isDoingComposition) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tthis._isDoingComposition = false;\r\n\r\n\t\t\tthis._onCompositionEnd.fire();\r\n\t\t}));\r\n\r\n\t\tthis._register(dom.addDisposableListener(textArea.domNode, 'input', () => {\r\n\t\t\t// Pretend here we touched the text area, as the `input` event will most likely\r\n\t\t\t// result in a `selectionchange` event which we want to ignore\r\n\t\t\tthis._textArea.setIgnoreSelectionChangeTime('received input event');\r\n\r\n\t\t\tif (this._isDoingComposition) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst [newState, typeInput] = deduceInputFromTextAreaValue(/*couldBeEmojiInput*/platform.isMacintosh);\r\n\t\t\tif (typeInput.replaceCharCnt === 0 && typeInput.text.length === 1 && strings.isHighSurrogate(typeInput.text.charCodeAt(0))) {\r\n\t\t\t\t// Ignore invalid input but keep it around for next time\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tthis._textAreaState = newState;\r\n\t\t\tif (this._nextCommand === ReadFromTextArea.Type) {\r\n\t\t\t\tif (typeInput.text !== '') {\r\n\t\t\t\t\tthis._onType.fire(typeInput);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tif (typeInput.text !== '' || typeInput.replaceCharCnt !== 0) {\r\n\t\t\t\t\tthis._firePaste(typeInput.text, null);\r\n\t\t\t\t}\r\n\t\t\t\tthis._nextCommand = ReadFromTextArea.Type;\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\t// --- Clipboard operations\r\n\r\n\t\tthis._register(dom.addDisposableListener(textArea.domNode, 'cut', (e: ClipboardEvent) => {\r\n\t\t\t// Pretend here we touched the text area, as the `cut` event will most likely\r\n\t\t\t// result in a `selectionchange` event which we want to ignore\r\n\t\t\tthis._textArea.setIgnoreSelectionChangeTime('received cut event');\r\n\r\n\t\t\tthis._ensureClipboardGetsEditorSelection(e);\r\n\t\t\tthis._asyncTriggerCut.schedule();\r\n\t\t}));\r\n\r\n\t\tthis._register(dom.addDisposableListener(textArea.domNode, 'copy', (e: ClipboardEvent) => {\r\n\t\t\tthis._ensureClipboardGetsEditorSelection(e);\r\n\t\t}));\r\n\r\n\t\tthis._register(dom.addDisposableListener(textArea.domNode, 'paste', (e: ClipboardEvent) => {\r\n\t\t\t// Pretend here we touched the text area, as the `paste` event will most likely\r\n\t\t\t// result in a `selectionchange` event which we want to ignore\r\n\t\t\tthis._textArea.setIgnoreSelectionChangeTime('received paste event');\r\n\r\n\t\t\tif (ClipboardEventUtils.canUseTextData(e)) {\r\n\t\t\t\tconst [pastePlainText, metadata] = ClipboardEventUtils.getTextData(e);\r\n\t\t\t\tif (pastePlainText !== '') {\r\n\t\t\t\t\tthis._firePaste(pastePlainText, metadata);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tif (this._textArea.getSelectionStart() !== this._textArea.getSelectionEnd()) {\r\n\t\t\t\t\t// Clean up the textarea, to get a clean paste\r\n\t\t\t\t\tthis._setAndWriteTextAreaState('paste', TextAreaState.EMPTY);\r\n\t\t\t\t}\r\n\t\t\t\tthis._nextCommand = ReadFromTextArea.Paste;\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._register(dom.addDisposableListener(textArea.domNode, 'focus', () => {\r\n\t\t\tconst hadFocus = this._hasFocus;\r\n\r\n\t\t\tthis._setHasFocus(true);\r\n\r\n\t\t\tif (browser.isSafari && !hadFocus && this._hasFocus) {\r\n\t\t\t\t// When \"tabbing into\" the textarea, immediately after dispatching the 'focus' event,\r\n\t\t\t\t// Safari will always move the selection at offset 0 in the textarea\r\n\t\t\t\tthis._asyncFocusGainWriteScreenReaderContent.schedule();\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._register(dom.addDisposableListener(textArea.domNode, 'blur', () => {\r\n\t\t\tif (this._isDoingComposition) {\r\n\t\t\t\t// See https://github.com/microsoft/vscode/issues/112621\r\n\t\t\t\t// where compositionend is not triggered when the editor\r\n\t\t\t\t// is taken off-dom during a composition\r\n\r\n\t\t\t\t// Clear the flag to be able to write to the textarea\r\n\t\t\t\tthis._isDoingComposition = false;\r\n\r\n\t\t\t\t// Clear the textarea to avoid an unwanted cursor type\r\n\t\t\t\tthis.writeScreenReaderContent('blurWithoutCompositionEnd');\r\n\r\n\t\t\t\t// Fire artificial composition end\r\n\t\t\t\tthis._onCompositionEnd.fire();\r\n\t\t\t}\r\n\t\t\tthis._setHasFocus(false);\r\n\t\t}));\r\n\t}\r\n\r\n\tprivate _installSelectionChangeListener(): IDisposable {\r\n\t\t// See https://github.com/microsoft/vscode/issues/27216 and https://github.com/microsoft/vscode/issues/98256\r\n\t\t// When using a Braille display, it is possible for users to reposition the\r\n\t\t// system caret. This is reflected in Chrome as a `selectionchange` event.\r\n\t\t//\r\n\t\t// The `selectionchange` event appears to be emitted under numerous other circumstances,\r\n\t\t// so it is quite a challenge to distinguish a `selectionchange` coming in from a user\r\n\t\t// using a Braille display from all the other cases.\r\n\t\t//\r\n\t\t// The problems with the `selectionchange` event are:\r\n\t\t// * the event is emitted when the textarea is focused programmatically -- textarea.focus()\r\n\t\t// * the event is emitted when the selection is changed in the textarea programmatically -- textarea.setSelectionRange(...)\r\n\t\t// * the event is emitted when the value of the textarea is changed programmatically -- textarea.value = '...'\r\n\t\t// * the event is emitted when tabbing into the textarea\r\n\t\t// * the event is emitted asynchronously (sometimes with a delay as high as a few tens of ms)\r\n\t\t// * the event sometimes comes in bursts for a single logical textarea operation\r\n\r\n\t\t// `selectionchange` events often come multiple times for a single logical change\r\n\t\t// so throttle multiple `selectionchange` events that burst in a short period of time.\r\n\t\tlet previousSelectionChangeEventTime = 0;\r\n\t\treturn dom.addDisposableListener(document, 'selectionchange', (e) => {\r\n\t\t\tif (!this._hasFocus) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (this._isDoingComposition) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (!browser.isChrome) {\r\n\t\t\t\t// Support only for Chrome until testing happens on other browsers\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst now = Date.now();\r\n\r\n\t\t\tconst delta1 = now - previousSelectionChangeEventTime;\r\n\t\t\tpreviousSelectionChangeEventTime = now;\r\n\t\t\tif (delta1 < 5) {\r\n\t\t\t\t// received another `selectionchange` event within 5ms of the previous `selectionchange` event\r\n\t\t\t\t// => ignore it\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst delta2 = now - this._textArea.getIgnoreSelectionChangeTime();\r\n\t\t\tthis._textArea.resetSelectionChangeTime();\r\n\t\t\tif (delta2 < 100) {\r\n\t\t\t\t// received a `selectionchange` event within 100ms since we touched the textarea\r\n\t\t\t\t// => ignore it, since we caused it\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (!this._textAreaState.selectionStartPosition || !this._textAreaState.selectionEndPosition) {\r\n\t\t\t\t// Cannot correlate a position in the textarea with a position in the editor...\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst newValue = this._textArea.getValue();\r\n\t\t\tif (this._textAreaState.value !== newValue) {\r\n\t\t\t\t// Cannot correlate a position in the textarea with a position in the editor...\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst newSelectionStart = this._textArea.getSelectionStart();\r\n\t\t\tconst newSelectionEnd = this._textArea.getSelectionEnd();\r\n\t\t\tif (this._textAreaState.selectionStart === newSelectionStart && this._textAreaState.selectionEnd === newSelectionEnd) {\r\n\t\t\t\t// Nothing to do...\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst _newSelectionStartPosition = this._textAreaState.deduceEditorPosition(newSelectionStart);\r\n\t\t\tconst newSelectionStartPosition = this._host.deduceModelPosition(_newSelectionStartPosition[0]!, _newSelectionStartPosition[1], _newSelectionStartPosition[2]);\r\n\r\n\t\t\tconst _newSelectionEndPosition = this._textAreaState.deduceEditorPosition(newSelectionEnd);\r\n\t\t\tconst newSelectionEndPosition = this._host.deduceModelPosition(_newSelectionEndPosition[0]!, _newSelectionEndPosition[1], _newSelectionEndPosition[2]);\r\n\r\n\t\t\tconst newSelection = new Selection(\r\n\t\t\t\tnewSelectionStartPosition.lineNumber, newSelectionStartPosition.column,\r\n\t\t\t\tnewSelectionEndPosition.lineNumber, newSelectionEndPosition.column\r\n\t\t\t);\r\n\r\n\t\t\tthis._onSelectionChangeRequest.fire(newSelection);\r\n\t\t});\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tsuper.dispose();\r\n\t\tif (this._selectionChangeListener) {\r\n\t\t\tthis._selectionChangeListener.dispose();\r\n\t\t\tthis._selectionChangeListener = null;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic focusTextArea(): void {\r\n\t\t// Setting this._hasFocus and writing the screen reader content\r\n\t\t// will result in a focus() and setSelectionRange() in the textarea\r\n\t\tthis._setHasFocus(true);\r\n\r\n\t\t// If the editor is off DOM, focus cannot be really set, so let's double check that we have managed to set the focus\r\n\t\tthis.refreshFocusState();\r\n\t}\r\n\r\n\tpublic isFocused(): boolean {\r\n\t\treturn this._hasFocus;\r\n\t}\r\n\r\n\tpublic refreshFocusState(): void {\r\n\t\tconst shadowRoot = dom.getShadowRoot(this.textArea.domNode);\r\n\t\tif (shadowRoot) {\r\n\t\t\tthis._setHasFocus(shadowRoot.activeElement === this.textArea.domNode);\r\n\t\t} else if (dom.isInDOM(this.textArea.domNode)) {\r\n\t\t\tthis._setHasFocus(document.activeElement === this.textArea.domNode);\r\n\t\t} else {\r\n\t\t\tthis._setHasFocus(false);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _setHasFocus(newHasFocus: boolean): void {\r\n\t\tif (this._hasFocus === newHasFocus) {\r\n\t\t\t// no change\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._hasFocus = newHasFocus;\r\n\r\n\t\tif (this._selectionChangeListener) {\r\n\t\t\tthis._selectionChangeListener.dispose();\r\n\t\t\tthis._selectionChangeListener = null;\r\n\t\t}\r\n\t\tif (this._hasFocus) {\r\n\t\t\tthis._selectionChangeListener = this._installSelectionChangeListener();\r\n\t\t}\r\n\r\n\t\tif (this._hasFocus) {\r\n\t\t\tthis.writeScreenReaderContent('focusgain');\r\n\t\t}\r\n\r\n\t\tif (this._hasFocus) {\r\n\t\t\tthis._onFocus.fire();\r\n\t\t} else {\r\n\t\t\tthis._onBlur.fire();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _setAndWriteTextAreaState(reason: string, textAreaState: TextAreaState): void {\r\n\t\tif (!this._hasFocus) {\r\n\t\t\ttextAreaState = textAreaState.collapseSelection();\r\n\t\t}\r\n\r\n\t\ttextAreaState.writeToTextArea(reason, this._textArea, this._hasFocus);\r\n\t\tthis._textAreaState = textAreaState;\r\n\t}\r\n\r\n\tpublic writeScreenReaderContent(reason: string): void {\r\n\t\tif (this._isDoingComposition) {\r\n\t\t\t// Do not write to the text area when doing composition\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._setAndWriteTextAreaState(reason, this._host.getScreenReaderContent(this._textAreaState));\r\n\t}\r\n\r\n\tprivate _ensureClipboardGetsEditorSelection(e: ClipboardEvent): void {\r\n\t\tconst dataToCopy = this._host.getDataToCopy(ClipboardEventUtils.canUseTextData(e) && BrowserFeatures.clipboard.richText);\r\n\t\tconst storedMetadata: ClipboardStoredMetadata = {\r\n\t\t\tversion: 1,\r\n\t\t\tisFromEmptySelection: dataToCopy.isFromEmptySelection,\r\n\t\t\tmulticursorText: dataToCopy.multicursorText,\r\n\t\t\tmode: dataToCopy.mode\r\n\t\t};\r\n\t\tInMemoryClipboardMetadataManager.INSTANCE.set(\r\n\t\t\t// When writing \"LINE\\r\\n\" to the clipboard and then pasting,\r\n\t\t\t// Firefox pastes \"LINE\\n\", so let's work around this quirk\r\n\t\t\t(browser.isFirefox ? dataToCopy.text.replace(/\\r\\n/g, '\\n') : dataToCopy.text),\r\n\t\t\tstoredMetadata\r\n\t\t);\r\n\r\n\t\tif (!ClipboardEventUtils.canUseTextData(e)) {\r\n\t\t\t// Looks like an old browser. The strategy is to place the text\r\n\t\t\t// we'd like to be copied to the clipboard in the textarea and select it.\r\n\t\t\tthis._setAndWriteTextAreaState('copy or cut', TextAreaState.selectedText(dataToCopy.text));\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tClipboardEventUtils.setTextData(e, dataToCopy.text, dataToCopy.html, storedMetadata);\r\n\t}\r\n\r\n\tprivate _firePaste(text: string, metadata: ClipboardStoredMetadata | null): void {\r\n\t\tif (!metadata) {\r\n\t\t\t// try the in-memory store\r\n\t\t\tmetadata = InMemoryClipboardMetadataManager.INSTANCE.get(text);\r\n\t\t}\r\n\t\tthis._onPaste.fire({\r\n\t\t\ttext: text,\r\n\t\t\tmetadata: metadata\r\n\t\t});\r\n\t}\r\n}\r\n\r\nclass ClipboardEventUtils {\r\n\r\n\tpublic static canUseTextData(e: ClipboardEvent): boolean {\r\n\t\tif (e.clipboardData) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif ((window).clipboardData) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic static getTextData(e: ClipboardEvent): [string, ClipboardStoredMetadata | null] {\r\n\t\tif (e.clipboardData) {\r\n\t\t\te.preventDefault();\r\n\r\n\t\t\tconst text = e.clipboardData.getData('text/plain');\r\n\t\t\tlet metadata: ClipboardStoredMetadata | null = null;\r\n\t\t\tconst rawmetadata = e.clipboardData.getData('vscode-editor-data');\r\n\t\t\tif (typeof rawmetadata === 'string') {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tmetadata = JSON.parse(rawmetadata);\r\n\t\t\t\t\tif (metadata.version !== 1) {\r\n\t\t\t\t\t\tmetadata = null;\r\n\t\t\t\t\t}\r\n\t\t\t\t} catch (err) {\r\n\t\t\t\t\t// no problem!\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn [text, metadata];\r\n\t\t}\r\n\r\n\t\tif ((window).clipboardData) {\r\n\t\t\te.preventDefault();\r\n\t\t\tconst text: string = (window).clipboardData.getData('Text');\r\n\t\t\treturn [text, null];\r\n\t\t}\r\n\r\n\t\tthrow new Error('ClipboardEventUtils.getTextData: Cannot use text data!');\r\n\t}\r\n\r\n\tpublic static setTextData(e: ClipboardEvent, text: string, html: string | null | undefined, metadata: ClipboardStoredMetadata): void {\r\n\t\tif (e.clipboardData) {\r\n\t\t\te.clipboardData.setData('text/plain', text);\r\n\t\t\tif (typeof html === 'string') {\r\n\t\t\t\te.clipboardData.setData('text/html', html);\r\n\t\t\t}\r\n\t\t\te.clipboardData.setData('vscode-editor-data', JSON.stringify(metadata));\r\n\t\t\te.preventDefault();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif ((window).clipboardData) {\r\n\t\t\t(window).clipboardData.setData('Text', text);\r\n\t\t\te.preventDefault();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthrow new Error('ClipboardEventUtils.setTextData: Cannot use text data!');\r\n\t}\r\n}\r\n\r\nclass TextAreaWrapper extends Disposable implements ITextAreaWrapper {\r\n\r\n\tprivate readonly _actual: FastDomNode;\r\n\tprivate _ignoreSelectionChangeTime: number;\r\n\r\n\tconstructor(_textArea: FastDomNode) {\r\n\t\tsuper();\r\n\t\tthis._actual = _textArea;\r\n\t\tthis._ignoreSelectionChangeTime = 0;\r\n\t}\r\n\r\n\tpublic setIgnoreSelectionChangeTime(reason: string): void {\r\n\t\tthis._ignoreSelectionChangeTime = Date.now();\r\n\t}\r\n\r\n\tpublic getIgnoreSelectionChangeTime(): number {\r\n\t\treturn this._ignoreSelectionChangeTime;\r\n\t}\r\n\r\n\tpublic resetSelectionChangeTime(): void {\r\n\t\tthis._ignoreSelectionChangeTime = 0;\r\n\t}\r\n\r\n\tpublic getValue(): string {\r\n\t\t// console.log('current value: ' + this._textArea.value);\r\n\t\treturn this._actual.domNode.value;\r\n\t}\r\n\r\n\tpublic setValue(reason: string, value: string): void {\r\n\t\tconst textArea = this._actual.domNode;\r\n\t\tif (textArea.value === value) {\r\n\t\t\t// No change\r\n\t\t\treturn;\r\n\t\t}\r\n\t\t// console.log('reason: ' + reason + ', current value: ' + textArea.value + ' => new value: ' + value);\r\n\t\tthis.setIgnoreSelectionChangeTime('setValue');\r\n\t\ttextArea.value = value;\r\n\t}\r\n\r\n\tpublic getSelectionStart(): number {\r\n\t\treturn this._actual.domNode.selectionStart;\r\n\t}\r\n\r\n\tpublic getSelectionEnd(): number {\r\n\t\treturn this._actual.domNode.selectionEnd;\r\n\t}\r\n\r\n\tpublic setSelectionRange(reason: string, selectionStart: number, selectionEnd: number): void {\r\n\t\tconst textArea = this._actual.domNode;\r\n\r\n\t\tlet activeElement: Element | null = null;\r\n\t\tconst shadowRoot = dom.getShadowRoot(textArea);\r\n\t\tif (shadowRoot) {\r\n\t\t\tactiveElement = shadowRoot.activeElement;\r\n\t\t} else {\r\n\t\t\tactiveElement = document.activeElement;\r\n\t\t}\r\n\r\n\t\tconst currentIsFocused = (activeElement === textArea);\r\n\t\tconst currentSelectionStart = textArea.selectionStart;\r\n\t\tconst currentSelectionEnd = textArea.selectionEnd;\r\n\r\n\t\tif (currentIsFocused && currentSelectionStart === selectionStart && currentSelectionEnd === selectionEnd) {\r\n\t\t\t// No change\r\n\t\t\t// Firefox iframe bug https://github.com/microsoft/monaco-editor/issues/643#issuecomment-367871377\r\n\t\t\tif (browser.isFirefox && window.parent !== window) {\r\n\t\t\t\ttextArea.focus();\r\n\t\t\t}\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// console.log('reason: ' + reason + ', setSelectionRange: ' + selectionStart + ' -> ' + selectionEnd);\r\n\r\n\t\tif (currentIsFocused) {\r\n\t\t\t// No need to focus, only need to change the selection range\r\n\t\t\tthis.setIgnoreSelectionChangeTime('setSelectionRange');\r\n\t\t\ttextArea.setSelectionRange(selectionStart, selectionEnd);\r\n\t\t\tif (browser.isFirefox && window.parent !== window) {\r\n\t\t\t\ttextArea.focus();\r\n\t\t\t}\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// If the focus is outside the textarea, browsers will try really hard to reveal the textarea.\r\n\t\t// Here, we try to undo the browser's desperate reveal.\r\n\t\ttry {\r\n\t\t\tconst scrollState = dom.saveParentsScrollTop(textArea);\r\n\t\t\tthis.setIgnoreSelectionChangeTime('setSelectionRange');\r\n\t\t\ttextArea.focus();\r\n\t\t\ttextArea.setSelectionRange(selectionStart, selectionEnd);\r\n\t\t\tdom.restoreParentsScrollTop(textArea, scrollState);\r\n\t\t} catch (e) {\r\n\t\t\t// Sometimes IE throws when setting selection (e.g. textarea is off-DOM)\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { ICommand, ICursorStateComputerData, IEditOperationBuilder } from 'vs/editor/common/editorCommon';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\n\r\nexport class ReplaceCommand implements ICommand {\r\n\r\n\tprivate readonly _range: Range;\r\n\tprivate readonly _text: string;\r\n\tpublic readonly insertsAutoWhitespace: boolean;\r\n\r\n\tconstructor(range: Range, text: string, insertsAutoWhitespace: boolean = false) {\r\n\t\tthis._range = range;\r\n\t\tthis._text = text;\r\n\t\tthis.insertsAutoWhitespace = insertsAutoWhitespace;\r\n\t}\r\n\r\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\r\n\t\tbuilder.addTrackedEditOperation(this._range, this._text);\r\n\t}\r\n\r\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\r\n\t\tlet inverseEditOperations = helper.getInverseEditOperations();\r\n\t\tlet srcRange = inverseEditOperations[0].range;\r\n\t\treturn new Selection(\r\n\t\t\tsrcRange.endLineNumber,\r\n\t\t\tsrcRange.endColumn,\r\n\t\t\tsrcRange.endLineNumber,\r\n\t\t\tsrcRange.endColumn\r\n\t\t);\r\n\t}\r\n}\r\n\r\nexport class ReplaceCommandThatSelectsText implements ICommand {\r\n\r\n\tprivate readonly _range: Range;\r\n\tprivate readonly _text: string;\r\n\r\n\tconstructor(range: Range, text: string) {\r\n\t\tthis._range = range;\r\n\t\tthis._text = text;\r\n\t}\r\n\r\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\r\n\t\tbuilder.addTrackedEditOperation(this._range, this._text);\r\n\t}\r\n\r\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\r\n\t\tconst inverseEditOperations = helper.getInverseEditOperations();\r\n\t\tconst srcRange = inverseEditOperations[0].range;\r\n\t\treturn new Selection(srcRange.startLineNumber, srcRange.startColumn, srcRange.endLineNumber, srcRange.endColumn);\r\n\t}\r\n}\r\n\r\nexport class ReplaceCommandWithoutChangingPosition implements ICommand {\r\n\r\n\tprivate readonly _range: Range;\r\n\tprivate readonly _text: string;\r\n\tpublic readonly insertsAutoWhitespace: boolean;\r\n\r\n\tconstructor(range: Range, text: string, insertsAutoWhitespace: boolean = false) {\r\n\t\tthis._range = range;\r\n\t\tthis._text = text;\r\n\t\tthis.insertsAutoWhitespace = insertsAutoWhitespace;\r\n\t}\r\n\r\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\r\n\t\tbuilder.addTrackedEditOperation(this._range, this._text);\r\n\t}\r\n\r\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\r\n\t\tlet inverseEditOperations = helper.getInverseEditOperations();\r\n\t\tlet srcRange = inverseEditOperations[0].range;\r\n\t\treturn new Selection(\r\n\t\t\tsrcRange.startLineNumber,\r\n\t\t\tsrcRange.startColumn,\r\n\t\t\tsrcRange.startLineNumber,\r\n\t\t\tsrcRange.startColumn\r\n\t\t);\r\n\t}\r\n}\r\n\r\nexport class ReplaceCommandWithOffsetCursorState implements ICommand {\r\n\r\n\tprivate readonly _range: Range;\r\n\tprivate readonly _text: string;\r\n\tprivate readonly _columnDeltaOffset: number;\r\n\tprivate readonly _lineNumberDeltaOffset: number;\r\n\tpublic readonly insertsAutoWhitespace: boolean;\r\n\r\n\tconstructor(range: Range, text: string, lineNumberDeltaOffset: number, columnDeltaOffset: number, insertsAutoWhitespace: boolean = false) {\r\n\t\tthis._range = range;\r\n\t\tthis._text = text;\r\n\t\tthis._columnDeltaOffset = columnDeltaOffset;\r\n\t\tthis._lineNumberDeltaOffset = lineNumberDeltaOffset;\r\n\t\tthis.insertsAutoWhitespace = insertsAutoWhitespace;\r\n\t}\r\n\r\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\r\n\t\tbuilder.addTrackedEditOperation(this._range, this._text);\r\n\t}\r\n\r\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\r\n\t\tlet inverseEditOperations = helper.getInverseEditOperations();\r\n\t\tlet srcRange = inverseEditOperations[0].range;\r\n\t\treturn new Selection(\r\n\t\t\tsrcRange.endLineNumber + this._lineNumberDeltaOffset,\r\n\t\t\tsrcRange.endColumn + this._columnDeltaOffset,\r\n\t\t\tsrcRange.endLineNumber + this._lineNumberDeltaOffset,\r\n\t\t\tsrcRange.endColumn + this._columnDeltaOffset\r\n\t\t);\r\n\t}\r\n}\r\n\r\nexport class ReplaceCommandThatPreservesSelection implements ICommand {\r\n\r\n\tprivate readonly _range: Range;\r\n\tprivate readonly _text: string;\r\n\tprivate readonly _initialSelection: Selection;\r\n\tprivate readonly _forceMoveMarkers: boolean;\r\n\tprivate _selectionId: string | null;\r\n\r\n\tconstructor(editRange: Range, text: string, initialSelection: Selection, forceMoveMarkers: boolean = false) {\r\n\t\tthis._range = editRange;\r\n\t\tthis._text = text;\r\n\t\tthis._initialSelection = initialSelection;\r\n\t\tthis._forceMoveMarkers = forceMoveMarkers;\r\n\t\tthis._selectionId = null;\r\n\t}\r\n\r\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\r\n\t\tbuilder.addTrackedEditOperation(this._range, this._text, this._forceMoveMarkers);\r\n\t\tthis._selectionId = builder.trackSelection(this._initialSelection);\r\n\t}\r\n\r\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\r\n\t\treturn helper.getTrackedSelection(this._selectionId!);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { ICommand, ICursorStateComputerData, IEditOperationBuilder } from 'vs/editor/common/editorCommon';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\n\r\nexport class SurroundSelectionCommand implements ICommand {\r\n\tprivate readonly _range: Selection;\r\n\tprivate readonly _charBeforeSelection: string;\r\n\tprivate readonly _charAfterSelection: string;\r\n\r\n\tconstructor(range: Selection, charBeforeSelection: string, charAfterSelection: string) {\r\n\t\tthis._range = range;\r\n\t\tthis._charBeforeSelection = charBeforeSelection;\r\n\t\tthis._charAfterSelection = charAfterSelection;\r\n\t}\r\n\r\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\r\n\t\tbuilder.addTrackedEditOperation(new Range(\r\n\t\t\tthis._range.startLineNumber,\r\n\t\t\tthis._range.startColumn,\r\n\t\t\tthis._range.startLineNumber,\r\n\t\t\tthis._range.startColumn\r\n\t\t), this._charBeforeSelection);\r\n\r\n\t\tbuilder.addTrackedEditOperation(new Range(\r\n\t\t\tthis._range.endLineNumber,\r\n\t\t\tthis._range.endColumn,\r\n\t\t\tthis._range.endLineNumber,\r\n\t\t\tthis._range.endColumn\r\n\t\t), this._charAfterSelection);\r\n\t}\r\n\r\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\r\n\t\tlet inverseEditOperations = helper.getInverseEditOperations();\r\n\t\tlet firstOperationRange = inverseEditOperations[0].range;\r\n\t\tlet secondOperationRange = inverseEditOperations[1].range;\r\n\r\n\t\treturn new Selection(\r\n\t\t\tfirstOperationRange.endLineNumber,\r\n\t\t\tfirstOperationRange.endColumn,\r\n\t\t\tsecondOperationRange.endLineNumber,\r\n\t\t\tsecondOperationRange.endColumn - this._charAfterSelection.length\r\n\t\t);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as strings from 'vs/base/common/strings';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport * as buffer from 'vs/base/common/buffer';\r\n\r\ndeclare const TextDecoder: {\r\n\tprototype: TextDecoder;\r\n\tnew(label?: string): TextDecoder;\r\n};\r\ninterface TextDecoder {\r\n\tdecode(view: Uint16Array): string;\r\n}\r\n\r\nexport interface IStringBuilder {\r\n\tbuild(): string;\r\n\treset(): void;\r\n\twrite1(charCode: number): void;\r\n\tappendASCII(charCode: number): void;\r\n\tappendASCIIString(str: string): void;\r\n}\r\n\r\nlet _platformTextDecoder: TextDecoder | null;\r\nexport function getPlatformTextDecoder(): TextDecoder {\r\n\tif (!_platformTextDecoder) {\r\n\t\t_platformTextDecoder = new TextDecoder(platform.isLittleEndian() ? 'UTF-16LE' : 'UTF-16BE');\r\n\t}\r\n\treturn _platformTextDecoder;\r\n}\r\n\r\nexport const hasTextDecoder = (typeof TextDecoder !== 'undefined');\r\nexport let createStringBuilder: (capacity: number) => IStringBuilder;\r\nexport let decodeUTF16LE: (source: Uint8Array, offset: number, len: number) => string;\r\n\r\nif (hasTextDecoder) {\r\n\tcreateStringBuilder = (capacity) => new StringBuilder(capacity);\r\n\tdecodeUTF16LE = standardDecodeUTF16LE;\r\n} else {\r\n\tcreateStringBuilder = (capacity) => new CompatStringBuilder();\r\n\tdecodeUTF16LE = compatDecodeUTF16LE;\r\n}\r\n\r\nfunction standardDecodeUTF16LE(source: Uint8Array, offset: number, len: number): string {\r\n\tconst view = new Uint16Array(source.buffer, offset, len);\r\n\treturn getPlatformTextDecoder().decode(view);\r\n}\r\n\r\nfunction compatDecodeUTF16LE(source: Uint8Array, offset: number, len: number): string {\r\n\tlet result: string[] = [];\r\n\tlet resultLen = 0;\r\n\tfor (let i = 0; i < len; i++) {\r\n\t\tconst charCode = buffer.readUInt16LE(source, offset); offset += 2;\r\n\t\tresult[resultLen++] = String.fromCharCode(charCode);\r\n\t}\r\n\treturn result.join('');\r\n}\r\n\r\nclass StringBuilder implements IStringBuilder {\r\n\r\n\tprivate readonly _capacity: number;\r\n\tprivate readonly _buffer: Uint16Array;\r\n\r\n\tprivate _completedStrings: string[] | null;\r\n\tprivate _bufferLength: number;\r\n\r\n\tconstructor(capacity: number) {\r\n\t\tthis._capacity = capacity | 0;\r\n\t\tthis._buffer = new Uint16Array(this._capacity);\r\n\r\n\t\tthis._completedStrings = null;\r\n\t\tthis._bufferLength = 0;\r\n\t}\r\n\r\n\tpublic reset(): void {\r\n\t\tthis._completedStrings = null;\r\n\t\tthis._bufferLength = 0;\r\n\t}\r\n\r\n\tpublic build(): string {\r\n\t\tif (this._completedStrings !== null) {\r\n\t\t\tthis._flushBuffer();\r\n\t\t\treturn this._completedStrings.join('');\r\n\t\t}\r\n\t\treturn this._buildBuffer();\r\n\t}\r\n\r\n\tprivate _buildBuffer(): string {\r\n\t\tif (this._bufferLength === 0) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\r\n\t\tconst view = new Uint16Array(this._buffer.buffer, 0, this._bufferLength);\r\n\t\treturn getPlatformTextDecoder().decode(view);\r\n\t}\r\n\r\n\tprivate _flushBuffer(): void {\r\n\t\tconst bufferString = this._buildBuffer();\r\n\t\tthis._bufferLength = 0;\r\n\r\n\t\tif (this._completedStrings === null) {\r\n\t\t\tthis._completedStrings = [bufferString];\r\n\t\t} else {\r\n\t\t\tthis._completedStrings[this._completedStrings.length] = bufferString;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic write1(charCode: number): void {\r\n\t\tconst remainingSpace = this._capacity - this._bufferLength;\r\n\r\n\t\tif (remainingSpace <= 1) {\r\n\t\t\tif (remainingSpace === 0 || strings.isHighSurrogate(charCode)) {\r\n\t\t\t\tthis._flushBuffer();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._buffer[this._bufferLength++] = charCode;\r\n\t}\r\n\r\n\tpublic appendASCII(charCode: number): void {\r\n\t\tif (this._bufferLength === this._capacity) {\r\n\t\t\t// buffer is full\r\n\t\t\tthis._flushBuffer();\r\n\t\t}\r\n\t\tthis._buffer[this._bufferLength++] = charCode;\r\n\t}\r\n\r\n\tpublic appendASCIIString(str: string): void {\r\n\t\tconst strLen = str.length;\r\n\r\n\t\tif (this._bufferLength + strLen >= this._capacity) {\r\n\t\t\t// This string does not fit in the remaining buffer space\r\n\r\n\t\t\tthis._flushBuffer();\r\n\t\t\tthis._completedStrings![this._completedStrings!.length] = str;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tfor (let i = 0; i < strLen; i++) {\r\n\t\t\tthis._buffer[this._bufferLength++] = str.charCodeAt(i);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass CompatStringBuilder implements IStringBuilder {\r\n\r\n\tprivate _pieces: string[];\r\n\tprivate _piecesLen: number;\r\n\r\n\tconstructor() {\r\n\t\tthis._pieces = [];\r\n\t\tthis._piecesLen = 0;\r\n\t}\r\n\r\n\tpublic reset(): void {\r\n\t\tthis._pieces = [];\r\n\t\tthis._piecesLen = 0;\r\n\t}\r\n\r\n\tpublic build(): string {\r\n\t\treturn this._pieces.join('');\r\n\t}\r\n\r\n\tpublic write1(charCode: number): void {\r\n\t\tthis._pieces[this._piecesLen++] = String.fromCharCode(charCode);\r\n\t}\r\n\r\n\tpublic appendASCII(charCode: number): void {\r\n\t\tthis._pieces[this._piecesLen++] = String.fromCharCode(charCode);\r\n\t}\r\n\r\n\tpublic appendASCIIString(str: string): void {\r\n\t\tthis._pieces[this._piecesLen++] = str;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { IStringBuilder, createStringBuilder } from 'vs/editor/common/core/stringBuilder';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\n/**\r\n * Represents a visible line\r\n */\r\nexport interface IVisibleLine extends ILine {\r\n\tgetDomNode(): HTMLElement | null;\r\n\tsetDomNode(domNode: HTMLElement): void;\r\n\r\n\t/**\r\n\t * Return null if the HTML should not be touched.\r\n\t * Return the new HTML otherwise.\r\n\t */\r\n\trenderLine(lineNumber: number, deltaTop: number, viewportData: ViewportData, sb: IStringBuilder): boolean;\r\n\r\n\t/**\r\n\t * Layout the line.\r\n\t */\r\n\tlayoutLine(lineNumber: number, deltaTop: number): void;\r\n}\r\n\r\nexport interface ILine {\r\n\tonContentChanged(): void;\r\n\tonTokensChanged(): void;\r\n}\r\n\r\nexport class RenderedLinesCollection {\r\n\tprivate readonly _createLine: () => T;\r\n\tprivate _lines!: T[];\r\n\tprivate _rendLineNumberStart!: number;\r\n\r\n\tconstructor(createLine: () => T) {\r\n\t\tthis._createLine = createLine;\r\n\t\tthis._set(1, []);\r\n\t}\r\n\r\n\tpublic flush(): void {\r\n\t\tthis._set(1, []);\r\n\t}\r\n\r\n\t_set(rendLineNumberStart: number, lines: T[]): void {\r\n\t\tthis._lines = lines;\r\n\t\tthis._rendLineNumberStart = rendLineNumberStart;\r\n\t}\r\n\r\n\t_get(): { rendLineNumberStart: number; lines: T[]; } {\r\n\t\treturn {\r\n\t\t\trendLineNumberStart: this._rendLineNumberStart,\r\n\t\t\tlines: this._lines\r\n\t\t};\r\n\t}\r\n\r\n\t/**\r\n\t * @returns Inclusive line number that is inside this collection\r\n\t */\r\n\tpublic getStartLineNumber(): number {\r\n\t\treturn this._rendLineNumberStart;\r\n\t}\r\n\r\n\t/**\r\n\t * @returns Inclusive line number that is inside this collection\r\n\t */\r\n\tpublic getEndLineNumber(): number {\r\n\t\treturn this._rendLineNumberStart + this._lines.length - 1;\r\n\t}\r\n\r\n\tpublic getCount(): number {\r\n\t\treturn this._lines.length;\r\n\t}\r\n\r\n\tpublic getLine(lineNumber: number): T {\r\n\t\tconst lineIndex = lineNumber - this._rendLineNumberStart;\r\n\t\tif (lineIndex < 0 || lineIndex >= this._lines.length) {\r\n\t\t\tthrow new Error('Illegal value for lineNumber');\r\n\t\t}\r\n\t\treturn this._lines[lineIndex];\r\n\t}\r\n\r\n\t/**\r\n\t * @returns Lines that were removed from this collection\r\n\t */\r\n\tpublic onLinesDeleted(deleteFromLineNumber: number, deleteToLineNumber: number): T[] | null {\r\n\t\tif (this.getCount() === 0) {\r\n\t\t\t// no lines\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst startLineNumber = this.getStartLineNumber();\r\n\t\tconst endLineNumber = this.getEndLineNumber();\r\n\r\n\t\tif (deleteToLineNumber < startLineNumber) {\r\n\t\t\t// deleting above the viewport\r\n\t\t\tconst deleteCnt = deleteToLineNumber - deleteFromLineNumber + 1;\r\n\t\t\tthis._rendLineNumberStart -= deleteCnt;\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (deleteFromLineNumber > endLineNumber) {\r\n\t\t\t// deleted below the viewport\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\t// Record what needs to be deleted\r\n\t\tlet deleteStartIndex = 0;\r\n\t\tlet deleteCount = 0;\r\n\t\tfor (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {\r\n\t\t\tconst lineIndex = lineNumber - this._rendLineNumberStart;\r\n\r\n\t\t\tif (deleteFromLineNumber <= lineNumber && lineNumber <= deleteToLineNumber) {\r\n\t\t\t\t// this is a line to be deleted\r\n\t\t\t\tif (deleteCount === 0) {\r\n\t\t\t\t\t// this is the first line to be deleted\r\n\t\t\t\t\tdeleteStartIndex = lineIndex;\r\n\t\t\t\t\tdeleteCount = 1;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tdeleteCount++;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Adjust this._rendLineNumberStart for lines deleted above\r\n\t\tif (deleteFromLineNumber < startLineNumber) {\r\n\t\t\t// Something was deleted above\r\n\t\t\tlet deleteAboveCount = 0;\r\n\r\n\t\t\tif (deleteToLineNumber < startLineNumber) {\r\n\t\t\t\t// the entire deleted lines are above\r\n\t\t\t\tdeleteAboveCount = deleteToLineNumber - deleteFromLineNumber + 1;\r\n\t\t\t} else {\r\n\t\t\t\tdeleteAboveCount = startLineNumber - deleteFromLineNumber;\r\n\t\t\t}\r\n\r\n\t\t\tthis._rendLineNumberStart -= deleteAboveCount;\r\n\t\t}\r\n\r\n\t\tconst deleted = this._lines.splice(deleteStartIndex, deleteCount);\r\n\t\treturn deleted;\r\n\t}\r\n\r\n\tpublic onLinesChanged(changeFromLineNumber: number, changeToLineNumber: number): boolean {\r\n\t\tif (this.getCount() === 0) {\r\n\t\t\t// no lines\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tconst startLineNumber = this.getStartLineNumber();\r\n\t\tconst endLineNumber = this.getEndLineNumber();\r\n\r\n\t\tlet someoneNotified = false;\r\n\r\n\t\tfor (let changedLineNumber = changeFromLineNumber; changedLineNumber <= changeToLineNumber; changedLineNumber++) {\r\n\t\t\tif (changedLineNumber >= startLineNumber && changedLineNumber <= endLineNumber) {\r\n\t\t\t\t// Notify the line\r\n\t\t\t\tthis._lines[changedLineNumber - this._rendLineNumberStart].onContentChanged();\r\n\t\t\t\tsomeoneNotified = true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn someoneNotified;\r\n\t}\r\n\r\n\tpublic onLinesInserted(insertFromLineNumber: number, insertToLineNumber: number): T[] | null {\r\n\t\tif (this.getCount() === 0) {\r\n\t\t\t// no lines\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst insertCnt = insertToLineNumber - insertFromLineNumber + 1;\r\n\t\tconst startLineNumber = this.getStartLineNumber();\r\n\t\tconst endLineNumber = this.getEndLineNumber();\r\n\r\n\t\tif (insertFromLineNumber <= startLineNumber) {\r\n\t\t\t// inserting above the viewport\r\n\t\t\tthis._rendLineNumberStart += insertCnt;\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (insertFromLineNumber > endLineNumber) {\r\n\t\t\t// inserting below the viewport\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (insertCnt + insertFromLineNumber > endLineNumber) {\r\n\t\t\t// insert inside the viewport in such a way that all remaining lines are pushed outside\r\n\t\t\tconst deleted = this._lines.splice(insertFromLineNumber - this._rendLineNumberStart, endLineNumber - insertFromLineNumber + 1);\r\n\t\t\treturn deleted;\r\n\t\t}\r\n\r\n\t\t// insert inside the viewport, push out some lines, but not all remaining lines\r\n\t\tconst newLines: T[] = [];\r\n\t\tfor (let i = 0; i < insertCnt; i++) {\r\n\t\t\tnewLines[i] = this._createLine();\r\n\t\t}\r\n\t\tconst insertIndex = insertFromLineNumber - this._rendLineNumberStart;\r\n\t\tconst beforeLines = this._lines.slice(0, insertIndex);\r\n\t\tconst afterLines = this._lines.slice(insertIndex, this._lines.length - insertCnt);\r\n\t\tconst deletedLines = this._lines.slice(this._lines.length - insertCnt, this._lines.length);\r\n\r\n\t\tthis._lines = beforeLines.concat(newLines).concat(afterLines);\r\n\r\n\t\treturn deletedLines;\r\n\t}\r\n\r\n\tpublic onTokensChanged(ranges: { fromLineNumber: number; toLineNumber: number; }[]): boolean {\r\n\t\tif (this.getCount() === 0) {\r\n\t\t\t// no lines\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tconst startLineNumber = this.getStartLineNumber();\r\n\t\tconst endLineNumber = this.getEndLineNumber();\r\n\r\n\t\tlet notifiedSomeone = false;\r\n\t\tfor (let i = 0, len = ranges.length; i < len; i++) {\r\n\t\t\tconst rng = ranges[i];\r\n\r\n\t\t\tif (rng.toLineNumber < startLineNumber || rng.fromLineNumber > endLineNumber) {\r\n\t\t\t\t// range outside viewport\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tconst from = Math.max(startLineNumber, rng.fromLineNumber);\r\n\t\t\tconst to = Math.min(endLineNumber, rng.toLineNumber);\r\n\r\n\t\t\tfor (let lineNumber = from; lineNumber <= to; lineNumber++) {\r\n\t\t\t\tconst lineIndex = lineNumber - this._rendLineNumberStart;\r\n\t\t\t\tthis._lines[lineIndex].onTokensChanged();\r\n\t\t\t\tnotifiedSomeone = true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn notifiedSomeone;\r\n\t}\r\n}\r\n\r\nexport interface IVisibleLinesHost {\r\n\tcreateVisibleLine(): T;\r\n}\r\n\r\nexport class VisibleLinesCollection {\r\n\r\n\tprivate readonly _host: IVisibleLinesHost;\r\n\tpublic readonly domNode: FastDomNode;\r\n\tprivate readonly _linesCollection: RenderedLinesCollection;\r\n\r\n\tconstructor(host: IVisibleLinesHost) {\r\n\t\tthis._host = host;\r\n\t\tthis.domNode = this._createDomNode();\r\n\t\tthis._linesCollection = new RenderedLinesCollection(() => this._host.createVisibleLine());\r\n\t}\r\n\r\n\tprivate _createDomNode(): FastDomNode {\r\n\t\tconst domNode = createFastDomNode(document.createElement('div'));\r\n\t\tdomNode.setClassName('view-layer');\r\n\t\tdomNode.setPosition('absolute');\r\n\t\tdomNode.domNode.setAttribute('role', 'presentation');\r\n\t\tdomNode.domNode.setAttribute('aria-hidden', 'true');\r\n\t\treturn domNode;\r\n\t}\r\n\r\n\t// ---- begin view event handlers\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tif (e.hasChanged(EditorOption.layoutInfo)) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\r\n\t\tthis._linesCollection.flush();\r\n\t\t// No need to clear the dom node because a full .innerHTML will occur in ViewLayerRenderer._render\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\r\n\t\treturn this._linesCollection.onLinesChanged(e.fromLineNumber, e.toLineNumber);\r\n\t}\r\n\r\n\tpublic onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\r\n\t\tconst deleted = this._linesCollection.onLinesDeleted(e.fromLineNumber, e.toLineNumber);\r\n\t\tif (deleted) {\r\n\t\t\t// Remove from DOM\r\n\t\t\tfor (let i = 0, len = deleted.length; i < len; i++) {\r\n\t\t\t\tconst lineDomNode = deleted[i].getDomNode();\r\n\t\t\t\tif (lineDomNode) {\r\n\t\t\t\t\tthis.domNode.domNode.removeChild(lineDomNode);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\r\n\t\tconst deleted = this._linesCollection.onLinesInserted(e.fromLineNumber, e.toLineNumber);\r\n\t\tif (deleted) {\r\n\t\t\t// Remove from DOM\r\n\t\t\tfor (let i = 0, len = deleted.length; i < len; i++) {\r\n\t\t\t\tconst lineDomNode = deleted[i].getDomNode();\r\n\t\t\t\tif (lineDomNode) {\r\n\t\t\t\t\tthis.domNode.domNode.removeChild(lineDomNode);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\treturn e.scrollTopChanged;\r\n\t}\r\n\r\n\tpublic onTokensChanged(e: viewEvents.ViewTokensChangedEvent): boolean {\r\n\t\treturn this._linesCollection.onTokensChanged(e.ranges);\r\n\t}\r\n\r\n\tpublic onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// ---- end view event handlers\r\n\r\n\tpublic getStartLineNumber(): number {\r\n\t\treturn this._linesCollection.getStartLineNumber();\r\n\t}\r\n\r\n\tpublic getEndLineNumber(): number {\r\n\t\treturn this._linesCollection.getEndLineNumber();\r\n\t}\r\n\r\n\tpublic getVisibleLine(lineNumber: number): T {\r\n\t\treturn this._linesCollection.getLine(lineNumber);\r\n\t}\r\n\r\n\tpublic renderLines(viewportData: ViewportData): void {\r\n\r\n\t\tconst inp = this._linesCollection._get();\r\n\r\n\t\tconst renderer = new ViewLayerRenderer(this.domNode.domNode, this._host, viewportData);\r\n\r\n\t\tconst ctx: IRendererContext = {\r\n\t\t\trendLineNumberStart: inp.rendLineNumberStart,\r\n\t\t\tlines: inp.lines,\r\n\t\t\tlinesLength: inp.lines.length\r\n\t\t};\r\n\r\n\t\t// Decide if this render will do a single update (single large .innerHTML) or many updates (inserting/removing dom nodes)\r\n\t\tconst resCtx = renderer.render(ctx, viewportData.startLineNumber, viewportData.endLineNumber, viewportData.relativeVerticalOffset);\r\n\r\n\t\tthis._linesCollection._set(resCtx.rendLineNumberStart, resCtx.lines);\r\n\t}\r\n}\r\n\r\ninterface IRendererContext {\r\n\trendLineNumberStart: number;\r\n\tlines: T[];\r\n\tlinesLength: number;\r\n}\r\n\r\nclass ViewLayerRenderer {\r\n\r\n\tprivate static _ttPolicy = window.trustedTypes?.createPolicy('editorViewLayer', { createHTML: value => value });\r\n\r\n\treadonly domNode: HTMLElement;\r\n\treadonly host: IVisibleLinesHost;\r\n\treadonly viewportData: ViewportData;\r\n\r\n\tconstructor(domNode: HTMLElement, host: IVisibleLinesHost, viewportData: ViewportData) {\r\n\t\tthis.domNode = domNode;\r\n\t\tthis.host = host;\r\n\t\tthis.viewportData = viewportData;\r\n\t}\r\n\r\n\tpublic render(inContext: IRendererContext, startLineNumber: number, stopLineNumber: number, deltaTop: number[]): IRendererContext {\r\n\r\n\t\tconst ctx: IRendererContext = {\r\n\t\t\trendLineNumberStart: inContext.rendLineNumberStart,\r\n\t\t\tlines: inContext.lines.slice(0),\r\n\t\t\tlinesLength: inContext.linesLength\r\n\t\t};\r\n\r\n\t\tif ((ctx.rendLineNumberStart + ctx.linesLength - 1 < startLineNumber) || (stopLineNumber < ctx.rendLineNumberStart)) {\r\n\t\t\t// There is no overlap whatsoever\r\n\t\t\tctx.rendLineNumberStart = startLineNumber;\r\n\t\t\tctx.linesLength = stopLineNumber - startLineNumber + 1;\r\n\t\t\tctx.lines = [];\r\n\t\t\tfor (let x = startLineNumber; x <= stopLineNumber; x++) {\r\n\t\t\t\tctx.lines[x - startLineNumber] = this.host.createVisibleLine();\r\n\t\t\t}\r\n\t\t\tthis._finishRendering(ctx, true, deltaTop);\r\n\t\t\treturn ctx;\r\n\t\t}\r\n\r\n\t\t// Update lines which will remain untouched\r\n\t\tthis._renderUntouchedLines(\r\n\t\t\tctx,\r\n\t\t\tMath.max(startLineNumber - ctx.rendLineNumberStart, 0),\r\n\t\t\tMath.min(stopLineNumber - ctx.rendLineNumberStart, ctx.linesLength - 1),\r\n\t\t\tdeltaTop,\r\n\t\t\tstartLineNumber\r\n\t\t);\r\n\r\n\t\tif (ctx.rendLineNumberStart > startLineNumber) {\r\n\t\t\t// Insert lines before\r\n\t\t\tconst fromLineNumber = startLineNumber;\r\n\t\t\tconst toLineNumber = Math.min(stopLineNumber, ctx.rendLineNumberStart - 1);\r\n\t\t\tif (fromLineNumber <= toLineNumber) {\r\n\t\t\t\tthis._insertLinesBefore(ctx, fromLineNumber, toLineNumber, deltaTop, startLineNumber);\r\n\t\t\t\tctx.linesLength += toLineNumber - fromLineNumber + 1;\r\n\t\t\t}\r\n\t\t} else if (ctx.rendLineNumberStart < startLineNumber) {\r\n\t\t\t// Remove lines before\r\n\t\t\tconst removeCnt = Math.min(ctx.linesLength, startLineNumber - ctx.rendLineNumberStart);\r\n\t\t\tif (removeCnt > 0) {\r\n\t\t\t\tthis._removeLinesBefore(ctx, removeCnt);\r\n\t\t\t\tctx.linesLength -= removeCnt;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tctx.rendLineNumberStart = startLineNumber;\r\n\r\n\t\tif (ctx.rendLineNumberStart + ctx.linesLength - 1 < stopLineNumber) {\r\n\t\t\t// Insert lines after\r\n\t\t\tconst fromLineNumber = ctx.rendLineNumberStart + ctx.linesLength;\r\n\t\t\tconst toLineNumber = stopLineNumber;\r\n\r\n\t\t\tif (fromLineNumber <= toLineNumber) {\r\n\t\t\t\tthis._insertLinesAfter(ctx, fromLineNumber, toLineNumber, deltaTop, startLineNumber);\r\n\t\t\t\tctx.linesLength += toLineNumber - fromLineNumber + 1;\r\n\t\t\t}\r\n\r\n\t\t} else if (ctx.rendLineNumberStart + ctx.linesLength - 1 > stopLineNumber) {\r\n\t\t\t// Remove lines after\r\n\t\t\tconst fromLineNumber = Math.max(0, stopLineNumber - ctx.rendLineNumberStart + 1);\r\n\t\t\tconst toLineNumber = ctx.linesLength - 1;\r\n\t\t\tconst removeCnt = toLineNumber - fromLineNumber + 1;\r\n\r\n\t\t\tif (removeCnt > 0) {\r\n\t\t\t\tthis._removeLinesAfter(ctx, removeCnt);\r\n\t\t\t\tctx.linesLength -= removeCnt;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._finishRendering(ctx, false, deltaTop);\r\n\r\n\t\treturn ctx;\r\n\t}\r\n\r\n\tprivate _renderUntouchedLines(ctx: IRendererContext, startIndex: number, endIndex: number, deltaTop: number[], deltaLN: number): void {\r\n\t\tconst rendLineNumberStart = ctx.rendLineNumberStart;\r\n\t\tconst lines = ctx.lines;\r\n\r\n\t\tfor (let i = startIndex; i <= endIndex; i++) {\r\n\t\t\tconst lineNumber = rendLineNumberStart + i;\r\n\t\t\tlines[i].layoutLine(lineNumber, deltaTop[lineNumber - deltaLN]);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _insertLinesBefore(ctx: IRendererContext, fromLineNumber: number, toLineNumber: number, deltaTop: number[], deltaLN: number): void {\r\n\t\tconst newLines: T[] = [];\r\n\t\tlet newLinesLen = 0;\r\n\t\tfor (let lineNumber = fromLineNumber; lineNumber <= toLineNumber; lineNumber++) {\r\n\t\t\tnewLines[newLinesLen++] = this.host.createVisibleLine();\r\n\t\t}\r\n\t\tctx.lines = newLines.concat(ctx.lines);\r\n\t}\r\n\r\n\tprivate _removeLinesBefore(ctx: IRendererContext, removeCount: number): void {\r\n\t\tfor (let i = 0; i < removeCount; i++) {\r\n\t\t\tconst lineDomNode = ctx.lines[i].getDomNode();\r\n\t\t\tif (lineDomNode) {\r\n\t\t\t\tthis.domNode.removeChild(lineDomNode);\r\n\t\t\t}\r\n\t\t}\r\n\t\tctx.lines.splice(0, removeCount);\r\n\t}\r\n\r\n\tprivate _insertLinesAfter(ctx: IRendererContext, fromLineNumber: number, toLineNumber: number, deltaTop: number[], deltaLN: number): void {\r\n\t\tconst newLines: T[] = [];\r\n\t\tlet newLinesLen = 0;\r\n\t\tfor (let lineNumber = fromLineNumber; lineNumber <= toLineNumber; lineNumber++) {\r\n\t\t\tnewLines[newLinesLen++] = this.host.createVisibleLine();\r\n\t\t}\r\n\t\tctx.lines = ctx.lines.concat(newLines);\r\n\t}\r\n\r\n\tprivate _removeLinesAfter(ctx: IRendererContext, removeCount: number): void {\r\n\t\tconst removeIndex = ctx.linesLength - removeCount;\r\n\r\n\t\tfor (let i = 0; i < removeCount; i++) {\r\n\t\t\tconst lineDomNode = ctx.lines[removeIndex + i].getDomNode();\r\n\t\t\tif (lineDomNode) {\r\n\t\t\t\tthis.domNode.removeChild(lineDomNode);\r\n\t\t\t}\r\n\t\t}\r\n\t\tctx.lines.splice(removeIndex, removeCount);\r\n\t}\r\n\r\n\tprivate _finishRenderingNewLines(ctx: IRendererContext, domNodeIsEmpty: boolean, newLinesHTML: string | TrustedHTML, wasNew: boolean[]): void {\r\n\t\tif (ViewLayerRenderer._ttPolicy) {\r\n\t\t\tnewLinesHTML = ViewLayerRenderer._ttPolicy.createHTML(newLinesHTML as string);\r\n\t\t}\r\n\t\tconst lastChild = this.domNode.lastChild;\r\n\t\tif (domNodeIsEmpty || !lastChild) {\r\n\t\t\tthis.domNode.innerHTML = newLinesHTML as string; // explains the ugly casts -> https://github.com/microsoft/vscode/issues/106396#issuecomment-692625393;\r\n\t\t} else {\r\n\t\t\tlastChild.insertAdjacentHTML('afterend', newLinesHTML as string);\r\n\t\t}\r\n\r\n\t\tlet currChild = this.domNode.lastChild;\r\n\t\tfor (let i = ctx.linesLength - 1; i >= 0; i--) {\r\n\t\t\tconst line = ctx.lines[i];\r\n\t\t\tif (wasNew[i]) {\r\n\t\t\t\tline.setDomNode(currChild);\r\n\t\t\t\tcurrChild = currChild.previousSibling;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _finishRenderingInvalidLines(ctx: IRendererContext, invalidLinesHTML: string | TrustedHTML, wasInvalid: boolean[]): void {\r\n\t\tconst hugeDomNode = document.createElement('div');\r\n\r\n\t\tif (ViewLayerRenderer._ttPolicy) {\r\n\t\t\tinvalidLinesHTML = ViewLayerRenderer._ttPolicy.createHTML(invalidLinesHTML as string);\r\n\t\t}\r\n\t\thugeDomNode.innerHTML = invalidLinesHTML as string;\r\n\r\n\t\tfor (let i = 0; i < ctx.linesLength; i++) {\r\n\t\t\tconst line = ctx.lines[i];\r\n\t\t\tif (wasInvalid[i]) {\r\n\t\t\t\tconst source = hugeDomNode.firstChild;\r\n\t\t\t\tconst lineDomNode = line.getDomNode()!;\r\n\t\t\t\tlineDomNode.parentNode!.replaceChild(source, lineDomNode);\r\n\t\t\t\tline.setDomNode(source);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static readonly _sb = createStringBuilder(100000);\r\n\r\n\tprivate _finishRendering(ctx: IRendererContext, domNodeIsEmpty: boolean, deltaTop: number[]): void {\r\n\r\n\t\tconst sb = ViewLayerRenderer._sb;\r\n\t\tconst linesLength = ctx.linesLength;\r\n\t\tconst lines = ctx.lines;\r\n\t\tconst rendLineNumberStart = ctx.rendLineNumberStart;\r\n\r\n\t\tconst wasNew: boolean[] = [];\r\n\t\t{\r\n\t\t\tsb.reset();\r\n\t\t\tlet hadNewLine = false;\r\n\r\n\t\t\tfor (let i = 0; i < linesLength; i++) {\r\n\t\t\t\tconst line = lines[i];\r\n\t\t\t\twasNew[i] = false;\r\n\r\n\t\t\t\tconst lineDomNode = line.getDomNode();\r\n\t\t\t\tif (lineDomNode) {\r\n\t\t\t\t\t// line is not new\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst renderResult = line.renderLine(i + rendLineNumberStart, deltaTop[i], this.viewportData, sb);\r\n\t\t\t\tif (!renderResult) {\r\n\t\t\t\t\t// line does not need rendering\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\twasNew[i] = true;\r\n\t\t\t\thadNewLine = true;\r\n\t\t\t}\r\n\r\n\t\t\tif (hadNewLine) {\r\n\t\t\t\tthis._finishRenderingNewLines(ctx, domNodeIsEmpty, sb.build(), wasNew);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t{\r\n\t\t\tsb.reset();\r\n\r\n\t\t\tlet hadInvalidLine = false;\r\n\t\t\tconst wasInvalid: boolean[] = [];\r\n\r\n\t\t\tfor (let i = 0; i < linesLength; i++) {\r\n\t\t\t\tconst line = lines[i];\r\n\t\t\t\twasInvalid[i] = false;\r\n\r\n\t\t\t\tif (wasNew[i]) {\r\n\t\t\t\t\t// line was new\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst renderResult = line.renderLine(i + rendLineNumberStart, deltaTop[i], this.viewportData, sb);\r\n\t\t\t\tif (!renderResult) {\r\n\t\t\t\t\t// line does not need rendering\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\twasInvalid[i] = true;\r\n\t\t\t\thadInvalidLine = true;\r\n\t\t\t}\r\n\r\n\t\t\tif (hadInvalidLine) {\r\n\t\t\t\tthis._finishRenderingInvalidLines(ctx, sb.build(), wasInvalid);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IState } from 'vs/editor/common/modes';\r\n\r\nexport class Token {\r\n\t_tokenBrand: void;\r\n\r\n\tpublic readonly offset: number;\r\n\tpublic readonly type: string;\r\n\tpublic readonly language: string;\r\n\r\n\tconstructor(offset: number, type: string, language: string) {\r\n\t\tthis.offset = offset | 0;// @perf\r\n\t\tthis.type = type;\r\n\t\tthis.language = language;\r\n\t}\r\n\r\n\tpublic toString(): string {\r\n\t\treturn '(' + this.offset + ', ' + this.type + ')';\r\n\t}\r\n}\r\n\r\nexport class TokenizationResult {\r\n\t_tokenizationResultBrand: void;\r\n\r\n\tpublic readonly tokens: Token[];\r\n\tpublic readonly endState: IState;\r\n\r\n\tconstructor(tokens: Token[], endState: IState) {\r\n\t\tthis.tokens = tokens;\r\n\t\tthis.endState = endState;\r\n\t}\r\n}\r\n\r\nexport class TokenizationResult2 {\r\n\t_tokenizationResult2Brand: void;\r\n\r\n\t/**\r\n\t * The tokens in binary format. Each token occupies two array indices. For token i:\r\n\t * - at offset 2*i => startIndex\r\n\t * - at offset 2*i + 1 => metadata\r\n\t *\r\n\t */\r\n\tpublic readonly tokens: Uint32Array;\r\n\tpublic readonly endState: IState;\r\n\r\n\tconstructor(tokens: Uint32Array, endState: IState) {\r\n\t\tthis.tokens = tokens;\r\n\t\tthis.endState = endState;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IDiffChange, ISequence, LcsDiff, IDiffResult } from 'vs/base/common/diff/diff';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { ICharChange, ILineChange } from 'vs/editor/common/editorCommon';\r\n\r\nconst MINIMUM_MATCHING_CHARACTER_LENGTH = 3;\r\n\r\nexport interface IDiffComputerResult {\r\n\tquitEarly: boolean;\r\n\tchanges: ILineChange[];\r\n}\r\n\r\nfunction computeDiff(originalSequence: ISequence, modifiedSequence: ISequence, continueProcessingPredicate: () => boolean, pretty: boolean): IDiffResult {\r\n\tconst diffAlgo = new LcsDiff(originalSequence, modifiedSequence, continueProcessingPredicate);\r\n\treturn diffAlgo.ComputeDiff(pretty);\r\n}\r\n\r\nclass LineSequence implements ISequence {\r\n\r\n\tpublic readonly lines: string[];\r\n\tprivate readonly _startColumns: number[];\r\n\tprivate readonly _endColumns: number[];\r\n\r\n\tconstructor(lines: string[]) {\r\n\t\tconst startColumns: number[] = [];\r\n\t\tconst endColumns: number[] = [];\r\n\t\tfor (let i = 0, length = lines.length; i < length; i++) {\r\n\t\t\tstartColumns[i] = getFirstNonBlankColumn(lines[i], 1);\r\n\t\t\tendColumns[i] = getLastNonBlankColumn(lines[i], 1);\r\n\t\t}\r\n\t\tthis.lines = lines;\r\n\t\tthis._startColumns = startColumns;\r\n\t\tthis._endColumns = endColumns;\r\n\t}\r\n\r\n\tpublic getElements(): Int32Array | number[] | string[] {\r\n\t\tconst elements: string[] = [];\r\n\t\tfor (let i = 0, len = this.lines.length; i < len; i++) {\r\n\t\t\telements[i] = this.lines[i].substring(this._startColumns[i] - 1, this._endColumns[i] - 1);\r\n\t\t}\r\n\t\treturn elements;\r\n\t}\r\n\r\n\tpublic getStartLineNumber(i: number): number {\r\n\t\treturn i + 1;\r\n\t}\r\n\r\n\tpublic getEndLineNumber(i: number): number {\r\n\t\treturn i + 1;\r\n\t}\r\n\r\n\tpublic createCharSequence(shouldIgnoreTrimWhitespace: boolean, startIndex: number, endIndex: number): CharSequence {\r\n\t\tconst charCodes: number[] = [];\r\n\t\tconst lineNumbers: number[] = [];\r\n\t\tconst columns: number[] = [];\r\n\t\tlet len = 0;\r\n\t\tfor (let index = startIndex; index <= endIndex; index++) {\r\n\t\t\tconst lineContent = this.lines[index];\r\n\t\t\tconst startColumn = (shouldIgnoreTrimWhitespace ? this._startColumns[index] : 1);\r\n\t\t\tconst endColumn = (shouldIgnoreTrimWhitespace ? this._endColumns[index] : lineContent.length + 1);\r\n\t\t\tfor (let col = startColumn; col < endColumn; col++) {\r\n\t\t\t\tcharCodes[len] = lineContent.charCodeAt(col - 1);\r\n\t\t\t\tlineNumbers[len] = index + 1;\r\n\t\t\t\tcolumns[len] = col;\r\n\t\t\t\tlen++;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn new CharSequence(charCodes, lineNumbers, columns);\r\n\t}\r\n}\r\n\r\nclass CharSequence implements ISequence {\r\n\r\n\tprivate readonly _charCodes: number[];\r\n\tprivate readonly _lineNumbers: number[];\r\n\tprivate readonly _columns: number[];\r\n\r\n\tconstructor(charCodes: number[], lineNumbers: number[], columns: number[]) {\r\n\t\tthis._charCodes = charCodes;\r\n\t\tthis._lineNumbers = lineNumbers;\r\n\t\tthis._columns = columns;\r\n\t}\r\n\r\n\tpublic getElements(): Int32Array | number[] | string[] {\r\n\t\treturn this._charCodes;\r\n\t}\r\n\r\n\tpublic getStartLineNumber(i: number): number {\r\n\t\treturn this._lineNumbers[i];\r\n\t}\r\n\r\n\tpublic getStartColumn(i: number): number {\r\n\t\treturn this._columns[i];\r\n\t}\r\n\r\n\tpublic getEndLineNumber(i: number): number {\r\n\t\treturn this._lineNumbers[i];\r\n\t}\r\n\r\n\tpublic getEndColumn(i: number): number {\r\n\t\treturn this._columns[i] + 1;\r\n\t}\r\n}\r\n\r\nclass CharChange implements ICharChange {\r\n\r\n\tpublic originalStartLineNumber: number;\r\n\tpublic originalStartColumn: number;\r\n\tpublic originalEndLineNumber: number;\r\n\tpublic originalEndColumn: number;\r\n\r\n\tpublic modifiedStartLineNumber: number;\r\n\tpublic modifiedStartColumn: number;\r\n\tpublic modifiedEndLineNumber: number;\r\n\tpublic modifiedEndColumn: number;\r\n\r\n\tconstructor(\r\n\t\toriginalStartLineNumber: number,\r\n\t\toriginalStartColumn: number,\r\n\t\toriginalEndLineNumber: number,\r\n\t\toriginalEndColumn: number,\r\n\t\tmodifiedStartLineNumber: number,\r\n\t\tmodifiedStartColumn: number,\r\n\t\tmodifiedEndLineNumber: number,\r\n\t\tmodifiedEndColumn: number\r\n\t) {\r\n\t\tthis.originalStartLineNumber = originalStartLineNumber;\r\n\t\tthis.originalStartColumn = originalStartColumn;\r\n\t\tthis.originalEndLineNumber = originalEndLineNumber;\r\n\t\tthis.originalEndColumn = originalEndColumn;\r\n\t\tthis.modifiedStartLineNumber = modifiedStartLineNumber;\r\n\t\tthis.modifiedStartColumn = modifiedStartColumn;\r\n\t\tthis.modifiedEndLineNumber = modifiedEndLineNumber;\r\n\t\tthis.modifiedEndColumn = modifiedEndColumn;\r\n\t}\r\n\r\n\tpublic static createFromDiffChange(diffChange: IDiffChange, originalCharSequence: CharSequence, modifiedCharSequence: CharSequence): CharChange {\r\n\t\tlet originalStartLineNumber: number;\r\n\t\tlet originalStartColumn: number;\r\n\t\tlet originalEndLineNumber: number;\r\n\t\tlet originalEndColumn: number;\r\n\t\tlet modifiedStartLineNumber: number;\r\n\t\tlet modifiedStartColumn: number;\r\n\t\tlet modifiedEndLineNumber: number;\r\n\t\tlet modifiedEndColumn: number;\r\n\r\n\t\tif (diffChange.originalLength === 0) {\r\n\t\t\toriginalStartLineNumber = 0;\r\n\t\t\toriginalStartColumn = 0;\r\n\t\t\toriginalEndLineNumber = 0;\r\n\t\t\toriginalEndColumn = 0;\r\n\t\t} else {\r\n\t\t\toriginalStartLineNumber = originalCharSequence.getStartLineNumber(diffChange.originalStart);\r\n\t\t\toriginalStartColumn = originalCharSequence.getStartColumn(diffChange.originalStart);\r\n\t\t\toriginalEndLineNumber = originalCharSequence.getEndLineNumber(diffChange.originalStart + diffChange.originalLength - 1);\r\n\t\t\toriginalEndColumn = originalCharSequence.getEndColumn(diffChange.originalStart + diffChange.originalLength - 1);\r\n\t\t}\r\n\r\n\t\tif (diffChange.modifiedLength === 0) {\r\n\t\t\tmodifiedStartLineNumber = 0;\r\n\t\t\tmodifiedStartColumn = 0;\r\n\t\t\tmodifiedEndLineNumber = 0;\r\n\t\t\tmodifiedEndColumn = 0;\r\n\t\t} else {\r\n\t\t\tmodifiedStartLineNumber = modifiedCharSequence.getStartLineNumber(diffChange.modifiedStart);\r\n\t\t\tmodifiedStartColumn = modifiedCharSequence.getStartColumn(diffChange.modifiedStart);\r\n\t\t\tmodifiedEndLineNumber = modifiedCharSequence.getEndLineNumber(diffChange.modifiedStart + diffChange.modifiedLength - 1);\r\n\t\t\tmodifiedEndColumn = modifiedCharSequence.getEndColumn(diffChange.modifiedStart + diffChange.modifiedLength - 1);\r\n\t\t}\r\n\r\n\t\treturn new CharChange(\r\n\t\t\toriginalStartLineNumber, originalStartColumn, originalEndLineNumber, originalEndColumn,\r\n\t\t\tmodifiedStartLineNumber, modifiedStartColumn, modifiedEndLineNumber, modifiedEndColumn,\r\n\t\t);\r\n\t}\r\n}\r\n\r\nfunction postProcessCharChanges(rawChanges: IDiffChange[]): IDiffChange[] {\r\n\tif (rawChanges.length <= 1) {\r\n\t\treturn rawChanges;\r\n\t}\r\n\r\n\tconst result = [rawChanges[0]];\r\n\tlet prevChange = result[0];\r\n\r\n\tfor (let i = 1, len = rawChanges.length; i < len; i++) {\r\n\t\tconst currChange = rawChanges[i];\r\n\r\n\t\tconst originalMatchingLength = currChange.originalStart - (prevChange.originalStart + prevChange.originalLength);\r\n\t\tconst modifiedMatchingLength = currChange.modifiedStart - (prevChange.modifiedStart + prevChange.modifiedLength);\r\n\t\t// Both of the above should be equal, but the continueProcessingPredicate may prevent this from being true\r\n\t\tconst matchingLength = Math.min(originalMatchingLength, modifiedMatchingLength);\r\n\r\n\t\tif (matchingLength < MINIMUM_MATCHING_CHARACTER_LENGTH) {\r\n\t\t\t// Merge the current change into the previous one\r\n\t\t\tprevChange.originalLength = (currChange.originalStart + currChange.originalLength) - prevChange.originalStart;\r\n\t\t\tprevChange.modifiedLength = (currChange.modifiedStart + currChange.modifiedLength) - prevChange.modifiedStart;\r\n\t\t} else {\r\n\t\t\t// Add the current change\r\n\t\t\tresult.push(currChange);\r\n\t\t\tprevChange = currChange;\r\n\t\t}\r\n\t}\r\n\r\n\treturn result;\r\n}\r\n\r\nclass LineChange implements ILineChange {\r\n\tpublic originalStartLineNumber: number;\r\n\tpublic originalEndLineNumber: number;\r\n\tpublic modifiedStartLineNumber: number;\r\n\tpublic modifiedEndLineNumber: number;\r\n\tpublic charChanges: CharChange[] | undefined;\r\n\r\n\tconstructor(\r\n\t\toriginalStartLineNumber: number,\r\n\t\toriginalEndLineNumber: number,\r\n\t\tmodifiedStartLineNumber: number,\r\n\t\tmodifiedEndLineNumber: number,\r\n\t\tcharChanges: CharChange[] | undefined\r\n\t) {\r\n\t\tthis.originalStartLineNumber = originalStartLineNumber;\r\n\t\tthis.originalEndLineNumber = originalEndLineNumber;\r\n\t\tthis.modifiedStartLineNumber = modifiedStartLineNumber;\r\n\t\tthis.modifiedEndLineNumber = modifiedEndLineNumber;\r\n\t\tthis.charChanges = charChanges;\r\n\t}\r\n\r\n\tpublic static createFromDiffResult(shouldIgnoreTrimWhitespace: boolean, diffChange: IDiffChange, originalLineSequence: LineSequence, modifiedLineSequence: LineSequence, continueCharDiff: () => boolean, shouldComputeCharChanges: boolean, shouldPostProcessCharChanges: boolean): LineChange {\r\n\t\tlet originalStartLineNumber: number;\r\n\t\tlet originalEndLineNumber: number;\r\n\t\tlet modifiedStartLineNumber: number;\r\n\t\tlet modifiedEndLineNumber: number;\r\n\t\tlet charChanges: CharChange[] | undefined = undefined;\r\n\r\n\t\tif (diffChange.originalLength === 0) {\r\n\t\t\toriginalStartLineNumber = originalLineSequence.getStartLineNumber(diffChange.originalStart) - 1;\r\n\t\t\toriginalEndLineNumber = 0;\r\n\t\t} else {\r\n\t\t\toriginalStartLineNumber = originalLineSequence.getStartLineNumber(diffChange.originalStart);\r\n\t\t\toriginalEndLineNumber = originalLineSequence.getEndLineNumber(diffChange.originalStart + diffChange.originalLength - 1);\r\n\t\t}\r\n\r\n\t\tif (diffChange.modifiedLength === 0) {\r\n\t\t\tmodifiedStartLineNumber = modifiedLineSequence.getStartLineNumber(diffChange.modifiedStart) - 1;\r\n\t\t\tmodifiedEndLineNumber = 0;\r\n\t\t} else {\r\n\t\t\tmodifiedStartLineNumber = modifiedLineSequence.getStartLineNumber(diffChange.modifiedStart);\r\n\t\t\tmodifiedEndLineNumber = modifiedLineSequence.getEndLineNumber(diffChange.modifiedStart + diffChange.modifiedLength - 1);\r\n\t\t}\r\n\r\n\t\tif (shouldComputeCharChanges && diffChange.originalLength > 0 && diffChange.originalLength < 20 && diffChange.modifiedLength > 0 && diffChange.modifiedLength < 20 && continueCharDiff()) {\r\n\t\t\t// Compute character changes for diff chunks of at most 20 lines...\r\n\t\t\tconst originalCharSequence = originalLineSequence.createCharSequence(shouldIgnoreTrimWhitespace, diffChange.originalStart, diffChange.originalStart + diffChange.originalLength - 1);\r\n\t\t\tconst modifiedCharSequence = modifiedLineSequence.createCharSequence(shouldIgnoreTrimWhitespace, diffChange.modifiedStart, diffChange.modifiedStart + diffChange.modifiedLength - 1);\r\n\r\n\t\t\tlet rawChanges = computeDiff(originalCharSequence, modifiedCharSequence, continueCharDiff, true).changes;\r\n\r\n\t\t\tif (shouldPostProcessCharChanges) {\r\n\t\t\t\trawChanges = postProcessCharChanges(rawChanges);\r\n\t\t\t}\r\n\r\n\t\t\tcharChanges = [];\r\n\t\t\tfor (let i = 0, length = rawChanges.length; i < length; i++) {\r\n\t\t\t\tcharChanges.push(CharChange.createFromDiffChange(rawChanges[i], originalCharSequence, modifiedCharSequence));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn new LineChange(originalStartLineNumber, originalEndLineNumber, modifiedStartLineNumber, modifiedEndLineNumber, charChanges);\r\n\t}\r\n}\r\n\r\nexport interface IDiffComputerOpts {\r\n\tshouldComputeCharChanges: boolean;\r\n\tshouldPostProcessCharChanges: boolean;\r\n\tshouldIgnoreTrimWhitespace: boolean;\r\n\tshouldMakePrettyDiff: boolean;\r\n\tmaxComputationTime: number;\r\n}\r\n\r\nexport class DiffComputer {\r\n\r\n\tprivate readonly shouldComputeCharChanges: boolean;\r\n\tprivate readonly shouldPostProcessCharChanges: boolean;\r\n\tprivate readonly shouldIgnoreTrimWhitespace: boolean;\r\n\tprivate readonly shouldMakePrettyDiff: boolean;\r\n\tprivate readonly originalLines: string[];\r\n\tprivate readonly modifiedLines: string[];\r\n\tprivate readonly original: LineSequence;\r\n\tprivate readonly modified: LineSequence;\r\n\tprivate readonly continueLineDiff: () => boolean;\r\n\tprivate readonly continueCharDiff: () => boolean;\r\n\r\n\tconstructor(originalLines: string[], modifiedLines: string[], opts: IDiffComputerOpts) {\r\n\t\tthis.shouldComputeCharChanges = opts.shouldComputeCharChanges;\r\n\t\tthis.shouldPostProcessCharChanges = opts.shouldPostProcessCharChanges;\r\n\t\tthis.shouldIgnoreTrimWhitespace = opts.shouldIgnoreTrimWhitespace;\r\n\t\tthis.shouldMakePrettyDiff = opts.shouldMakePrettyDiff;\r\n\t\tthis.originalLines = originalLines;\r\n\t\tthis.modifiedLines = modifiedLines;\r\n\t\tthis.original = new LineSequence(originalLines);\r\n\t\tthis.modified = new LineSequence(modifiedLines);\r\n\r\n\t\tthis.continueLineDiff = createContinueProcessingPredicate(opts.maxComputationTime);\r\n\t\tthis.continueCharDiff = createContinueProcessingPredicate(opts.maxComputationTime === 0 ? 0 : Math.min(opts.maxComputationTime, 5000)); // never run after 5s for character changes...\r\n\t}\r\n\r\n\tpublic computeDiff(): IDiffComputerResult {\r\n\r\n\t\tif (this.original.lines.length === 1 && this.original.lines[0].length === 0) {\r\n\t\t\t// empty original => fast path\r\n\t\t\tif (this.modified.lines.length === 1 && this.modified.lines[0].length === 0) {\r\n\t\t\t\treturn {\r\n\t\t\t\t\tquitEarly: false,\r\n\t\t\t\t\tchanges: []\r\n\t\t\t\t};\r\n\t\t\t}\r\n\r\n\t\t\treturn {\r\n\t\t\t\tquitEarly: false,\r\n\t\t\t\tchanges: [{\r\n\t\t\t\t\toriginalStartLineNumber: 1,\r\n\t\t\t\t\toriginalEndLineNumber: 1,\r\n\t\t\t\t\tmodifiedStartLineNumber: 1,\r\n\t\t\t\t\tmodifiedEndLineNumber: this.modified.lines.length,\r\n\t\t\t\t\tcharChanges: [{\r\n\t\t\t\t\t\tmodifiedEndColumn: 0,\r\n\t\t\t\t\t\tmodifiedEndLineNumber: 0,\r\n\t\t\t\t\t\tmodifiedStartColumn: 0,\r\n\t\t\t\t\t\tmodifiedStartLineNumber: 0,\r\n\t\t\t\t\t\toriginalEndColumn: 0,\r\n\t\t\t\t\t\toriginalEndLineNumber: 0,\r\n\t\t\t\t\t\toriginalStartColumn: 0,\r\n\t\t\t\t\t\toriginalStartLineNumber: 0\r\n\t\t\t\t\t}]\r\n\t\t\t\t}]\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tif (this.modified.lines.length === 1 && this.modified.lines[0].length === 0) {\r\n\t\t\t// empty modified => fast path\r\n\t\t\treturn {\r\n\t\t\t\tquitEarly: false,\r\n\t\t\t\tchanges: [{\r\n\t\t\t\t\toriginalStartLineNumber: 1,\r\n\t\t\t\t\toriginalEndLineNumber: this.original.lines.length,\r\n\t\t\t\t\tmodifiedStartLineNumber: 1,\r\n\t\t\t\t\tmodifiedEndLineNumber: 1,\r\n\t\t\t\t\tcharChanges: [{\r\n\t\t\t\t\t\tmodifiedEndColumn: 0,\r\n\t\t\t\t\t\tmodifiedEndLineNumber: 0,\r\n\t\t\t\t\t\tmodifiedStartColumn: 0,\r\n\t\t\t\t\t\tmodifiedStartLineNumber: 0,\r\n\t\t\t\t\t\toriginalEndColumn: 0,\r\n\t\t\t\t\t\toriginalEndLineNumber: 0,\r\n\t\t\t\t\t\toriginalStartColumn: 0,\r\n\t\t\t\t\t\toriginalStartLineNumber: 0\r\n\t\t\t\t\t}]\r\n\t\t\t\t}]\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tconst diffResult = computeDiff(this.original, this.modified, this.continueLineDiff, this.shouldMakePrettyDiff);\r\n\t\tconst rawChanges = diffResult.changes;\r\n\t\tconst quitEarly = diffResult.quitEarly;\r\n\r\n\t\t// The diff is always computed with ignoring trim whitespace\r\n\t\t// This ensures we get the prettiest diff\r\n\r\n\t\tif (this.shouldIgnoreTrimWhitespace) {\r\n\t\t\tconst lineChanges: LineChange[] = [];\r\n\t\t\tfor (let i = 0, length = rawChanges.length; i < length; i++) {\r\n\t\t\t\tlineChanges.push(LineChange.createFromDiffResult(this.shouldIgnoreTrimWhitespace, rawChanges[i], this.original, this.modified, this.continueCharDiff, this.shouldComputeCharChanges, this.shouldPostProcessCharChanges));\r\n\t\t\t}\r\n\t\t\treturn {\r\n\t\t\t\tquitEarly: quitEarly,\r\n\t\t\t\tchanges: lineChanges\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\t// Need to post-process and introduce changes where the trim whitespace is different\r\n\t\t// Note that we are looping starting at -1 to also cover the lines before the first change\r\n\t\tconst result: LineChange[] = [];\r\n\r\n\t\tlet originalLineIndex = 0;\r\n\t\tlet modifiedLineIndex = 0;\r\n\t\tfor (let i = -1 /* !!!! */, len = rawChanges.length; i < len; i++) {\r\n\t\t\tconst nextChange = (i + 1 < len ? rawChanges[i + 1] : null);\r\n\t\t\tconst originalStop = (nextChange ? nextChange.originalStart : this.originalLines.length);\r\n\t\t\tconst modifiedStop = (nextChange ? nextChange.modifiedStart : this.modifiedLines.length);\r\n\r\n\t\t\twhile (originalLineIndex < originalStop && modifiedLineIndex < modifiedStop) {\r\n\t\t\t\tconst originalLine = this.originalLines[originalLineIndex];\r\n\t\t\t\tconst modifiedLine = this.modifiedLines[modifiedLineIndex];\r\n\r\n\t\t\t\tif (originalLine !== modifiedLine) {\r\n\t\t\t\t\t// These lines differ only in trim whitespace\r\n\r\n\t\t\t\t\t// Check the leading whitespace\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tlet originalStartColumn = getFirstNonBlankColumn(originalLine, 1);\r\n\t\t\t\t\t\tlet modifiedStartColumn = getFirstNonBlankColumn(modifiedLine, 1);\r\n\t\t\t\t\t\twhile (originalStartColumn > 1 && modifiedStartColumn > 1) {\r\n\t\t\t\t\t\t\tconst originalChar = originalLine.charCodeAt(originalStartColumn - 2);\r\n\t\t\t\t\t\t\tconst modifiedChar = modifiedLine.charCodeAt(modifiedStartColumn - 2);\r\n\t\t\t\t\t\t\tif (originalChar !== modifiedChar) {\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\toriginalStartColumn--;\r\n\t\t\t\t\t\t\tmodifiedStartColumn--;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif (originalStartColumn > 1 || modifiedStartColumn > 1) {\r\n\t\t\t\t\t\t\tthis._pushTrimWhitespaceCharChange(result,\r\n\t\t\t\t\t\t\t\toriginalLineIndex + 1, 1, originalStartColumn,\r\n\t\t\t\t\t\t\t\tmodifiedLineIndex + 1, 1, modifiedStartColumn\r\n\t\t\t\t\t\t\t);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t// Check the trailing whitespace\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tlet originalEndColumn = getLastNonBlankColumn(originalLine, 1);\r\n\t\t\t\t\t\tlet modifiedEndColumn = getLastNonBlankColumn(modifiedLine, 1);\r\n\t\t\t\t\t\tconst originalMaxColumn = originalLine.length + 1;\r\n\t\t\t\t\t\tconst modifiedMaxColumn = modifiedLine.length + 1;\r\n\t\t\t\t\t\twhile (originalEndColumn < originalMaxColumn && modifiedEndColumn < modifiedMaxColumn) {\r\n\t\t\t\t\t\t\tconst originalChar = originalLine.charCodeAt(originalEndColumn - 1);\r\n\t\t\t\t\t\t\tconst modifiedChar = originalLine.charCodeAt(modifiedEndColumn - 1);\r\n\t\t\t\t\t\t\tif (originalChar !== modifiedChar) {\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\toriginalEndColumn++;\r\n\t\t\t\t\t\t\tmodifiedEndColumn++;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif (originalEndColumn < originalMaxColumn || modifiedEndColumn < modifiedMaxColumn) {\r\n\t\t\t\t\t\t\tthis._pushTrimWhitespaceCharChange(result,\r\n\t\t\t\t\t\t\t\toriginalLineIndex + 1, originalEndColumn, originalMaxColumn,\r\n\t\t\t\t\t\t\t\tmodifiedLineIndex + 1, modifiedEndColumn, modifiedMaxColumn\r\n\t\t\t\t\t\t\t);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\toriginalLineIndex++;\r\n\t\t\t\tmodifiedLineIndex++;\r\n\t\t\t}\r\n\r\n\t\t\tif (nextChange) {\r\n\t\t\t\t// Emit the actual change\r\n\t\t\t\tresult.push(LineChange.createFromDiffResult(this.shouldIgnoreTrimWhitespace, nextChange, this.original, this.modified, this.continueCharDiff, this.shouldComputeCharChanges, this.shouldPostProcessCharChanges));\r\n\r\n\t\t\t\toriginalLineIndex += nextChange.originalLength;\r\n\t\t\t\tmodifiedLineIndex += nextChange.modifiedLength;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tquitEarly: quitEarly,\r\n\t\t\tchanges: result\r\n\t\t};\r\n\t}\r\n\r\n\tprivate _pushTrimWhitespaceCharChange(\r\n\t\tresult: LineChange[],\r\n\t\toriginalLineNumber: number, originalStartColumn: number, originalEndColumn: number,\r\n\t\tmodifiedLineNumber: number, modifiedStartColumn: number, modifiedEndColumn: number\r\n\t): void {\r\n\t\tif (this._mergeTrimWhitespaceCharChange(result, originalLineNumber, originalStartColumn, originalEndColumn, modifiedLineNumber, modifiedStartColumn, modifiedEndColumn)) {\r\n\t\t\t// Merged into previous\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet charChanges: CharChange[] | undefined = undefined;\r\n\t\tif (this.shouldComputeCharChanges) {\r\n\t\t\tcharChanges = [new CharChange(\r\n\t\t\t\toriginalLineNumber, originalStartColumn, originalLineNumber, originalEndColumn,\r\n\t\t\t\tmodifiedLineNumber, modifiedStartColumn, modifiedLineNumber, modifiedEndColumn\r\n\t\t\t)];\r\n\t\t}\r\n\t\tresult.push(new LineChange(\r\n\t\t\toriginalLineNumber, originalLineNumber,\r\n\t\t\tmodifiedLineNumber, modifiedLineNumber,\r\n\t\t\tcharChanges\r\n\t\t));\r\n\t}\r\n\r\n\tprivate _mergeTrimWhitespaceCharChange(\r\n\t\tresult: LineChange[],\r\n\t\toriginalLineNumber: number, originalStartColumn: number, originalEndColumn: number,\r\n\t\tmodifiedLineNumber: number, modifiedStartColumn: number, modifiedEndColumn: number\r\n\t): boolean {\r\n\t\tconst len = result.length;\r\n\t\tif (len === 0) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tconst prevChange = result[len - 1];\r\n\r\n\t\tif (prevChange.originalEndLineNumber === 0 || prevChange.modifiedEndLineNumber === 0) {\r\n\t\t\t// Don't merge with inserts/deletes\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tif (prevChange.originalEndLineNumber + 1 === originalLineNumber && prevChange.modifiedEndLineNumber + 1 === modifiedLineNumber) {\r\n\t\t\tprevChange.originalEndLineNumber = originalLineNumber;\r\n\t\t\tprevChange.modifiedEndLineNumber = modifiedLineNumber;\r\n\t\t\tif (this.shouldComputeCharChanges && prevChange.charChanges) {\r\n\t\t\t\tprevChange.charChanges.push(new CharChange(\r\n\t\t\t\t\toriginalLineNumber, originalStartColumn, originalLineNumber, originalEndColumn,\r\n\t\t\t\t\tmodifiedLineNumber, modifiedStartColumn, modifiedLineNumber, modifiedEndColumn\r\n\t\t\t\t));\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\nfunction getFirstNonBlankColumn(txt: string, defaultValue: number): number {\r\n\tconst r = strings.firstNonWhitespaceIndex(txt);\r\n\tif (r === -1) {\r\n\t\treturn defaultValue;\r\n\t}\r\n\treturn r + 1;\r\n}\r\n\r\nfunction getLastNonBlankColumn(txt: string, defaultValue: number): number {\r\n\tconst r = strings.lastNonWhitespaceIndex(txt);\r\n\tif (r === -1) {\r\n\t\treturn defaultValue;\r\n\t}\r\n\treturn r + 2;\r\n}\r\n\r\nfunction createContinueProcessingPredicate(maximumRuntime: number): () => boolean {\r\n\tif (maximumRuntime === 0) {\r\n\t\treturn () => true;\r\n\t}\r\n\r\n\tconst startTime = Date.now();\r\n\treturn () => {\r\n\t\treturn Date.now() - startTime < maximumRuntime;\r\n\t};\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IEditorAction } from 'vs/editor/common/editorCommon';\r\nimport { IContextKeyService, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';\r\n\r\nexport class InternalEditorAction implements IEditorAction {\r\n\r\n\tpublic readonly id: string;\r\n\tpublic readonly label: string;\r\n\tpublic readonly alias: string;\r\n\r\n\tprivate readonly _precondition: ContextKeyExpression | undefined;\r\n\tprivate readonly _run: () => Promise;\r\n\tprivate readonly _contextKeyService: IContextKeyService;\r\n\r\n\tconstructor(\r\n\t\tid: string,\r\n\t\tlabel: string,\r\n\t\talias: string,\r\n\t\tprecondition: ContextKeyExpression | undefined,\r\n\t\trun: () => Promise,\r\n\t\tcontextKeyService: IContextKeyService\r\n\t) {\r\n\t\tthis.id = id;\r\n\t\tthis.label = label;\r\n\t\tthis.alias = alias;\r\n\t\tthis._precondition = precondition;\r\n\t\tthis._run = run;\r\n\t\tthis._contextKeyService = contextKeyService;\r\n\t}\r\n\r\n\tpublic isSupported(): boolean {\r\n\t\treturn this._contextKeyService.contextMatchesRules(this._precondition);\r\n\t}\r\n\r\n\tpublic run(): Promise {\r\n\t\tif (!this.isSupported()) {\r\n\t\t\treturn Promise.resolve(undefined);\r\n\t\t}\r\n\r\n\t\treturn this._run();\r\n\t}\r\n}\r\n","\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { URI, UriComponents } from 'vs/base/common/uri';\r\nimport { ConfigurationChangedEvent, IComputedEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions';\r\nimport { IPosition, Position } from 'vs/editor/common/core/position';\r\nimport { IRange, Range } from 'vs/editor/common/core/range';\r\nimport { ISelection, Selection } from 'vs/editor/common/core/selection';\r\nimport { IModelDecorationsChangeAccessor, ITextModel, OverviewRulerLane, TrackedRangeStickiness, IValidEditOperation } from 'vs/editor/common/model';\r\nimport { ThemeColor } from 'vs/platform/theme/common/themeService';\r\n\r\n/**\r\n * A builder and helper for edit operations for a command.\r\n */\r\nexport interface IEditOperationBuilder {\r\n\t/**\r\n\t * Add a new edit operation (a replace operation).\r\n\t * @param range The range to replace (delete). May be empty to represent a simple insert.\r\n\t * @param text The text to replace with. May be null to represent a simple delete.\r\n\t */\r\n\taddEditOperation(range: IRange, text: string | null, forceMoveMarkers?: boolean): void;\r\n\r\n\t/**\r\n\t * Add a new edit operation (a replace operation).\r\n\t * The inverse edits will be accessible in `ICursorStateComputerData.getInverseEditOperations()`\r\n\t * @param range The range to replace (delete). May be empty to represent a simple insert.\r\n\t * @param text The text to replace with. May be null to represent a simple delete.\r\n\t */\r\n\taddTrackedEditOperation(range: IRange, text: string | null, forceMoveMarkers?: boolean): void;\r\n\r\n\t/**\r\n\t * Track `selection` when applying edit operations.\r\n\t * A best effort will be made to not grow/expand the selection.\r\n\t * An empty selection will clamp to a nearby character.\r\n\t * @param selection The selection to track.\r\n\t * @param trackPreviousOnEmpty If set, and the selection is empty, indicates whether the selection\r\n\t * should clamp to the previous or the next character.\r\n\t * @return A unique identifier.\r\n\t */\r\n\ttrackSelection(selection: Selection, trackPreviousOnEmpty?: boolean): string;\r\n}\r\n\r\n/**\r\n * A helper for computing cursor state after a command.\r\n */\r\nexport interface ICursorStateComputerData {\r\n\t/**\r\n\t * Get the inverse edit operations of the added edit operations.\r\n\t */\r\n\tgetInverseEditOperations(): IValidEditOperation[];\r\n\t/**\r\n\t * Get a previously tracked selection.\r\n\t * @param id The unique identifier returned by `trackSelection`.\r\n\t * @return The selection.\r\n\t */\r\n\tgetTrackedSelection(id: string): Selection;\r\n}\r\n\r\n/**\r\n * A command that modifies text / cursor state on a model.\r\n */\r\nexport interface ICommand {\r\n\r\n\t/**\r\n\t * Signal that this command is inserting automatic whitespace that should be trimmed if possible.\r\n\t * @internal\r\n\t */\r\n\treadonly insertsAutoWhitespace?: boolean;\r\n\r\n\t/**\r\n\t * Get the edit operations needed to execute this command.\r\n\t * @param model The model the command will execute on.\r\n\t * @param builder A helper to collect the needed edit operations and to track selections.\r\n\t */\r\n\tgetEditOperations(model: ITextModel, builder: IEditOperationBuilder): void;\r\n\r\n\t/**\r\n\t * Compute the cursor state after the edit operations were applied.\r\n\t * @param model The model the command has executed on.\r\n\t * @param helper A helper to get inverse edit operations and to get previously tracked selections.\r\n\t * @return The cursor state after the command executed.\r\n\t */\r\n\tcomputeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection;\r\n}\r\n\r\n/**\r\n * A model for the diff editor.\r\n */\r\nexport interface IDiffEditorModel {\r\n\t/**\r\n\t * Original model.\r\n\t */\r\n\toriginal: ITextModel;\r\n\t/**\r\n\t * Modified model.\r\n\t */\r\n\tmodified: ITextModel;\r\n}\r\n\r\n/**\r\n * An event describing that an editor has had its model reset (i.e. `editor.setModel()`).\r\n */\r\nexport interface IModelChangedEvent {\r\n\t/**\r\n\t * The `uri` of the previous model or null.\r\n\t */\r\n\treadonly oldModelUrl: URI | null;\r\n\t/**\r\n\t * The `uri` of the new model or null.\r\n\t */\r\n\treadonly newModelUrl: URI | null;\r\n}\r\n\r\nexport interface IDimension {\r\n\twidth: number;\r\n\theight: number;\r\n}\r\n\r\n/**\r\n * A change\r\n */\r\nexport interface IChange {\r\n\treadonly originalStartLineNumber: number;\r\n\treadonly originalEndLineNumber: number;\r\n\treadonly modifiedStartLineNumber: number;\r\n\treadonly modifiedEndLineNumber: number;\r\n}\r\n/**\r\n * A character level change.\r\n */\r\nexport interface ICharChange extends IChange {\r\n\treadonly originalStartColumn: number;\r\n\treadonly originalEndColumn: number;\r\n\treadonly modifiedStartColumn: number;\r\n\treadonly modifiedEndColumn: number;\r\n}\r\n/**\r\n * A line change\r\n */\r\nexport interface ILineChange extends IChange {\r\n\treadonly charChanges: ICharChange[] | undefined;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface IConfiguration extends IDisposable {\r\n\tonDidChangeFast(listener: (e: ConfigurationChangedEvent) => void): IDisposable;\r\n\tonDidChange(listener: (e: ConfigurationChangedEvent) => void): IDisposable;\r\n\r\n\treadonly options: IComputedEditorOptions;\r\n\r\n\tsetMaxLineNumber(maxLineNumber: number): void;\r\n\tsetViewLineCount(viewLineCount: number): void;\r\n\tupdateOptions(newOptions: Readonly): void;\r\n\tgetRawOptions(): IEditorOptions;\r\n\tobserveReferenceElement(dimension?: IDimension): void;\r\n\tupdatePixelRatio(): void;\r\n\tsetIsDominatedByLongLines(isDominatedByLongLines: boolean): void;\r\n}\r\n\r\n// --- view\r\n\r\nexport interface IScrollEvent {\r\n\treadonly scrollTop: number;\r\n\treadonly scrollLeft: number;\r\n\treadonly scrollWidth: number;\r\n\treadonly scrollHeight: number;\r\n\r\n\treadonly scrollTopChanged: boolean;\r\n\treadonly scrollLeftChanged: boolean;\r\n\treadonly scrollWidthChanged: boolean;\r\n\treadonly scrollHeightChanged: boolean;\r\n}\r\n\r\nexport interface IContentSizeChangedEvent {\r\n\treadonly contentWidth: number;\r\n\treadonly contentHeight: number;\r\n\r\n\treadonly contentWidthChanged: boolean;\r\n\treadonly contentHeightChanged: boolean;\r\n}\r\n\r\nexport interface INewScrollPosition {\r\n\tscrollLeft?: number;\r\n\tscrollTop?: number;\r\n}\r\n\r\nexport interface IEditorAction {\r\n\treadonly id: string;\r\n\treadonly label: string;\r\n\treadonly alias: string;\r\n\tisSupported(): boolean;\r\n\trun(): Promise;\r\n}\r\n\r\nexport type IEditorModel = ITextModel | IDiffEditorModel;\r\n\r\n/**\r\n * A (serializable) state of the cursors.\r\n */\r\nexport interface ICursorState {\r\n\tinSelectionMode: boolean;\r\n\tselectionStart: IPosition;\r\n\tposition: IPosition;\r\n}\r\n/**\r\n * A (serializable) state of the view.\r\n */\r\nexport interface IViewState {\r\n\t/** written by previous versions */\r\n\tscrollTop?: number;\r\n\t/** written by previous versions */\r\n\tscrollTopWithoutViewZones?: number;\r\n\tscrollLeft: number;\r\n\tfirstPosition: IPosition;\r\n\tfirstPositionDeltaTop: number;\r\n}\r\n/**\r\n * A (serializable) state of the code editor.\r\n */\r\nexport interface ICodeEditorViewState {\r\n\tcursorState: ICursorState[];\r\n\tviewState: IViewState;\r\n\tcontributionsState: { [id: string]: any };\r\n}\r\n/**\r\n * (Serializable) View state for the diff editor.\r\n */\r\nexport interface IDiffEditorViewState {\r\n\toriginal: ICodeEditorViewState | null;\r\n\tmodified: ICodeEditorViewState | null;\r\n}\r\n/**\r\n * An editor view state.\r\n */\r\nexport type IEditorViewState = ICodeEditorViewState | IDiffEditorViewState;\r\n\r\nexport const enum ScrollType {\r\n\tSmooth = 0,\r\n\tImmediate = 1,\r\n}\r\n\r\n/**\r\n * An editor.\r\n */\r\nexport interface IEditor {\r\n\t/**\r\n\t * An event emitted when the editor has been disposed.\r\n\t * @event\r\n\t */\r\n\tonDidDispose(listener: () => void): IDisposable;\r\n\r\n\t/**\r\n\t * Dispose the editor.\r\n\t */\r\n\tdispose(): void;\r\n\r\n\t/**\r\n\t * Get a unique id for this editor instance.\r\n\t */\r\n\tgetId(): string;\r\n\r\n\t/**\r\n\t * Get the editor type. Please see `EditorType`.\r\n\t * This is to avoid an instanceof check\r\n\t */\r\n\tgetEditorType(): string;\r\n\r\n\t/**\r\n\t * Update the editor's options after the editor has been created.\r\n\t */\r\n\tupdateOptions(newOptions: IEditorOptions): void;\r\n\r\n\t/**\r\n\t * Instructs the editor to remeasure its container. This method should\r\n\t * be called when the container of the editor gets resized.\r\n\t *\r\n\t * If a dimension is passed in, the passed in value will be used.\r\n\t */\r\n\tlayout(dimension?: IDimension): void;\r\n\r\n\t/**\r\n\t * Brings browser focus to the editor text\r\n\t */\r\n\tfocus(): void;\r\n\r\n\t/**\r\n\t * Returns true if the text inside this editor is focused (i.e. cursor is blinking).\r\n\t */\r\n\thasTextFocus(): boolean;\r\n\r\n\t/**\r\n\t * Returns all actions associated with this editor.\r\n\t */\r\n\tgetSupportedActions(): IEditorAction[];\r\n\r\n\t/**\r\n\t * Saves current view state of the editor in a serializable object.\r\n\t */\r\n\tsaveViewState(): IEditorViewState | null;\r\n\r\n\t/**\r\n\t * Restores the view state of the editor from a serializable object generated by `saveViewState`.\r\n\t */\r\n\trestoreViewState(state: IEditorViewState): void;\r\n\r\n\t/**\r\n\t * Given a position, returns a column number that takes tab-widths into account.\r\n\t */\r\n\tgetVisibleColumnFromPosition(position: IPosition): number;\r\n\r\n\t/**\r\n\t * Returns the primary position of the cursor.\r\n\t */\r\n\tgetPosition(): Position | null;\r\n\r\n\t/**\r\n\t * Set the primary position of the cursor. This will remove any secondary cursors.\r\n\t * @param position New primary cursor's position\r\n\t */\r\n\tsetPosition(position: IPosition): void;\r\n\r\n\t/**\r\n\t * Scroll vertically as necessary and reveal a line.\r\n\t */\r\n\trevealLine(lineNumber: number, scrollType?: ScrollType): void;\r\n\r\n\t/**\r\n\t * Scroll vertically as necessary and reveal a line centered vertically.\r\n\t */\r\n\trevealLineInCenter(lineNumber: number, scrollType?: ScrollType): void;\r\n\r\n\t/**\r\n\t * Scroll vertically as necessary and reveal a line centered vertically only if it lies outside the viewport.\r\n\t */\r\n\trevealLineInCenterIfOutsideViewport(lineNumber: number, scrollType?: ScrollType): void;\r\n\r\n\t/**\r\n\t * Scroll vertically as necessary and reveal a line close to the top of the viewport,\r\n\t * optimized for viewing a code definition.\r\n\t */\r\n\trevealLineNearTop(lineNumber: number, scrollType?: ScrollType): void;\r\n\r\n\t/**\r\n\t * Scroll vertically or horizontally as necessary and reveal a position.\r\n\t */\r\n\trevealPosition(position: IPosition, scrollType?: ScrollType): void;\r\n\r\n\t/**\r\n\t * Scroll vertically or horizontally as necessary and reveal a position centered vertically.\r\n\t */\r\n\trevealPositionInCenter(position: IPosition, scrollType?: ScrollType): void;\r\n\r\n\t/**\r\n\t * Scroll vertically or horizontally as necessary and reveal a position centered vertically only if it lies outside the viewport.\r\n\t */\r\n\trevealPositionInCenterIfOutsideViewport(position: IPosition, scrollType?: ScrollType): void;\r\n\r\n\t/**\r\n\t * Scroll vertically or horizontally as necessary and reveal a position close to the top of the viewport,\r\n\t * optimized for viewing a code definition.\r\n\t */\r\n\trevealPositionNearTop(position: IPosition, scrollType?: ScrollType): void;\r\n\r\n\t/**\r\n\t * Returns the primary selection of the editor.\r\n\t */\r\n\tgetSelection(): Selection | null;\r\n\r\n\t/**\r\n\t * Returns all the selections of the editor.\r\n\t */\r\n\tgetSelections(): Selection[] | null;\r\n\r\n\t/**\r\n\t * Set the primary selection of the editor. This will remove any secondary cursors.\r\n\t * @param selection The new selection\r\n\t */\r\n\tsetSelection(selection: IRange): void;\r\n\t/**\r\n\t * Set the primary selection of the editor. This will remove any secondary cursors.\r\n\t * @param selection The new selection\r\n\t */\r\n\tsetSelection(selection: Range): void;\r\n\t/**\r\n\t * Set the primary selection of the editor. This will remove any secondary cursors.\r\n\t * @param selection The new selection\r\n\t */\r\n\tsetSelection(selection: ISelection): void;\r\n\t/**\r\n\t * Set the primary selection of the editor. This will remove any secondary cursors.\r\n\t * @param selection The new selection\r\n\t */\r\n\tsetSelection(selection: Selection): void;\r\n\r\n\t/**\r\n\t * Set the selections for all the cursors of the editor.\r\n\t * Cursors will be removed or added, as necessary.\r\n\t */\r\n\tsetSelections(selections: readonly ISelection[]): void;\r\n\r\n\t/**\r\n\t * Scroll vertically as necessary and reveal lines.\r\n\t */\r\n\trevealLines(startLineNumber: number, endLineNumber: number, scrollType?: ScrollType): void;\r\n\r\n\t/**\r\n\t * Scroll vertically as necessary and reveal lines centered vertically.\r\n\t */\r\n\trevealLinesInCenter(lineNumber: number, endLineNumber: number, scrollType?: ScrollType): void;\r\n\r\n\t/**\r\n\t * Scroll vertically as necessary and reveal lines centered vertically only if it lies outside the viewport.\r\n\t */\r\n\trevealLinesInCenterIfOutsideViewport(lineNumber: number, endLineNumber: number, scrollType?: ScrollType): void;\r\n\r\n\t/**\r\n\t * Scroll vertically as necessary and reveal lines close to the top of the viewport,\r\n\t * optimized for viewing a code definition.\r\n\t */\r\n\trevealLinesNearTop(lineNumber: number, endLineNumber: number, scrollType?: ScrollType): void;\r\n\r\n\t/**\r\n\t * Scroll vertically or horizontally as necessary and reveal a range.\r\n\t */\r\n\trevealRange(range: IRange, scrollType?: ScrollType): void;\r\n\r\n\t/**\r\n\t * Scroll vertically or horizontally as necessary and reveal a range centered vertically.\r\n\t */\r\n\trevealRangeInCenter(range: IRange, scrollType?: ScrollType): void;\r\n\r\n\t/**\r\n\t * Scroll vertically or horizontally as necessary and reveal a range at the top of the viewport.\r\n\t */\r\n\trevealRangeAtTop(range: IRange, scrollType?: ScrollType): void;\r\n\r\n\t/**\r\n\t * Scroll vertically or horizontally as necessary and reveal a range centered vertically only if it lies outside the viewport.\r\n\t */\r\n\trevealRangeInCenterIfOutsideViewport(range: IRange, scrollType?: ScrollType): void;\r\n\r\n\t/**\r\n\t * Scroll vertically or horizontally as necessary and reveal a range close to the top of the viewport,\r\n\t * optimized for viewing a code definition.\r\n\t */\r\n\trevealRangeNearTop(range: IRange, scrollType?: ScrollType): void;\r\n\r\n\t/**\r\n\t * Scroll vertically or horizontally as necessary and reveal a range close to the top of the viewport,\r\n\t * optimized for viewing a code definition. Only if it lies outside the viewport.\r\n\t */\r\n\trevealRangeNearTopIfOutsideViewport(range: IRange, scrollType?: ScrollType): void;\r\n\r\n\t/**\r\n\t * Directly trigger a handler or an editor action.\r\n\t * @param source The source of the call.\r\n\t * @param handlerId The id of the handler or the id of a contribution.\r\n\t * @param payload Extra data to be sent to the handler.\r\n\t */\r\n\ttrigger(source: string | null | undefined, handlerId: string, payload: any): void;\r\n\r\n\t/**\r\n\t * Gets the current model attached to this editor.\r\n\t */\r\n\tgetModel(): IEditorModel | null;\r\n\r\n\t/**\r\n\t * Sets the current model attached to this editor.\r\n\t * If the previous model was created by the editor via the value key in the options\r\n\t * literal object, it will be destroyed. Otherwise, if the previous model was set\r\n\t * via setModel, or the model key in the options literal object, the previous model\r\n\t * will not be destroyed.\r\n\t * It is safe to call setModel(null) to simply detach the current model from the editor.\r\n\t */\r\n\tsetModel(model: IEditorModel | null): void;\r\n\r\n\t/**\r\n\t * Change the decorations. All decorations added through this changeAccessor\r\n\t * will get the ownerId of the editor (meaning they will not show up in other\r\n\t * editors).\r\n\t * @see `ITextModel.changeDecorations`\r\n\t * @internal\r\n\t */\r\n\tchangeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => any): any;\r\n}\r\n\r\n/**\r\n * A diff editor.\r\n *\r\n * @internal\r\n */\r\nexport interface IDiffEditor extends IEditor {\r\n\r\n\t/**\r\n\t * Type the getModel() of IEditor.\r\n\t */\r\n\tgetModel(): IDiffEditorModel | null;\r\n}\r\n\r\n\r\n/**\r\n * An editor contribution that gets created every time a new editor gets created and gets disposed when the editor gets disposed.\r\n */\r\nexport interface IEditorContribution {\r\n\t/**\r\n\t * Dispose this contribution.\r\n\t */\r\n\tdispose(): void;\r\n\t/**\r\n\t * Store view state.\r\n\t */\r\n\tsaveViewState?(): any;\r\n\t/**\r\n\t * Restore view state.\r\n\t */\r\n\trestoreViewState?(state: any): void;\r\n}\r\n\r\n/**\r\n * A diff editor contribution that gets created every time a new diffeditor gets created and gets disposed when the diff editor gets disposed.\r\n * @internal\r\n */\r\nexport interface IDiffEditorContribution {\r\n\t/**\r\n\t * Dispose this contribution.\r\n\t */\r\n\tdispose(): void;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport function isThemeColor(o: any): o is ThemeColor {\r\n\treturn o && typeof o.id === 'string';\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface IThemeDecorationRenderOptions {\r\n\tletterSpacing?: string;\r\n\r\n\tgutterIconPath?: UriComponents;\r\n\tgutterIconSize?: string;\r\n\r\n\toverviewRulerColor?: string | ThemeColor;\r\n\r\n\tbefore?: IContentDecorationRenderOptions;\r\n\tafter?: IContentDecorationRenderOptions;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface IContentDecorationRenderOptions {\r\n\tcontentText?: string;\r\n\tcontentIconPath?: UriComponents;\r\n\r\n\tborder?: string;\r\n\tborderRadius?: string;\r\n\tfontSize?: string;\r\n\tfontFamily?: string;\r\n\tcolor?: string | ThemeColor;\r\n\tbackgroundColor?: string | ThemeColor;\r\n\r\n\tmargin?: string;\r\n\tpadding?: string;\r\n\twidth?: string;\r\n\theight?: string;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface IDecorationRenderOptions extends IThemeDecorationRenderOptions {\r\n\tisWholeLine?: boolean;\r\n\trangeBehavior?: TrackedRangeStickiness;\r\n\toverviewRulerLane?: OverviewRulerLane;\r\n\r\n\tlight?: IThemeDecorationRenderOptions;\r\n\tdark?: IThemeDecorationRenderOptions;\r\n}\r\n\r\n/**\r\n * The type of the `IEditor`.\r\n */\r\nexport const EditorType = {\r\n\tICodeEditor: 'vs.editor.ICodeEditor',\r\n\tIDiffEditor: 'vs.editor.IDiffEditor'\r\n};\r\n\r\n/**\r\n * Built-in commands.\r\n * @internal\r\n */\r\nexport const enum Handler {\r\n\tCompositionStart = 'compositionStart',\r\n\tCompositionEnd = 'compositionEnd',\r\n\tType = 'type',\r\n\tReplacePreviousChar = 'replacePreviousChar',\r\n\tPaste = 'paste',\r\n\tCut = 'cut',\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface TypePayload {\r\n\ttext: string;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface ReplacePreviousCharPayload {\r\n\ttext: string;\r\n\treplaceCharCnt: number;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface PastePayload {\r\n\ttext: string;\r\n\tpasteOnNewLine: boolean;\r\n\tmulticursorText: string[] | null;\r\n\tmode: string | null;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { IMouseEvent, IMouseWheelEvent } from 'vs/base/browser/mouseEvent';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { OverviewRulerPosition, ConfigurationChangedEvent, EditorLayoutInfo, IComputedEditorOptions, EditorOption, FindComputedEditorOptionValueById, IEditorOptions, IDiffEditorOptions } from 'vs/editor/common/config/editorOptions';\r\nimport { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';\r\nimport { IPosition, Position } from 'vs/editor/common/core/position';\r\nimport { IRange, Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport * as editorCommon from 'vs/editor/common/editorCommon';\r\nimport { IIdentifiedSingleEditOperation, IModelDecoration, IModelDeltaDecoration, ITextModel, ICursorStateComputer, IWordAtPosition } from 'vs/editor/common/model';\r\nimport { IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelLanguageConfigurationChangedEvent, IModelOptionsChangedEvent } from 'vs/editor/common/model/textModelEvents';\r\nimport { OverviewRulerZone } from 'vs/editor/common/view/overviewZoneManager';\r\nimport { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IViewModel } from 'vs/editor/common/viewModel/viewModel';\r\n\r\n/**\r\n * A view zone is a full horizontal rectangle that 'pushes' text down.\r\n * The editor reserves space for view zones when rendering.\r\n */\r\nexport interface IViewZone {\r\n\t/**\r\n\t * The line number after which this zone should appear.\r\n\t * Use 0 to place a view zone before the first line number.\r\n\t */\r\n\tafterLineNumber: number;\r\n\t/**\r\n\t * The column after which this zone should appear.\r\n\t * If not set, the maxLineColumn of `afterLineNumber` will be used.\r\n\t */\r\n\tafterColumn?: number;\r\n\t/**\r\n\t * Suppress mouse down events.\r\n\t * If set, the editor will attach a mouse down listener to the view zone and .preventDefault on it.\r\n\t * Defaults to false\r\n\t */\r\n\tsuppressMouseDown?: boolean;\r\n\t/**\r\n\t * The height in lines of the view zone.\r\n\t * If specified, `heightInPx` will be used instead of this.\r\n\t * If neither `heightInPx` nor `heightInLines` is specified, a default of `heightInLines` = 1 will be chosen.\r\n\t */\r\n\theightInLines?: number;\r\n\t/**\r\n\t * The height in px of the view zone.\r\n\t * If this is set, the editor will give preference to it rather than `heightInLines` above.\r\n\t * If neither `heightInPx` nor `heightInLines` is specified, a default of `heightInLines` = 1 will be chosen.\r\n\t */\r\n\theightInPx?: number;\r\n\t/**\r\n\t * The minimum width in px of the view zone.\r\n\t * If this is set, the editor will ensure that the scroll width is >= than this value.\r\n\t */\r\n\tminWidthInPx?: number;\r\n\t/**\r\n\t * The dom node of the view zone\r\n\t */\r\n\tdomNode: HTMLElement;\r\n\t/**\r\n\t * An optional dom node for the view zone that will be placed in the margin area.\r\n\t */\r\n\tmarginDomNode?: HTMLElement | null;\r\n\t/**\r\n\t * Callback which gives the relative top of the view zone as it appears (taking scrolling into account).\r\n\t */\r\n\tonDomNodeTop?: (top: number) => void;\r\n\t/**\r\n\t * Callback which gives the height in pixels of the view zone.\r\n\t */\r\n\tonComputedHeight?: (height: number) => void;\r\n}\r\n/**\r\n * An accessor that allows for zones to be added or removed.\r\n */\r\nexport interface IViewZoneChangeAccessor {\r\n\t/**\r\n\t * Create a new view zone.\r\n\t * @param zone Zone to create\r\n\t * @return A unique identifier to the view zone.\r\n\t */\r\n\taddZone(zone: IViewZone): string;\r\n\t/**\r\n\t * Remove a zone\r\n\t * @param id A unique identifier to the view zone, as returned by the `addZone` call.\r\n\t */\r\n\tremoveZone(id: string): void;\r\n\t/**\r\n\t * Change a zone's position.\r\n\t * The editor will rescan the `afterLineNumber` and `afterColumn` properties of a view zone.\r\n\t */\r\n\tlayoutZone(id: string): void;\r\n}\r\n\r\n/**\r\n * A positioning preference for rendering content widgets.\r\n */\r\nexport const enum ContentWidgetPositionPreference {\r\n\t/**\r\n\t * Place the content widget exactly at a position\r\n\t */\r\n\tEXACT,\r\n\t/**\r\n\t * Place the content widget above a position\r\n\t */\r\n\tABOVE,\r\n\t/**\r\n\t * Place the content widget below a position\r\n\t */\r\n\tBELOW\r\n}\r\n/**\r\n * A position for rendering content widgets.\r\n */\r\nexport interface IContentWidgetPosition {\r\n\t/**\r\n\t * Desired position for the content widget.\r\n\t * `preference` will also affect the placement.\r\n\t */\r\n\tposition: IPosition | null;\r\n\t/**\r\n\t * Optionally, a range can be provided to further\r\n\t * define the position of the content widget.\r\n\t */\r\n\trange?: IRange | null;\r\n\t/**\r\n\t * Placement preference for position, in order of preference.\r\n\t */\r\n\tpreference: ContentWidgetPositionPreference[];\r\n}\r\n/**\r\n * A content widget renders inline with the text and can be easily placed 'near' an editor position.\r\n */\r\nexport interface IContentWidget {\r\n\t/**\r\n\t * Render this content widget in a location where it could overflow the editor's view dom node.\r\n\t */\r\n\tallowEditorOverflow?: boolean;\r\n\r\n\tsuppressMouseDown?: boolean;\r\n\t/**\r\n\t * Get a unique identifier of the content widget.\r\n\t */\r\n\tgetId(): string;\r\n\t/**\r\n\t * Get the dom node of the content widget.\r\n\t */\r\n\tgetDomNode(): HTMLElement;\r\n\t/**\r\n\t * Get the placement of the content widget.\r\n\t * If null is returned, the content widget will be placed off screen.\r\n\t */\r\n\tgetPosition(): IContentWidgetPosition | null;\r\n\t/**\r\n\t * Optional function that is invoked before rendering\r\n\t * the content widget. If a dimension is returned the editor will\r\n\t * attempt to use it.\r\n\t */\r\n\tbeforeRender?(): editorCommon.IDimension | null;\r\n\t/**\r\n\t * Optional function that is invoked after rendering the content\r\n\t * widget. Is being invoked with the selected position preference\r\n\t * or `null` if not rendered.\r\n\t */\r\n\tafterRender?(position: ContentWidgetPositionPreference | null): void;\r\n}\r\n\r\n/**\r\n * A positioning preference for rendering overlay widgets.\r\n */\r\nexport const enum OverlayWidgetPositionPreference {\r\n\t/**\r\n\t * Position the overlay widget in the top right corner\r\n\t */\r\n\tTOP_RIGHT_CORNER,\r\n\r\n\t/**\r\n\t * Position the overlay widget in the bottom right corner\r\n\t */\r\n\tBOTTOM_RIGHT_CORNER,\r\n\r\n\t/**\r\n\t * Position the overlay widget in the top center\r\n\t */\r\n\tTOP_CENTER\r\n}\r\n/**\r\n * A position for rendering overlay widgets.\r\n */\r\nexport interface IOverlayWidgetPosition {\r\n\t/**\r\n\t * The position preference for the overlay widget.\r\n\t */\r\n\tpreference: OverlayWidgetPositionPreference | null;\r\n}\r\n/**\r\n * An overlay widgets renders on top of the text.\r\n */\r\nexport interface IOverlayWidget {\r\n\t/**\r\n\t * Get a unique identifier of the overlay widget.\r\n\t */\r\n\tgetId(): string;\r\n\t/**\r\n\t * Get the dom node of the overlay widget.\r\n\t */\r\n\tgetDomNode(): HTMLElement;\r\n\t/**\r\n\t * Get the placement of the overlay widget.\r\n\t * If null is returned, the overlay widget is responsible to place itself.\r\n\t */\r\n\tgetPosition(): IOverlayWidgetPosition | null;\r\n}\r\n\r\n/**\r\n * Type of hit element with the mouse in the editor.\r\n */\r\nexport const enum MouseTargetType {\r\n\t/**\r\n\t * Mouse is on top of an unknown element.\r\n\t */\r\n\tUNKNOWN,\r\n\t/**\r\n\t * Mouse is on top of the textarea used for input.\r\n\t */\r\n\tTEXTAREA,\r\n\t/**\r\n\t * Mouse is on top of the glyph margin\r\n\t */\r\n\tGUTTER_GLYPH_MARGIN,\r\n\t/**\r\n\t * Mouse is on top of the line numbers\r\n\t */\r\n\tGUTTER_LINE_NUMBERS,\r\n\t/**\r\n\t * Mouse is on top of the line decorations\r\n\t */\r\n\tGUTTER_LINE_DECORATIONS,\r\n\t/**\r\n\t * Mouse is on top of the whitespace left in the gutter by a view zone.\r\n\t */\r\n\tGUTTER_VIEW_ZONE,\r\n\t/**\r\n\t * Mouse is on top of text in the content.\r\n\t */\r\n\tCONTENT_TEXT,\r\n\t/**\r\n\t * Mouse is on top of empty space in the content (e.g. after line text or below last line)\r\n\t */\r\n\tCONTENT_EMPTY,\r\n\t/**\r\n\t * Mouse is on top of a view zone in the content.\r\n\t */\r\n\tCONTENT_VIEW_ZONE,\r\n\t/**\r\n\t * Mouse is on top of a content widget.\r\n\t */\r\n\tCONTENT_WIDGET,\r\n\t/**\r\n\t * Mouse is on top of the decorations overview ruler.\r\n\t */\r\n\tOVERVIEW_RULER,\r\n\t/**\r\n\t * Mouse is on top of a scrollbar.\r\n\t */\r\n\tSCROLLBAR,\r\n\t/**\r\n\t * Mouse is on top of an overlay widget.\r\n\t */\r\n\tOVERLAY_WIDGET,\r\n\t/**\r\n\t * Mouse is outside of the editor.\r\n\t */\r\n\tOUTSIDE_EDITOR,\r\n}\r\n\r\n/**\r\n * Target hit with the mouse in the editor.\r\n */\r\nexport interface IMouseTarget {\r\n\t/**\r\n\t * The target element\r\n\t */\r\n\treadonly element: Element | null;\r\n\t/**\r\n\t * The target type\r\n\t */\r\n\treadonly type: MouseTargetType;\r\n\t/**\r\n\t * The 'approximate' editor position\r\n\t */\r\n\treadonly position: Position | null;\r\n\t/**\r\n\t * Desired mouse column (e.g. when position.column gets clamped to text length -- clicking after text on a line).\r\n\t */\r\n\treadonly mouseColumn: number;\r\n\t/**\r\n\t * The 'approximate' editor range\r\n\t */\r\n\treadonly range: Range | null;\r\n\t/**\r\n\t * Some extra detail.\r\n\t */\r\n\treadonly detail: any;\r\n}\r\n/**\r\n * A mouse event originating from the editor.\r\n */\r\nexport interface IEditorMouseEvent {\r\n\treadonly event: IMouseEvent;\r\n\treadonly target: IMouseTarget;\r\n}\r\nexport interface IPartialEditorMouseEvent {\r\n\treadonly event: IMouseEvent;\r\n\treadonly target: IMouseTarget | null;\r\n}\r\n\r\n/**\r\n * A paste event originating from the editor.\r\n */\r\nexport interface IPasteEvent {\r\n\treadonly range: Range;\r\n\treadonly mode: string | null;\r\n}\r\n\r\n/**\r\n * An overview ruler\r\n * @internal\r\n */\r\nexport interface IOverviewRuler {\r\n\tgetDomNode(): HTMLElement;\r\n\tdispose(): void;\r\n\tsetZones(zones: OverviewRulerZone[]): void;\r\n\tsetLayout(position: OverviewRulerPosition): void;\r\n}\r\n\r\n/**\r\n * Editor aria options.\r\n * @internal\r\n */\r\nexport interface IEditorAriaOptions {\r\n\tactiveDescendant: string | undefined;\r\n\trole?: string;\r\n}\r\n\r\nexport interface IEditorConstructionOptions extends IEditorOptions {\r\n\t/**\r\n\t * The initial editor dimension (to avoid measuring the container).\r\n\t */\r\n\tdimension?: editorCommon.IDimension;\r\n\t/**\r\n\t * Place overflow widgets inside an external DOM node.\r\n\t * Defaults to an internal DOM node.\r\n\t */\r\n\toverflowWidgetsDomNode?: HTMLElement;\r\n}\r\n\r\nexport interface IDiffEditorConstructionOptions extends IDiffEditorOptions {\r\n\t/**\r\n\t * The initial editor dimension (to avoid measuring the container).\r\n\t */\r\n\tdimension?: editorCommon.IDimension;\r\n\r\n\t/**\r\n\t * Place overflow widgets inside an external DOM node.\r\n\t * Defaults to an internal DOM node.\r\n\t */\r\n\toverflowWidgetsDomNode?: HTMLElement;\r\n}\r\n\r\n/**\r\n * A rich code editor.\r\n */\r\nexport interface ICodeEditor extends editorCommon.IEditor {\r\n\t/**\r\n\t * An event emitted when the content of the current model has changed.\r\n\t * @event\r\n\t */\r\n\tonDidChangeModelContent(listener: (e: IModelContentChangedEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted when the language of the current model has changed.\r\n\t * @event\r\n\t */\r\n\tonDidChangeModelLanguage(listener: (e: IModelLanguageChangedEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted when the language configuration of the current model has changed.\r\n\t * @event\r\n\t */\r\n\tonDidChangeModelLanguageConfiguration(listener: (e: IModelLanguageConfigurationChangedEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted when the options of the current model has changed.\r\n\t * @event\r\n\t */\r\n\tonDidChangeModelOptions(listener: (e: IModelOptionsChangedEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted when the configuration of the editor has changed. (e.g. `editor.updateOptions()`)\r\n\t * @event\r\n\t */\r\n\tonDidChangeConfiguration(listener: (e: ConfigurationChangedEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted when the cursor position has changed.\r\n\t * @event\r\n\t */\r\n\tonDidChangeCursorPosition(listener: (e: ICursorPositionChangedEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted when the cursor selection has changed.\r\n\t * @event\r\n\t */\r\n\tonDidChangeCursorSelection(listener: (e: ICursorSelectionChangedEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted when the model of this editor has changed (e.g. `editor.setModel()`).\r\n\t * @event\r\n\t */\r\n\tonDidChangeModel(listener: (e: editorCommon.IModelChangedEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted when the decorations of the current model have changed.\r\n\t * @event\r\n\t */\r\n\tonDidChangeModelDecorations(listener: (e: IModelDecorationsChangedEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted when the text inside this editor gained focus (i.e. cursor starts blinking).\r\n\t * @event\r\n\t */\r\n\tonDidFocusEditorText(listener: () => void): IDisposable;\r\n\t/**\r\n\t * An event emitted when the text inside this editor lost focus (i.e. cursor stops blinking).\r\n\t * @event\r\n\t */\r\n\tonDidBlurEditorText(listener: () => void): IDisposable;\r\n\t/**\r\n\t * An event emitted when the text inside this editor or an editor widget gained focus.\r\n\t * @event\r\n\t */\r\n\tonDidFocusEditorWidget(listener: () => void): IDisposable;\r\n\t/**\r\n\t * An event emitted when the text inside this editor or an editor widget lost focus.\r\n\t * @event\r\n\t */\r\n\tonDidBlurEditorWidget(listener: () => void): IDisposable;\r\n\t/**\r\n\t * An event emitted before interpreting typed characters (on the keyboard).\r\n\t * @event\r\n\t * @internal\r\n\t */\r\n\tonWillType(listener: (text: string) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted after interpreting typed characters (on the keyboard).\r\n\t * @event\r\n\t * @internal\r\n\t */\r\n\tonDidType(listener: (text: string) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted after composition has started.\r\n\t */\r\n\tonDidCompositionStart(listener: () => void): IDisposable;\r\n\t/**\r\n\t * An event emitted after composition has ended.\r\n\t */\r\n\tonDidCompositionEnd(listener: () => void): IDisposable;\r\n\t/**\r\n\t * An event emitted when editing failed because the editor is read-only.\r\n\t * @event\r\n\t */\r\n\tonDidAttemptReadOnlyEdit(listener: () => void): IDisposable;\r\n\t/**\r\n\t * An event emitted when users paste text in the editor.\r\n\t * @event\r\n\t */\r\n\tonDidPaste(listener: (e: IPasteEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted on a \"mouseup\".\r\n\t * @event\r\n\t */\r\n\tonMouseUp(listener: (e: IEditorMouseEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted on a \"mousedown\".\r\n\t * @event\r\n\t */\r\n\tonMouseDown(listener: (e: IEditorMouseEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted on a \"mousedrag\".\r\n\t * @internal\r\n\t * @event\r\n\t */\r\n\tonMouseDrag(listener: (e: IEditorMouseEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted on a \"mousedrop\".\r\n\t * @internal\r\n\t * @event\r\n\t */\r\n\tonMouseDrop(listener: (e: IPartialEditorMouseEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted on a \"mousedropcanceled\".\r\n\t * @internal\r\n\t * @event\r\n\t */\r\n\tonMouseDropCanceled(listener: () => void): IDisposable;\r\n\t/**\r\n\t * An event emitted on a \"contextmenu\".\r\n\t * @event\r\n\t */\r\n\tonContextMenu(listener: (e: IEditorMouseEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted on a \"mousemove\".\r\n\t * @event\r\n\t */\r\n\tonMouseMove(listener: (e: IEditorMouseEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted on a \"mouseleave\".\r\n\t * @event\r\n\t */\r\n\tonMouseLeave(listener: (e: IPartialEditorMouseEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted on a \"mousewheel\"\r\n\t * @event\r\n\t * @internal\r\n\t */\r\n\tonMouseWheel(listener: (e: IMouseWheelEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted on a \"keyup\".\r\n\t * @event\r\n\t */\r\n\tonKeyUp(listener: (e: IKeyboardEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted on a \"keydown\".\r\n\t * @event\r\n\t */\r\n\tonKeyDown(listener: (e: IKeyboardEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted when the layout of the editor has changed.\r\n\t * @event\r\n\t */\r\n\tonDidLayoutChange(listener: (e: EditorLayoutInfo) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted when the content width or content height in the editor has changed.\r\n\t * @event\r\n\t */\r\n\tonDidContentSizeChange(listener: (e: editorCommon.IContentSizeChangedEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted when the scroll in the editor has changed.\r\n\t * @event\r\n\t */\r\n\tonDidScrollChange(listener: (e: editorCommon.IScrollEvent) => void): IDisposable;\r\n\r\n\t/**\r\n\t * Saves current view state of the editor in a serializable object.\r\n\t */\r\n\tsaveViewState(): editorCommon.ICodeEditorViewState | null;\r\n\r\n\t/**\r\n\t * Restores the view state of the editor from a serializable object generated by `saveViewState`.\r\n\t */\r\n\trestoreViewState(state: editorCommon.ICodeEditorViewState): void;\r\n\r\n\t/**\r\n\t * Returns true if the text inside this editor or an editor widget has focus.\r\n\t */\r\n\thasWidgetFocus(): boolean;\r\n\r\n\t/**\r\n\t * Get a contribution of this editor.\r\n\t * @id Unique identifier of the contribution.\r\n\t * @return The contribution or null if contribution not found.\r\n\t */\r\n\tgetContribution(id: string): T;\r\n\r\n\t/**\r\n\t * Execute `fn` with the editor's services.\r\n\t * @internal\r\n\t */\r\n\tinvokeWithinContext(fn: (accessor: ServicesAccessor) => T): T;\r\n\r\n\t/**\r\n\t * Type the getModel() of IEditor.\r\n\t */\r\n\tgetModel(): ITextModel | null;\r\n\r\n\t/**\r\n\t * Sets the current model attached to this editor.\r\n\t * If the previous model was created by the editor via the value key in the options\r\n\t * literal object, it will be destroyed. Otherwise, if the previous model was set\r\n\t * via setModel, or the model key in the options literal object, the previous model\r\n\t * will not be destroyed.\r\n\t * It is safe to call setModel(null) to simply detach the current model from the editor.\r\n\t */\r\n\tsetModel(model: ITextModel | null): void;\r\n\r\n\t/**\r\n\t * Gets all the editor computed options.\r\n\t */\r\n\tgetOptions(): IComputedEditorOptions;\r\n\r\n\t/**\r\n\t * Gets a specific editor option.\r\n\t */\r\n\tgetOption(id: T): FindComputedEditorOptionValueById;\r\n\r\n\t/**\r\n\t * Returns the editor's configuration (without any validation or defaults).\r\n\t */\r\n\tgetRawOptions(): IEditorOptions;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tgetOverflowWidgetsDomNode(): HTMLElement | undefined;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tgetConfiguredWordAtPosition(position: Position): IWordAtPosition | null;\r\n\r\n\t/**\r\n\t * Get value of the current model attached to this editor.\r\n\t * @see `ITextModel.getValue`\r\n\t */\r\n\tgetValue(options?: { preserveBOM: boolean; lineEnding: string; }): string;\r\n\r\n\t/**\r\n\t * Set the value of the current model attached to this editor.\r\n\t * @see `ITextModel.setValue`\r\n\t */\r\n\tsetValue(newValue: string): void;\r\n\r\n\t/**\r\n\t * Get the width of the editor's content.\r\n\t * This is information that is \"erased\" when computing `scrollWidth = Math.max(contentWidth, width)`\r\n\t */\r\n\tgetContentWidth(): number;\r\n\t/**\r\n\t * Get the scrollWidth of the editor's viewport.\r\n\t */\r\n\tgetScrollWidth(): number;\r\n\t/**\r\n\t * Get the scrollLeft of the editor's viewport.\r\n\t */\r\n\tgetScrollLeft(): number;\r\n\r\n\t/**\r\n\t * Get the height of the editor's content.\r\n\t * This is information that is \"erased\" when computing `scrollHeight = Math.max(contentHeight, height)`\r\n\t */\r\n\tgetContentHeight(): number;\r\n\t/**\r\n\t * Get the scrollHeight of the editor's viewport.\r\n\t */\r\n\tgetScrollHeight(): number;\r\n\t/**\r\n\t * Get the scrollTop of the editor's viewport.\r\n\t */\r\n\tgetScrollTop(): number;\r\n\r\n\t/**\r\n\t * Change the scrollLeft of the editor's viewport.\r\n\t */\r\n\tsetScrollLeft(newScrollLeft: number, scrollType?: editorCommon.ScrollType): void;\r\n\t/**\r\n\t * Change the scrollTop of the editor's viewport.\r\n\t */\r\n\tsetScrollTop(newScrollTop: number, scrollType?: editorCommon.ScrollType): void;\r\n\t/**\r\n\t * Change the scroll position of the editor's viewport.\r\n\t */\r\n\tsetScrollPosition(position: editorCommon.INewScrollPosition, scrollType?: editorCommon.ScrollType): void;\r\n\r\n\t/**\r\n\t * Get an action that is a contribution to this editor.\r\n\t * @id Unique identifier of the contribution.\r\n\t * @return The action or null if action not found.\r\n\t */\r\n\tgetAction(id: string): editorCommon.IEditorAction;\r\n\r\n\t/**\r\n\t * Execute a command on the editor.\r\n\t * The edits will land on the undo-redo stack, but no \"undo stop\" will be pushed.\r\n\t * @param source The source of the call.\r\n\t * @param command The command to execute\r\n\t */\r\n\texecuteCommand(source: string | null | undefined, command: editorCommon.ICommand): void;\r\n\r\n\t/**\r\n\t * Create an \"undo stop\" in the undo-redo stack.\r\n\t */\r\n\tpushUndoStop(): boolean;\r\n\r\n\t/**\r\n\t * Remove the \"undo stop\" in the undo-redo stack.\r\n\t */\r\n\tpopUndoStop(): boolean;\r\n\r\n\t/**\r\n\t * Execute edits on the editor.\r\n\t * The edits will land on the undo-redo stack, but no \"undo stop\" will be pushed.\r\n\t * @param source The source of the call.\r\n\t * @param edits The edits to execute.\r\n\t * @param endCursorState Cursor state after the edits were applied.\r\n\t */\r\n\texecuteEdits(source: string | null | undefined, edits: IIdentifiedSingleEditOperation[], endCursorState?: ICursorStateComputer | Selection[]): boolean;\r\n\r\n\t/**\r\n\t * Execute multiple (concomitant) commands on the editor.\r\n\t * @param source The source of the call.\r\n\t * @param command The commands to execute\r\n\t */\r\n\texecuteCommands(source: string | null | undefined, commands: (editorCommon.ICommand | null)[]): void;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\t_getViewModel(): IViewModel | null;\r\n\r\n\t/**\r\n\t * Get all the decorations on a line (filtering out decorations from other editors).\r\n\t */\r\n\tgetLineDecorations(lineNumber: number): IModelDecoration[] | null;\r\n\r\n\t/**\r\n\t * All decorations added through this call will get the ownerId of this editor.\r\n\t * @see `ITextModel.deltaDecorations`\r\n\t */\r\n\tdeltaDecorations(oldDecorations: string[], newDecorations: IModelDeltaDecoration[]): string[];\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tremoveDecorations(decorationTypeKey: string): void;\r\n\r\n\t/**\r\n\t * Get the layout info for the editor.\r\n\t */\r\n\tgetLayoutInfo(): EditorLayoutInfo;\r\n\r\n\t/**\r\n\t * Returns the ranges that are currently visible.\r\n\t * Does not account for horizontal scrolling.\r\n\t */\r\n\tgetVisibleRanges(): Range[];\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tgetVisibleRangesPlusViewportAboveBelow(): Range[];\r\n\r\n\t/**\r\n\t * Get the vertical position (top offset) for the line w.r.t. to the first line.\r\n\t */\r\n\tgetTopForLineNumber(lineNumber: number): number;\r\n\r\n\t/**\r\n\t * Get the vertical position (top offset) for the position w.r.t. to the first line.\r\n\t */\r\n\tgetTopForPosition(lineNumber: number, column: number): number;\r\n\r\n\t/**\r\n\t * Set the model ranges that will be hidden in the view.\r\n\t * @internal\r\n\t */\r\n\tsetHiddenAreas(ranges: IRange[]): void;\r\n\r\n\t/**\r\n\t * Sets the editor aria options, primarily the active descendent.\r\n\t * @internal\r\n\t */\r\n\tsetAriaOptions(options: IEditorAriaOptions): void;\r\n\r\n\t/**\r\n\t * Returns the editor's container dom node\r\n\t */\r\n\tgetContainerDomNode(): HTMLElement;\r\n\r\n\t/**\r\n\t * Returns the editor's dom node\r\n\t */\r\n\tgetDomNode(): HTMLElement | null;\r\n\r\n\t/**\r\n\t * Add a content widget. Widgets must have unique ids, otherwise they will be overwritten.\r\n\t */\r\n\taddContentWidget(widget: IContentWidget): void;\r\n\t/**\r\n\t * Layout/Reposition a content widget. This is a ping to the editor to call widget.getPosition()\r\n\t * and update appropriately.\r\n\t */\r\n\tlayoutContentWidget(widget: IContentWidget): void;\r\n\t/**\r\n\t * Remove a content widget.\r\n\t */\r\n\tremoveContentWidget(widget: IContentWidget): void;\r\n\r\n\t/**\r\n\t * Add an overlay widget. Widgets must have unique ids, otherwise they will be overwritten.\r\n\t */\r\n\taddOverlayWidget(widget: IOverlayWidget): void;\r\n\t/**\r\n\t * Layout/Reposition an overlay widget. This is a ping to the editor to call widget.getPosition()\r\n\t * and update appropriately.\r\n\t */\r\n\tlayoutOverlayWidget(widget: IOverlayWidget): void;\r\n\t/**\r\n\t * Remove an overlay widget.\r\n\t */\r\n\tremoveOverlayWidget(widget: IOverlayWidget): void;\r\n\r\n\t/**\r\n\t * Change the view zones. View zones are lost when a new model is attached to the editor.\r\n\t */\r\n\tchangeViewZones(callback: (accessor: IViewZoneChangeAccessor) => void): void;\r\n\r\n\t/**\r\n\t * Get the horizontal position (left offset) for the column w.r.t to the beginning of the line.\r\n\t * This method works only if the line `lineNumber` is currently rendered (in the editor's viewport).\r\n\t * Use this method with caution.\r\n\t */\r\n\tgetOffsetForColumn(lineNumber: number, column: number): number;\r\n\r\n\t/**\r\n\t * Force an editor render now.\r\n\t */\r\n\trender(forceRedraw?: boolean): void;\r\n\r\n\t/**\r\n\t * Get the hit test target at coordinates `clientX` and `clientY`.\r\n\t * The coordinates are relative to the top-left of the viewport.\r\n\t *\r\n\t * @returns Hit test target or null if the coordinates fall outside the editor or the editor has no model.\r\n\t */\r\n\tgetTargetAtClientPoint(clientX: number, clientY: number): IMouseTarget | null;\r\n\r\n\t/**\r\n\t * Get the visible position for `position`.\r\n\t * The result position takes scrolling into account and is relative to the top left corner of the editor.\r\n\t * Explanation 1: the results of this method will change for the same `position` if the user scrolls the editor.\r\n\t * Explanation 2: the results of this method will not change if the container of the editor gets repositioned.\r\n\t * Warning: the results of this method are inaccurate for positions that are outside the current editor viewport.\r\n\t */\r\n\tgetScrolledVisiblePosition(position: IPosition): { top: number; left: number; height: number; } | null;\r\n\r\n\t/**\r\n\t * Apply the same font settings as the editor to `target`.\r\n\t */\r\n\tapplyFontInfo(target: HTMLElement): void;\r\n\r\n\t/**\r\n\t * Check if the current instance has a model attached.\r\n\t * @internal\r\n\t */\r\n\thasModel(): this is IActiveCodeEditor;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface IActiveCodeEditor extends ICodeEditor {\r\n\t/**\r\n\t * Returns the primary position of the cursor.\r\n\t */\r\n\tgetPosition(): Position;\r\n\r\n\t/**\r\n\t * Returns the primary selection of the editor.\r\n\t */\r\n\tgetSelection(): Selection;\r\n\r\n\t/**\r\n\t * Returns all the selections of the editor.\r\n\t */\r\n\tgetSelections(): Selection[];\r\n\r\n\t/**\r\n\t * Type the getModel() of IEditor.\r\n\t */\r\n\tgetModel(): ITextModel;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\t_getViewModel(): IViewModel;\r\n\r\n\t/**\r\n\t * Get all the decorations on a line (filtering out decorations from other editors).\r\n\t */\r\n\tgetLineDecorations(lineNumber: number): IModelDecoration[];\r\n\r\n\t/**\r\n\t * Returns the editor's dom node\r\n\t */\r\n\tgetDomNode(): HTMLElement;\r\n\r\n\t/**\r\n\t * Get the visible position for `position`.\r\n\t * The result position takes scrolling into account and is relative to the top left corner of the editor.\r\n\t * Explanation 1: the results of this method will change for the same `position` if the user scrolls the editor.\r\n\t * Explanation 2: the results of this method will not change if the container of the editor gets repositioned.\r\n\t * Warning: the results of this method are inaccurate for positions that are outside the current editor viewport.\r\n\t */\r\n\tgetScrolledVisiblePosition(position: IPosition): { top: number; left: number; height: number; };\r\n}\r\n\r\n/**\r\n * Information about a line in the diff editor\r\n */\r\nexport interface IDiffLineInformation {\r\n\treadonly equivalentLineNumber: number;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const enum DiffEditorState {\r\n\tIdle,\r\n\tComputingDiff,\r\n\tDiffComputed\r\n}\r\n\r\n/**\r\n * A rich diff editor.\r\n */\r\nexport interface IDiffEditor extends editorCommon.IEditor {\r\n\r\n\t/**\r\n\t * @see ICodeEditor.getDomNode\r\n\t */\r\n\tgetDomNode(): HTMLElement;\r\n\r\n\t/**\r\n\t * An event emitted when the diff information computed by this diff editor has been updated.\r\n\t * @event\r\n\t */\r\n\tonDidUpdateDiff(listener: () => void): IDisposable;\r\n\r\n\t/**\r\n\t * Saves current view state of the editor in a serializable object.\r\n\t */\r\n\tsaveViewState(): editorCommon.IDiffEditorViewState | null;\r\n\r\n\t/**\r\n\t * Restores the view state of the editor from a serializable object generated by `saveViewState`.\r\n\t */\r\n\trestoreViewState(state: editorCommon.IDiffEditorViewState): void;\r\n\r\n\t/**\r\n\t * Type the getModel() of IEditor.\r\n\t */\r\n\tgetModel(): editorCommon.IDiffEditorModel | null;\r\n\r\n\t/**\r\n\t * Sets the current model attached to this editor.\r\n\t * If the previous model was created by the editor via the value key in the options\r\n\t * literal object, it will be destroyed. Otherwise, if the previous model was set\r\n\t * via setModel, or the model key in the options literal object, the previous model\r\n\t * will not be destroyed.\r\n\t * It is safe to call setModel(null) to simply detach the current model from the editor.\r\n\t */\r\n\tsetModel(model: editorCommon.IDiffEditorModel | null): void;\r\n\r\n\t/**\r\n\t * Get the `original` editor.\r\n\t */\r\n\tgetOriginalEditor(): ICodeEditor;\r\n\r\n\t/**\r\n\t * Get the `modified` editor.\r\n\t */\r\n\tgetModifiedEditor(): ICodeEditor;\r\n\r\n\t/**\r\n\t * Get the computed diff information.\r\n\t */\r\n\tgetLineChanges(): editorCommon.ILineChange[] | null;\r\n\r\n\t/**\r\n\t * Get information based on computed diff about a line number from the original model.\r\n\t * If the diff computation is not finished or the model is missing, will return null.\r\n\t */\r\n\tgetDiffLineInformationForOriginal(lineNumber: number): IDiffLineInformation | null;\r\n\r\n\t/**\r\n\t * Get information based on computed diff about a line number from the modified model.\r\n\t * If the diff computation is not finished or the model is missing, will return null.\r\n\t */\r\n\tgetDiffLineInformationForModified(lineNumber: number): IDiffLineInformation | null;\r\n\r\n\t/**\r\n\t * Update the editor's options after the editor has been created.\r\n\t */\r\n\tupdateOptions(newOptions: IDiffEditorOptions): void;\r\n}\r\n\r\n/**\r\n *@internal\r\n */\r\nexport function isCodeEditor(thing: unknown): thing is ICodeEditor {\r\n\tif (thing && typeof (thing).getEditorType === 'function') {\r\n\t\treturn (thing).getEditorType() === editorCommon.EditorType.ICodeEditor;\r\n\t} else {\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\n/**\r\n *@internal\r\n */\r\nexport function isDiffEditor(thing: unknown): thing is IDiffEditor {\r\n\tif (thing && typeof (thing).getEditorType === 'function') {\r\n\t\treturn (thing).getEditorType() === editorCommon.EditorType.IDiffEditor;\r\n\t} else {\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\n/**\r\n *@internal\r\n */\r\nexport function getCodeEditor(thing: unknown): ICodeEditor | null {\r\n\tif (isCodeEditor(thing)) {\r\n\t\treturn thing;\r\n\t}\r\n\r\n\tif (isDiffEditor(thing)) {\r\n\t\treturn thing.getModifiedEditor();\r\n\t}\r\n\r\n\treturn null;\r\n}\r\n","\r\nimport { IMarkdownString } from 'vs/base/common/htmlContent';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { LineTokens } from 'vs/editor/common/core/lineTokens';\r\nimport { IPosition, Position } from 'vs/editor/common/core/position';\r\nimport { IRange, Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { IModelContentChange, IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelLanguageConfigurationChangedEvent, IModelOptionsChangedEvent, IModelTokensChangedEvent, ModelRawContentChangedEvent } from 'vs/editor/common/model/textModelEvents';\r\nimport { SearchData } from 'vs/editor/common/model/textModelSearch';\r\nimport { LanguageId, LanguageIdentifier, FormattingOptions } from 'vs/editor/common/modes';\r\nimport { ThemeColor } from 'vs/platform/theme/common/themeService';\r\nimport { MultilineTokens2 } from 'vs/editor/common/model/tokensStore';\r\nimport { TextChange } from 'vs/editor/common/model/textChange';\r\n\r\n/**\r\n * Vertical Lane in the overview ruler of the editor.\r\n */\r\nexport enum OverviewRulerLane {\r\n\tLeft = 1,\r\n\tCenter = 2,\r\n\tRight = 4,\r\n\tFull = 7\r\n}\r\n\r\n/**\r\n * Position in the minimap to render the decoration.\r\n */\r\nexport enum MinimapPosition {\r\n\tInline = 1,\r\n\tGutter = 2\r\n}\r\n\r\nexport interface IDecorationOptions {\r\n\t/**\r\n\t * CSS color to render.\r\n\t * e.g.: rgba(100, 100, 100, 0.5) or a color from the color registry\r\n\t */\r\n\tcolor: string | ThemeColor | undefined;\r\n\t/**\r\n\t * CSS color to render.\r\n\t * e.g.: rgba(100, 100, 100, 0.5) or a color from the color registry\r\n\t */\r\n\tdarkColor?: string | ThemeColor;\r\n}\r\n\r\n/**\r\n * Options for rendering a model decoration in the overview ruler.\r\n */\r\nexport interface IModelDecorationOverviewRulerOptions extends IDecorationOptions {\r\n\t/**\r\n\t * The position in the overview ruler.\r\n\t */\r\n\tposition: OverviewRulerLane;\r\n}\r\n\r\n/**\r\n * Options for rendering a model decoration in the overview ruler.\r\n */\r\nexport interface IModelDecorationMinimapOptions extends IDecorationOptions {\r\n\t/**\r\n\t * The position in the overview ruler.\r\n\t */\r\n\tposition: MinimapPosition;\r\n}\r\n\r\n/**\r\n * Options for a model decoration.\r\n */\r\nexport interface IModelDecorationOptions {\r\n\t/**\r\n\t * Customize the growing behavior of the decoration when typing at the edges of the decoration.\r\n\t * Defaults to TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges\r\n\t */\r\n\tstickiness?: TrackedRangeStickiness;\r\n\t/**\r\n\t * CSS class name describing the decoration.\r\n\t */\r\n\tclassName?: string | null;\r\n\t/**\r\n\t * Message to be rendered when hovering over the glyph margin decoration.\r\n\t */\r\n\tglyphMarginHoverMessage?: IMarkdownString | IMarkdownString[] | null;\r\n\t/**\r\n\t * Array of MarkdownString to render as the decoration message.\r\n\t */\r\n\thoverMessage?: IMarkdownString | IMarkdownString[] | null;\r\n\t/**\r\n\t * Should the decoration expand to encompass a whole line.\r\n\t */\r\n\tisWholeLine?: boolean;\r\n\t/**\r\n\t * Always render the decoration (even when the range it encompasses is collapsed).\r\n\t * @internal\r\n\t */\r\n\tshowIfCollapsed?: boolean;\r\n\t/**\r\n\t * Collapse the decoration if its entire range is being replaced via an edit.\r\n\t * @internal\r\n\t */\r\n\tcollapseOnReplaceEdit?: boolean;\r\n\t/**\r\n\t * Specifies the stack order of a decoration.\r\n\t * A decoration with greater stack order is always in front of a decoration with a lower stack order.\r\n\t */\r\n\tzIndex?: number;\r\n\t/**\r\n\t * If set, render this decoration in the overview ruler.\r\n\t */\r\n\toverviewRuler?: IModelDecorationOverviewRulerOptions | null;\r\n\t/**\r\n\t * If set, render this decoration in the minimap.\r\n\t */\r\n\tminimap?: IModelDecorationMinimapOptions | null;\r\n\t/**\r\n\t * If set, the decoration will be rendered in the glyph margin with this CSS class name.\r\n\t */\r\n\tglyphMarginClassName?: string | null;\r\n\t/**\r\n\t * If set, the decoration will be rendered in the lines decorations with this CSS class name.\r\n\t */\r\n\tlinesDecorationsClassName?: string | null;\r\n\t/**\r\n\t * If set, the decoration will be rendered in the lines decorations with this CSS class name, but only for the first line in case of line wrapping.\r\n\t */\r\n\tfirstLineDecorationClassName?: string | null;\r\n\t/**\r\n\t * If set, the decoration will be rendered in the margin (covering its full width) with this CSS class name.\r\n\t */\r\n\tmarginClassName?: string | null;\r\n\t/**\r\n\t * If set, the decoration will be rendered inline with the text with this CSS class name.\r\n\t * Please use this only for CSS rules that must impact the text. For example, use `className`\r\n\t * to have a background color decoration.\r\n\t */\r\n\tinlineClassName?: string | null;\r\n\t/**\r\n\t * If there is an `inlineClassName` which affects letter spacing.\r\n\t */\r\n\tinlineClassNameAffectsLetterSpacing?: boolean;\r\n\t/**\r\n\t * If set, the decoration will be rendered before the text with this CSS class name.\r\n\t */\r\n\tbeforeContentClassName?: string | null;\r\n\t/**\r\n\t * If set, the decoration will be rendered after the text with this CSS class name.\r\n\t */\r\n\tafterContentClassName?: string | null;\r\n}\r\n\r\n/**\r\n * New model decorations.\r\n */\r\nexport interface IModelDeltaDecoration {\r\n\t/**\r\n\t * Range that this decoration covers.\r\n\t */\r\n\trange: IRange;\r\n\t/**\r\n\t * Options associated with this decoration.\r\n\t */\r\n\toptions: IModelDecorationOptions;\r\n}\r\n\r\n/**\r\n * A decoration in the model.\r\n */\r\nexport interface IModelDecoration {\r\n\t/**\r\n\t * Identifier for a decoration.\r\n\t */\r\n\treadonly id: string;\r\n\t/**\r\n\t * Identifier for a decoration's owner.\r\n\t */\r\n\treadonly ownerId: number;\r\n\t/**\r\n\t * Range that this decoration covers.\r\n\t */\r\n\treadonly range: Range;\r\n\t/**\r\n\t * Options associated with this decoration.\r\n\t */\r\n\treadonly options: IModelDecorationOptions;\r\n}\r\n\r\n/**\r\n * An accessor that can add, change or remove model decorations.\r\n * @internal\r\n */\r\nexport interface IModelDecorationsChangeAccessor {\r\n\t/**\r\n\t * Add a new decoration.\r\n\t * @param range Range that this decoration covers.\r\n\t * @param options Options associated with this decoration.\r\n\t * @return An unique identifier associated with this decoration.\r\n\t */\r\n\taddDecoration(range: IRange, options: IModelDecorationOptions): string;\r\n\t/**\r\n\t * Change the range that an existing decoration covers.\r\n\t * @param id The unique identifier associated with the decoration.\r\n\t * @param newRange The new range that this decoration covers.\r\n\t */\r\n\tchangeDecoration(id: string, newRange: IRange): void;\r\n\t/**\r\n\t * Change the options associated with an existing decoration.\r\n\t * @param id The unique identifier associated with the decoration.\r\n\t * @param newOptions The new options associated with this decoration.\r\n\t */\r\n\tchangeDecorationOptions(id: string, newOptions: IModelDecorationOptions): void;\r\n\t/**\r\n\t * Remove an existing decoration.\r\n\t * @param id The unique identifier associated with the decoration.\r\n\t */\r\n\tremoveDecoration(id: string): void;\r\n\t/**\r\n\t * Perform a minimum amount of operations, in order to transform the decorations\r\n\t * identified by `oldDecorations` to the decorations described by `newDecorations`\r\n\t * and returns the new identifiers associated with the resulting decorations.\r\n\t *\r\n\t * @param oldDecorations Array containing previous decorations identifiers.\r\n\t * @param newDecorations Array describing what decorations should result after the call.\r\n\t * @return An array containing the new decorations identifiers.\r\n\t */\r\n\tdeltaDecorations(oldDecorations: string[], newDecorations: IModelDeltaDecoration[]): string[];\r\n}\r\n\r\n/**\r\n * Word inside a model.\r\n */\r\nexport interface IWordAtPosition {\r\n\t/**\r\n\t * The word.\r\n\t */\r\n\treadonly word: string;\r\n\t/**\r\n\t * The column where the word starts.\r\n\t */\r\n\treadonly startColumn: number;\r\n\t/**\r\n\t * The column where the word ends.\r\n\t */\r\n\treadonly endColumn: number;\r\n}\r\n\r\n/**\r\n * End of line character preference.\r\n */\r\nexport const enum EndOfLinePreference {\r\n\t/**\r\n\t * Use the end of line character identified in the text buffer.\r\n\t */\r\n\tTextDefined = 0,\r\n\t/**\r\n\t * Use line feed (\\n) as the end of line character.\r\n\t */\r\n\tLF = 1,\r\n\t/**\r\n\t * Use carriage return and line feed (\\r\\n) as the end of line character.\r\n\t */\r\n\tCRLF = 2\r\n}\r\n\r\n/**\r\n * The default end of line to use when instantiating models.\r\n */\r\nexport const enum DefaultEndOfLine {\r\n\t/**\r\n\t * Use line feed (\\n) as the end of line character.\r\n\t */\r\n\tLF = 1,\r\n\t/**\r\n\t * Use carriage return and line feed (\\r\\n) as the end of line character.\r\n\t */\r\n\tCRLF = 2\r\n}\r\n\r\n/**\r\n * End of line character preference.\r\n */\r\nexport const enum EndOfLineSequence {\r\n\t/**\r\n\t * Use line feed (\\n) as the end of line character.\r\n\t */\r\n\tLF = 0,\r\n\t/**\r\n\t * Use carriage return and line feed (\\r\\n) as the end of line character.\r\n\t */\r\n\tCRLF = 1\r\n}\r\n\r\n/**\r\n * An identifier for a single edit operation.\r\n * @internal\r\n */\r\nexport interface ISingleEditOperationIdentifier {\r\n\t/**\r\n\t * Identifier major\r\n\t */\r\n\tmajor: number;\r\n\t/**\r\n\t * Identifier minor\r\n\t */\r\n\tminor: number;\r\n}\r\n\r\n/**\r\n * A single edit operation, that acts as a simple replace.\r\n * i.e. Replace text at `range` with `text` in model.\r\n */\r\nexport interface ISingleEditOperation {\r\n\t/**\r\n\t * The range to replace. This can be empty to emulate a simple insert.\r\n\t */\r\n\trange: IRange;\r\n\t/**\r\n\t * The text to replace with. This can be null to emulate a simple delete.\r\n\t */\r\n\ttext: string | null;\r\n\t/**\r\n\t * This indicates that this operation has \"insert\" semantics.\r\n\t * i.e. forceMoveMarkers = true => if `range` is collapsed, all markers at the position will be moved.\r\n\t */\r\n\tforceMoveMarkers?: boolean;\r\n}\r\n\r\n/**\r\n * A single edit operation, that has an identifier.\r\n */\r\nexport interface IIdentifiedSingleEditOperation {\r\n\t/**\r\n\t * An identifier associated with this single edit operation.\r\n\t * @internal\r\n\t */\r\n\tidentifier?: ISingleEditOperationIdentifier | null;\r\n\t/**\r\n\t * The range to replace. This can be empty to emulate a simple insert.\r\n\t */\r\n\trange: IRange;\r\n\t/**\r\n\t * The text to replace with. This can be null to emulate a simple delete.\r\n\t */\r\n\ttext: string | null;\r\n\t/**\r\n\t * This indicates that this operation has \"insert\" semantics.\r\n\t * i.e. forceMoveMarkers = true => if `range` is collapsed, all markers at the position will be moved.\r\n\t */\r\n\tforceMoveMarkers?: boolean;\r\n\t/**\r\n\t * This indicates that this operation is inserting automatic whitespace\r\n\t * that can be removed on next model edit operation if `config.trimAutoWhitespace` is true.\r\n\t * @internal\r\n\t */\r\n\tisAutoWhitespaceEdit?: boolean;\r\n\t/**\r\n\t * This indicates that this operation is in a set of operations that are tracked and should not be \"simplified\".\r\n\t * @internal\r\n\t */\r\n\t_isTracked?: boolean;\r\n}\r\n\r\nexport interface IValidEditOperation {\r\n\t/**\r\n\t * An identifier associated with this single edit operation.\r\n\t * @internal\r\n\t */\r\n\tidentifier: ISingleEditOperationIdentifier | null;\r\n\t/**\r\n\t * The range to replace. This can be empty to emulate a simple insert.\r\n\t */\r\n\trange: Range;\r\n\t/**\r\n\t * The text to replace with. This can be empty to emulate a simple delete.\r\n\t */\r\n\ttext: string;\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\ttextChange: TextChange;\r\n}\r\n\r\n/**\r\n * A callback that can compute the cursor state after applying a series of edit operations.\r\n */\r\nexport interface ICursorStateComputer {\r\n\t/**\r\n\t * A callback that can compute the resulting cursors state after some edit operations have been executed.\r\n\t */\r\n\t(inverseEditOperations: IValidEditOperation[]): Selection[] | null;\r\n}\r\n\r\nexport class TextModelResolvedOptions {\r\n\t_textModelResolvedOptionsBrand: void;\r\n\r\n\treadonly tabSize: number;\r\n\treadonly indentSize: number;\r\n\treadonly insertSpaces: boolean;\r\n\treadonly defaultEOL: DefaultEndOfLine;\r\n\treadonly trimAutoWhitespace: boolean;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tconstructor(src: {\r\n\t\ttabSize: number;\r\n\t\tindentSize: number;\r\n\t\tinsertSpaces: boolean;\r\n\t\tdefaultEOL: DefaultEndOfLine;\r\n\t\ttrimAutoWhitespace: boolean;\r\n\t}) {\r\n\t\tthis.tabSize = Math.max(1, src.tabSize | 0);\r\n\t\tthis.indentSize = src.tabSize | 0;\r\n\t\tthis.insertSpaces = Boolean(src.insertSpaces);\r\n\t\tthis.defaultEOL = src.defaultEOL | 0;\r\n\t\tthis.trimAutoWhitespace = Boolean(src.trimAutoWhitespace);\r\n\t}\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tpublic equals(other: TextModelResolvedOptions): boolean {\r\n\t\treturn (\r\n\t\t\tthis.tabSize === other.tabSize\r\n\t\t\t&& this.indentSize === other.indentSize\r\n\t\t\t&& this.insertSpaces === other.insertSpaces\r\n\t\t\t&& this.defaultEOL === other.defaultEOL\r\n\t\t\t&& this.trimAutoWhitespace === other.trimAutoWhitespace\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tpublic createChangeEvent(newOpts: TextModelResolvedOptions): IModelOptionsChangedEvent {\r\n\t\treturn {\r\n\t\t\ttabSize: this.tabSize !== newOpts.tabSize,\r\n\t\t\tindentSize: this.indentSize !== newOpts.indentSize,\r\n\t\t\tinsertSpaces: this.insertSpaces !== newOpts.insertSpaces,\r\n\t\t\ttrimAutoWhitespace: this.trimAutoWhitespace !== newOpts.trimAutoWhitespace,\r\n\t\t};\r\n\t}\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface ITextModelCreationOptions {\r\n\ttabSize: number;\r\n\tindentSize: number;\r\n\tinsertSpaces: boolean;\r\n\tdetectIndentation: boolean;\r\n\ttrimAutoWhitespace: boolean;\r\n\tdefaultEOL: DefaultEndOfLine;\r\n\tisForSimpleWidget: boolean;\r\n\tlargeFileOptimizations: boolean;\r\n}\r\n\r\nexport interface ITextModelUpdateOptions {\r\n\ttabSize?: number;\r\n\tindentSize?: number;\r\n\tinsertSpaces?: boolean;\r\n\ttrimAutoWhitespace?: boolean;\r\n}\r\n\r\nexport class FindMatch {\r\n\t_findMatchBrand: void;\r\n\r\n\tpublic readonly range: Range;\r\n\tpublic readonly matches: string[] | null;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tconstructor(range: Range, matches: string[] | null) {\r\n\t\tthis.range = range;\r\n\t\tthis.matches = matches;\r\n\t}\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface IFoundBracket {\r\n\trange: Range;\r\n\topen: string[];\r\n\tclose: string[];\r\n\tisOpen: boolean;\r\n}\r\n\r\n/**\r\n * Describes the behavior of decorations when typing/editing near their edges.\r\n * Note: Please do not edit the values, as they very carefully match `DecorationRangeBehavior`\r\n */\r\nexport const enum TrackedRangeStickiness {\r\n\tAlwaysGrowsWhenTypingAtEdges = 0,\r\n\tNeverGrowsWhenTypingAtEdges = 1,\r\n\tGrowsOnlyWhenTypingBefore = 2,\r\n\tGrowsOnlyWhenTypingAfter = 3,\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface IActiveIndentGuideInfo {\r\n\tstartLineNumber: number;\r\n\tendLineNumber: number;\r\n\tindent: number;\r\n}\r\n\r\n/**\r\n * Text snapshot that works like an iterator.\r\n * Will try to return chunks of roughly ~64KB size.\r\n * Will return null when finished.\r\n *\r\n * @internal\r\n */\r\nexport interface ITextSnapshot {\r\n\tread(): string | null;\r\n}\r\n\r\n/**\r\n * A model.\r\n */\r\nexport interface ITextModel {\r\n\r\n\t/**\r\n\t * Gets the resource associated with this editor model.\r\n\t */\r\n\treadonly uri: URI;\r\n\r\n\t/**\r\n\t * A unique identifier associated with this model.\r\n\t */\r\n\treadonly id: string;\r\n\r\n\t/**\r\n\t * This model is constructed for a simple widget code editor.\r\n\t * @internal\r\n\t */\r\n\treadonly isForSimpleWidget: boolean;\r\n\r\n\t/**\r\n\t * If true, the text model might contain RTL.\r\n\t * If false, the text model **contains only** contain LTR.\r\n\t * @internal\r\n\t */\r\n\tmightContainRTL(): boolean;\r\n\r\n\t/**\r\n\t * If true, the text model might contain LINE SEPARATOR (LS), PARAGRAPH SEPARATOR (PS).\r\n\t * If false, the text model definitely does not contain these.\r\n\t * @internal\r\n\t */\r\n\tmightContainUnusualLineTerminators(): boolean;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tremoveUnusualLineTerminators(selections?: Selection[]): void;\r\n\r\n\t/**\r\n\t * If true, the text model might contain non basic ASCII.\r\n\t * If false, the text model **contains only** basic ASCII.\r\n\t * @internal\r\n\t */\r\n\tmightContainNonBasicASCII(): boolean;\r\n\r\n\t/**\r\n\t * Get the resolved options for this model.\r\n\t */\r\n\tgetOptions(): TextModelResolvedOptions;\r\n\r\n\t/**\r\n\t * Get the formatting options for this model.\r\n\t * @internal\r\n\t */\r\n\tgetFormattingOptions(): FormattingOptions;\r\n\r\n\t/**\r\n\t * Get the current version id of the model.\r\n\t * Anytime a change happens to the model (even undo/redo),\r\n\t * the version id is incremented.\r\n\t */\r\n\tgetVersionId(): number;\r\n\r\n\t/**\r\n\t * Get the alternative version id of the model.\r\n\t * This alternative version id is not always incremented,\r\n\t * it will return the same values in the case of undo-redo.\r\n\t */\r\n\tgetAlternativeVersionId(): number;\r\n\r\n\t/**\r\n\t * Replace the entire text buffer value contained in this model.\r\n\t */\r\n\tsetValue(newValue: string): void;\r\n\r\n\t/**\r\n\t * Get the text stored in this model.\r\n\t * @param eol The end of line character preference. Defaults to `EndOfLinePreference.TextDefined`.\r\n\t * @param preserverBOM Preserve a BOM character if it was detected when the model was constructed.\r\n\t * @return The text.\r\n\t */\r\n\tgetValue(eol?: EndOfLinePreference, preserveBOM?: boolean): string;\r\n\r\n\t/**\r\n\t * Get the text stored in this model.\r\n\t * @param preserverBOM Preserve a BOM character if it was detected when the model was constructed.\r\n\t * @return The text snapshot (it is safe to consume it asynchronously).\r\n\t * @internal\r\n\t */\r\n\tcreateSnapshot(preserveBOM?: boolean): ITextSnapshot;\r\n\r\n\t/**\r\n\t * Get the length of the text stored in this model.\r\n\t */\r\n\tgetValueLength(eol?: EndOfLinePreference, preserveBOM?: boolean): number;\r\n\r\n\t/**\r\n\t * Get the text in a certain range.\r\n\t * @param range The range describing what text to get.\r\n\t * @param eol The end of line character preference. This will only be used for multiline ranges. Defaults to `EndOfLinePreference.TextDefined`.\r\n\t * @return The text.\r\n\t */\r\n\tgetValueInRange(range: IRange, eol?: EndOfLinePreference): string;\r\n\r\n\t/**\r\n\t * Get the length of text in a certain range.\r\n\t * @param range The range describing what text length to get.\r\n\t * @return The text length.\r\n\t */\r\n\tgetValueLengthInRange(range: IRange): number;\r\n\r\n\t/**\r\n\t * Get the character count of text in a certain range.\r\n\t * @param range The range describing what text length to get.\r\n\t */\r\n\tgetCharacterCountInRange(range: IRange): number;\r\n\r\n\t/**\r\n\t * Splits characters in two buckets. First bucket (A) is of characters that\r\n\t * sit in lines with length < `LONG_LINE_BOUNDARY`. Second bucket (B) is of\r\n\t * characters that sit in lines with length >= `LONG_LINE_BOUNDARY`.\r\n\t * If count(B) > count(A) return true. Returns false otherwise.\r\n\t * @internal\r\n\t */\r\n\tisDominatedByLongLines(): boolean;\r\n\r\n\t/**\r\n\t * Get the number of lines in the model.\r\n\t */\r\n\tgetLineCount(): number;\r\n\r\n\t/**\r\n\t * Get the text for a certain line.\r\n\t */\r\n\tgetLineContent(lineNumber: number): string;\r\n\r\n\t/**\r\n\t * Get the text length for a certain line.\r\n\t */\r\n\tgetLineLength(lineNumber: number): number;\r\n\r\n\t/**\r\n\t * Get the text for all lines.\r\n\t */\r\n\tgetLinesContent(): string[];\r\n\r\n\t/**\r\n\t * Get the end of line sequence predominantly used in the text buffer.\r\n\t * @return EOL char sequence (e.g.: '\\n' or '\\r\\n').\r\n\t */\r\n\tgetEOL(): string;\r\n\r\n\t/**\r\n\t * Get the end of line sequence predominantly used in the text buffer.\r\n\t */\r\n\tgetEndOfLineSequence(): EndOfLineSequence;\r\n\r\n\t/**\r\n\t * Get the minimum legal column for line at `lineNumber`\r\n\t */\r\n\tgetLineMinColumn(lineNumber: number): number;\r\n\r\n\t/**\r\n\t * Get the maximum legal column for line at `lineNumber`\r\n\t */\r\n\tgetLineMaxColumn(lineNumber: number): number;\r\n\r\n\t/**\r\n\t * Returns the column before the first non whitespace character for line at `lineNumber`.\r\n\t * Returns 0 if line is empty or contains only whitespace.\r\n\t */\r\n\tgetLineFirstNonWhitespaceColumn(lineNumber: number): number;\r\n\r\n\t/**\r\n\t * Returns the column after the last non whitespace character for line at `lineNumber`.\r\n\t * Returns 0 if line is empty or contains only whitespace.\r\n\t */\r\n\tgetLineLastNonWhitespaceColumn(lineNumber: number): number;\r\n\r\n\t/**\r\n\t * Create a valid position,\r\n\t */\r\n\tvalidatePosition(position: IPosition): Position;\r\n\r\n\t/**\r\n\t * Advances the given position by the given offset (negative offsets are also accepted)\r\n\t * and returns it as a new valid position.\r\n\t *\r\n\t * If the offset and position are such that their combination goes beyond the beginning or\r\n\t * end of the model, throws an exception.\r\n\t *\r\n\t * If the offset is such that the new position would be in the middle of a multi-byte\r\n\t * line terminator, throws an exception.\r\n\t */\r\n\tmodifyPosition(position: IPosition, offset: number): Position;\r\n\r\n\t/**\r\n\t * Create a valid range.\r\n\t */\r\n\tvalidateRange(range: IRange): Range;\r\n\r\n\t/**\r\n\t * Converts the position to a zero-based offset.\r\n\t *\r\n\t * The position will be [adjusted](#TextDocument.validatePosition).\r\n\t *\r\n\t * @param position A position.\r\n\t * @return A valid zero-based offset.\r\n\t */\r\n\tgetOffsetAt(position: IPosition): number;\r\n\r\n\t/**\r\n\t * Converts a zero-based offset to a position.\r\n\t *\r\n\t * @param offset A zero-based offset.\r\n\t * @return A valid [position](#Position).\r\n\t */\r\n\tgetPositionAt(offset: number): Position;\r\n\r\n\t/**\r\n\t * Get a range covering the entire model\r\n\t */\r\n\tgetFullModelRange(): Range;\r\n\r\n\t/**\r\n\t * Returns if the model was disposed or not.\r\n\t */\r\n\tisDisposed(): boolean;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\ttokenizeViewport(startLineNumber: number, endLineNumber: number): void;\r\n\r\n\t/**\r\n\t * This model is so large that it would not be a good idea to sync it over\r\n\t * to web workers or other places.\r\n\t * @internal\r\n\t */\r\n\tisTooLargeForSyncing(): boolean;\r\n\r\n\t/**\r\n\t * The file is so large, that even tokenization is disabled.\r\n\t * @internal\r\n\t */\r\n\tisTooLargeForTokenization(): boolean;\r\n\r\n\t/**\r\n\t * Search the model.\r\n\t * @param searchString The string used to search. If it is a regular expression, set `isRegex` to true.\r\n\t * @param searchOnlyEditableRange Limit the searching to only search inside the editable range of the model.\r\n\t * @param isRegex Used to indicate that `searchString` is a regular expression.\r\n\t * @param matchCase Force the matching to match lower/upper case exactly.\r\n\t * @param wordSeparators Force the matching to match entire words only. Pass null otherwise.\r\n\t * @param captureMatches The result will contain the captured groups.\r\n\t * @param limitResultCount Limit the number of results\r\n\t * @return The ranges where the matches are. It is empty if not matches have been found.\r\n\t */\r\n\tfindMatches(searchString: string, searchOnlyEditableRange: boolean, isRegex: boolean, matchCase: boolean, wordSeparators: string | null, captureMatches: boolean, limitResultCount?: number): FindMatch[];\r\n\t/**\r\n\t * Search the model.\r\n\t * @param searchString The string used to search. If it is a regular expression, set `isRegex` to true.\r\n\t * @param searchScope Limit the searching to only search inside these ranges.\r\n\t * @param isRegex Used to indicate that `searchString` is a regular expression.\r\n\t * @param matchCase Force the matching to match lower/upper case exactly.\r\n\t * @param wordSeparators Force the matching to match entire words only. Pass null otherwise.\r\n\t * @param captureMatches The result will contain the captured groups.\r\n\t * @param limitResultCount Limit the number of results\r\n\t * @return The ranges where the matches are. It is empty if no matches have been found.\r\n\t */\r\n\tfindMatches(searchString: string, searchScope: IRange | IRange[], isRegex: boolean, matchCase: boolean, wordSeparators: string | null, captureMatches: boolean, limitResultCount?: number): FindMatch[];\r\n\t/**\r\n\t * Search the model for the next match. Loops to the beginning of the model if needed.\r\n\t * @param searchString The string used to search. If it is a regular expression, set `isRegex` to true.\r\n\t * @param searchStart Start the searching at the specified position.\r\n\t * @param isRegex Used to indicate that `searchString` is a regular expression.\r\n\t * @param matchCase Force the matching to match lower/upper case exactly.\r\n\t * @param wordSeparators Force the matching to match entire words only. Pass null otherwise.\r\n\t * @param captureMatches The result will contain the captured groups.\r\n\t * @return The range where the next match is. It is null if no next match has been found.\r\n\t */\r\n\tfindNextMatch(searchString: string, searchStart: IPosition, isRegex: boolean, matchCase: boolean, wordSeparators: string | null, captureMatches: boolean): FindMatch | null;\r\n\t/**\r\n\t * Search the model for the previous match. Loops to the end of the model if needed.\r\n\t * @param searchString The string used to search. If it is a regular expression, set `isRegex` to true.\r\n\t * @param searchStart Start the searching at the specified position.\r\n\t * @param isRegex Used to indicate that `searchString` is a regular expression.\r\n\t * @param matchCase Force the matching to match lower/upper case exactly.\r\n\t * @param wordSeparators Force the matching to match entire words only. Pass null otherwise.\r\n\t * @param captureMatches The result will contain the captured groups.\r\n\t * @return The range where the previous match is. It is null if no previous match has been found.\r\n\t */\r\n\tfindPreviousMatch(searchString: string, searchStart: IPosition, isRegex: boolean, matchCase: boolean, wordSeparators: string | null, captureMatches: boolean): FindMatch | null;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tsetSemanticTokens(tokens: MultilineTokens2[] | null, isComplete: boolean): void;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tsetPartialSemanticTokens(range: Range, tokens: MultilineTokens2[] | null): void;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\thasCompleteSemanticTokens(): boolean;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\thasSomeSemanticTokens(): boolean;\r\n\r\n\t/**\r\n\t * Flush all tokenization state.\r\n\t * @internal\r\n\t */\r\n\tresetTokenization(): void;\r\n\r\n\t/**\r\n\t * Force tokenization information for `lineNumber` to be accurate.\r\n\t * @internal\r\n\t */\r\n\tforceTokenization(lineNumber: number): void;\r\n\r\n\t/**\r\n\t * If it is cheap, force tokenization information for `lineNumber` to be accurate.\r\n\t * This is based on a heuristic.\r\n\t * @internal\r\n\t */\r\n\ttokenizeIfCheap(lineNumber: number): void;\r\n\r\n\t/**\r\n\t * Check if calling `forceTokenization` for this `lineNumber` will be cheap (time-wise).\r\n\t * This is based on a heuristic.\r\n\t * @internal\r\n\t */\r\n\tisCheapToTokenize(lineNumber: number): boolean;\r\n\r\n\t/**\r\n\t * Get the tokens for the line `lineNumber`.\r\n\t * The tokens might be inaccurate. Use `forceTokenization` to ensure accurate tokens.\r\n\t * @internal\r\n\t */\r\n\tgetLineTokens(lineNumber: number): LineTokens;\r\n\r\n\t/**\r\n\t * Get the language associated with this model.\r\n\t * @internal\r\n\t */\r\n\tgetLanguageIdentifier(): LanguageIdentifier;\r\n\r\n\t/**\r\n\t * Get the language associated with this model.\r\n\t */\r\n\tgetModeId(): string;\r\n\r\n\t/**\r\n\t * Returns the real (inner-most) language mode at a given position.\r\n\t * The result might be inaccurate. Use `forceTokenization` to ensure accurate tokens.\r\n\t * @internal\r\n\t */\r\n\tgetLanguageIdAtPosition(lineNumber: number, column: number): LanguageId;\r\n\r\n\t/**\r\n\t * Get the word under or besides `position`.\r\n\t * @param position The position to look for a word.\r\n\t * @return The word under or besides `position`. Might be null.\r\n\t */\r\n\tgetWordAtPosition(position: IPosition): IWordAtPosition | null;\r\n\r\n\t/**\r\n\t * Get the word under or besides `position` trimmed to `position`.column\r\n\t * @param position The position to look for a word.\r\n\t * @return The word under or besides `position`. Will never be null.\r\n\t */\r\n\tgetWordUntilPosition(position: IPosition): IWordAtPosition;\r\n\r\n\t/**\r\n\t * Find the matching bracket of `request` up, counting brackets.\r\n\t * @param request The bracket we're searching for\r\n\t * @param position The position at which to start the search.\r\n\t * @return The range of the matching bracket, or null if the bracket match was not found.\r\n\t * @internal\r\n\t */\r\n\tfindMatchingBracketUp(bracket: string, position: IPosition): Range | null;\r\n\r\n\t/**\r\n\t * Find the first bracket in the model before `position`.\r\n\t * @param position The position at which to start the search.\r\n\t * @return The info for the first bracket before `position`, or null if there are no more brackets before `positions`.\r\n\t * @internal\r\n\t */\r\n\tfindPrevBracket(position: IPosition): IFoundBracket | null;\r\n\r\n\t/**\r\n\t * Find the first bracket in the model after `position`.\r\n\t * @param position The position at which to start the search.\r\n\t * @return The info for the first bracket after `position`, or null if there are no more brackets after `positions`.\r\n\t * @internal\r\n\t */\r\n\tfindNextBracket(position: IPosition): IFoundBracket | null;\r\n\r\n\t/**\r\n\t * Find the enclosing brackets that contain `position`.\r\n\t * @param position The position at which to start the search.\r\n\t * @internal\r\n\t */\r\n\tfindEnclosingBrackets(position: IPosition, maxDuration?: number): [Range, Range] | null;\r\n\r\n\t/**\r\n\t * Given a `position`, if the position is on top or near a bracket,\r\n\t * find the matching bracket of that bracket and return the ranges of both brackets.\r\n\t * @param position The position at which to look for a bracket.\r\n\t * @internal\r\n\t */\r\n\tmatchBracket(position: IPosition): [Range, Range] | null;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tgetActiveIndentGuide(lineNumber: number, minLineNumber: number, maxLineNumber: number): IActiveIndentGuideInfo;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tgetLinesIndentGuides(startLineNumber: number, endLineNumber: number): number[];\r\n\r\n\t/**\r\n\t * Change the decorations. The callback will be called with a change accessor\r\n\t * that becomes invalid as soon as the callback finishes executing.\r\n\t * This allows for all events to be queued up until the change\r\n\t * is completed. Returns whatever the callback returns.\r\n\t * @param ownerId Identifies the editor id in which these decorations should appear. If no `ownerId` is provided, the decorations will appear in all editors that attach this model.\r\n\t * @internal\r\n\t */\r\n\tchangeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => T, ownerId?: number): T | null;\r\n\r\n\t/**\r\n\t * Perform a minimum amount of operations, in order to transform the decorations\r\n\t * identified by `oldDecorations` to the decorations described by `newDecorations`\r\n\t * and returns the new identifiers associated with the resulting decorations.\r\n\t *\r\n\t * @param oldDecorations Array containing previous decorations identifiers.\r\n\t * @param newDecorations Array describing what decorations should result after the call.\r\n\t * @param ownerId Identifies the editor id in which these decorations should appear. If no `ownerId` is provided, the decorations will appear in all editors that attach this model.\r\n\t * @return An array containing the new decorations identifiers.\r\n\t */\r\n\tdeltaDecorations(oldDecorations: string[], newDecorations: IModelDeltaDecoration[], ownerId?: number): string[];\r\n\r\n\t/**\r\n\t * Remove all decorations that have been added with this specific ownerId.\r\n\t * @param ownerId The owner id to search for.\r\n\t * @internal\r\n\t */\r\n\tremoveAllDecorationsWithOwnerId(ownerId: number): void;\r\n\r\n\t/**\r\n\t * Get the options associated with a decoration.\r\n\t * @param id The decoration id.\r\n\t * @return The decoration options or null if the decoration was not found.\r\n\t */\r\n\tgetDecorationOptions(id: string): IModelDecorationOptions | null;\r\n\r\n\t/**\r\n\t * Get the range associated with a decoration.\r\n\t * @param id The decoration id.\r\n\t * @return The decoration range or null if the decoration was not found.\r\n\t */\r\n\tgetDecorationRange(id: string): Range | null;\r\n\r\n\t/**\r\n\t * Gets all the decorations for the line `lineNumber` as an array.\r\n\t * @param lineNumber The line number\r\n\t * @param ownerId If set, it will ignore decorations belonging to other owners.\r\n\t * @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors).\r\n\t * @return An array with the decorations\r\n\t */\r\n\tgetLineDecorations(lineNumber: number, ownerId?: number, filterOutValidation?: boolean): IModelDecoration[];\r\n\r\n\t/**\r\n\t * Gets all the decorations for the lines between `startLineNumber` and `endLineNumber` as an array.\r\n\t * @param startLineNumber The start line number\r\n\t * @param endLineNumber The end line number\r\n\t * @param ownerId If set, it will ignore decorations belonging to other owners.\r\n\t * @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors).\r\n\t * @return An array with the decorations\r\n\t */\r\n\tgetLinesDecorations(startLineNumber: number, endLineNumber: number, ownerId?: number, filterOutValidation?: boolean): IModelDecoration[];\r\n\r\n\t/**\r\n\t * Gets all the decorations in a range as an array. Only `startLineNumber` and `endLineNumber` from `range` are used for filtering.\r\n\t * So for now it returns all the decorations on the same line as `range`.\r\n\t * @param range The range to search in\r\n\t * @param ownerId If set, it will ignore decorations belonging to other owners.\r\n\t * @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors).\r\n\t * @return An array with the decorations\r\n\t */\r\n\tgetDecorationsInRange(range: IRange, ownerId?: number, filterOutValidation?: boolean): IModelDecoration[];\r\n\r\n\t/**\r\n\t * Gets all the decorations as an array.\r\n\t * @param ownerId If set, it will ignore decorations belonging to other owners.\r\n\t * @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors).\r\n\t */\r\n\tgetAllDecorations(ownerId?: number, filterOutValidation?: boolean): IModelDecoration[];\r\n\r\n\t/**\r\n\t * Gets all the decorations that should be rendered in the overview ruler as an array.\r\n\t * @param ownerId If set, it will ignore decorations belonging to other owners.\r\n\t * @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors).\r\n\t */\r\n\tgetOverviewRulerDecorations(ownerId?: number, filterOutValidation?: boolean): IModelDecoration[];\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\t_getTrackedRange(id: string): Range | null;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\t_setTrackedRange(id: string | null, newRange: null, newStickiness: TrackedRangeStickiness): null;\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\t_setTrackedRange(id: string | null, newRange: Range, newStickiness: TrackedRangeStickiness): string;\r\n\r\n\t/**\r\n\t * Normalize a string containing whitespace according to indentation rules (converts to spaces or to tabs).\r\n\t */\r\n\tnormalizeIndentation(str: string): string;\r\n\r\n\t/**\r\n\t * Change the options of this model.\r\n\t */\r\n\tupdateOptions(newOpts: ITextModelUpdateOptions): void;\r\n\r\n\t/**\r\n\t * Detect the indentation options for this model from its content.\r\n\t */\r\n\tdetectIndentation(defaultInsertSpaces: boolean, defaultTabSize: number): void;\r\n\r\n\t/**\r\n\t * Close the current undo-redo element.\r\n\t * This offers a way to create an undo/redo stop point.\r\n\t */\r\n\tpushStackElement(): void;\r\n\r\n\t/**\r\n\t * Open the current undo-redo element.\r\n\t * This offers a way to remove the current undo/redo stop point.\r\n\t */\r\n\tpopStackElement(): void;\r\n\r\n\t/**\r\n\t * Push edit operations, basically editing the model. This is the preferred way\r\n\t * of editing the model. The edit operations will land on the undo stack.\r\n\t * @param beforeCursorState The cursor state before the edit operations. This cursor state will be returned when `undo` or `redo` are invoked.\r\n\t * @param editOperations The edit operations.\r\n\t * @param cursorStateComputer A callback that can compute the resulting cursors state after the edit operations have been executed.\r\n\t * @return The cursor state returned by the `cursorStateComputer`.\r\n\t */\r\n\tpushEditOperations(beforeCursorState: Selection[] | null, editOperations: IIdentifiedSingleEditOperation[], cursorStateComputer: ICursorStateComputer): Selection[] | null;\r\n\r\n\t/**\r\n\t * Change the end of line sequence. This is the preferred way of\r\n\t * changing the eol sequence. This will land on the undo stack.\r\n\t */\r\n\tpushEOL(eol: EndOfLineSequence): void;\r\n\r\n\t/**\r\n\t * Edit the model without adding the edits to the undo stack.\r\n\t * This can have dire consequences on the undo stack! See @pushEditOperations for the preferred way.\r\n\t * @param operations The edit operations.\r\n\t * @return If desired, the inverse edit operations, that, when applied, will bring the model back to the previous state.\r\n\t */\r\n\tapplyEdits(operations: IIdentifiedSingleEditOperation[]): void;\r\n\tapplyEdits(operations: IIdentifiedSingleEditOperation[], computeUndoEdits: false): void;\r\n\tapplyEdits(operations: IIdentifiedSingleEditOperation[], computeUndoEdits: true): IValidEditOperation[];\r\n\r\n\t/**\r\n\t * Change the end of line sequence without recording in the undo stack.\r\n\t * This can have dire consequences on the undo stack! See @pushEOL for the preferred way.\r\n\t */\r\n\tsetEOL(eol: EndOfLineSequence): void;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\t_applyUndo(changes: TextChange[], eol: EndOfLineSequence, resultingAlternativeVersionId: number, resultingSelection: Selection[] | null): void;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\t_applyRedo(changes: TextChange[], eol: EndOfLineSequence, resultingAlternativeVersionId: number, resultingSelection: Selection[] | null): void;\r\n\r\n\t/**\r\n\t * Undo edit operations until the previous undo/redo point.\r\n\t * The inverse edit operations will be pushed on the redo stack.\r\n\t * @internal\r\n\t */\r\n\tundo(): void | Promise;\r\n\r\n\t/**\r\n\t * Is there anything in the undo stack?\r\n\t * @internal\r\n\t */\r\n\tcanUndo(): boolean;\r\n\r\n\t/**\r\n\t * Redo edit operations until the next undo/redo point.\r\n\t * The inverse edit operations will be pushed on the undo stack.\r\n\t * @internal\r\n\t */\r\n\tredo(): void | Promise;\r\n\r\n\t/**\r\n\t * Is there anything in the redo stack?\r\n\t * @internal\r\n\t */\r\n\tcanRedo(): boolean;\r\n\r\n\t/**\r\n\t * @deprecated Please use `onDidChangeContent` instead.\r\n\t * An event emitted when the contents of the model have changed.\r\n\t * @internal\r\n\t * @event\r\n\t */\r\n\tonDidChangeRawContentFast(listener: (e: ModelRawContentChangedEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted when the contents of the model have changed.\r\n\t * @event\r\n\t */\r\n\tonDidChangeContent(listener: (e: IModelContentChangedEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted when decorations of the model have changed.\r\n\t * @event\r\n\t */\r\n\tonDidChangeDecorations(listener: (e: IModelDecorationsChangedEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted when the model options have changed.\r\n\t * @event\r\n\t */\r\n\tonDidChangeOptions(listener: (e: IModelOptionsChangedEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted when the language associated with the model has changed.\r\n\t * @event\r\n\t */\r\n\tonDidChangeLanguage(listener: (e: IModelLanguageChangedEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted when the language configuration associated with the model has changed.\r\n\t * @event\r\n\t */\r\n\tonDidChangeLanguageConfiguration(listener: (e: IModelLanguageConfigurationChangedEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted when the tokens associated with the model have changed.\r\n\t * @event\r\n\t * @internal\r\n\t */\r\n\tonDidChangeTokens(listener: (e: IModelTokensChangedEvent) => void): IDisposable;\r\n\t/**\r\n\t * An event emitted right before disposing the model.\r\n\t * @event\r\n\t */\r\n\tonWillDispose(listener: () => void): IDisposable;\r\n\r\n\t/**\r\n\t * Destroy this model. This will unbind the model from the mode\r\n\t * and make all necessary clean-up to release this object to the GC.\r\n\t */\r\n\tdispose(): void;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tonBeforeAttached(): void;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tonBeforeDetached(): void;\r\n\r\n\t/**\r\n\t * Returns the count of editors this model is attached to.\r\n\t * @internal\r\n\t */\r\n\tgetAttachedEditorCount(): number;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface ITextBufferBuilder {\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface ITextBufferFactory {\r\n\tcreate(defaultEOL: DefaultEndOfLine): { textBuffer: ITextBuffer; disposable: IDisposable; };\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport class ValidAnnotatedEditOperation implements IIdentifiedSingleEditOperation {\r\n\tconstructor(\r\n\t\tpublic readonly identifier: ISingleEditOperationIdentifier | null,\r\n\t\tpublic readonly range: Range,\r\n\t\tpublic readonly text: string | null,\r\n\t\tpublic readonly forceMoveMarkers: boolean,\r\n\t\tpublic readonly isAutoWhitespaceEdit: boolean,\r\n\t\tpublic readonly _isTracked: boolean,\r\n\t) { }\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface IReadonlyTextBuffer {\r\n\tmightContainRTL(): boolean;\r\n\tmightContainUnusualLineTerminators(): boolean;\r\n\tresetMightContainUnusualLineTerminators(): void;\r\n\tmightContainNonBasicASCII(): boolean;\r\n\tgetBOM(): string;\r\n\tgetEOL(): string;\r\n\r\n\tgetOffsetAt(lineNumber: number, column: number): number;\r\n\tgetPositionAt(offset: number): Position;\r\n\tgetRangeAt(offset: number, length: number): Range;\r\n\r\n\tgetValueInRange(range: Range, eol: EndOfLinePreference): string;\r\n\tcreateSnapshot(preserveBOM: boolean): ITextSnapshot;\r\n\tgetValueLengthInRange(range: Range, eol: EndOfLinePreference): number;\r\n\tgetCharacterCountInRange(range: Range, eol: EndOfLinePreference): number;\r\n\tgetLength(): number;\r\n\tgetLineCount(): number;\r\n\tgetLinesContent(): string[];\r\n\tgetLineContent(lineNumber: number): string;\r\n\tgetLineCharCode(lineNumber: number, index: number): number;\r\n\tgetLineLength(lineNumber: number): number;\r\n\tgetLineFirstNonWhitespaceColumn(lineNumber: number): number;\r\n\tgetLineLastNonWhitespaceColumn(lineNumber: number): number;\r\n\tfindMatchesLineByLine(searchRange: Range, searchData: SearchData, captureMatches: boolean, limitResultCount: number): FindMatch[];\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface ITextBuffer extends IReadonlyTextBuffer {\r\n\tsetEOL(newEOL: '\\r\\n' | '\\n'): void;\r\n\tapplyEdits(rawOperations: ValidAnnotatedEditOperation[], recordTrimAutoWhitespace: boolean, computeUndoEdits: boolean): ApplyEditsResult;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport class ApplyEditsResult {\r\n\r\n\tconstructor(\r\n\t\tpublic readonly reverseEdits: IValidEditOperation[] | null,\r\n\t\tpublic readonly changes: IInternalModelContentChange[],\r\n\t\tpublic readonly trimAutoWhitespaceLineNumbers: number[] | null\r\n\t) { }\r\n\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface IInternalModelContentChange extends IModelContentChange {\r\n\trange: Range;\r\n\tforceMoveMarkers: boolean;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport { ITextBuffer } from 'vs/editor/common/model';\r\n\r\nclass SpacesDiffResult {\r\n\tpublic spacesDiff: number = 0;\r\n\tpublic looksLikeAlignment: boolean = false;\r\n}\r\n\r\n/**\r\n * Compute the diff in spaces between two line's indentation.\r\n */\r\nfunction spacesDiff(a: string, aLength: number, b: string, bLength: number, result: SpacesDiffResult): void {\r\n\r\n\tresult.spacesDiff = 0;\r\n\tresult.looksLikeAlignment = false;\r\n\r\n\t// This can go both ways (e.g.):\r\n\t// - a: \"\\t\"\r\n\t// - b: \"\\t \"\r\n\t// => This should count 1 tab and 4 spaces\r\n\r\n\tlet i: number;\r\n\r\n\tfor (i = 0; i < aLength && i < bLength; i++) {\r\n\t\tlet aCharCode = a.charCodeAt(i);\r\n\t\tlet bCharCode = b.charCodeAt(i);\r\n\r\n\t\tif (aCharCode !== bCharCode) {\r\n\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n\r\n\tlet aSpacesCnt = 0, aTabsCount = 0;\r\n\tfor (let j = i; j < aLength; j++) {\r\n\t\tlet aCharCode = a.charCodeAt(j);\r\n\t\tif (aCharCode === CharCode.Space) {\r\n\t\t\taSpacesCnt++;\r\n\t\t} else {\r\n\t\t\taTabsCount++;\r\n\t\t}\r\n\t}\r\n\r\n\tlet bSpacesCnt = 0, bTabsCount = 0;\r\n\tfor (let j = i; j < bLength; j++) {\r\n\t\tlet bCharCode = b.charCodeAt(j);\r\n\t\tif (bCharCode === CharCode.Space) {\r\n\t\t\tbSpacesCnt++;\r\n\t\t} else {\r\n\t\t\tbTabsCount++;\r\n\t\t}\r\n\t}\r\n\r\n\tif (aSpacesCnt > 0 && aTabsCount > 0) {\r\n\t\treturn;\r\n\t}\r\n\tif (bSpacesCnt > 0 && bTabsCount > 0) {\r\n\t\treturn;\r\n\t}\r\n\r\n\tlet tabsDiff = Math.abs(aTabsCount - bTabsCount);\r\n\tlet spacesDiff = Math.abs(aSpacesCnt - bSpacesCnt);\r\n\r\n\tif (tabsDiff === 0) {\r\n\t\t// check if the indentation difference might be caused by alignment reasons\r\n\t\t// sometime folks like to align their code, but this should not be used as a hint\r\n\t\tresult.spacesDiff = spacesDiff;\r\n\r\n\t\tif (spacesDiff > 0 && 0 <= bSpacesCnt - 1 && bSpacesCnt - 1 < a.length && bSpacesCnt < b.length) {\r\n\t\t\tif (b.charCodeAt(bSpacesCnt) !== CharCode.Space && a.charCodeAt(bSpacesCnt - 1) === CharCode.Space) {\r\n\t\t\t\tif (a.charCodeAt(a.length - 1) === CharCode.Comma) {\r\n\t\t\t\t\t// This looks like an alignment desire: e.g.\r\n\t\t\t\t\t// const a = b + c,\r\n\t\t\t\t\t// d = b - c;\r\n\t\t\t\t\tresult.looksLikeAlignment = true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn;\r\n\t}\r\n\tif (spacesDiff % tabsDiff === 0) {\r\n\t\tresult.spacesDiff = spacesDiff / tabsDiff;\r\n\t\treturn;\r\n\t}\r\n}\r\n\r\n/**\r\n * Result for a guessIndentation\r\n */\r\nexport interface IGuessedIndentation {\r\n\t/**\r\n\t * If indentation is based on spaces (`insertSpaces` = true), then what is the number of spaces that make an indent?\r\n\t */\r\n\ttabSize: number;\r\n\t/**\r\n\t * Is indentation based on spaces?\r\n\t */\r\n\tinsertSpaces: boolean;\r\n}\r\n\r\nexport function guessIndentation(source: ITextBuffer, defaultTabSize: number, defaultInsertSpaces: boolean): IGuessedIndentation {\r\n\t// Look at most at the first 10k lines\r\n\tconst linesCount = Math.min(source.getLineCount(), 10000);\r\n\r\n\tlet linesIndentedWithTabsCount = 0;\t\t\t\t// number of lines that contain at least one tab in indentation\r\n\tlet linesIndentedWithSpacesCount = 0;\t\t\t// number of lines that contain only spaces in indentation\r\n\r\n\tlet previousLineText = '';\t\t\t\t\t\t// content of latest line that contained non-whitespace chars\r\n\tlet previousLineIndentation = 0;\t\t\t\t// index at which latest line contained the first non-whitespace char\r\n\r\n\tconst ALLOWED_TAB_SIZE_GUESSES = [2, 4, 6, 8, 3, 5, 7];\t// prefer even guesses for `tabSize`, limit to [2, 8].\r\n\tconst MAX_ALLOWED_TAB_SIZE_GUESS = 8;\t\t\t// max(ALLOWED_TAB_SIZE_GUESSES) = 8\r\n\r\n\tlet spacesDiffCount = [0, 0, 0, 0, 0, 0, 0, 0, 0];\t\t// `tabSize` scores\r\n\tlet tmp = new SpacesDiffResult();\r\n\r\n\tfor (let lineNumber = 1; lineNumber <= linesCount; lineNumber++) {\r\n\t\tlet currentLineLength = source.getLineLength(lineNumber);\r\n\t\tlet currentLineText = source.getLineContent(lineNumber);\r\n\r\n\t\t// if the text buffer is chunk based, so long lines are cons-string, v8 will flattern the string when we check charCode.\r\n\t\t// checking charCode on chunks directly is cheaper.\r\n\t\tconst useCurrentLineText = (currentLineLength <= 65536);\r\n\r\n\t\tlet currentLineHasContent = false;\t\t\t// does `currentLineText` contain non-whitespace chars\r\n\t\tlet currentLineIndentation = 0;\t\t\t\t// index at which `currentLineText` contains the first non-whitespace char\r\n\t\tlet currentLineSpacesCount = 0;\t\t\t\t// count of spaces found in `currentLineText` indentation\r\n\t\tlet currentLineTabsCount = 0;\t\t\t\t// count of tabs found in `currentLineText` indentation\r\n\t\tfor (let j = 0, lenJ = currentLineLength; j < lenJ; j++) {\r\n\t\t\tlet charCode = (useCurrentLineText ? currentLineText.charCodeAt(j) : source.getLineCharCode(lineNumber, j));\r\n\r\n\t\t\tif (charCode === CharCode.Tab) {\r\n\t\t\t\tcurrentLineTabsCount++;\r\n\t\t\t} else if (charCode === CharCode.Space) {\r\n\t\t\t\tcurrentLineSpacesCount++;\r\n\t\t\t} else {\r\n\t\t\t\t// Hit non whitespace character on this line\r\n\t\t\t\tcurrentLineHasContent = true;\r\n\t\t\t\tcurrentLineIndentation = j;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Ignore empty or only whitespace lines\r\n\t\tif (!currentLineHasContent) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tif (currentLineTabsCount > 0) {\r\n\t\t\tlinesIndentedWithTabsCount++;\r\n\t\t} else if (currentLineSpacesCount > 1) {\r\n\t\t\tlinesIndentedWithSpacesCount++;\r\n\t\t}\r\n\r\n\t\tspacesDiff(previousLineText, previousLineIndentation, currentLineText, currentLineIndentation, tmp);\r\n\r\n\t\tif (tmp.looksLikeAlignment) {\r\n\t\t\t// if defaultInsertSpaces === true && the spaces count == tabSize, we may want to count it as valid indentation\r\n\t\t\t//\r\n\t\t\t// - item1\r\n\t\t\t// - item2\r\n\t\t\t//\r\n\t\t\t// otherwise skip this line entirely\r\n\t\t\t//\r\n\t\t\t// const a = 1,\r\n\t\t\t// b = 2;\r\n\r\n\t\t\tif (!(defaultInsertSpaces && defaultTabSize === tmp.spacesDiff)) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet currentSpacesDiff = tmp.spacesDiff;\r\n\t\tif (currentSpacesDiff <= MAX_ALLOWED_TAB_SIZE_GUESS) {\r\n\t\t\tspacesDiffCount[currentSpacesDiff]++;\r\n\t\t}\r\n\r\n\t\tpreviousLineText = currentLineText;\r\n\t\tpreviousLineIndentation = currentLineIndentation;\r\n\t}\r\n\r\n\tlet insertSpaces = defaultInsertSpaces;\r\n\tif (linesIndentedWithTabsCount !== linesIndentedWithSpacesCount) {\r\n\t\tinsertSpaces = (linesIndentedWithTabsCount < linesIndentedWithSpacesCount);\r\n\t}\r\n\r\n\tlet tabSize = defaultTabSize;\r\n\r\n\t// Guess tabSize only if inserting spaces...\r\n\tif (insertSpaces) {\r\n\t\tlet tabSizeScore = (insertSpaces ? 0 : 0.1 * linesCount);\r\n\r\n\t\t// console.log(\"score threshold: \" + tabSizeScore);\r\n\r\n\t\tALLOWED_TAB_SIZE_GUESSES.forEach((possibleTabSize) => {\r\n\t\t\tlet possibleTabSizeScore = spacesDiffCount[possibleTabSize];\r\n\t\t\tif (possibleTabSizeScore > tabSizeScore) {\r\n\t\t\t\ttabSizeScore = possibleTabSizeScore;\r\n\t\t\t\ttabSize = possibleTabSize;\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\t// Let a tabSize of 2 win even if it is not the maximum\r\n\t\t// (only in case 4 was guessed)\r\n\t\tif (tabSize === 4 && spacesDiffCount[4] > 0 && spacesDiffCount[2] > 0 && spacesDiffCount[2] >= spacesDiffCount[4] / 2) {\r\n\t\t\ttabSize = 2;\r\n\t\t}\r\n\t}\r\n\r\n\r\n\t// console.log('--------------------------');\r\n\t// console.log('linesIndentedWithTabsCount: ' + linesIndentedWithTabsCount + ', linesIndentedWithSpacesCount: ' + linesIndentedWithSpacesCount);\r\n\t// console.log('spacesDiffCount: ' + spacesDiffCount);\r\n\t// console.log('tabSize: ' + tabSize + ', tabSizeScore: ' + tabSizeScore);\r\n\r\n\treturn {\r\n\t\tinsertSpaces: insertSpaces,\r\n\t\ttabSize: tabSize\r\n\t};\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { IModelDecoration, TrackedRangeStickiness } from 'vs/editor/common/model';\r\nimport { ModelDecorationOptions } from 'vs/editor/common/model/textModel';\r\n\r\n//\r\n// The red-black tree is based on the \"Introduction to Algorithms\" by Cormen, Leiserson and Rivest.\r\n//\r\n\r\nexport const enum ClassName {\r\n\tEditorHintDecoration = 'squiggly-hint',\r\n\tEditorInfoDecoration = 'squiggly-info',\r\n\tEditorWarningDecoration = 'squiggly-warning',\r\n\tEditorErrorDecoration = 'squiggly-error',\r\n\tEditorUnnecessaryDecoration = 'squiggly-unnecessary',\r\n\tEditorUnnecessaryInlineDecoration = 'squiggly-inline-unnecessary',\r\n\tEditorDeprecatedInlineDecoration = 'squiggly-inline-deprecated'\r\n}\r\n\r\nexport const enum NodeColor {\r\n\tBlack = 0,\r\n\tRed = 1,\r\n}\r\n\r\nconst enum Constants {\r\n\tColorMask = 0b00000001,\r\n\tColorMaskInverse = 0b11111110,\r\n\tColorOffset = 0,\r\n\r\n\tIsVisitedMask = 0b00000010,\r\n\tIsVisitedMaskInverse = 0b11111101,\r\n\tIsVisitedOffset = 1,\r\n\r\n\tIsForValidationMask = 0b00000100,\r\n\tIsForValidationMaskInverse = 0b11111011,\r\n\tIsForValidationOffset = 2,\r\n\r\n\tIsInOverviewRulerMask = 0b00001000,\r\n\tIsInOverviewRulerMaskInverse = 0b11110111,\r\n\tIsInOverviewRulerOffset = 3,\r\n\r\n\tStickinessMask = 0b00110000,\r\n\tStickinessMaskInverse = 0b11001111,\r\n\tStickinessOffset = 4,\r\n\r\n\tCollapseOnReplaceEditMask = 0b01000000,\r\n\tCollapseOnReplaceEditMaskInverse = 0b10111111,\r\n\tCollapseOnReplaceEditOffset = 6,\r\n\r\n\t/**\r\n\t * Due to how deletion works (in order to avoid always walking the right subtree of the deleted node),\r\n\t * the deltas for nodes can grow and shrink dramatically. It has been observed, in practice, that unless\r\n\t * the deltas are corrected, integer overflow will occur.\r\n\t *\r\n\t * The integer overflow occurs when 53 bits are used in the numbers, but we will try to avoid it as\r\n\t * a node's delta gets below a negative 30 bits number.\r\n\t *\r\n\t * MIN SMI (SMall Integer) as defined in v8.\r\n\t * one bit is lost for boxing/unboxing flag.\r\n\t * one bit is lost for sign flag.\r\n\t * See https://thibaultlaurens.github.io/javascript/2013/04/29/how-the-v8-engine-works/#tagged-values\r\n\t */\r\n\tMIN_SAFE_DELTA = -(1 << 30),\r\n\t/**\r\n\t * MAX SMI (SMall Integer) as defined in v8.\r\n\t * one bit is lost for boxing/unboxing flag.\r\n\t * one bit is lost for sign flag.\r\n\t * See https://thibaultlaurens.github.io/javascript/2013/04/29/how-the-v8-engine-works/#tagged-values\r\n\t */\r\n\tMAX_SAFE_DELTA = 1 << 30,\r\n}\r\n\r\nexport function getNodeColor(node: IntervalNode): NodeColor {\r\n\treturn ((node.metadata & Constants.ColorMask) >>> Constants.ColorOffset);\r\n}\r\nfunction setNodeColor(node: IntervalNode, color: NodeColor): void {\r\n\tnode.metadata = (\r\n\t\t(node.metadata & Constants.ColorMaskInverse) | (color << Constants.ColorOffset)\r\n\t);\r\n}\r\nfunction getNodeIsVisited(node: IntervalNode): boolean {\r\n\treturn ((node.metadata & Constants.IsVisitedMask) >>> Constants.IsVisitedOffset) === 1;\r\n}\r\nfunction setNodeIsVisited(node: IntervalNode, value: boolean): void {\r\n\tnode.metadata = (\r\n\t\t(node.metadata & Constants.IsVisitedMaskInverse) | ((value ? 1 : 0) << Constants.IsVisitedOffset)\r\n\t);\r\n}\r\nfunction getNodeIsForValidation(node: IntervalNode): boolean {\r\n\treturn ((node.metadata & Constants.IsForValidationMask) >>> Constants.IsForValidationOffset) === 1;\r\n}\r\nfunction setNodeIsForValidation(node: IntervalNode, value: boolean): void {\r\n\tnode.metadata = (\r\n\t\t(node.metadata & Constants.IsForValidationMaskInverse) | ((value ? 1 : 0) << Constants.IsForValidationOffset)\r\n\t);\r\n}\r\nexport function getNodeIsInOverviewRuler(node: IntervalNode): boolean {\r\n\treturn ((node.metadata & Constants.IsInOverviewRulerMask) >>> Constants.IsInOverviewRulerOffset) === 1;\r\n}\r\nfunction setNodeIsInOverviewRuler(node: IntervalNode, value: boolean): void {\r\n\tnode.metadata = (\r\n\t\t(node.metadata & Constants.IsInOverviewRulerMaskInverse) | ((value ? 1 : 0) << Constants.IsInOverviewRulerOffset)\r\n\t);\r\n}\r\nfunction getNodeStickiness(node: IntervalNode): TrackedRangeStickiness {\r\n\treturn ((node.metadata & Constants.StickinessMask) >>> Constants.StickinessOffset);\r\n}\r\nfunction _setNodeStickiness(node: IntervalNode, stickiness: TrackedRangeStickiness): void {\r\n\tnode.metadata = (\r\n\t\t(node.metadata & Constants.StickinessMaskInverse) | (stickiness << Constants.StickinessOffset)\r\n\t);\r\n}\r\nfunction getCollapseOnReplaceEdit(node: IntervalNode): boolean {\r\n\treturn ((node.metadata & Constants.CollapseOnReplaceEditMask) >>> Constants.CollapseOnReplaceEditOffset) === 1;\r\n}\r\nfunction setCollapseOnReplaceEdit(node: IntervalNode, value: boolean): void {\r\n\tnode.metadata = (\r\n\t\t(node.metadata & Constants.CollapseOnReplaceEditMaskInverse) | ((value ? 1 : 0) << Constants.CollapseOnReplaceEditOffset)\r\n\t);\r\n}\r\n\r\nexport class IntervalNode implements IModelDecoration {\r\n\r\n\t/**\r\n\t * contains binary encoded information for color, visited, isForValidation and stickiness.\r\n\t */\r\n\tpublic metadata: number;\r\n\r\n\tpublic parent: IntervalNode;\r\n\tpublic left: IntervalNode;\r\n\tpublic right: IntervalNode;\r\n\r\n\tpublic start: number;\r\n\tpublic end: number;\r\n\tpublic delta: number;\r\n\tpublic maxEnd: number;\r\n\r\n\tpublic id: string;\r\n\tpublic ownerId: number;\r\n\tpublic options: ModelDecorationOptions;\r\n\r\n\tpublic cachedVersionId: number;\r\n\tpublic cachedAbsoluteStart: number;\r\n\tpublic cachedAbsoluteEnd: number;\r\n\tpublic range: Range;\r\n\r\n\tconstructor(id: string, start: number, end: number) {\r\n\t\tthis.metadata = 0;\r\n\r\n\t\tthis.parent = this;\r\n\t\tthis.left = this;\r\n\t\tthis.right = this;\r\n\t\tsetNodeColor(this, NodeColor.Red);\r\n\r\n\t\tthis.start = start;\r\n\t\tthis.end = end;\r\n\t\t// FORCE_OVERFLOWING_TEST: this.delta = start;\r\n\t\tthis.delta = 0;\r\n\t\tthis.maxEnd = end;\r\n\r\n\t\tthis.id = id;\r\n\t\tthis.ownerId = 0;\r\n\t\tthis.options = null!;\r\n\t\tsetNodeIsForValidation(this, false);\r\n\t\t_setNodeStickiness(this, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges);\r\n\t\tsetNodeIsInOverviewRuler(this, false);\r\n\t\tsetCollapseOnReplaceEdit(this, false);\r\n\r\n\t\tthis.cachedVersionId = 0;\r\n\t\tthis.cachedAbsoluteStart = start;\r\n\t\tthis.cachedAbsoluteEnd = end;\r\n\t\tthis.range = null!;\r\n\r\n\t\tsetNodeIsVisited(this, false);\r\n\t}\r\n\r\n\tpublic reset(versionId: number, start: number, end: number, range: Range): void {\r\n\t\tthis.start = start;\r\n\t\tthis.end = end;\r\n\t\tthis.maxEnd = end;\r\n\t\tthis.cachedVersionId = versionId;\r\n\t\tthis.cachedAbsoluteStart = start;\r\n\t\tthis.cachedAbsoluteEnd = end;\r\n\t\tthis.range = range;\r\n\t}\r\n\r\n\tpublic setOptions(options: ModelDecorationOptions) {\r\n\t\tthis.options = options;\r\n\t\tlet className = this.options.className;\r\n\t\tsetNodeIsForValidation(this, (\r\n\t\t\tclassName === ClassName.EditorErrorDecoration\r\n\t\t\t|| className === ClassName.EditorWarningDecoration\r\n\t\t\t|| className === ClassName.EditorInfoDecoration\r\n\t\t));\r\n\t\t_setNodeStickiness(this, this.options.stickiness);\r\n\t\tsetNodeIsInOverviewRuler(this, (this.options.overviewRuler && this.options.overviewRuler.color) ? true : false);\r\n\t\tsetCollapseOnReplaceEdit(this, this.options.collapseOnReplaceEdit);\r\n\t}\r\n\r\n\tpublic setCachedOffsets(absoluteStart: number, absoluteEnd: number, cachedVersionId: number): void {\r\n\t\tif (this.cachedVersionId !== cachedVersionId) {\r\n\t\t\tthis.range = null!;\r\n\t\t}\r\n\t\tthis.cachedVersionId = cachedVersionId;\r\n\t\tthis.cachedAbsoluteStart = absoluteStart;\r\n\t\tthis.cachedAbsoluteEnd = absoluteEnd;\r\n\t}\r\n\r\n\tpublic detach(): void {\r\n\t\tthis.parent = null!;\r\n\t\tthis.left = null!;\r\n\t\tthis.right = null!;\r\n\t}\r\n}\r\n\r\nexport const SENTINEL: IntervalNode = new IntervalNode(null!, 0, 0);\r\nSENTINEL.parent = SENTINEL;\r\nSENTINEL.left = SENTINEL;\r\nSENTINEL.right = SENTINEL;\r\nsetNodeColor(SENTINEL, NodeColor.Black);\r\n\r\nexport class IntervalTree {\r\n\r\n\tpublic root: IntervalNode;\r\n\tpublic requestNormalizeDelta: boolean;\r\n\r\n\tconstructor() {\r\n\t\tthis.root = SENTINEL;\r\n\t\tthis.requestNormalizeDelta = false;\r\n\t}\r\n\r\n\tpublic intervalSearch(start: number, end: number, filterOwnerId: number, filterOutValidation: boolean, cachedVersionId: number): IntervalNode[] {\r\n\t\tif (this.root === SENTINEL) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\t\treturn intervalSearch(this, start, end, filterOwnerId, filterOutValidation, cachedVersionId);\r\n\t}\r\n\r\n\tpublic search(filterOwnerId: number, filterOutValidation: boolean, cachedVersionId: number): IntervalNode[] {\r\n\t\tif (this.root === SENTINEL) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\t\treturn search(this, filterOwnerId, filterOutValidation, cachedVersionId);\r\n\t}\r\n\r\n\t/**\r\n\t * Will not set `cachedAbsoluteStart` nor `cachedAbsoluteEnd` on the returned nodes!\r\n\t */\r\n\tpublic collectNodesFromOwner(ownerId: number): IntervalNode[] {\r\n\t\treturn collectNodesFromOwner(this, ownerId);\r\n\t}\r\n\r\n\t/**\r\n\t * Will not set `cachedAbsoluteStart` nor `cachedAbsoluteEnd` on the returned nodes!\r\n\t */\r\n\tpublic collectNodesPostOrder(): IntervalNode[] {\r\n\t\treturn collectNodesPostOrder(this);\r\n\t}\r\n\r\n\tpublic insert(node: IntervalNode): void {\r\n\t\trbTreeInsert(this, node);\r\n\t\tthis._normalizeDeltaIfNecessary();\r\n\t}\r\n\r\n\tpublic delete(node: IntervalNode): void {\r\n\t\trbTreeDelete(this, node);\r\n\t\tthis._normalizeDeltaIfNecessary();\r\n\t}\r\n\r\n\tpublic resolveNode(node: IntervalNode, cachedVersionId: number): void {\r\n\t\tconst initialNode = node;\r\n\t\tlet delta = 0;\r\n\t\twhile (node !== this.root) {\r\n\t\t\tif (node === node.parent.right) {\r\n\t\t\t\tdelta += node.parent.delta;\r\n\t\t\t}\r\n\t\t\tnode = node.parent;\r\n\t\t}\r\n\r\n\t\tconst nodeStart = initialNode.start + delta;\r\n\t\tconst nodeEnd = initialNode.end + delta;\r\n\t\tinitialNode.setCachedOffsets(nodeStart, nodeEnd, cachedVersionId);\r\n\t}\r\n\r\n\tpublic acceptReplace(offset: number, length: number, textLength: number, forceMoveMarkers: boolean): void {\r\n\t\t// Our strategy is to remove all directly impacted nodes, and then add them back to the tree.\r\n\r\n\t\t// (1) collect all nodes that are intersecting this edit as nodes of interest\r\n\t\tconst nodesOfInterest = searchForEditing(this, offset, offset + length);\r\n\r\n\t\t// (2) remove all nodes that are intersecting this edit\r\n\t\tfor (let i = 0, len = nodesOfInterest.length; i < len; i++) {\r\n\t\t\tconst node = nodesOfInterest[i];\r\n\t\t\trbTreeDelete(this, node);\r\n\t\t}\r\n\t\tthis._normalizeDeltaIfNecessary();\r\n\r\n\t\t// (3) edit all tree nodes except the nodes of interest\r\n\t\tnoOverlapReplace(this, offset, offset + length, textLength);\r\n\t\tthis._normalizeDeltaIfNecessary();\r\n\r\n\t\t// (4) edit the nodes of interest and insert them back in the tree\r\n\t\tfor (let i = 0, len = nodesOfInterest.length; i < len; i++) {\r\n\t\t\tconst node = nodesOfInterest[i];\r\n\t\t\tnode.start = node.cachedAbsoluteStart;\r\n\t\t\tnode.end = node.cachedAbsoluteEnd;\r\n\t\t\tnodeAcceptEdit(node, offset, (offset + length), textLength, forceMoveMarkers);\r\n\t\t\tnode.maxEnd = node.end;\r\n\t\t\trbTreeInsert(this, node);\r\n\t\t}\r\n\t\tthis._normalizeDeltaIfNecessary();\r\n\t}\r\n\r\n\tprivate _normalizeDeltaIfNecessary(): void {\r\n\t\tif (!this.requestNormalizeDelta) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis.requestNormalizeDelta = false;\r\n\t\tnormalizeDelta(this);\r\n\t}\r\n}\r\n\r\n//#region Delta Normalization\r\nfunction normalizeDelta(T: IntervalTree): void {\r\n\tlet node = T.root;\r\n\tlet delta = 0;\r\n\twhile (node !== SENTINEL) {\r\n\r\n\t\tif (node.left !== SENTINEL && !getNodeIsVisited(node.left)) {\r\n\t\t\t// go left\r\n\t\t\tnode = node.left;\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tif (node.right !== SENTINEL && !getNodeIsVisited(node.right)) {\r\n\t\t\t// go right\r\n\t\t\tdelta += node.delta;\r\n\t\t\tnode = node.right;\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\t// handle current node\r\n\t\tnode.start = delta + node.start;\r\n\t\tnode.end = delta + node.end;\r\n\t\tnode.delta = 0;\r\n\t\trecomputeMaxEnd(node);\r\n\r\n\t\tsetNodeIsVisited(node, true);\r\n\r\n\t\t// going up from this node\r\n\t\tsetNodeIsVisited(node.left, false);\r\n\t\tsetNodeIsVisited(node.right, false);\r\n\t\tif (node === node.parent.right) {\r\n\t\t\tdelta -= node.parent.delta;\r\n\t\t}\r\n\t\tnode = node.parent;\r\n\t}\r\n\r\n\tsetNodeIsVisited(T.root, false);\r\n}\r\n//#endregion\r\n\r\n//#region Editing\r\n\r\nconst enum MarkerMoveSemantics {\r\n\tMarkerDefined = 0,\r\n\tForceMove = 1,\r\n\tForceStay = 2\r\n}\r\n\r\nfunction adjustMarkerBeforeColumn(markerOffset: number, markerStickToPreviousCharacter: boolean, checkOffset: number, moveSemantics: MarkerMoveSemantics): boolean {\r\n\tif (markerOffset < checkOffset) {\r\n\t\treturn true;\r\n\t}\r\n\tif (markerOffset > checkOffset) {\r\n\t\treturn false;\r\n\t}\r\n\tif (moveSemantics === MarkerMoveSemantics.ForceMove) {\r\n\t\treturn false;\r\n\t}\r\n\tif (moveSemantics === MarkerMoveSemantics.ForceStay) {\r\n\t\treturn true;\r\n\t}\r\n\treturn markerStickToPreviousCharacter;\r\n}\r\n\r\n/**\r\n * This is a lot more complicated than strictly necessary to maintain the same behaviour\r\n * as when decorations were implemented using two markers.\r\n */\r\nexport function nodeAcceptEdit(node: IntervalNode, start: number, end: number, textLength: number, forceMoveMarkers: boolean): void {\r\n\tconst nodeStickiness = getNodeStickiness(node);\r\n\tconst startStickToPreviousCharacter = (\r\n\t\tnodeStickiness === TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges\r\n\t\t|| nodeStickiness === TrackedRangeStickiness.GrowsOnlyWhenTypingBefore\r\n\t);\r\n\tconst endStickToPreviousCharacter = (\r\n\t\tnodeStickiness === TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges\r\n\t\t|| nodeStickiness === TrackedRangeStickiness.GrowsOnlyWhenTypingBefore\r\n\t);\r\n\r\n\tconst deletingCnt = (end - start);\r\n\tconst insertingCnt = textLength;\r\n\tconst commonLength = Math.min(deletingCnt, insertingCnt);\r\n\r\n\tconst nodeStart = node.start;\r\n\tlet startDone = false;\r\n\r\n\tconst nodeEnd = node.end;\r\n\tlet endDone = false;\r\n\r\n\tif (start <= nodeStart && nodeEnd <= end && getCollapseOnReplaceEdit(node)) {\r\n\t\t// This edit encompasses the entire decoration range\r\n\t\t// and the decoration has asked to become collapsed\r\n\t\tnode.start = start;\r\n\t\tstartDone = true;\r\n\t\tnode.end = start;\r\n\t\tendDone = true;\r\n\t}\r\n\r\n\t{\r\n\t\tconst moveSemantics = forceMoveMarkers ? MarkerMoveSemantics.ForceMove : (deletingCnt > 0 ? MarkerMoveSemantics.ForceStay : MarkerMoveSemantics.MarkerDefined);\r\n\t\tif (!startDone && adjustMarkerBeforeColumn(nodeStart, startStickToPreviousCharacter, start, moveSemantics)) {\r\n\t\t\tstartDone = true;\r\n\t\t}\r\n\t\tif (!endDone && adjustMarkerBeforeColumn(nodeEnd, endStickToPreviousCharacter, start, moveSemantics)) {\r\n\t\t\tendDone = true;\r\n\t\t}\r\n\t}\r\n\r\n\tif (commonLength > 0 && !forceMoveMarkers) {\r\n\t\tconst moveSemantics = (deletingCnt > insertingCnt ? MarkerMoveSemantics.ForceStay : MarkerMoveSemantics.MarkerDefined);\r\n\t\tif (!startDone && adjustMarkerBeforeColumn(nodeStart, startStickToPreviousCharacter, start + commonLength, moveSemantics)) {\r\n\t\t\tstartDone = true;\r\n\t\t}\r\n\t\tif (!endDone && adjustMarkerBeforeColumn(nodeEnd, endStickToPreviousCharacter, start + commonLength, moveSemantics)) {\r\n\t\t\tendDone = true;\r\n\t\t}\r\n\t}\r\n\r\n\t{\r\n\t\tconst moveSemantics = forceMoveMarkers ? MarkerMoveSemantics.ForceMove : MarkerMoveSemantics.MarkerDefined;\r\n\t\tif (!startDone && adjustMarkerBeforeColumn(nodeStart, startStickToPreviousCharacter, end, moveSemantics)) {\r\n\t\t\tnode.start = start + insertingCnt;\r\n\t\t\tstartDone = true;\r\n\t\t}\r\n\t\tif (!endDone && adjustMarkerBeforeColumn(nodeEnd, endStickToPreviousCharacter, end, moveSemantics)) {\r\n\t\t\tnode.end = start + insertingCnt;\r\n\t\t\tendDone = true;\r\n\t\t}\r\n\t}\r\n\r\n\t// Finish\r\n\tconst deltaColumn = (insertingCnt - deletingCnt);\r\n\tif (!startDone) {\r\n\t\tnode.start = Math.max(0, nodeStart + deltaColumn);\r\n\t}\r\n\tif (!endDone) {\r\n\t\tnode.end = Math.max(0, nodeEnd + deltaColumn);\r\n\t}\r\n\r\n\tif (node.start > node.end) {\r\n\t\tnode.end = node.start;\r\n\t}\r\n}\r\n\r\nfunction searchForEditing(T: IntervalTree, start: number, end: number): IntervalNode[] {\r\n\t// https://en.wikipedia.org/wiki/Interval_tree#Augmented_tree\r\n\t// Now, it is known that two intervals A and B overlap only when both\r\n\t// A.low <= B.high and A.high >= B.low. When searching the trees for\r\n\t// nodes overlapping with a given interval, you can immediately skip:\r\n\t// a) all nodes to the right of nodes whose low value is past the end of the given interval.\r\n\t// b) all nodes that have their maximum 'high' value below the start of the given interval.\r\n\tlet node = T.root;\r\n\tlet delta = 0;\r\n\tlet nodeMaxEnd = 0;\r\n\tlet nodeStart = 0;\r\n\tlet nodeEnd = 0;\r\n\tlet result: IntervalNode[] = [];\r\n\tlet resultLen = 0;\r\n\twhile (node !== SENTINEL) {\r\n\t\tif (getNodeIsVisited(node)) {\r\n\t\t\t// going up from this node\r\n\t\t\tsetNodeIsVisited(node.left, false);\r\n\t\t\tsetNodeIsVisited(node.right, false);\r\n\t\t\tif (node === node.parent.right) {\r\n\t\t\t\tdelta -= node.parent.delta;\r\n\t\t\t}\r\n\t\t\tnode = node.parent;\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tif (!getNodeIsVisited(node.left)) {\r\n\t\t\t// first time seeing this node\r\n\t\t\tnodeMaxEnd = delta + node.maxEnd;\r\n\t\t\tif (nodeMaxEnd < start) {\r\n\t\t\t\t// cover case b) from above\r\n\t\t\t\t// there is no need to search this node or its children\r\n\t\t\t\tsetNodeIsVisited(node, true);\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (node.left !== SENTINEL) {\r\n\t\t\t\t// go left\r\n\t\t\t\tnode = node.left;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// handle current node\r\n\t\tnodeStart = delta + node.start;\r\n\t\tif (nodeStart > end) {\r\n\t\t\t// cover case a) from above\r\n\t\t\t// there is no need to search this node or its right subtree\r\n\t\t\tsetNodeIsVisited(node, true);\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tnodeEnd = delta + node.end;\r\n\t\tif (nodeEnd >= start) {\r\n\t\t\tnode.setCachedOffsets(nodeStart, nodeEnd, 0);\r\n\t\t\tresult[resultLen++] = node;\r\n\t\t}\r\n\t\tsetNodeIsVisited(node, true);\r\n\r\n\t\tif (node.right !== SENTINEL && !getNodeIsVisited(node.right)) {\r\n\t\t\t// go right\r\n\t\t\tdelta += node.delta;\r\n\t\t\tnode = node.right;\r\n\t\t\tcontinue;\r\n\t\t}\r\n\t}\r\n\r\n\tsetNodeIsVisited(T.root, false);\r\n\r\n\treturn result;\r\n}\r\n\r\nfunction noOverlapReplace(T: IntervalTree, start: number, end: number, textLength: number): void {\r\n\t// https://en.wikipedia.org/wiki/Interval_tree#Augmented_tree\r\n\t// Now, it is known that two intervals A and B overlap only when both\r\n\t// A.low <= B.high and A.high >= B.low. When searching the trees for\r\n\t// nodes overlapping with a given interval, you can immediately skip:\r\n\t// a) all nodes to the right of nodes whose low value is past the end of the given interval.\r\n\t// b) all nodes that have their maximum 'high' value below the start of the given interval.\r\n\tlet node = T.root;\r\n\tlet delta = 0;\r\n\tlet nodeMaxEnd = 0;\r\n\tlet nodeStart = 0;\r\n\tconst editDelta = (textLength - (end - start));\r\n\twhile (node !== SENTINEL) {\r\n\t\tif (getNodeIsVisited(node)) {\r\n\t\t\t// going up from this node\r\n\t\t\tsetNodeIsVisited(node.left, false);\r\n\t\t\tsetNodeIsVisited(node.right, false);\r\n\t\t\tif (node === node.parent.right) {\r\n\t\t\t\tdelta -= node.parent.delta;\r\n\t\t\t}\r\n\t\t\trecomputeMaxEnd(node);\r\n\t\t\tnode = node.parent;\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tif (!getNodeIsVisited(node.left)) {\r\n\t\t\t// first time seeing this node\r\n\t\t\tnodeMaxEnd = delta + node.maxEnd;\r\n\t\t\tif (nodeMaxEnd < start) {\r\n\t\t\t\t// cover case b) from above\r\n\t\t\t\t// there is no need to search this node or its children\r\n\t\t\t\tsetNodeIsVisited(node, true);\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (node.left !== SENTINEL) {\r\n\t\t\t\t// go left\r\n\t\t\t\tnode = node.left;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// handle current node\r\n\t\tnodeStart = delta + node.start;\r\n\t\tif (nodeStart > end) {\r\n\t\t\tnode.start += editDelta;\r\n\t\t\tnode.end += editDelta;\r\n\t\t\tnode.delta += editDelta;\r\n\t\t\tif (node.delta < Constants.MIN_SAFE_DELTA || node.delta > Constants.MAX_SAFE_DELTA) {\r\n\t\t\t\tT.requestNormalizeDelta = true;\r\n\t\t\t}\r\n\t\t\t// cover case a) from above\r\n\t\t\t// there is no need to search this node or its right subtree\r\n\t\t\tsetNodeIsVisited(node, true);\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tsetNodeIsVisited(node, true);\r\n\r\n\t\tif (node.right !== SENTINEL && !getNodeIsVisited(node.right)) {\r\n\t\t\t// go right\r\n\t\t\tdelta += node.delta;\r\n\t\t\tnode = node.right;\r\n\t\t\tcontinue;\r\n\t\t}\r\n\t}\r\n\r\n\tsetNodeIsVisited(T.root, false);\r\n}\r\n\r\n//#endregion\r\n\r\n//#region Searching\r\n\r\nfunction collectNodesFromOwner(T: IntervalTree, ownerId: number): IntervalNode[] {\r\n\tlet node = T.root;\r\n\tlet result: IntervalNode[] = [];\r\n\tlet resultLen = 0;\r\n\twhile (node !== SENTINEL) {\r\n\t\tif (getNodeIsVisited(node)) {\r\n\t\t\t// going up from this node\r\n\t\t\tsetNodeIsVisited(node.left, false);\r\n\t\t\tsetNodeIsVisited(node.right, false);\r\n\t\t\tnode = node.parent;\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tif (node.left !== SENTINEL && !getNodeIsVisited(node.left)) {\r\n\t\t\t// go left\r\n\t\t\tnode = node.left;\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\t// handle current node\r\n\t\tif (node.ownerId === ownerId) {\r\n\t\t\tresult[resultLen++] = node;\r\n\t\t}\r\n\r\n\t\tsetNodeIsVisited(node, true);\r\n\r\n\t\tif (node.right !== SENTINEL && !getNodeIsVisited(node.right)) {\r\n\t\t\t// go right\r\n\t\t\tnode = node.right;\r\n\t\t\tcontinue;\r\n\t\t}\r\n\t}\r\n\r\n\tsetNodeIsVisited(T.root, false);\r\n\r\n\treturn result;\r\n}\r\n\r\nfunction collectNodesPostOrder(T: IntervalTree): IntervalNode[] {\r\n\tlet node = T.root;\r\n\tlet result: IntervalNode[] = [];\r\n\tlet resultLen = 0;\r\n\twhile (node !== SENTINEL) {\r\n\t\tif (getNodeIsVisited(node)) {\r\n\t\t\t// going up from this node\r\n\t\t\tsetNodeIsVisited(node.left, false);\r\n\t\t\tsetNodeIsVisited(node.right, false);\r\n\t\t\tnode = node.parent;\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tif (node.left !== SENTINEL && !getNodeIsVisited(node.left)) {\r\n\t\t\t// go left\r\n\t\t\tnode = node.left;\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tif (node.right !== SENTINEL && !getNodeIsVisited(node.right)) {\r\n\t\t\t// go right\r\n\t\t\tnode = node.right;\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\t// handle current node\r\n\t\tresult[resultLen++] = node;\r\n\t\tsetNodeIsVisited(node, true);\r\n\t}\r\n\r\n\tsetNodeIsVisited(T.root, false);\r\n\r\n\treturn result;\r\n}\r\n\r\nfunction search(T: IntervalTree, filterOwnerId: number, filterOutValidation: boolean, cachedVersionId: number): IntervalNode[] {\r\n\tlet node = T.root;\r\n\tlet delta = 0;\r\n\tlet nodeStart = 0;\r\n\tlet nodeEnd = 0;\r\n\tlet result: IntervalNode[] = [];\r\n\tlet resultLen = 0;\r\n\twhile (node !== SENTINEL) {\r\n\t\tif (getNodeIsVisited(node)) {\r\n\t\t\t// going up from this node\r\n\t\t\tsetNodeIsVisited(node.left, false);\r\n\t\t\tsetNodeIsVisited(node.right, false);\r\n\t\t\tif (node === node.parent.right) {\r\n\t\t\t\tdelta -= node.parent.delta;\r\n\t\t\t}\r\n\t\t\tnode = node.parent;\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tif (node.left !== SENTINEL && !getNodeIsVisited(node.left)) {\r\n\t\t\t// go left\r\n\t\t\tnode = node.left;\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\t// handle current node\r\n\t\tnodeStart = delta + node.start;\r\n\t\tnodeEnd = delta + node.end;\r\n\r\n\t\tnode.setCachedOffsets(nodeStart, nodeEnd, cachedVersionId);\r\n\r\n\t\tlet include = true;\r\n\t\tif (filterOwnerId && node.ownerId && node.ownerId !== filterOwnerId) {\r\n\t\t\tinclude = false;\r\n\t\t}\r\n\t\tif (filterOutValidation && getNodeIsForValidation(node)) {\r\n\t\t\tinclude = false;\r\n\t\t}\r\n\t\tif (include) {\r\n\t\t\tresult[resultLen++] = node;\r\n\t\t}\r\n\r\n\t\tsetNodeIsVisited(node, true);\r\n\r\n\t\tif (node.right !== SENTINEL && !getNodeIsVisited(node.right)) {\r\n\t\t\t// go right\r\n\t\t\tdelta += node.delta;\r\n\t\t\tnode = node.right;\r\n\t\t\tcontinue;\r\n\t\t}\r\n\t}\r\n\r\n\tsetNodeIsVisited(T.root, false);\r\n\r\n\treturn result;\r\n}\r\n\r\nfunction intervalSearch(T: IntervalTree, intervalStart: number, intervalEnd: number, filterOwnerId: number, filterOutValidation: boolean, cachedVersionId: number): IntervalNode[] {\r\n\t// https://en.wikipedia.org/wiki/Interval_tree#Augmented_tree\r\n\t// Now, it is known that two intervals A and B overlap only when both\r\n\t// A.low <= B.high and A.high >= B.low. When searching the trees for\r\n\t// nodes overlapping with a given interval, you can immediately skip:\r\n\t// a) all nodes to the right of nodes whose low value is past the end of the given interval.\r\n\t// b) all nodes that have their maximum 'high' value below the start of the given interval.\r\n\r\n\tlet node = T.root;\r\n\tlet delta = 0;\r\n\tlet nodeMaxEnd = 0;\r\n\tlet nodeStart = 0;\r\n\tlet nodeEnd = 0;\r\n\tlet result: IntervalNode[] = [];\r\n\tlet resultLen = 0;\r\n\twhile (node !== SENTINEL) {\r\n\t\tif (getNodeIsVisited(node)) {\r\n\t\t\t// going up from this node\r\n\t\t\tsetNodeIsVisited(node.left, false);\r\n\t\t\tsetNodeIsVisited(node.right, false);\r\n\t\t\tif (node === node.parent.right) {\r\n\t\t\t\tdelta -= node.parent.delta;\r\n\t\t\t}\r\n\t\t\tnode = node.parent;\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tif (!getNodeIsVisited(node.left)) {\r\n\t\t\t// first time seeing this node\r\n\t\t\tnodeMaxEnd = delta + node.maxEnd;\r\n\t\t\tif (nodeMaxEnd < intervalStart) {\r\n\t\t\t\t// cover case b) from above\r\n\t\t\t\t// there is no need to search this node or its children\r\n\t\t\t\tsetNodeIsVisited(node, true);\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (node.left !== SENTINEL) {\r\n\t\t\t\t// go left\r\n\t\t\t\tnode = node.left;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// handle current node\r\n\t\tnodeStart = delta + node.start;\r\n\t\tif (nodeStart > intervalEnd) {\r\n\t\t\t// cover case a) from above\r\n\t\t\t// there is no need to search this node or its right subtree\r\n\t\t\tsetNodeIsVisited(node, true);\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tnodeEnd = delta + node.end;\r\n\r\n\t\tif (nodeEnd >= intervalStart) {\r\n\t\t\t// There is overlap\r\n\t\t\tnode.setCachedOffsets(nodeStart, nodeEnd, cachedVersionId);\r\n\r\n\t\t\tlet include = true;\r\n\t\t\tif (filterOwnerId && node.ownerId && node.ownerId !== filterOwnerId) {\r\n\t\t\t\tinclude = false;\r\n\t\t\t}\r\n\t\t\tif (filterOutValidation && getNodeIsForValidation(node)) {\r\n\t\t\t\tinclude = false;\r\n\t\t\t}\r\n\r\n\t\t\tif (include) {\r\n\t\t\t\tresult[resultLen++] = node;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tsetNodeIsVisited(node, true);\r\n\r\n\t\tif (node.right !== SENTINEL && !getNodeIsVisited(node.right)) {\r\n\t\t\t// go right\r\n\t\t\tdelta += node.delta;\r\n\t\t\tnode = node.right;\r\n\t\t\tcontinue;\r\n\t\t}\r\n\t}\r\n\r\n\tsetNodeIsVisited(T.root, false);\r\n\r\n\treturn result;\r\n}\r\n\r\n//#endregion\r\n\r\n//#region Insertion\r\nfunction rbTreeInsert(T: IntervalTree, newNode: IntervalNode): IntervalNode {\r\n\tif (T.root === SENTINEL) {\r\n\t\tnewNode.parent = SENTINEL;\r\n\t\tnewNode.left = SENTINEL;\r\n\t\tnewNode.right = SENTINEL;\r\n\t\tsetNodeColor(newNode, NodeColor.Black);\r\n\t\tT.root = newNode;\r\n\t\treturn T.root;\r\n\t}\r\n\r\n\ttreeInsert(T, newNode);\r\n\r\n\trecomputeMaxEndWalkToRoot(newNode.parent);\r\n\r\n\t// repair tree\r\n\tlet x = newNode;\r\n\twhile (x !== T.root && getNodeColor(x.parent) === NodeColor.Red) {\r\n\t\tif (x.parent === x.parent.parent.left) {\r\n\t\t\tconst y = x.parent.parent.right;\r\n\r\n\t\t\tif (getNodeColor(y) === NodeColor.Red) {\r\n\t\t\t\tsetNodeColor(x.parent, NodeColor.Black);\r\n\t\t\t\tsetNodeColor(y, NodeColor.Black);\r\n\t\t\t\tsetNodeColor(x.parent.parent, NodeColor.Red);\r\n\t\t\t\tx = x.parent.parent;\r\n\t\t\t} else {\r\n\t\t\t\tif (x === x.parent.right) {\r\n\t\t\t\t\tx = x.parent;\r\n\t\t\t\t\tleftRotate(T, x);\r\n\t\t\t\t}\r\n\t\t\t\tsetNodeColor(x.parent, NodeColor.Black);\r\n\t\t\t\tsetNodeColor(x.parent.parent, NodeColor.Red);\r\n\t\t\t\trightRotate(T, x.parent.parent);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tconst y = x.parent.parent.left;\r\n\r\n\t\t\tif (getNodeColor(y) === NodeColor.Red) {\r\n\t\t\t\tsetNodeColor(x.parent, NodeColor.Black);\r\n\t\t\t\tsetNodeColor(y, NodeColor.Black);\r\n\t\t\t\tsetNodeColor(x.parent.parent, NodeColor.Red);\r\n\t\t\t\tx = x.parent.parent;\r\n\t\t\t} else {\r\n\t\t\t\tif (x === x.parent.left) {\r\n\t\t\t\t\tx = x.parent;\r\n\t\t\t\t\trightRotate(T, x);\r\n\t\t\t\t}\r\n\t\t\t\tsetNodeColor(x.parent, NodeColor.Black);\r\n\t\t\t\tsetNodeColor(x.parent.parent, NodeColor.Red);\r\n\t\t\t\tleftRotate(T, x.parent.parent);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tsetNodeColor(T.root, NodeColor.Black);\r\n\r\n\treturn newNode;\r\n}\r\n\r\nfunction treeInsert(T: IntervalTree, z: IntervalNode): void {\r\n\tlet delta: number = 0;\r\n\tlet x = T.root;\r\n\tconst zAbsoluteStart = z.start;\r\n\tconst zAbsoluteEnd = z.end;\r\n\twhile (true) {\r\n\t\tconst cmp = intervalCompare(zAbsoluteStart, zAbsoluteEnd, x.start + delta, x.end + delta);\r\n\t\tif (cmp < 0) {\r\n\t\t\t// this node should be inserted to the left\r\n\t\t\t// => it is not affected by the node's delta\r\n\t\t\tif (x.left === SENTINEL) {\r\n\t\t\t\tz.start -= delta;\r\n\t\t\t\tz.end -= delta;\r\n\t\t\t\tz.maxEnd -= delta;\r\n\t\t\t\tx.left = z;\r\n\t\t\t\tbreak;\r\n\t\t\t} else {\r\n\t\t\t\tx = x.left;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\t// this node should be inserted to the right\r\n\t\t\t// => it is not affected by the node's delta\r\n\t\t\tif (x.right === SENTINEL) {\r\n\t\t\t\tz.start -= (delta + x.delta);\r\n\t\t\t\tz.end -= (delta + x.delta);\r\n\t\t\t\tz.maxEnd -= (delta + x.delta);\r\n\t\t\t\tx.right = z;\r\n\t\t\t\tbreak;\r\n\t\t\t} else {\r\n\t\t\t\tdelta += x.delta;\r\n\t\t\t\tx = x.right;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tz.parent = x;\r\n\tz.left = SENTINEL;\r\n\tz.right = SENTINEL;\r\n\tsetNodeColor(z, NodeColor.Red);\r\n}\r\n//#endregion\r\n\r\n//#region Deletion\r\nfunction rbTreeDelete(T: IntervalTree, z: IntervalNode): void {\r\n\r\n\tlet x: IntervalNode;\r\n\tlet y: IntervalNode;\r\n\r\n\t// RB-DELETE except we don't swap z and y in case c)\r\n\t// i.e. we always delete what's pointed at by z.\r\n\r\n\tif (z.left === SENTINEL) {\r\n\t\tx = z.right;\r\n\t\ty = z;\r\n\r\n\t\t// x's delta is no longer influenced by z's delta\r\n\t\tx.delta += z.delta;\r\n\t\tif (x.delta < Constants.MIN_SAFE_DELTA || x.delta > Constants.MAX_SAFE_DELTA) {\r\n\t\t\tT.requestNormalizeDelta = true;\r\n\t\t}\r\n\t\tx.start += z.delta;\r\n\t\tx.end += z.delta;\r\n\r\n\t} else if (z.right === SENTINEL) {\r\n\t\tx = z.left;\r\n\t\ty = z;\r\n\r\n\t} else {\r\n\t\ty = leftest(z.right);\r\n\t\tx = y.right;\r\n\r\n\t\t// y's delta is no longer influenced by z's delta,\r\n\t\t// but we don't want to walk the entire right-hand-side subtree of x.\r\n\t\t// we therefore maintain z's delta in y, and adjust only x\r\n\t\tx.start += y.delta;\r\n\t\tx.end += y.delta;\r\n\t\tx.delta += y.delta;\r\n\t\tif (x.delta < Constants.MIN_SAFE_DELTA || x.delta > Constants.MAX_SAFE_DELTA) {\r\n\t\t\tT.requestNormalizeDelta = true;\r\n\t\t}\r\n\r\n\t\ty.start += z.delta;\r\n\t\ty.end += z.delta;\r\n\t\ty.delta = z.delta;\r\n\t\tif (y.delta < Constants.MIN_SAFE_DELTA || y.delta > Constants.MAX_SAFE_DELTA) {\r\n\t\t\tT.requestNormalizeDelta = true;\r\n\t\t}\r\n\t}\r\n\r\n\tif (y === T.root) {\r\n\t\tT.root = x;\r\n\t\tsetNodeColor(x, NodeColor.Black);\r\n\r\n\t\tz.detach();\r\n\t\tresetSentinel();\r\n\t\trecomputeMaxEnd(x);\r\n\t\tT.root.parent = SENTINEL;\r\n\t\treturn;\r\n\t}\r\n\r\n\tlet yWasRed = (getNodeColor(y) === NodeColor.Red);\r\n\r\n\tif (y === y.parent.left) {\r\n\t\ty.parent.left = x;\r\n\t} else {\r\n\t\ty.parent.right = x;\r\n\t}\r\n\r\n\tif (y === z) {\r\n\t\tx.parent = y.parent;\r\n\t} else {\r\n\r\n\t\tif (y.parent === z) {\r\n\t\t\tx.parent = y;\r\n\t\t} else {\r\n\t\t\tx.parent = y.parent;\r\n\t\t}\r\n\r\n\t\ty.left = z.left;\r\n\t\ty.right = z.right;\r\n\t\ty.parent = z.parent;\r\n\t\tsetNodeColor(y, getNodeColor(z));\r\n\r\n\t\tif (z === T.root) {\r\n\t\t\tT.root = y;\r\n\t\t} else {\r\n\t\t\tif (z === z.parent.left) {\r\n\t\t\t\tz.parent.left = y;\r\n\t\t\t} else {\r\n\t\t\t\tz.parent.right = y;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (y.left !== SENTINEL) {\r\n\t\t\ty.left.parent = y;\r\n\t\t}\r\n\t\tif (y.right !== SENTINEL) {\r\n\t\t\ty.right.parent = y;\r\n\t\t}\r\n\t}\r\n\r\n\tz.detach();\r\n\r\n\tif (yWasRed) {\r\n\t\trecomputeMaxEndWalkToRoot(x.parent);\r\n\t\tif (y !== z) {\r\n\t\t\trecomputeMaxEndWalkToRoot(y);\r\n\t\t\trecomputeMaxEndWalkToRoot(y.parent);\r\n\t\t}\r\n\t\tresetSentinel();\r\n\t\treturn;\r\n\t}\r\n\r\n\trecomputeMaxEndWalkToRoot(x);\r\n\trecomputeMaxEndWalkToRoot(x.parent);\r\n\tif (y !== z) {\r\n\t\trecomputeMaxEndWalkToRoot(y);\r\n\t\trecomputeMaxEndWalkToRoot(y.parent);\r\n\t}\r\n\r\n\t// RB-DELETE-FIXUP\r\n\tlet w: IntervalNode;\r\n\twhile (x !== T.root && getNodeColor(x) === NodeColor.Black) {\r\n\r\n\t\tif (x === x.parent.left) {\r\n\t\t\tw = x.parent.right;\r\n\r\n\t\t\tif (getNodeColor(w) === NodeColor.Red) {\r\n\t\t\t\tsetNodeColor(w, NodeColor.Black);\r\n\t\t\t\tsetNodeColor(x.parent, NodeColor.Red);\r\n\t\t\t\tleftRotate(T, x.parent);\r\n\t\t\t\tw = x.parent.right;\r\n\t\t\t}\r\n\r\n\t\t\tif (getNodeColor(w.left) === NodeColor.Black && getNodeColor(w.right) === NodeColor.Black) {\r\n\t\t\t\tsetNodeColor(w, NodeColor.Red);\r\n\t\t\t\tx = x.parent;\r\n\t\t\t} else {\r\n\t\t\t\tif (getNodeColor(w.right) === NodeColor.Black) {\r\n\t\t\t\t\tsetNodeColor(w.left, NodeColor.Black);\r\n\t\t\t\t\tsetNodeColor(w, NodeColor.Red);\r\n\t\t\t\t\trightRotate(T, w);\r\n\t\t\t\t\tw = x.parent.right;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tsetNodeColor(w, getNodeColor(x.parent));\r\n\t\t\t\tsetNodeColor(x.parent, NodeColor.Black);\r\n\t\t\t\tsetNodeColor(w.right, NodeColor.Black);\r\n\t\t\t\tleftRotate(T, x.parent);\r\n\t\t\t\tx = T.root;\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\t\t\tw = x.parent.left;\r\n\r\n\t\t\tif (getNodeColor(w) === NodeColor.Red) {\r\n\t\t\t\tsetNodeColor(w, NodeColor.Black);\r\n\t\t\t\tsetNodeColor(x.parent, NodeColor.Red);\r\n\t\t\t\trightRotate(T, x.parent);\r\n\t\t\t\tw = x.parent.left;\r\n\t\t\t}\r\n\r\n\t\t\tif (getNodeColor(w.left) === NodeColor.Black && getNodeColor(w.right) === NodeColor.Black) {\r\n\t\t\t\tsetNodeColor(w, NodeColor.Red);\r\n\t\t\t\tx = x.parent;\r\n\r\n\t\t\t} else {\r\n\t\t\t\tif (getNodeColor(w.left) === NodeColor.Black) {\r\n\t\t\t\t\tsetNodeColor(w.right, NodeColor.Black);\r\n\t\t\t\t\tsetNodeColor(w, NodeColor.Red);\r\n\t\t\t\t\tleftRotate(T, w);\r\n\t\t\t\t\tw = x.parent.left;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tsetNodeColor(w, getNodeColor(x.parent));\r\n\t\t\t\tsetNodeColor(x.parent, NodeColor.Black);\r\n\t\t\t\tsetNodeColor(w.left, NodeColor.Black);\r\n\t\t\t\trightRotate(T, x.parent);\r\n\t\t\t\tx = T.root;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tsetNodeColor(x, NodeColor.Black);\r\n\tresetSentinel();\r\n}\r\n\r\nfunction leftest(node: IntervalNode): IntervalNode {\r\n\twhile (node.left !== SENTINEL) {\r\n\t\tnode = node.left;\r\n\t}\r\n\treturn node;\r\n}\r\n\r\nfunction resetSentinel(): void {\r\n\tSENTINEL.parent = SENTINEL;\r\n\tSENTINEL.delta = 0; // optional\r\n\tSENTINEL.start = 0; // optional\r\n\tSENTINEL.end = 0; // optional\r\n}\r\n//#endregion\r\n\r\n//#region Rotations\r\nfunction leftRotate(T: IntervalTree, x: IntervalNode): void {\r\n\tconst y = x.right;\t\t\t\t// set y.\r\n\r\n\ty.delta += x.delta;\t\t\t\t// y's delta is no longer influenced by x's delta\r\n\tif (y.delta < Constants.MIN_SAFE_DELTA || y.delta > Constants.MAX_SAFE_DELTA) {\r\n\t\tT.requestNormalizeDelta = true;\r\n\t}\r\n\ty.start += x.delta;\r\n\ty.end += x.delta;\r\n\r\n\tx.right = y.left;\t\t\t\t// turn y's left subtree into x's right subtree.\r\n\tif (y.left !== SENTINEL) {\r\n\t\ty.left.parent = x;\r\n\t}\r\n\ty.parent = x.parent;\t\t\t// link x's parent to y.\r\n\tif (x.parent === SENTINEL) {\r\n\t\tT.root = y;\r\n\t} else if (x === x.parent.left) {\r\n\t\tx.parent.left = y;\r\n\t} else {\r\n\t\tx.parent.right = y;\r\n\t}\r\n\r\n\ty.left = x;\t\t\t\t\t\t// put x on y's left.\r\n\tx.parent = y;\r\n\r\n\trecomputeMaxEnd(x);\r\n\trecomputeMaxEnd(y);\r\n}\r\n\r\nfunction rightRotate(T: IntervalTree, y: IntervalNode): void {\r\n\tconst x = y.left;\r\n\r\n\ty.delta -= x.delta;\r\n\tif (y.delta < Constants.MIN_SAFE_DELTA || y.delta > Constants.MAX_SAFE_DELTA) {\r\n\t\tT.requestNormalizeDelta = true;\r\n\t}\r\n\ty.start -= x.delta;\r\n\ty.end -= x.delta;\r\n\r\n\ty.left = x.right;\r\n\tif (x.right !== SENTINEL) {\r\n\t\tx.right.parent = y;\r\n\t}\r\n\tx.parent = y.parent;\r\n\tif (y.parent === SENTINEL) {\r\n\t\tT.root = x;\r\n\t} else if (y === y.parent.right) {\r\n\t\ty.parent.right = x;\r\n\t} else {\r\n\t\ty.parent.left = x;\r\n\t}\r\n\r\n\tx.right = y;\r\n\ty.parent = x;\r\n\r\n\trecomputeMaxEnd(y);\r\n\trecomputeMaxEnd(x);\r\n}\r\n//#endregion\r\n\r\n//#region max end computation\r\n\r\nfunction computeMaxEnd(node: IntervalNode): number {\r\n\tlet maxEnd = node.end;\r\n\tif (node.left !== SENTINEL) {\r\n\t\tconst leftMaxEnd = node.left.maxEnd;\r\n\t\tif (leftMaxEnd > maxEnd) {\r\n\t\t\tmaxEnd = leftMaxEnd;\r\n\t\t}\r\n\t}\r\n\tif (node.right !== SENTINEL) {\r\n\t\tconst rightMaxEnd = node.right.maxEnd + node.delta;\r\n\t\tif (rightMaxEnd > maxEnd) {\r\n\t\t\tmaxEnd = rightMaxEnd;\r\n\t\t}\r\n\t}\r\n\treturn maxEnd;\r\n}\r\n\r\nexport function recomputeMaxEnd(node: IntervalNode): void {\r\n\tnode.maxEnd = computeMaxEnd(node);\r\n}\r\n\r\nfunction recomputeMaxEndWalkToRoot(node: IntervalNode): void {\r\n\twhile (node !== SENTINEL) {\r\n\r\n\t\tconst maxEnd = computeMaxEnd(node);\r\n\r\n\t\tif (node.maxEnd === maxEnd) {\r\n\t\t\t// no need to go further\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tnode.maxEnd = maxEnd;\r\n\t\tnode = node.parent;\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region utils\r\nexport function intervalCompare(aStart: number, aEnd: number, bStart: number, bEnd: number): number {\r\n\tif (aStart === bStart) {\r\n\t\treturn aEnd - bEnd;\r\n\t}\r\n\treturn aStart - bStart;\r\n}\r\n//#endregion\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Piece, PieceTreeBase } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase';\r\n\r\nexport class TreeNode {\r\n\tparent: TreeNode;\r\n\tleft: TreeNode;\r\n\tright: TreeNode;\r\n\tcolor: NodeColor;\r\n\r\n\t// Piece\r\n\tpiece: Piece;\r\n\tsize_left: number; // size of the left subtree (not inorder)\r\n\tlf_left: number; // line feeds cnt in the left subtree (not in order)\r\n\r\n\tconstructor(piece: Piece, color: NodeColor) {\r\n\t\tthis.piece = piece;\r\n\t\tthis.color = color;\r\n\t\tthis.size_left = 0;\r\n\t\tthis.lf_left = 0;\r\n\t\tthis.parent = this;\r\n\t\tthis.left = this;\r\n\t\tthis.right = this;\r\n\t}\r\n\r\n\tpublic next(): TreeNode {\r\n\t\tif (this.right !== SENTINEL) {\r\n\t\t\treturn leftest(this.right);\r\n\t\t}\r\n\r\n\t\tlet node: TreeNode = this;\r\n\r\n\t\twhile (node.parent !== SENTINEL) {\r\n\t\t\tif (node.parent.left === node) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tnode = node.parent;\r\n\t\t}\r\n\r\n\t\tif (node.parent === SENTINEL) {\r\n\t\t\treturn SENTINEL;\r\n\t\t} else {\r\n\t\t\treturn node.parent;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic prev(): TreeNode {\r\n\t\tif (this.left !== SENTINEL) {\r\n\t\t\treturn righttest(this.left);\r\n\t\t}\r\n\r\n\t\tlet node: TreeNode = this;\r\n\r\n\t\twhile (node.parent !== SENTINEL) {\r\n\t\t\tif (node.parent.right === node) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tnode = node.parent;\r\n\t\t}\r\n\r\n\t\tif (node.parent === SENTINEL) {\r\n\t\t\treturn SENTINEL;\r\n\t\t} else {\r\n\t\t\treturn node.parent;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic detach(): void {\r\n\t\tthis.parent = null!;\r\n\t\tthis.left = null!;\r\n\t\tthis.right = null!;\r\n\t}\r\n}\r\n\r\nexport const enum NodeColor {\r\n\tBlack = 0,\r\n\tRed = 1,\r\n}\r\n\r\nexport const SENTINEL: TreeNode = new TreeNode(null!, NodeColor.Black);\r\nSENTINEL.parent = SENTINEL;\r\nSENTINEL.left = SENTINEL;\r\nSENTINEL.right = SENTINEL;\r\nSENTINEL.color = NodeColor.Black;\r\n\r\nexport function leftest(node: TreeNode): TreeNode {\r\n\twhile (node.left !== SENTINEL) {\r\n\t\tnode = node.left;\r\n\t}\r\n\treturn node;\r\n}\r\n\r\nexport function righttest(node: TreeNode): TreeNode {\r\n\twhile (node.right !== SENTINEL) {\r\n\t\tnode = node.right;\r\n\t}\r\n\treturn node;\r\n}\r\n\r\nexport function calculateSize(node: TreeNode): number {\r\n\tif (node === SENTINEL) {\r\n\t\treturn 0;\r\n\t}\r\n\r\n\treturn node.size_left + node.piece.length + calculateSize(node.right);\r\n}\r\n\r\nexport function calculateLF(node: TreeNode): number {\r\n\tif (node === SENTINEL) {\r\n\t\treturn 0;\r\n\t}\r\n\r\n\treturn node.lf_left + node.piece.lineFeedCnt + calculateLF(node.right);\r\n}\r\n\r\nexport function resetSentinel(): void {\r\n\tSENTINEL.parent = SENTINEL;\r\n}\r\n\r\nexport function leftRotate(tree: PieceTreeBase, x: TreeNode) {\r\n\tlet y = x.right;\r\n\r\n\t// fix size_left\r\n\ty.size_left += x.size_left + (x.piece ? x.piece.length : 0);\r\n\ty.lf_left += x.lf_left + (x.piece ? x.piece.lineFeedCnt : 0);\r\n\tx.right = y.left;\r\n\r\n\tif (y.left !== SENTINEL) {\r\n\t\ty.left.parent = x;\r\n\t}\r\n\ty.parent = x.parent;\r\n\tif (x.parent === SENTINEL) {\r\n\t\ttree.root = y;\r\n\t} else if (x.parent.left === x) {\r\n\t\tx.parent.left = y;\r\n\t} else {\r\n\t\tx.parent.right = y;\r\n\t}\r\n\ty.left = x;\r\n\tx.parent = y;\r\n}\r\n\r\nexport function rightRotate(tree: PieceTreeBase, y: TreeNode) {\r\n\tlet x = y.left;\r\n\ty.left = x.right;\r\n\tif (x.right !== SENTINEL) {\r\n\t\tx.right.parent = y;\r\n\t}\r\n\tx.parent = y.parent;\r\n\r\n\t// fix size_left\r\n\ty.size_left -= x.size_left + (x.piece ? x.piece.length : 0);\r\n\ty.lf_left -= x.lf_left + (x.piece ? x.piece.lineFeedCnt : 0);\r\n\r\n\tif (y.parent === SENTINEL) {\r\n\t\ttree.root = x;\r\n\t} else if (y === y.parent.right) {\r\n\t\ty.parent.right = x;\r\n\t} else {\r\n\t\ty.parent.left = x;\r\n\t}\r\n\r\n\tx.right = y;\r\n\ty.parent = x;\r\n}\r\n\r\nexport function rbDelete(tree: PieceTreeBase, z: TreeNode) {\r\n\tlet x: TreeNode;\r\n\tlet y: TreeNode;\r\n\r\n\tif (z.left === SENTINEL) {\r\n\t\ty = z;\r\n\t\tx = y.right;\r\n\t} else if (z.right === SENTINEL) {\r\n\t\ty = z;\r\n\t\tx = y.left;\r\n\t} else {\r\n\t\ty = leftest(z.right);\r\n\t\tx = y.right;\r\n\t}\r\n\r\n\tif (y === tree.root) {\r\n\t\ttree.root = x;\r\n\r\n\t\t// if x is null, we are removing the only node\r\n\t\tx.color = NodeColor.Black;\r\n\t\tz.detach();\r\n\t\tresetSentinel();\r\n\t\ttree.root.parent = SENTINEL;\r\n\r\n\t\treturn;\r\n\t}\r\n\r\n\tlet yWasRed = (y.color === NodeColor.Red);\r\n\r\n\tif (y === y.parent.left) {\r\n\t\ty.parent.left = x;\r\n\t} else {\r\n\t\ty.parent.right = x;\r\n\t}\r\n\r\n\tif (y === z) {\r\n\t\tx.parent = y.parent;\r\n\t\trecomputeTreeMetadata(tree, x);\r\n\t} else {\r\n\t\tif (y.parent === z) {\r\n\t\t\tx.parent = y;\r\n\t\t} else {\r\n\t\t\tx.parent = y.parent;\r\n\t\t}\r\n\r\n\t\t// as we make changes to x's hierarchy, update size_left of subtree first\r\n\t\trecomputeTreeMetadata(tree, x);\r\n\r\n\t\ty.left = z.left;\r\n\t\ty.right = z.right;\r\n\t\ty.parent = z.parent;\r\n\t\ty.color = z.color;\r\n\r\n\t\tif (z === tree.root) {\r\n\t\t\ttree.root = y;\r\n\t\t} else {\r\n\t\t\tif (z === z.parent.left) {\r\n\t\t\t\tz.parent.left = y;\r\n\t\t\t} else {\r\n\t\t\t\tz.parent.right = y;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (y.left !== SENTINEL) {\r\n\t\t\ty.left.parent = y;\r\n\t\t}\r\n\t\tif (y.right !== SENTINEL) {\r\n\t\t\ty.right.parent = y;\r\n\t\t}\r\n\t\t// update metadata\r\n\t\t// we replace z with y, so in this sub tree, the length change is z.item.length\r\n\t\ty.size_left = z.size_left;\r\n\t\ty.lf_left = z.lf_left;\r\n\t\trecomputeTreeMetadata(tree, y);\r\n\t}\r\n\r\n\tz.detach();\r\n\r\n\tif (x.parent.left === x) {\r\n\t\tlet newSizeLeft = calculateSize(x);\r\n\t\tlet newLFLeft = calculateLF(x);\r\n\t\tif (newSizeLeft !== x.parent.size_left || newLFLeft !== x.parent.lf_left) {\r\n\t\t\tlet delta = newSizeLeft - x.parent.size_left;\r\n\t\t\tlet lf_delta = newLFLeft - x.parent.lf_left;\r\n\t\t\tx.parent.size_left = newSizeLeft;\r\n\t\t\tx.parent.lf_left = newLFLeft;\r\n\t\t\tupdateTreeMetadata(tree, x.parent, delta, lf_delta);\r\n\t\t}\r\n\t}\r\n\r\n\trecomputeTreeMetadata(tree, x.parent);\r\n\r\n\tif (yWasRed) {\r\n\t\tresetSentinel();\r\n\t\treturn;\r\n\t}\r\n\r\n\t// RB-DELETE-FIXUP\r\n\tlet w: TreeNode;\r\n\twhile (x !== tree.root && x.color === NodeColor.Black) {\r\n\t\tif (x === x.parent.left) {\r\n\t\t\tw = x.parent.right;\r\n\r\n\t\t\tif (w.color === NodeColor.Red) {\r\n\t\t\t\tw.color = NodeColor.Black;\r\n\t\t\t\tx.parent.color = NodeColor.Red;\r\n\t\t\t\tleftRotate(tree, x.parent);\r\n\t\t\t\tw = x.parent.right;\r\n\t\t\t}\r\n\r\n\t\t\tif (w.left.color === NodeColor.Black && w.right.color === NodeColor.Black) {\r\n\t\t\t\tw.color = NodeColor.Red;\r\n\t\t\t\tx = x.parent;\r\n\t\t\t} else {\r\n\t\t\t\tif (w.right.color === NodeColor.Black) {\r\n\t\t\t\t\tw.left.color = NodeColor.Black;\r\n\t\t\t\t\tw.color = NodeColor.Red;\r\n\t\t\t\t\trightRotate(tree, w);\r\n\t\t\t\t\tw = x.parent.right;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tw.color = x.parent.color;\r\n\t\t\t\tx.parent.color = NodeColor.Black;\r\n\t\t\t\tw.right.color = NodeColor.Black;\r\n\t\t\t\tleftRotate(tree, x.parent);\r\n\t\t\t\tx = tree.root;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tw = x.parent.left;\r\n\r\n\t\t\tif (w.color === NodeColor.Red) {\r\n\t\t\t\tw.color = NodeColor.Black;\r\n\t\t\t\tx.parent.color = NodeColor.Red;\r\n\t\t\t\trightRotate(tree, x.parent);\r\n\t\t\t\tw = x.parent.left;\r\n\t\t\t}\r\n\r\n\t\t\tif (w.left.color === NodeColor.Black && w.right.color === NodeColor.Black) {\r\n\t\t\t\tw.color = NodeColor.Red;\r\n\t\t\t\tx = x.parent;\r\n\r\n\t\t\t} else {\r\n\t\t\t\tif (w.left.color === NodeColor.Black) {\r\n\t\t\t\t\tw.right.color = NodeColor.Black;\r\n\t\t\t\t\tw.color = NodeColor.Red;\r\n\t\t\t\t\tleftRotate(tree, w);\r\n\t\t\t\t\tw = x.parent.left;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tw.color = x.parent.color;\r\n\t\t\t\tx.parent.color = NodeColor.Black;\r\n\t\t\t\tw.left.color = NodeColor.Black;\r\n\t\t\t\trightRotate(tree, x.parent);\r\n\t\t\t\tx = tree.root;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\tx.color = NodeColor.Black;\r\n\tresetSentinel();\r\n}\r\n\r\nexport function fixInsert(tree: PieceTreeBase, x: TreeNode) {\r\n\trecomputeTreeMetadata(tree, x);\r\n\r\n\twhile (x !== tree.root && x.parent.color === NodeColor.Red) {\r\n\t\tif (x.parent === x.parent.parent.left) {\r\n\t\t\tconst y = x.parent.parent.right;\r\n\r\n\t\t\tif (y.color === NodeColor.Red) {\r\n\t\t\t\tx.parent.color = NodeColor.Black;\r\n\t\t\t\ty.color = NodeColor.Black;\r\n\t\t\t\tx.parent.parent.color = NodeColor.Red;\r\n\t\t\t\tx = x.parent.parent;\r\n\t\t\t} else {\r\n\t\t\t\tif (x === x.parent.right) {\r\n\t\t\t\t\tx = x.parent;\r\n\t\t\t\t\tleftRotate(tree, x);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tx.parent.color = NodeColor.Black;\r\n\t\t\t\tx.parent.parent.color = NodeColor.Red;\r\n\t\t\t\trightRotate(tree, x.parent.parent);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tconst y = x.parent.parent.left;\r\n\r\n\t\t\tif (y.color === NodeColor.Red) {\r\n\t\t\t\tx.parent.color = NodeColor.Black;\r\n\t\t\t\ty.color = NodeColor.Black;\r\n\t\t\t\tx.parent.parent.color = NodeColor.Red;\r\n\t\t\t\tx = x.parent.parent;\r\n\t\t\t} else {\r\n\t\t\t\tif (x === x.parent.left) {\r\n\t\t\t\t\tx = x.parent;\r\n\t\t\t\t\trightRotate(tree, x);\r\n\t\t\t\t}\r\n\t\t\t\tx.parent.color = NodeColor.Black;\r\n\t\t\t\tx.parent.parent.color = NodeColor.Red;\r\n\t\t\t\tleftRotate(tree, x.parent.parent);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\ttree.root.color = NodeColor.Black;\r\n}\r\n\r\nexport function updateTreeMetadata(tree: PieceTreeBase, x: TreeNode, delta: number, lineFeedCntDelta: number): void {\r\n\t// node length change or line feed count change\r\n\twhile (x !== tree.root && x !== SENTINEL) {\r\n\t\tif (x.parent.left === x) {\r\n\t\t\tx.parent.size_left += delta;\r\n\t\t\tx.parent.lf_left += lineFeedCntDelta;\r\n\t\t}\r\n\r\n\t\tx = x.parent;\r\n\t}\r\n}\r\n\r\nexport function recomputeTreeMetadata(tree: PieceTreeBase, x: TreeNode) {\r\n\tlet delta = 0;\r\n\tlet lf_delta = 0;\r\n\tif (x === tree.root) {\r\n\t\treturn;\r\n\t}\r\n\r\n\tif (delta === 0) {\r\n\t\t// go upwards till the node whose left subtree is changed.\r\n\t\twhile (x !== tree.root && x === x.parent.right) {\r\n\t\t\tx = x.parent;\r\n\t\t}\r\n\r\n\t\tif (x === tree.root) {\r\n\t\t\t// well, it means we add a node to the end (inorder)\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// x is the node whose right subtree is changed.\r\n\t\tx = x.parent;\r\n\r\n\t\tdelta = calculateSize(x.left) - x.size_left;\r\n\t\tlf_delta = calculateLF(x.left) - x.lf_left;\r\n\t\tx.size_left += delta;\r\n\t\tx.lf_left += lf_delta;\r\n\t}\r\n\r\n\t// go upwards till root. O(logN)\r\n\twhile (x !== tree.root && (delta !== 0 || lf_delta !== 0)) {\r\n\t\tif (x.parent.left === x) {\r\n\t\t\tx.parent.size_left += delta;\r\n\t\t\tx.parent.lf_left += lf_delta;\r\n\t\t}\r\n\r\n\t\tx = x.parent;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as buffer from 'vs/base/common/buffer';\r\nimport { decodeUTF16LE } from 'vs/editor/common/core/stringBuilder';\r\n\r\nfunction escapeNewLine(str: string): string {\r\n\treturn (\r\n\t\tstr\r\n\t\t\t.replace(/\\n/g, '\\\\n')\r\n\t\t\t.replace(/\\r/g, '\\\\r')\r\n\t);\r\n}\r\n\r\nexport class TextChange {\r\n\r\n\tpublic get oldLength(): number {\r\n\t\treturn this.oldText.length;\r\n\t}\r\n\r\n\tpublic get oldEnd(): number {\r\n\t\treturn this.oldPosition + this.oldText.length;\r\n\t}\r\n\r\n\tpublic get newLength(): number {\r\n\t\treturn this.newText.length;\r\n\t}\r\n\r\n\tpublic get newEnd(): number {\r\n\t\treturn this.newPosition + this.newText.length;\r\n\t}\r\n\r\n\tconstructor(\r\n\t\tpublic readonly oldPosition: number,\r\n\t\tpublic readonly oldText: string,\r\n\t\tpublic readonly newPosition: number,\r\n\t\tpublic readonly newText: string\r\n\t) { }\r\n\r\n\tpublic toString(): string {\r\n\t\tif (this.oldText.length === 0) {\r\n\t\t\treturn `(insert@${this.oldPosition} \"${escapeNewLine(this.newText)}\")`;\r\n\t\t}\r\n\t\tif (this.newText.length === 0) {\r\n\t\t\treturn `(delete@${this.oldPosition} \"${escapeNewLine(this.oldText)}\")`;\r\n\t\t}\r\n\t\treturn `(replace@${this.oldPosition} \"${escapeNewLine(this.oldText)}\" with \"${escapeNewLine(this.newText)}\")`;\r\n\t}\r\n\r\n\tprivate static _writeStringSize(str: string): number {\r\n\t\treturn (\r\n\t\t\t4 + 2 * str.length\r\n\t\t);\r\n\t}\r\n\r\n\tprivate static _writeString(b: Uint8Array, str: string, offset: number): number {\r\n\t\tconst len = str.length;\r\n\t\tbuffer.writeUInt32BE(b, len, offset); offset += 4;\r\n\t\tfor (let i = 0; i < len; i++) {\r\n\t\t\tbuffer.writeUInt16LE(b, str.charCodeAt(i), offset); offset += 2;\r\n\t\t}\r\n\t\treturn offset;\r\n\t}\r\n\r\n\tprivate static _readString(b: Uint8Array, offset: number): string {\r\n\t\tconst len = buffer.readUInt32BE(b, offset); offset += 4;\r\n\t\treturn decodeUTF16LE(b, offset, len);\r\n\t}\r\n\r\n\tpublic writeSize(): number {\r\n\t\treturn (\r\n\t\t\t+ 4 // oldPosition\r\n\t\t\t+ 4 // newPosition\r\n\t\t\t+ TextChange._writeStringSize(this.oldText)\r\n\t\t\t+ TextChange._writeStringSize(this.newText)\r\n\t\t);\r\n\t}\r\n\r\n\tpublic write(b: Uint8Array, offset: number): number {\r\n\t\tbuffer.writeUInt32BE(b, this.oldPosition, offset); offset += 4;\r\n\t\tbuffer.writeUInt32BE(b, this.newPosition, offset); offset += 4;\r\n\t\toffset = TextChange._writeString(b, this.oldText, offset);\r\n\t\toffset = TextChange._writeString(b, this.newText, offset);\r\n\t\treturn offset;\r\n\t}\r\n\r\n\tpublic static read(b: Uint8Array, offset: number, dest: TextChange[]): number {\r\n\t\tconst oldPosition = buffer.readUInt32BE(b, offset); offset += 4;\r\n\t\tconst newPosition = buffer.readUInt32BE(b, offset); offset += 4;\r\n\t\tconst oldText = TextChange._readString(b, offset); offset += TextChange._writeStringSize(oldText);\r\n\t\tconst newText = TextChange._readString(b, offset); offset += TextChange._writeStringSize(newText);\r\n\t\tdest.push(new TextChange(oldPosition, oldText, newPosition, newText));\r\n\t\treturn offset;\r\n\t}\r\n}\r\n\r\nexport function compressConsecutiveTextChanges(prevEdits: TextChange[] | null, currEdits: TextChange[]): TextChange[] {\r\n\tif (prevEdits === null || prevEdits.length === 0) {\r\n\t\treturn currEdits;\r\n\t}\r\n\tconst compressor = new TextChangeCompressor(prevEdits, currEdits);\r\n\treturn compressor.compress();\r\n}\r\n\r\nclass TextChangeCompressor {\r\n\r\n\tprivate _prevEdits: TextChange[];\r\n\tprivate _currEdits: TextChange[];\r\n\r\n\tprivate _result: TextChange[];\r\n\tprivate _resultLen: number;\r\n\r\n\tprivate _prevLen: number;\r\n\tprivate _prevDeltaOffset: number;\r\n\r\n\tprivate _currLen: number;\r\n\tprivate _currDeltaOffset: number;\r\n\r\n\tconstructor(prevEdits: TextChange[], currEdits: TextChange[]) {\r\n\t\tthis._prevEdits = prevEdits;\r\n\t\tthis._currEdits = currEdits;\r\n\r\n\t\tthis._result = [];\r\n\t\tthis._resultLen = 0;\r\n\r\n\t\tthis._prevLen = this._prevEdits.length;\r\n\t\tthis._prevDeltaOffset = 0;\r\n\r\n\t\tthis._currLen = this._currEdits.length;\r\n\t\tthis._currDeltaOffset = 0;\r\n\t}\r\n\r\n\tpublic compress(): TextChange[] {\r\n\t\tlet prevIndex = 0;\r\n\t\tlet currIndex = 0;\r\n\r\n\t\tlet prevEdit = this._getPrev(prevIndex);\r\n\t\tlet currEdit = this._getCurr(currIndex);\r\n\r\n\t\twhile (prevIndex < this._prevLen || currIndex < this._currLen) {\r\n\r\n\t\t\tif (prevEdit === null) {\r\n\t\t\t\tthis._acceptCurr(currEdit!);\r\n\t\t\t\tcurrEdit = this._getCurr(++currIndex);\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (currEdit === null) {\r\n\t\t\t\tthis._acceptPrev(prevEdit);\r\n\t\t\t\tprevEdit = this._getPrev(++prevIndex);\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (currEdit.oldEnd <= prevEdit.newPosition) {\r\n\t\t\t\tthis._acceptCurr(currEdit);\r\n\t\t\t\tcurrEdit = this._getCurr(++currIndex);\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (prevEdit.newEnd <= currEdit.oldPosition) {\r\n\t\t\t\tthis._acceptPrev(prevEdit);\r\n\t\t\t\tprevEdit = this._getPrev(++prevIndex);\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (currEdit.oldPosition < prevEdit.newPosition) {\r\n\t\t\t\tconst [e1, e2] = TextChangeCompressor._splitCurr(currEdit, prevEdit.newPosition - currEdit.oldPosition);\r\n\t\t\t\tthis._acceptCurr(e1);\r\n\t\t\t\tcurrEdit = e2;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (prevEdit.newPosition < currEdit.oldPosition) {\r\n\t\t\t\tconst [e1, e2] = TextChangeCompressor._splitPrev(prevEdit, currEdit.oldPosition - prevEdit.newPosition);\r\n\t\t\t\tthis._acceptPrev(e1);\r\n\t\t\t\tprevEdit = e2;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\t// At this point, currEdit.oldPosition === prevEdit.newPosition\r\n\r\n\t\t\tlet mergePrev: TextChange;\r\n\t\t\tlet mergeCurr: TextChange;\r\n\r\n\t\t\tif (currEdit.oldEnd === prevEdit.newEnd) {\r\n\t\t\t\tmergePrev = prevEdit;\r\n\t\t\t\tmergeCurr = currEdit;\r\n\t\t\t\tprevEdit = this._getPrev(++prevIndex);\r\n\t\t\t\tcurrEdit = this._getCurr(++currIndex);\r\n\t\t\t} else if (currEdit.oldEnd < prevEdit.newEnd) {\r\n\t\t\t\tconst [e1, e2] = TextChangeCompressor._splitPrev(prevEdit, currEdit.oldLength);\r\n\t\t\t\tmergePrev = e1;\r\n\t\t\t\tmergeCurr = currEdit;\r\n\t\t\t\tprevEdit = e2;\r\n\t\t\t\tcurrEdit = this._getCurr(++currIndex);\r\n\t\t\t} else {\r\n\t\t\t\tconst [e1, e2] = TextChangeCompressor._splitCurr(currEdit, prevEdit.newLength);\r\n\t\t\t\tmergePrev = prevEdit;\r\n\t\t\t\tmergeCurr = e1;\r\n\t\t\t\tprevEdit = this._getPrev(++prevIndex);\r\n\t\t\t\tcurrEdit = e2;\r\n\t\t\t}\r\n\r\n\t\t\tthis._result[this._resultLen++] = new TextChange(\r\n\t\t\t\tmergePrev.oldPosition,\r\n\t\t\t\tmergePrev.oldText,\r\n\t\t\t\tmergeCurr.newPosition,\r\n\t\t\t\tmergeCurr.newText\r\n\t\t\t);\r\n\t\t\tthis._prevDeltaOffset += mergePrev.newLength - mergePrev.oldLength;\r\n\t\t\tthis._currDeltaOffset += mergeCurr.newLength - mergeCurr.oldLength;\r\n\t\t}\r\n\r\n\t\tconst merged = TextChangeCompressor._merge(this._result);\r\n\t\tconst cleaned = TextChangeCompressor._removeNoOps(merged);\r\n\t\treturn cleaned;\r\n\t}\r\n\r\n\tprivate _acceptCurr(currEdit: TextChange): void {\r\n\t\tthis._result[this._resultLen++] = TextChangeCompressor._rebaseCurr(this._prevDeltaOffset, currEdit);\r\n\t\tthis._currDeltaOffset += currEdit.newLength - currEdit.oldLength;\r\n\t}\r\n\r\n\tprivate _getCurr(currIndex: number): TextChange | null {\r\n\t\treturn (currIndex < this._currLen ? this._currEdits[currIndex] : null);\r\n\t}\r\n\r\n\tprivate _acceptPrev(prevEdit: TextChange): void {\r\n\t\tthis._result[this._resultLen++] = TextChangeCompressor._rebasePrev(this._currDeltaOffset, prevEdit);\r\n\t\tthis._prevDeltaOffset += prevEdit.newLength - prevEdit.oldLength;\r\n\t}\r\n\r\n\tprivate _getPrev(prevIndex: number): TextChange | null {\r\n\t\treturn (prevIndex < this._prevLen ? this._prevEdits[prevIndex] : null);\r\n\t}\r\n\r\n\tprivate static _rebaseCurr(prevDeltaOffset: number, currEdit: TextChange): TextChange {\r\n\t\treturn new TextChange(\r\n\t\t\tcurrEdit.oldPosition - prevDeltaOffset,\r\n\t\t\tcurrEdit.oldText,\r\n\t\t\tcurrEdit.newPosition,\r\n\t\t\tcurrEdit.newText\r\n\t\t);\r\n\t}\r\n\r\n\tprivate static _rebasePrev(currDeltaOffset: number, prevEdit: TextChange): TextChange {\r\n\t\treturn new TextChange(\r\n\t\t\tprevEdit.oldPosition,\r\n\t\t\tprevEdit.oldText,\r\n\t\t\tprevEdit.newPosition + currDeltaOffset,\r\n\t\t\tprevEdit.newText\r\n\t\t);\r\n\t}\r\n\r\n\tprivate static _splitPrev(edit: TextChange, offset: number): [TextChange, TextChange] {\r\n\t\tconst preText = edit.newText.substr(0, offset);\r\n\t\tconst postText = edit.newText.substr(offset);\r\n\r\n\t\treturn [\r\n\t\t\tnew TextChange(\r\n\t\t\t\tedit.oldPosition,\r\n\t\t\t\tedit.oldText,\r\n\t\t\t\tedit.newPosition,\r\n\t\t\t\tpreText\r\n\t\t\t),\r\n\t\t\tnew TextChange(\r\n\t\t\t\tedit.oldEnd,\r\n\t\t\t\t'',\r\n\t\t\t\tedit.newPosition + offset,\r\n\t\t\t\tpostText\r\n\t\t\t)\r\n\t\t];\r\n\t}\r\n\r\n\tprivate static _splitCurr(edit: TextChange, offset: number): [TextChange, TextChange] {\r\n\t\tconst preText = edit.oldText.substr(0, offset);\r\n\t\tconst postText = edit.oldText.substr(offset);\r\n\r\n\t\treturn [\r\n\t\t\tnew TextChange(\r\n\t\t\t\tedit.oldPosition,\r\n\t\t\t\tpreText,\r\n\t\t\t\tedit.newPosition,\r\n\t\t\t\tedit.newText\r\n\t\t\t),\r\n\t\t\tnew TextChange(\r\n\t\t\t\tedit.oldPosition + offset,\r\n\t\t\t\tpostText,\r\n\t\t\t\tedit.newEnd,\r\n\t\t\t\t''\r\n\t\t\t)\r\n\t\t];\r\n\t}\r\n\r\n\tprivate static _merge(edits: TextChange[]): TextChange[] {\r\n\t\tif (edits.length === 0) {\r\n\t\t\treturn edits;\r\n\t\t}\r\n\r\n\t\tlet result: TextChange[] = [], resultLen = 0;\r\n\r\n\t\tlet prev = edits[0];\r\n\t\tfor (let i = 1; i < edits.length; i++) {\r\n\t\t\tconst curr = edits[i];\r\n\r\n\t\t\tif (prev.oldEnd === curr.oldPosition) {\r\n\t\t\t\t// Merge into `prev`\r\n\t\t\t\tprev = new TextChange(\r\n\t\t\t\t\tprev.oldPosition,\r\n\t\t\t\t\tprev.oldText + curr.oldText,\r\n\t\t\t\t\tprev.newPosition,\r\n\t\t\t\t\tprev.newText + curr.newText\r\n\t\t\t\t);\r\n\t\t\t} else {\r\n\t\t\t\tresult[resultLen++] = prev;\r\n\t\t\t\tprev = curr;\r\n\t\t\t}\r\n\t\t}\r\n\t\tresult[resultLen++] = prev;\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _removeNoOps(edits: TextChange[]): TextChange[] {\r\n\t\tif (edits.length === 0) {\r\n\t\t\treturn edits;\r\n\t\t}\r\n\r\n\t\tlet result: TextChange[] = [], resultLen = 0;\r\n\r\n\t\tfor (let i = 0; i < edits.length; i++) {\r\n\t\t\tconst edit = edits[i];\r\n\r\n\t\t\tif (edit.oldText === edit.newText) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tresult[resultLen++] = edit;\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IRange } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\n\r\n/**\r\n * An event describing that the current mode associated with a model has changed.\r\n */\r\nexport interface IModelLanguageChangedEvent {\r\n\t/**\r\n\t * Previous language\r\n\t */\r\n\treadonly oldLanguage: string;\r\n\t/**\r\n\t * New language\r\n\t */\r\n\treadonly newLanguage: string;\r\n}\r\n\r\n/**\r\n * An event describing that the language configuration associated with a model has changed.\r\n */\r\nexport interface IModelLanguageConfigurationChangedEvent {\r\n}\r\n\r\nexport interface IModelContentChange {\r\n\t/**\r\n\t * The range that got replaced.\r\n\t */\r\n\treadonly range: IRange;\r\n\t/**\r\n\t * The offset of the range that got replaced.\r\n\t */\r\n\treadonly rangeOffset: number;\r\n\t/**\r\n\t * The length of the range that got replaced.\r\n\t */\r\n\treadonly rangeLength: number;\r\n\t/**\r\n\t * The new text for the range.\r\n\t */\r\n\treadonly text: string;\r\n}\r\n\r\n/**\r\n * An event describing a change in the text of a model.\r\n */\r\nexport interface IModelContentChangedEvent {\r\n\treadonly changes: IModelContentChange[];\r\n\t/**\r\n\t * The (new) end-of-line character.\r\n\t */\r\n\treadonly eol: string;\r\n\t/**\r\n\t * The new version id the model has transitioned to.\r\n\t */\r\n\treadonly versionId: number;\r\n\t/**\r\n\t * Flag that indicates that this event was generated while undoing.\r\n\t */\r\n\treadonly isUndoing: boolean;\r\n\t/**\r\n\t * Flag that indicates that this event was generated while redoing.\r\n\t */\r\n\treadonly isRedoing: boolean;\r\n\t/**\r\n\t * Flag that indicates that all decorations were lost with this edit.\r\n\t * The model has been reset to a new value.\r\n\t */\r\n\treadonly isFlush: boolean;\r\n}\r\n\r\n/**\r\n * An event describing that model decorations have changed.\r\n */\r\nexport interface IModelDecorationsChangedEvent {\r\n\treadonly affectsMinimap: boolean;\r\n\treadonly affectsOverviewRuler: boolean;\r\n}\r\n\r\n/**\r\n * An event describing that some ranges of lines have been tokenized (their tokens have changed).\r\n * @internal\r\n */\r\nexport interface IModelTokensChangedEvent {\r\n\treadonly tokenizationSupportChanged: boolean;\r\n\treadonly semanticTokensApplied: boolean;\r\n\treadonly ranges: {\r\n\t\t/**\r\n\t\t * The start of the range (inclusive)\r\n\t\t */\r\n\t\treadonly fromLineNumber: number;\r\n\t\t/**\r\n\t\t * The end of the range (inclusive)\r\n\t\t */\r\n\t\treadonly toLineNumber: number;\r\n\t}[];\r\n}\r\n\r\nexport interface IModelOptionsChangedEvent {\r\n\treadonly tabSize: boolean;\r\n\treadonly indentSize: boolean;\r\n\treadonly insertSpaces: boolean;\r\n\treadonly trimAutoWhitespace: boolean;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const enum RawContentChangedType {\r\n\tFlush = 1,\r\n\tLineChanged = 2,\r\n\tLinesDeleted = 3,\r\n\tLinesInserted = 4,\r\n\tEOLChanged = 5\r\n}\r\n\r\n/**\r\n * An event describing that a model has been reset to a new value.\r\n * @internal\r\n */\r\nexport class ModelRawFlush {\r\n\tpublic readonly changeType = RawContentChangedType.Flush;\r\n}\r\n\r\n/**\r\n * An event describing that a line has changed in a model.\r\n * @internal\r\n */\r\nexport class ModelRawLineChanged {\r\n\tpublic readonly changeType = RawContentChangedType.LineChanged;\r\n\t/**\r\n\t * The line that has changed.\r\n\t */\r\n\tpublic readonly lineNumber: number;\r\n\t/**\r\n\t * The new value of the line.\r\n\t */\r\n\tpublic readonly detail: string;\r\n\r\n\tconstructor(lineNumber: number, detail: string) {\r\n\t\tthis.lineNumber = lineNumber;\r\n\t\tthis.detail = detail;\r\n\t}\r\n}\r\n\r\n/**\r\n * An event describing that line(s) have been deleted in a model.\r\n * @internal\r\n */\r\nexport class ModelRawLinesDeleted {\r\n\tpublic readonly changeType = RawContentChangedType.LinesDeleted;\r\n\t/**\r\n\t * At what line the deletion began (inclusive).\r\n\t */\r\n\tpublic readonly fromLineNumber: number;\r\n\t/**\r\n\t * At what line the deletion stopped (inclusive).\r\n\t */\r\n\tpublic readonly toLineNumber: number;\r\n\r\n\tconstructor(fromLineNumber: number, toLineNumber: number) {\r\n\t\tthis.fromLineNumber = fromLineNumber;\r\n\t\tthis.toLineNumber = toLineNumber;\r\n\t}\r\n}\r\n\r\n/**\r\n * An event describing that line(s) have been inserted in a model.\r\n * @internal\r\n */\r\nexport class ModelRawLinesInserted {\r\n\tpublic readonly changeType = RawContentChangedType.LinesInserted;\r\n\t/**\r\n\t * Before what line did the insertion begin\r\n\t */\r\n\tpublic readonly fromLineNumber: number;\r\n\t/**\r\n\t * `toLineNumber` - `fromLineNumber` + 1 denotes the number of lines that were inserted\r\n\t */\r\n\tpublic readonly toLineNumber: number;\r\n\t/**\r\n\t * The text that was inserted\r\n\t */\r\n\tpublic readonly detail: string[];\r\n\r\n\tconstructor(fromLineNumber: number, toLineNumber: number, detail: string[]) {\r\n\t\tthis.fromLineNumber = fromLineNumber;\r\n\t\tthis.toLineNumber = toLineNumber;\r\n\t\tthis.detail = detail;\r\n\t}\r\n}\r\n\r\n/**\r\n * An event describing that a model has had its EOL changed.\r\n * @internal\r\n */\r\nexport class ModelRawEOLChanged {\r\n\tpublic readonly changeType = RawContentChangedType.EOLChanged;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport type ModelRawChange = ModelRawFlush | ModelRawLineChanged | ModelRawLinesDeleted | ModelRawLinesInserted | ModelRawEOLChanged;\r\n\r\n/**\r\n * An event describing a change in the text of a model.\r\n * @internal\r\n */\r\nexport class ModelRawContentChangedEvent {\r\n\r\n\tpublic readonly changes: ModelRawChange[];\r\n\t/**\r\n\t * The new version id the model has transitioned to.\r\n\t */\r\n\tpublic readonly versionId: number;\r\n\t/**\r\n\t * Flag that indicates that this event was generated while undoing.\r\n\t */\r\n\tpublic readonly isUndoing: boolean;\r\n\t/**\r\n\t * Flag that indicates that this event was generated while redoing.\r\n\t */\r\n\tpublic readonly isRedoing: boolean;\r\n\r\n\tpublic resultingSelection: Selection[] | null;\r\n\r\n\tconstructor(changes: ModelRawChange[], versionId: number, isUndoing: boolean, isRedoing: boolean) {\r\n\t\tthis.changes = changes;\r\n\t\tthis.versionId = versionId;\r\n\t\tthis.isUndoing = isUndoing;\r\n\t\tthis.isRedoing = isRedoing;\r\n\t\tthis.resultingSelection = null;\r\n\t}\r\n\r\n\tpublic containsEvent(type: RawContentChangedType): boolean {\r\n\t\tfor (let i = 0, len = this.changes.length; i < len; i++) {\r\n\t\t\tconst change = this.changes[i];\r\n\t\t\tif (change.changeType === type) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic static merge(a: ModelRawContentChangedEvent, b: ModelRawContentChangedEvent): ModelRawContentChangedEvent {\r\n\t\tconst changes = ([] as ModelRawChange[]).concat(a.changes).concat(b.changes);\r\n\t\tconst versionId = b.versionId;\r\n\t\tconst isUndoing = (a.isUndoing || b.isUndoing);\r\n\t\tconst isRedoing = (a.isRedoing || b.isRedoing);\r\n\t\treturn new ModelRawContentChangedEvent(changes, versionId, isUndoing, isRedoing);\r\n\t}\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport class InternalModelContentChangeEvent {\r\n\tconstructor(\r\n\t\tpublic readonly rawContentChangedEvent: ModelRawContentChangedEvent,\r\n\t\tpublic readonly contentChangedEvent: IModelContentChangedEvent,\r\n\t) { }\r\n\r\n\tpublic merge(other: InternalModelContentChangeEvent): InternalModelContentChangeEvent {\r\n\t\tconst rawContentChangedEvent = ModelRawContentChangedEvent.merge(this.rawContentChangedEvent, other.rawContentChangedEvent);\r\n\t\tconst contentChangedEvent = InternalModelContentChangeEvent._mergeChangeEvents(this.contentChangedEvent, other.contentChangedEvent);\r\n\t\treturn new InternalModelContentChangeEvent(rawContentChangedEvent, contentChangedEvent);\r\n\t}\r\n\r\n\tprivate static _mergeChangeEvents(a: IModelContentChangedEvent, b: IModelContentChangedEvent): IModelContentChangedEvent {\r\n\t\tconst changes = ([] as IModelContentChange[]).concat(a.changes).concat(b.changes);\r\n\t\tconst eol = b.eol;\r\n\t\tconst versionId = b.versionId;\r\n\t\tconst isUndoing = (a.isUndoing || b.isUndoing);\r\n\t\tconst isRedoing = (a.isRedoing || b.isRedoing);\r\n\t\tconst isFlush = (a.isFlush || b.isFlush);\r\n\t\treturn {\r\n\t\t\tchanges: changes,\r\n\t\t\teol: eol,\r\n\t\t\tversionId: versionId,\r\n\t\t\tisUndoing: isUndoing,\r\n\t\t\tisRedoing: isRedoing,\r\n\t\t\tisFlush: isFlush\r\n\t\t};\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { WordCharacterClass, WordCharacterClassifier, getMapForWordSeparators } from 'vs/editor/common/controller/wordCharacterClassifier';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { EndOfLinePreference, FindMatch } from 'vs/editor/common/model';\r\nimport { TextModel } from 'vs/editor/common/model/textModel';\r\n\r\nconst LIMIT_FIND_COUNT = 999;\r\n\r\nexport class SearchParams {\r\n\tpublic readonly searchString: string;\r\n\tpublic readonly isRegex: boolean;\r\n\tpublic readonly matchCase: boolean;\r\n\tpublic readonly wordSeparators: string | null;\r\n\r\n\tconstructor(searchString: string, isRegex: boolean, matchCase: boolean, wordSeparators: string | null) {\r\n\t\tthis.searchString = searchString;\r\n\t\tthis.isRegex = isRegex;\r\n\t\tthis.matchCase = matchCase;\r\n\t\tthis.wordSeparators = wordSeparators;\r\n\t}\r\n\r\n\tpublic parseSearchRequest(): SearchData | null {\r\n\t\tif (this.searchString === '') {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\t// Try to create a RegExp out of the params\r\n\t\tlet multiline: boolean;\r\n\t\tif (this.isRegex) {\r\n\t\t\tmultiline = isMultilineRegexSource(this.searchString);\r\n\t\t} else {\r\n\t\t\tmultiline = (this.searchString.indexOf('\\n') >= 0);\r\n\t\t}\r\n\r\n\t\tlet regex: RegExp | null = null;\r\n\t\ttry {\r\n\t\t\tregex = strings.createRegExp(this.searchString, this.isRegex, {\r\n\t\t\t\tmatchCase: this.matchCase,\r\n\t\t\t\twholeWord: false,\r\n\t\t\t\tmultiline: multiline,\r\n\t\t\t\tglobal: true,\r\n\t\t\t\tunicode: true\r\n\t\t\t});\r\n\t\t} catch (err) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (!regex) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet canUseSimpleSearch = (!this.isRegex && !multiline);\r\n\t\tif (canUseSimpleSearch && this.searchString.toLowerCase() !== this.searchString.toUpperCase()) {\r\n\t\t\t// casing might make a difference\r\n\t\t\tcanUseSimpleSearch = this.matchCase;\r\n\t\t}\r\n\r\n\t\treturn new SearchData(regex, this.wordSeparators ? getMapForWordSeparators(this.wordSeparators) : null, canUseSimpleSearch ? this.searchString : null);\r\n\t}\r\n}\r\n\r\nexport function isMultilineRegexSource(searchString: string): boolean {\r\n\tif (!searchString || searchString.length === 0) {\r\n\t\treturn false;\r\n\t}\r\n\r\n\tfor (let i = 0, len = searchString.length; i < len; i++) {\r\n\t\tconst chCode = searchString.charCodeAt(i);\r\n\r\n\t\tif (chCode === CharCode.Backslash) {\r\n\r\n\t\t\t// move to next char\r\n\t\t\ti++;\r\n\r\n\t\t\tif (i >= len) {\r\n\t\t\t\t// string ends with a \\\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tconst nextChCode = searchString.charCodeAt(i);\r\n\t\t\tif (nextChCode === CharCode.n || nextChCode === CharCode.r || nextChCode === CharCode.W || nextChCode === CharCode.w) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\treturn false;\r\n}\r\n\r\nexport class SearchData {\r\n\r\n\t/**\r\n\t * The regex to search for. Always defined.\r\n\t */\r\n\tpublic readonly regex: RegExp;\r\n\t/**\r\n\t * The word separator classifier.\r\n\t */\r\n\tpublic readonly wordSeparators: WordCharacterClassifier | null;\r\n\t/**\r\n\t * The simple string to search for (if possible).\r\n\t */\r\n\tpublic readonly simpleSearch: string | null;\r\n\r\n\tconstructor(regex: RegExp, wordSeparators: WordCharacterClassifier | null, simpleSearch: string | null) {\r\n\t\tthis.regex = regex;\r\n\t\tthis.wordSeparators = wordSeparators;\r\n\t\tthis.simpleSearch = simpleSearch;\r\n\t}\r\n}\r\n\r\nexport function createFindMatch(range: Range, rawMatches: RegExpExecArray, captureMatches: boolean): FindMatch {\r\n\tif (!captureMatches) {\r\n\t\treturn new FindMatch(range, null);\r\n\t}\r\n\tlet matches: string[] = [];\r\n\tfor (let i = 0, len = rawMatches.length; i < len; i++) {\r\n\t\tmatches[i] = rawMatches[i];\r\n\t}\r\n\treturn new FindMatch(range, matches);\r\n}\r\n\r\nclass LineFeedCounter {\r\n\r\n\tprivate readonly _lineFeedsOffsets: number[];\r\n\r\n\tconstructor(text: string) {\r\n\t\tlet lineFeedsOffsets: number[] = [];\r\n\t\tlet lineFeedsOffsetsLen = 0;\r\n\t\tfor (let i = 0, textLen = text.length; i < textLen; i++) {\r\n\t\t\tif (text.charCodeAt(i) === CharCode.LineFeed) {\r\n\t\t\t\tlineFeedsOffsets[lineFeedsOffsetsLen++] = i;\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis._lineFeedsOffsets = lineFeedsOffsets;\r\n\t}\r\n\r\n\tpublic findLineFeedCountBeforeOffset(offset: number): number {\r\n\t\tconst lineFeedsOffsets = this._lineFeedsOffsets;\r\n\t\tlet min = 0;\r\n\t\tlet max = lineFeedsOffsets.length - 1;\r\n\r\n\t\tif (max === -1) {\r\n\t\t\t// no line feeds\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tif (offset <= lineFeedsOffsets[0]) {\r\n\t\t\t// before first line feed\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\twhile (min < max) {\r\n\t\t\tconst mid = min + ((max - min) / 2 >> 0);\r\n\r\n\t\t\tif (lineFeedsOffsets[mid] >= offset) {\r\n\t\t\t\tmax = mid - 1;\r\n\t\t\t} else {\r\n\t\t\t\tif (lineFeedsOffsets[mid + 1] >= offset) {\r\n\t\t\t\t\t// bingo!\r\n\t\t\t\t\tmin = mid;\r\n\t\t\t\t\tmax = mid;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tmin = mid + 1;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn min + 1;\r\n\t}\r\n}\r\n\r\nexport class TextModelSearch {\r\n\r\n\tpublic static findMatches(model: TextModel, searchParams: SearchParams, searchRange: Range, captureMatches: boolean, limitResultCount: number): FindMatch[] {\r\n\t\tconst searchData = searchParams.parseSearchRequest();\r\n\t\tif (!searchData) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tif (searchData.regex.multiline) {\r\n\t\t\treturn this._doFindMatchesMultiline(model, searchRange, new Searcher(searchData.wordSeparators, searchData.regex), captureMatches, limitResultCount);\r\n\t\t}\r\n\t\treturn this._doFindMatchesLineByLine(model, searchRange, searchData, captureMatches, limitResultCount);\r\n\t}\r\n\r\n\t/**\r\n\t * Multiline search always executes on the lines concatenated with \\n.\r\n\t * We must therefore compensate for the count of \\n in case the model is CRLF\r\n\t */\r\n\tprivate static _getMultilineMatchRange(model: TextModel, deltaOffset: number, text: string, lfCounter: LineFeedCounter | null, matchIndex: number, match0: string): Range {\r\n\t\tlet startOffset: number;\r\n\t\tlet lineFeedCountBeforeMatch = 0;\r\n\t\tif (lfCounter) {\r\n\t\t\tlineFeedCountBeforeMatch = lfCounter.findLineFeedCountBeforeOffset(matchIndex);\r\n\t\t\tstartOffset = deltaOffset + matchIndex + lineFeedCountBeforeMatch /* add as many \\r as there were \\n */;\r\n\t\t} else {\r\n\t\t\tstartOffset = deltaOffset + matchIndex;\r\n\t\t}\r\n\r\n\t\tlet endOffset: number;\r\n\t\tif (lfCounter) {\r\n\t\t\tlet lineFeedCountBeforeEndOfMatch = lfCounter.findLineFeedCountBeforeOffset(matchIndex + match0.length);\r\n\t\t\tlet lineFeedCountInMatch = lineFeedCountBeforeEndOfMatch - lineFeedCountBeforeMatch;\r\n\t\t\tendOffset = startOffset + match0.length + lineFeedCountInMatch /* add as many \\r as there were \\n */;\r\n\t\t} else {\r\n\t\t\tendOffset = startOffset + match0.length;\r\n\t\t}\r\n\r\n\t\tconst startPosition = model.getPositionAt(startOffset);\r\n\t\tconst endPosition = model.getPositionAt(endOffset);\r\n\t\treturn new Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column);\r\n\t}\r\n\r\n\tprivate static _doFindMatchesMultiline(model: TextModel, searchRange: Range, searcher: Searcher, captureMatches: boolean, limitResultCount: number): FindMatch[] {\r\n\t\tconst deltaOffset = model.getOffsetAt(searchRange.getStartPosition());\r\n\t\t// We always execute multiline search over the lines joined with \\n\r\n\t\t// This makes it that \\n will match the EOL for both CRLF and LF models\r\n\t\t// We compensate for offset errors in `_getMultilineMatchRange`\r\n\t\tconst text = model.getValueInRange(searchRange, EndOfLinePreference.LF);\r\n\t\tconst lfCounter = (model.getEOL() === '\\r\\n' ? new LineFeedCounter(text) : null);\r\n\r\n\t\tconst result: FindMatch[] = [];\r\n\t\tlet counter = 0;\r\n\r\n\t\tlet m: RegExpExecArray | null;\r\n\t\tsearcher.reset(0);\r\n\t\twhile ((m = searcher.next(text))) {\r\n\t\t\tresult[counter++] = createFindMatch(this._getMultilineMatchRange(model, deltaOffset, text, lfCounter, m.index, m[0]), m, captureMatches);\r\n\t\t\tif (counter >= limitResultCount) {\r\n\t\t\t\treturn result;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _doFindMatchesLineByLine(model: TextModel, searchRange: Range, searchData: SearchData, captureMatches: boolean, limitResultCount: number): FindMatch[] {\r\n\t\tconst result: FindMatch[] = [];\r\n\t\tlet resultLen = 0;\r\n\r\n\t\t// Early case for a search range that starts & stops on the same line number\r\n\t\tif (searchRange.startLineNumber === searchRange.endLineNumber) {\r\n\t\t\tconst text = model.getLineContent(searchRange.startLineNumber).substring(searchRange.startColumn - 1, searchRange.endColumn - 1);\r\n\t\t\tresultLen = this._findMatchesInLine(searchData, text, searchRange.startLineNumber, searchRange.startColumn - 1, resultLen, result, captureMatches, limitResultCount);\r\n\t\t\treturn result;\r\n\t\t}\r\n\r\n\t\t// Collect results from first line\r\n\t\tconst text = model.getLineContent(searchRange.startLineNumber).substring(searchRange.startColumn - 1);\r\n\t\tresultLen = this._findMatchesInLine(searchData, text, searchRange.startLineNumber, searchRange.startColumn - 1, resultLen, result, captureMatches, limitResultCount);\r\n\r\n\t\t// Collect results from middle lines\r\n\t\tfor (let lineNumber = searchRange.startLineNumber + 1; lineNumber < searchRange.endLineNumber && resultLen < limitResultCount; lineNumber++) {\r\n\t\t\tresultLen = this._findMatchesInLine(searchData, model.getLineContent(lineNumber), lineNumber, 0, resultLen, result, captureMatches, limitResultCount);\r\n\t\t}\r\n\r\n\t\t// Collect results from last line\r\n\t\tif (resultLen < limitResultCount) {\r\n\t\t\tconst text = model.getLineContent(searchRange.endLineNumber).substring(0, searchRange.endColumn - 1);\r\n\t\t\tresultLen = this._findMatchesInLine(searchData, text, searchRange.endLineNumber, 0, resultLen, result, captureMatches, limitResultCount);\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _findMatchesInLine(searchData: SearchData, text: string, lineNumber: number, deltaOffset: number, resultLen: number, result: FindMatch[], captureMatches: boolean, limitResultCount: number): number {\r\n\t\tconst wordSeparators = searchData.wordSeparators;\r\n\t\tif (!captureMatches && searchData.simpleSearch) {\r\n\t\t\tconst searchString = searchData.simpleSearch;\r\n\t\t\tconst searchStringLen = searchString.length;\r\n\t\t\tconst textLength = text.length;\r\n\r\n\t\t\tlet lastMatchIndex = -searchStringLen;\r\n\t\t\twhile ((lastMatchIndex = text.indexOf(searchString, lastMatchIndex + searchStringLen)) !== -1) {\r\n\t\t\t\tif (!wordSeparators || isValidMatch(wordSeparators, text, textLength, lastMatchIndex, searchStringLen)) {\r\n\t\t\t\t\tresult[resultLen++] = new FindMatch(new Range(lineNumber, lastMatchIndex + 1 + deltaOffset, lineNumber, lastMatchIndex + 1 + searchStringLen + deltaOffset), null);\r\n\t\t\t\t\tif (resultLen >= limitResultCount) {\r\n\t\t\t\t\t\treturn resultLen;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn resultLen;\r\n\t\t}\r\n\r\n\t\tconst searcher = new Searcher(searchData.wordSeparators, searchData.regex);\r\n\t\tlet m: RegExpExecArray | null;\r\n\t\t// Reset regex to search from the beginning\r\n\t\tsearcher.reset(0);\r\n\t\tdo {\r\n\t\t\tm = searcher.next(text);\r\n\t\t\tif (m) {\r\n\t\t\t\tresult[resultLen++] = createFindMatch(new Range(lineNumber, m.index + 1 + deltaOffset, lineNumber, m.index + 1 + m[0].length + deltaOffset), m, captureMatches);\r\n\t\t\t\tif (resultLen >= limitResultCount) {\r\n\t\t\t\t\treturn resultLen;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} while (m);\r\n\t\treturn resultLen;\r\n\t}\r\n\r\n\tpublic static findNextMatch(model: TextModel, searchParams: SearchParams, searchStart: Position, captureMatches: boolean): FindMatch | null {\r\n\t\tconst searchData = searchParams.parseSearchRequest();\r\n\t\tif (!searchData) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst searcher = new Searcher(searchData.wordSeparators, searchData.regex);\r\n\r\n\t\tif (searchData.regex.multiline) {\r\n\t\t\treturn this._doFindNextMatchMultiline(model, searchStart, searcher, captureMatches);\r\n\t\t}\r\n\t\treturn this._doFindNextMatchLineByLine(model, searchStart, searcher, captureMatches);\r\n\t}\r\n\r\n\tprivate static _doFindNextMatchMultiline(model: TextModel, searchStart: Position, searcher: Searcher, captureMatches: boolean): FindMatch | null {\r\n\t\tconst searchTextStart = new Position(searchStart.lineNumber, 1);\r\n\t\tconst deltaOffset = model.getOffsetAt(searchTextStart);\r\n\t\tconst lineCount = model.getLineCount();\r\n\t\t// We always execute multiline search over the lines joined with \\n\r\n\t\t// This makes it that \\n will match the EOL for both CRLF and LF models\r\n\t\t// We compensate for offset errors in `_getMultilineMatchRange`\r\n\t\tconst text = model.getValueInRange(new Range(searchTextStart.lineNumber, searchTextStart.column, lineCount, model.getLineMaxColumn(lineCount)), EndOfLinePreference.LF);\r\n\t\tconst lfCounter = (model.getEOL() === '\\r\\n' ? new LineFeedCounter(text) : null);\r\n\t\tsearcher.reset(searchStart.column - 1);\r\n\t\tlet m = searcher.next(text);\r\n\t\tif (m) {\r\n\t\t\treturn createFindMatch(\r\n\t\t\t\tthis._getMultilineMatchRange(model, deltaOffset, text, lfCounter, m.index, m[0]),\r\n\t\t\t\tm,\r\n\t\t\t\tcaptureMatches\r\n\t\t\t);\r\n\t\t}\r\n\r\n\t\tif (searchStart.lineNumber !== 1 || searchStart.column !== 1) {\r\n\t\t\t// Try again from the top\r\n\t\t\treturn this._doFindNextMatchMultiline(model, new Position(1, 1), searcher, captureMatches);\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate static _doFindNextMatchLineByLine(model: TextModel, searchStart: Position, searcher: Searcher, captureMatches: boolean): FindMatch | null {\r\n\t\tconst lineCount = model.getLineCount();\r\n\t\tconst startLineNumber = searchStart.lineNumber;\r\n\r\n\t\t// Look in first line\r\n\t\tconst text = model.getLineContent(startLineNumber);\r\n\t\tconst r = this._findFirstMatchInLine(searcher, text, startLineNumber, searchStart.column, captureMatches);\r\n\t\tif (r) {\r\n\t\t\treturn r;\r\n\t\t}\r\n\r\n\t\tfor (let i = 1; i <= lineCount; i++) {\r\n\t\t\tconst lineIndex = (startLineNumber + i - 1) % lineCount;\r\n\t\t\tconst text = model.getLineContent(lineIndex + 1);\r\n\t\t\tconst r = this._findFirstMatchInLine(searcher, text, lineIndex + 1, 1, captureMatches);\r\n\t\t\tif (r) {\r\n\t\t\t\treturn r;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate static _findFirstMatchInLine(searcher: Searcher, text: string, lineNumber: number, fromColumn: number, captureMatches: boolean): FindMatch | null {\r\n\t\t// Set regex to search from column\r\n\t\tsearcher.reset(fromColumn - 1);\r\n\t\tconst m: RegExpExecArray | null = searcher.next(text);\r\n\t\tif (m) {\r\n\t\t\treturn createFindMatch(\r\n\t\t\t\tnew Range(lineNumber, m.index + 1, lineNumber, m.index + 1 + m[0].length),\r\n\t\t\t\tm,\r\n\t\t\t\tcaptureMatches\r\n\t\t\t);\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic static findPreviousMatch(model: TextModel, searchParams: SearchParams, searchStart: Position, captureMatches: boolean): FindMatch | null {\r\n\t\tconst searchData = searchParams.parseSearchRequest();\r\n\t\tif (!searchData) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst searcher = new Searcher(searchData.wordSeparators, searchData.regex);\r\n\r\n\t\tif (searchData.regex.multiline) {\r\n\t\t\treturn this._doFindPreviousMatchMultiline(model, searchStart, searcher, captureMatches);\r\n\t\t}\r\n\t\treturn this._doFindPreviousMatchLineByLine(model, searchStart, searcher, captureMatches);\r\n\t}\r\n\r\n\tprivate static _doFindPreviousMatchMultiline(model: TextModel, searchStart: Position, searcher: Searcher, captureMatches: boolean): FindMatch | null {\r\n\t\tconst matches = this._doFindMatchesMultiline(model, new Range(1, 1, searchStart.lineNumber, searchStart.column), searcher, captureMatches, 10 * LIMIT_FIND_COUNT);\r\n\t\tif (matches.length > 0) {\r\n\t\t\treturn matches[matches.length - 1];\r\n\t\t}\r\n\r\n\t\tconst lineCount = model.getLineCount();\r\n\t\tif (searchStart.lineNumber !== lineCount || searchStart.column !== model.getLineMaxColumn(lineCount)) {\r\n\t\t\t// Try again with all content\r\n\t\t\treturn this._doFindPreviousMatchMultiline(model, new Position(lineCount, model.getLineMaxColumn(lineCount)), searcher, captureMatches);\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate static _doFindPreviousMatchLineByLine(model: TextModel, searchStart: Position, searcher: Searcher, captureMatches: boolean): FindMatch | null {\r\n\t\tconst lineCount = model.getLineCount();\r\n\t\tconst startLineNumber = searchStart.lineNumber;\r\n\r\n\t\t// Look in first line\r\n\t\tconst text = model.getLineContent(startLineNumber).substring(0, searchStart.column - 1);\r\n\t\tconst r = this._findLastMatchInLine(searcher, text, startLineNumber, captureMatches);\r\n\t\tif (r) {\r\n\t\t\treturn r;\r\n\t\t}\r\n\r\n\t\tfor (let i = 1; i <= lineCount; i++) {\r\n\t\t\tconst lineIndex = (lineCount + startLineNumber - i - 1) % lineCount;\r\n\t\t\tconst text = model.getLineContent(lineIndex + 1);\r\n\t\t\tconst r = this._findLastMatchInLine(searcher, text, lineIndex + 1, captureMatches);\r\n\t\t\tif (r) {\r\n\t\t\t\treturn r;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate static _findLastMatchInLine(searcher: Searcher, text: string, lineNumber: number, captureMatches: boolean): FindMatch | null {\r\n\t\tlet bestResult: FindMatch | null = null;\r\n\t\tlet m: RegExpExecArray | null;\r\n\t\tsearcher.reset(0);\r\n\t\twhile ((m = searcher.next(text))) {\r\n\t\t\tbestResult = createFindMatch(new Range(lineNumber, m.index + 1, lineNumber, m.index + 1 + m[0].length), m, captureMatches);\r\n\t\t}\r\n\t\treturn bestResult;\r\n\t}\r\n}\r\n\r\nfunction leftIsWordBounday(wordSeparators: WordCharacterClassifier, text: string, textLength: number, matchStartIndex: number, matchLength: number): boolean {\r\n\tif (matchStartIndex === 0) {\r\n\t\t// Match starts at start of string\r\n\t\treturn true;\r\n\t}\r\n\r\n\tconst charBefore = text.charCodeAt(matchStartIndex - 1);\r\n\tif (wordSeparators.get(charBefore) !== WordCharacterClass.Regular) {\r\n\t\t// The character before the match is a word separator\r\n\t\treturn true;\r\n\t}\r\n\r\n\tif (charBefore === CharCode.CarriageReturn || charBefore === CharCode.LineFeed) {\r\n\t\t// The character before the match is line break or carriage return.\r\n\t\treturn true;\r\n\t}\r\n\r\n\tif (matchLength > 0) {\r\n\t\tconst firstCharInMatch = text.charCodeAt(matchStartIndex);\r\n\t\tif (wordSeparators.get(firstCharInMatch) !== WordCharacterClass.Regular) {\r\n\t\t\t// The first character inside the match is a word separator\r\n\t\t\treturn true;\r\n\t\t}\r\n\t}\r\n\r\n\treturn false;\r\n}\r\n\r\nfunction rightIsWordBounday(wordSeparators: WordCharacterClassifier, text: string, textLength: number, matchStartIndex: number, matchLength: number): boolean {\r\n\tif (matchStartIndex + matchLength === textLength) {\r\n\t\t// Match ends at end of string\r\n\t\treturn true;\r\n\t}\r\n\r\n\tconst charAfter = text.charCodeAt(matchStartIndex + matchLength);\r\n\tif (wordSeparators.get(charAfter) !== WordCharacterClass.Regular) {\r\n\t\t// The character after the match is a word separator\r\n\t\treturn true;\r\n\t}\r\n\r\n\tif (charAfter === CharCode.CarriageReturn || charAfter === CharCode.LineFeed) {\r\n\t\t// The character after the match is line break or carriage return.\r\n\t\treturn true;\r\n\t}\r\n\r\n\tif (matchLength > 0) {\r\n\t\tconst lastCharInMatch = text.charCodeAt(matchStartIndex + matchLength - 1);\r\n\t\tif (wordSeparators.get(lastCharInMatch) !== WordCharacterClass.Regular) {\r\n\t\t\t// The last character in the match is a word separator\r\n\t\t\treturn true;\r\n\t\t}\r\n\t}\r\n\r\n\treturn false;\r\n}\r\n\r\nexport function isValidMatch(wordSeparators: WordCharacterClassifier, text: string, textLength: number, matchStartIndex: number, matchLength: number): boolean {\r\n\treturn (\r\n\t\tleftIsWordBounday(wordSeparators, text, textLength, matchStartIndex, matchLength)\r\n\t\t&& rightIsWordBounday(wordSeparators, text, textLength, matchStartIndex, matchLength)\r\n\t);\r\n}\r\n\r\nexport class Searcher {\r\n\tpublic readonly _wordSeparators: WordCharacterClassifier | null;\r\n\tprivate readonly _searchRegex: RegExp;\r\n\tprivate _prevMatchStartIndex: number;\r\n\tprivate _prevMatchLength: number;\r\n\r\n\tconstructor(wordSeparators: WordCharacterClassifier | null, searchRegex: RegExp,) {\r\n\t\tthis._wordSeparators = wordSeparators;\r\n\t\tthis._searchRegex = searchRegex;\r\n\t\tthis._prevMatchStartIndex = -1;\r\n\t\tthis._prevMatchLength = 0;\r\n\t}\r\n\r\n\tpublic reset(lastIndex: number): void {\r\n\t\tthis._searchRegex.lastIndex = lastIndex;\r\n\t\tthis._prevMatchStartIndex = -1;\r\n\t\tthis._prevMatchLength = 0;\r\n\t}\r\n\r\n\tpublic next(text: string): RegExpExecArray | null {\r\n\t\tconst textLength = text.length;\r\n\r\n\t\tlet m: RegExpExecArray | null;\r\n\t\tdo {\r\n\t\t\tif (this._prevMatchStartIndex + this._prevMatchLength === textLength) {\r\n\t\t\t\t// Reached the end of the line\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\r\n\t\t\tm = this._searchRegex.exec(text);\r\n\t\t\tif (!m) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\r\n\t\t\tconst matchStartIndex = m.index;\r\n\t\t\tconst matchLength = m[0].length;\r\n\t\t\tif (matchStartIndex === this._prevMatchStartIndex && matchLength === this._prevMatchLength) {\r\n\t\t\t\tif (matchLength === 0) {\r\n\t\t\t\t\t// the search result is an empty string and won't advance `regex.lastIndex`, so `regex.exec` will stuck here\r\n\t\t\t\t\t// we attempt to recover from that by advancing by two if surrogate pair found and by one otherwise\r\n\t\t\t\t\tif (strings.getNextCodePoint(text, textLength, this._searchRegex.lastIndex) > 0xFFFF) {\r\n\t\t\t\t\t\tthis._searchRegex.lastIndex += 2;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tthis._searchRegex.lastIndex += 1;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\t// Exit early if the regex matches the same range twice\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t\tthis._prevMatchStartIndex = matchStartIndex;\r\n\t\t\tthis._prevMatchLength = matchLength;\r\n\r\n\t\t\tif (!this._wordSeparators || isValidMatch(this._wordSeparators, text, textLength, matchStartIndex, matchLength)) {\r\n\t\t\t\treturn m;\r\n\t\t\t}\r\n\r\n\t\t} while (m);\r\n\r\n\t\treturn null;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { FindMatch, ITextSnapshot } from 'vs/editor/common/model';\r\nimport { NodeColor, SENTINEL, TreeNode, fixInsert, leftest, rbDelete, righttest, updateTreeMetadata } from 'vs/editor/common/model/pieceTreeTextBuffer/rbTreeBase';\r\nimport { SearchData, Searcher, createFindMatch, isValidMatch } from 'vs/editor/common/model/textModelSearch';\r\n\r\n// const lfRegex = new RegExp(/\\r\\n|\\r|\\n/g);\r\nexport const AverageBufferSize = 65535;\r\n\r\nexport function createUintArray(arr: number[]): Uint32Array | Uint16Array {\r\n\tlet r;\r\n\tif (arr[arr.length - 1] < 65536) {\r\n\t\tr = new Uint16Array(arr.length);\r\n\t} else {\r\n\t\tr = new Uint32Array(arr.length);\r\n\t}\r\n\tr.set(arr, 0);\r\n\treturn r;\r\n}\r\n\r\nexport class LineStarts {\r\n\tconstructor(\r\n\t\tpublic readonly lineStarts: Uint32Array | Uint16Array | number[],\r\n\t\tpublic readonly cr: number,\r\n\t\tpublic readonly lf: number,\r\n\t\tpublic readonly crlf: number,\r\n\t\tpublic readonly isBasicASCII: boolean\r\n\t) { }\r\n}\r\n\r\nexport function createLineStartsFast(str: string, readonly: boolean = true): Uint32Array | Uint16Array | number[] {\r\n\tlet r: number[] = [0], rLength = 1;\r\n\r\n\tfor (let i = 0, len = str.length; i < len; i++) {\r\n\t\tconst chr = str.charCodeAt(i);\r\n\r\n\t\tif (chr === CharCode.CarriageReturn) {\r\n\t\t\tif (i + 1 < len && str.charCodeAt(i + 1) === CharCode.LineFeed) {\r\n\t\t\t\t// \\r\\n... case\r\n\t\t\t\tr[rLength++] = i + 2;\r\n\t\t\t\ti++; // skip \\n\r\n\t\t\t} else {\r\n\t\t\t\t// \\r... case\r\n\t\t\t\tr[rLength++] = i + 1;\r\n\t\t\t}\r\n\t\t} else if (chr === CharCode.LineFeed) {\r\n\t\t\tr[rLength++] = i + 1;\r\n\t\t}\r\n\t}\r\n\tif (readonly) {\r\n\t\treturn createUintArray(r);\r\n\t} else {\r\n\t\treturn r;\r\n\t}\r\n}\r\n\r\nexport function createLineStarts(r: number[], str: string): LineStarts {\r\n\tr.length = 0;\r\n\tr[0] = 0;\r\n\tlet rLength = 1;\r\n\tlet cr = 0, lf = 0, crlf = 0;\r\n\tlet isBasicASCII = true;\r\n\tfor (let i = 0, len = str.length; i < len; i++) {\r\n\t\tconst chr = str.charCodeAt(i);\r\n\r\n\t\tif (chr === CharCode.CarriageReturn) {\r\n\t\t\tif (i + 1 < len && str.charCodeAt(i + 1) === CharCode.LineFeed) {\r\n\t\t\t\t// \\r\\n... case\r\n\t\t\t\tcrlf++;\r\n\t\t\t\tr[rLength++] = i + 2;\r\n\t\t\t\ti++; // skip \\n\r\n\t\t\t} else {\r\n\t\t\t\tcr++;\r\n\t\t\t\t// \\r... case\r\n\t\t\t\tr[rLength++] = i + 1;\r\n\t\t\t}\r\n\t\t} else if (chr === CharCode.LineFeed) {\r\n\t\t\tlf++;\r\n\t\t\tr[rLength++] = i + 1;\r\n\t\t} else {\r\n\t\t\tif (isBasicASCII) {\r\n\t\t\t\tif (chr !== CharCode.Tab && (chr < 32 || chr > 126)) {\r\n\t\t\t\t\tisBasicASCII = false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\tconst result = new LineStarts(createUintArray(r), cr, lf, crlf, isBasicASCII);\r\n\tr.length = 0;\r\n\r\n\treturn result;\r\n}\r\n\r\nexport interface NodePosition {\r\n\t/**\r\n\t * Piece Index\r\n\t */\r\n\tnode: TreeNode;\r\n\t/**\r\n\t * remainer in current piece.\r\n\t*/\r\n\tremainder: number;\r\n\t/**\r\n\t * node start offset in document.\r\n\t */\r\n\tnodeStartOffset: number;\r\n}\r\n\r\nexport interface BufferCursor {\r\n\t/**\r\n\t * Line number in current buffer\r\n\t */\r\n\tline: number;\r\n\t/**\r\n\t * Column number in current buffer\r\n\t */\r\n\tcolumn: number;\r\n}\r\n\r\nexport class Piece {\r\n\treadonly bufferIndex: number;\r\n\treadonly start: BufferCursor;\r\n\treadonly end: BufferCursor;\r\n\treadonly length: number;\r\n\treadonly lineFeedCnt: number;\r\n\r\n\tconstructor(bufferIndex: number, start: BufferCursor, end: BufferCursor, lineFeedCnt: number, length: number) {\r\n\t\tthis.bufferIndex = bufferIndex;\r\n\t\tthis.start = start;\r\n\t\tthis.end = end;\r\n\t\tthis.lineFeedCnt = lineFeedCnt;\r\n\t\tthis.length = length;\r\n\t}\r\n}\r\n\r\nexport class StringBuffer {\r\n\tbuffer: string;\r\n\tlineStarts: Uint32Array | Uint16Array | number[];\r\n\r\n\tconstructor(buffer: string, lineStarts: Uint32Array | Uint16Array | number[]) {\r\n\t\tthis.buffer = buffer;\r\n\t\tthis.lineStarts = lineStarts;\r\n\t}\r\n}\r\n\r\n/**\r\n * Readonly snapshot for piece tree.\r\n * In a real multiple thread environment, to make snapshot reading always work correctly, we need to\r\n * 1. Make TreeNode.piece immutable, then reading and writing can run in parallel.\r\n * 2. TreeNode/Buffers normalization should not happen during snapshot reading.\r\n */\r\nclass PieceTreeSnapshot implements ITextSnapshot {\r\n\tprivate readonly _pieces: Piece[];\r\n\tprivate _index: number;\r\n\tprivate readonly _tree: PieceTreeBase;\r\n\tprivate readonly _BOM: string;\r\n\r\n\tconstructor(tree: PieceTreeBase, BOM: string) {\r\n\t\tthis._pieces = [];\r\n\t\tthis._tree = tree;\r\n\t\tthis._BOM = BOM;\r\n\t\tthis._index = 0;\r\n\t\tif (tree.root !== SENTINEL) {\r\n\t\t\ttree.iterate(tree.root, node => {\r\n\t\t\t\tif (node !== SENTINEL) {\r\n\t\t\t\t\tthis._pieces.push(node.piece);\r\n\t\t\t\t}\r\n\t\t\t\treturn true;\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tread(): string | null {\r\n\t\tif (this._pieces.length === 0) {\r\n\t\t\tif (this._index === 0) {\r\n\t\t\t\tthis._index++;\r\n\t\t\t\treturn this._BOM;\r\n\t\t\t} else {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (this._index > this._pieces.length - 1) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (this._index === 0) {\r\n\t\t\treturn this._BOM + this._tree.getPieceContent(this._pieces[this._index++]);\r\n\t\t}\r\n\t\treturn this._tree.getPieceContent(this._pieces[this._index++]);\r\n\t}\r\n}\r\n\r\ninterface CacheEntry {\r\n\tnode: TreeNode;\r\n\tnodeStartOffset: number;\r\n\tnodeStartLineNumber?: number;\r\n}\r\n\r\nclass PieceTreeSearchCache {\r\n\tprivate readonly _limit: number;\r\n\tprivate _cache: CacheEntry[];\r\n\r\n\tconstructor(limit: number) {\r\n\t\tthis._limit = limit;\r\n\t\tthis._cache = [];\r\n\t}\r\n\r\n\tpublic get(offset: number): CacheEntry | null {\r\n\t\tfor (let i = this._cache.length - 1; i >= 0; i--) {\r\n\t\t\tlet nodePos = this._cache[i];\r\n\t\t\tif (nodePos.nodeStartOffset <= offset && nodePos.nodeStartOffset + nodePos.node.piece.length >= offset) {\r\n\t\t\t\treturn nodePos;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic get2(lineNumber: number): { node: TreeNode, nodeStartOffset: number, nodeStartLineNumber: number } | null {\r\n\t\tfor (let i = this._cache.length - 1; i >= 0; i--) {\r\n\t\t\tlet nodePos = this._cache[i];\r\n\t\t\tif (nodePos.nodeStartLineNumber && nodePos.nodeStartLineNumber < lineNumber && nodePos.nodeStartLineNumber + nodePos.node.piece.lineFeedCnt >= lineNumber) {\r\n\t\t\t\treturn <{ node: TreeNode, nodeStartOffset: number, nodeStartLineNumber: number }>nodePos;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic set(nodePosition: CacheEntry) {\r\n\t\tif (this._cache.length >= this._limit) {\r\n\t\t\tthis._cache.shift();\r\n\t\t}\r\n\t\tthis._cache.push(nodePosition);\r\n\t}\r\n\r\n\tpublic validate(offset: number) {\r\n\t\tlet hasInvalidVal = false;\r\n\t\tlet tmp: Array = this._cache;\r\n\t\tfor (let i = 0; i < tmp.length; i++) {\r\n\t\t\tlet nodePos = tmp[i]!;\r\n\t\t\tif (nodePos.node.parent === null || nodePos.nodeStartOffset >= offset) {\r\n\t\t\t\ttmp[i] = null;\r\n\t\t\t\thasInvalidVal = true;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (hasInvalidVal) {\r\n\t\t\tlet newArr: CacheEntry[] = [];\r\n\t\t\tfor (const entry of tmp) {\r\n\t\t\t\tif (entry !== null) {\r\n\t\t\t\t\tnewArr.push(entry);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tthis._cache = newArr;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class PieceTreeBase {\r\n\troot!: TreeNode;\r\n\tprotected _buffers!: StringBuffer[]; // 0 is change buffer, others are readonly original buffer.\r\n\tprotected _lineCnt!: number;\r\n\tprotected _length!: number;\r\n\tprotected _EOL!: '\\r\\n' | '\\n';\r\n\tprotected _EOLLength!: number;\r\n\tprotected _EOLNormalized!: boolean;\r\n\tprivate _lastChangeBufferPos!: BufferCursor;\r\n\tprivate _searchCache!: PieceTreeSearchCache;\r\n\tprivate _lastVisitedLine!: { lineNumber: number; value: string; };\r\n\r\n\tconstructor(chunks: StringBuffer[], eol: '\\r\\n' | '\\n', eolNormalized: boolean) {\r\n\t\tthis.create(chunks, eol, eolNormalized);\r\n\t}\r\n\r\n\tcreate(chunks: StringBuffer[], eol: '\\r\\n' | '\\n', eolNormalized: boolean) {\r\n\t\tthis._buffers = [\r\n\t\t\tnew StringBuffer('', [0])\r\n\t\t];\r\n\t\tthis._lastChangeBufferPos = { line: 0, column: 0 };\r\n\t\tthis.root = SENTINEL;\r\n\t\tthis._lineCnt = 1;\r\n\t\tthis._length = 0;\r\n\t\tthis._EOL = eol;\r\n\t\tthis._EOLLength = eol.length;\r\n\t\tthis._EOLNormalized = eolNormalized;\r\n\r\n\t\tlet lastNode: TreeNode | null = null;\r\n\t\tfor (let i = 0, len = chunks.length; i < len; i++) {\r\n\t\t\tif (chunks[i].buffer.length > 0) {\r\n\t\t\t\tif (!chunks[i].lineStarts) {\r\n\t\t\t\t\tchunks[i].lineStarts = createLineStartsFast(chunks[i].buffer);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tlet piece = new Piece(\r\n\t\t\t\t\ti + 1,\r\n\t\t\t\t\t{ line: 0, column: 0 },\r\n\t\t\t\t\t{ line: chunks[i].lineStarts.length - 1, column: chunks[i].buffer.length - chunks[i].lineStarts[chunks[i].lineStarts.length - 1] },\r\n\t\t\t\t\tchunks[i].lineStarts.length - 1,\r\n\t\t\t\t\tchunks[i].buffer.length\r\n\t\t\t\t);\r\n\t\t\t\tthis._buffers.push(chunks[i]);\r\n\t\t\t\tlastNode = this.rbInsertRight(lastNode, piece);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._searchCache = new PieceTreeSearchCache(1);\r\n\t\tthis._lastVisitedLine = { lineNumber: 0, value: '' };\r\n\t\tthis.computeBufferMetadata();\r\n\t}\r\n\r\n\tnormalizeEOL(eol: '\\r\\n' | '\\n') {\r\n\t\tlet averageBufferSize = AverageBufferSize;\r\n\t\tlet min = averageBufferSize - Math.floor(averageBufferSize / 3);\r\n\t\tlet max = min * 2;\r\n\r\n\t\tlet tempChunk = '';\r\n\t\tlet tempChunkLen = 0;\r\n\t\tlet chunks: StringBuffer[] = [];\r\n\r\n\t\tthis.iterate(this.root, node => {\r\n\t\t\tlet str = this.getNodeContent(node);\r\n\t\t\tlet len = str.length;\r\n\t\t\tif (tempChunkLen <= min || tempChunkLen + len < max) {\r\n\t\t\t\ttempChunk += str;\r\n\t\t\t\ttempChunkLen += len;\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\r\n\t\t\t// flush anyways\r\n\t\t\tlet text = tempChunk.replace(/\\r\\n|\\r|\\n/g, eol);\r\n\t\t\tchunks.push(new StringBuffer(text, createLineStartsFast(text)));\r\n\t\t\ttempChunk = str;\r\n\t\t\ttempChunkLen = len;\r\n\t\t\treturn true;\r\n\t\t});\r\n\r\n\t\tif (tempChunkLen > 0) {\r\n\t\t\tlet text = tempChunk.replace(/\\r\\n|\\r|\\n/g, eol);\r\n\t\t\tchunks.push(new StringBuffer(text, createLineStartsFast(text)));\r\n\t\t}\r\n\r\n\t\tthis.create(chunks, eol, true);\r\n\t}\r\n\r\n\t// #region Buffer API\r\n\tpublic getEOL(): '\\r\\n' | '\\n' {\r\n\t\treturn this._EOL;\r\n\t}\r\n\r\n\tpublic setEOL(newEOL: '\\r\\n' | '\\n'): void {\r\n\t\tthis._EOL = newEOL;\r\n\t\tthis._EOLLength = this._EOL.length;\r\n\t\tthis.normalizeEOL(newEOL);\r\n\t}\r\n\r\n\tpublic createSnapshot(BOM: string): ITextSnapshot {\r\n\t\treturn new PieceTreeSnapshot(this, BOM);\r\n\t}\r\n\r\n\tpublic getOffsetAt(lineNumber: number, column: number): number {\r\n\t\tlet leftLen = 0; // inorder\r\n\r\n\t\tlet x = this.root;\r\n\r\n\t\twhile (x !== SENTINEL) {\r\n\t\t\tif (x.left !== SENTINEL && x.lf_left + 1 >= lineNumber) {\r\n\t\t\t\tx = x.left;\r\n\t\t\t} else if (x.lf_left + x.piece.lineFeedCnt + 1 >= lineNumber) {\r\n\t\t\t\tleftLen += x.size_left;\r\n\t\t\t\t// lineNumber >= 2\r\n\t\t\t\tlet accumualtedValInCurrentIndex = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);\r\n\t\t\t\treturn leftLen += accumualtedValInCurrentIndex + column - 1;\r\n\t\t\t} else {\r\n\t\t\t\tlineNumber -= x.lf_left + x.piece.lineFeedCnt;\r\n\t\t\t\tleftLen += x.size_left + x.piece.length;\r\n\t\t\t\tx = x.right;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn leftLen;\r\n\t}\r\n\r\n\tpublic getPositionAt(offset: number): Position {\r\n\t\toffset = Math.floor(offset);\r\n\t\toffset = Math.max(0, offset);\r\n\r\n\t\tlet x = this.root;\r\n\t\tlet lfCnt = 0;\r\n\t\tlet originalOffset = offset;\r\n\r\n\t\twhile (x !== SENTINEL) {\r\n\t\t\tif (x.size_left !== 0 && x.size_left >= offset) {\r\n\t\t\t\tx = x.left;\r\n\t\t\t} else if (x.size_left + x.piece.length >= offset) {\r\n\t\t\t\tlet out = this.getIndexOf(x, offset - x.size_left);\r\n\r\n\t\t\t\tlfCnt += x.lf_left + out.index;\r\n\r\n\t\t\t\tif (out.index === 0) {\r\n\t\t\t\t\tlet lineStartOffset = this.getOffsetAt(lfCnt + 1, 1);\r\n\t\t\t\t\tlet column = originalOffset - lineStartOffset;\r\n\t\t\t\t\treturn new Position(lfCnt + 1, column + 1);\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn new Position(lfCnt + 1, out.remainder + 1);\r\n\t\t\t} else {\r\n\t\t\t\toffset -= x.size_left + x.piece.length;\r\n\t\t\t\tlfCnt += x.lf_left + x.piece.lineFeedCnt;\r\n\r\n\t\t\t\tif (x.right === SENTINEL) {\r\n\t\t\t\t\t// last node\r\n\t\t\t\t\tlet lineStartOffset = this.getOffsetAt(lfCnt + 1, 1);\r\n\t\t\t\t\tlet column = originalOffset - offset - lineStartOffset;\r\n\t\t\t\t\treturn new Position(lfCnt + 1, column + 1);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tx = x.right;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn new Position(1, 1);\r\n\t}\r\n\r\n\tpublic getValueInRange(range: Range, eol?: string): string {\r\n\t\tif (range.startLineNumber === range.endLineNumber && range.startColumn === range.endColumn) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\r\n\t\tlet startPosition = this.nodeAt2(range.startLineNumber, range.startColumn);\r\n\t\tlet endPosition = this.nodeAt2(range.endLineNumber, range.endColumn);\r\n\r\n\t\tlet value = this.getValueInRange2(startPosition, endPosition);\r\n\t\tif (eol) {\r\n\t\t\tif (eol !== this._EOL || !this._EOLNormalized) {\r\n\t\t\t\treturn value.replace(/\\r\\n|\\r|\\n/g, eol);\r\n\t\t\t}\r\n\r\n\t\t\tif (eol === this.getEOL() && this._EOLNormalized) {\r\n\t\t\t\tif (eol === '\\r\\n') {\r\n\r\n\t\t\t\t}\r\n\t\t\t\treturn value;\r\n\t\t\t}\r\n\t\t\treturn value.replace(/\\r\\n|\\r|\\n/g, eol);\r\n\t\t}\r\n\t\treturn value;\r\n\t}\r\n\r\n\tpublic getValueInRange2(startPosition: NodePosition, endPosition: NodePosition): string {\r\n\t\tif (startPosition.node === endPosition.node) {\r\n\t\t\tlet node = startPosition.node;\r\n\t\t\tlet buffer = this._buffers[node.piece.bufferIndex].buffer;\r\n\t\t\tlet startOffset = this.offsetInBuffer(node.piece.bufferIndex, node.piece.start);\r\n\t\t\treturn buffer.substring(startOffset + startPosition.remainder, startOffset + endPosition.remainder);\r\n\t\t}\r\n\r\n\t\tlet x = startPosition.node;\r\n\t\tlet buffer = this._buffers[x.piece.bufferIndex].buffer;\r\n\t\tlet startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);\r\n\t\tlet ret = buffer.substring(startOffset + startPosition.remainder, startOffset + x.piece.length);\r\n\r\n\t\tx = x.next();\r\n\t\twhile (x !== SENTINEL) {\r\n\t\t\tlet buffer = this._buffers[x.piece.bufferIndex].buffer;\r\n\t\t\tlet startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);\r\n\r\n\t\t\tif (x === endPosition.node) {\r\n\t\t\t\tret += buffer.substring(startOffset, startOffset + endPosition.remainder);\r\n\t\t\t\tbreak;\r\n\t\t\t} else {\r\n\t\t\t\tret += buffer.substr(startOffset, x.piece.length);\r\n\t\t\t}\r\n\r\n\t\t\tx = x.next();\r\n\t\t}\r\n\r\n\t\treturn ret;\r\n\t}\r\n\r\n\tpublic getLinesContent(): string[] {\r\n\t\tlet lines: string[] = [];\r\n\t\tlet linesLength = 0;\r\n\t\tlet currentLine = '';\r\n\t\tlet danglingCR = false;\r\n\r\n\t\tthis.iterate(this.root, node => {\r\n\t\t\tif (node === SENTINEL) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\r\n\t\t\tconst piece = node.piece;\r\n\t\t\tlet pieceLength = piece.length;\r\n\t\t\tif (pieceLength === 0) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\r\n\t\t\tconst buffer = this._buffers[piece.bufferIndex].buffer;\r\n\t\t\tconst lineStarts = this._buffers[piece.bufferIndex].lineStarts;\r\n\r\n\t\t\tconst pieceStartLine = piece.start.line;\r\n\t\t\tconst pieceEndLine = piece.end.line;\r\n\t\t\tlet pieceStartOffset = lineStarts[pieceStartLine] + piece.start.column;\r\n\r\n\t\t\tif (danglingCR) {\r\n\t\t\t\tif (buffer.charCodeAt(pieceStartOffset) === CharCode.LineFeed) {\r\n\t\t\t\t\t// pretend the \\n was in the previous piece..\r\n\t\t\t\t\tpieceStartOffset++;\r\n\t\t\t\t\tpieceLength--;\r\n\t\t\t\t}\r\n\t\t\t\tlines[linesLength++] = currentLine;\r\n\t\t\t\tcurrentLine = '';\r\n\t\t\t\tdanglingCR = false;\r\n\t\t\t\tif (pieceLength === 0) {\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (pieceStartLine === pieceEndLine) {\r\n\t\t\t\t// this piece has no new lines\r\n\t\t\t\tif (!this._EOLNormalized && buffer.charCodeAt(pieceStartOffset + pieceLength - 1) === CharCode.CarriageReturn) {\r\n\t\t\t\t\tdanglingCR = true;\r\n\t\t\t\t\tcurrentLine += buffer.substr(pieceStartOffset, pieceLength - 1);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tcurrentLine += buffer.substr(pieceStartOffset, pieceLength);\r\n\t\t\t\t}\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\r\n\t\t\t// add the text before the first line start in this piece\r\n\t\t\tcurrentLine += (\r\n\t\t\t\tthis._EOLNormalized\r\n\t\t\t\t\t? buffer.substring(pieceStartOffset, Math.max(pieceStartOffset, lineStarts[pieceStartLine + 1] - this._EOLLength))\r\n\t\t\t\t\t: buffer.substring(pieceStartOffset, lineStarts[pieceStartLine + 1]).replace(/(\\r\\n|\\r|\\n)$/, '')\r\n\t\t\t);\r\n\t\t\tlines[linesLength++] = currentLine;\r\n\r\n\t\t\tfor (let line = pieceStartLine + 1; line < pieceEndLine; line++) {\r\n\t\t\t\tcurrentLine = (\r\n\t\t\t\t\tthis._EOLNormalized\r\n\t\t\t\t\t\t? buffer.substring(lineStarts[line], lineStarts[line + 1] - this._EOLLength)\r\n\t\t\t\t\t\t: buffer.substring(lineStarts[line], lineStarts[line + 1]).replace(/(\\r\\n|\\r|\\n)$/, '')\r\n\t\t\t\t);\r\n\t\t\t\tlines[linesLength++] = currentLine;\r\n\t\t\t}\r\n\r\n\t\t\tif (!this._EOLNormalized && buffer.charCodeAt(lineStarts[pieceEndLine] + piece.end.column - 1) === CharCode.CarriageReturn) {\r\n\t\t\t\tdanglingCR = true;\r\n\t\t\t\tif (piece.end.column === 0) {\r\n\t\t\t\t\t// The last line ended with a \\r, let's undo the push, it will be pushed by next iteration\r\n\t\t\t\t\tlinesLength--;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tcurrentLine = buffer.substr(lineStarts[pieceEndLine], piece.end.column - 1);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tcurrentLine = buffer.substr(lineStarts[pieceEndLine], piece.end.column);\r\n\t\t\t}\r\n\r\n\t\t\treturn true;\r\n\t\t});\r\n\r\n\t\tif (danglingCR) {\r\n\t\t\tlines[linesLength++] = currentLine;\r\n\t\t\tcurrentLine = '';\r\n\t\t}\r\n\r\n\t\tlines[linesLength++] = currentLine;\r\n\t\treturn lines;\r\n\t}\r\n\r\n\tpublic getLength(): number {\r\n\t\treturn this._length;\r\n\t}\r\n\r\n\tpublic getLineCount(): number {\r\n\t\treturn this._lineCnt;\r\n\t}\r\n\r\n\tpublic getLineContent(lineNumber: number): string {\r\n\t\tif (this._lastVisitedLine.lineNumber === lineNumber) {\r\n\t\t\treturn this._lastVisitedLine.value;\r\n\t\t}\r\n\r\n\t\tthis._lastVisitedLine.lineNumber = lineNumber;\r\n\r\n\t\tif (lineNumber === this._lineCnt) {\r\n\t\t\tthis._lastVisitedLine.value = this.getLineRawContent(lineNumber);\r\n\t\t} else if (this._EOLNormalized) {\r\n\t\t\tthis._lastVisitedLine.value = this.getLineRawContent(lineNumber, this._EOLLength);\r\n\t\t} else {\r\n\t\t\tthis._lastVisitedLine.value = this.getLineRawContent(lineNumber).replace(/(\\r\\n|\\r|\\n)$/, '');\r\n\t\t}\r\n\r\n\t\treturn this._lastVisitedLine.value;\r\n\t}\r\n\r\n\tprivate _getCharCode(nodePos: NodePosition): number {\r\n\t\tif (nodePos.remainder === nodePos.node.piece.length) {\r\n\t\t\t// the char we want to fetch is at the head of next node.\r\n\t\t\tlet matchingNode = nodePos.node.next();\r\n\t\t\tif (!matchingNode) {\r\n\t\t\t\treturn 0;\r\n\t\t\t}\r\n\r\n\t\t\tlet buffer = this._buffers[matchingNode.piece.bufferIndex];\r\n\t\t\tlet startOffset = this.offsetInBuffer(matchingNode.piece.bufferIndex, matchingNode.piece.start);\r\n\t\t\treturn buffer.buffer.charCodeAt(startOffset);\r\n\t\t} else {\r\n\t\t\tlet buffer = this._buffers[nodePos.node.piece.bufferIndex];\r\n\t\t\tlet startOffset = this.offsetInBuffer(nodePos.node.piece.bufferIndex, nodePos.node.piece.start);\r\n\t\t\tlet targetOffset = startOffset + nodePos.remainder;\r\n\r\n\t\t\treturn buffer.buffer.charCodeAt(targetOffset);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getLineCharCode(lineNumber: number, index: number): number {\r\n\t\tlet nodePos = this.nodeAt2(lineNumber, index + 1);\r\n\t\treturn this._getCharCode(nodePos);\r\n\t}\r\n\r\n\tpublic getLineLength(lineNumber: number): number {\r\n\t\tif (lineNumber === this.getLineCount()) {\r\n\t\t\tlet startOffset = this.getOffsetAt(lineNumber, 1);\r\n\t\t\treturn this.getLength() - startOffset;\r\n\t\t}\r\n\t\treturn this.getOffsetAt(lineNumber + 1, 1) - this.getOffsetAt(lineNumber, 1) - this._EOLLength;\r\n\t}\r\n\r\n\tpublic findMatchesInNode(node: TreeNode, searcher: Searcher, startLineNumber: number, startColumn: number, startCursor: BufferCursor, endCursor: BufferCursor, searchData: SearchData, captureMatches: boolean, limitResultCount: number, resultLen: number, result: FindMatch[]) {\r\n\t\tlet buffer = this._buffers[node.piece.bufferIndex];\r\n\t\tlet startOffsetInBuffer = this.offsetInBuffer(node.piece.bufferIndex, node.piece.start);\r\n\t\tlet start = this.offsetInBuffer(node.piece.bufferIndex, startCursor);\r\n\t\tlet end = this.offsetInBuffer(node.piece.bufferIndex, endCursor);\r\n\r\n\t\tlet m: RegExpExecArray | null;\r\n\t\t// Reset regex to search from the beginning\r\n\t\tlet ret: BufferCursor = { line: 0, column: 0 };\r\n\t\tlet searchText: string;\r\n\t\tlet offsetInBuffer: (offset: number) => number;\r\n\r\n\t\tif (searcher._wordSeparators) {\r\n\t\t\tsearchText = buffer.buffer.substring(start, end);\r\n\t\t\toffsetInBuffer = (offset: number) => offset + start;\r\n\t\t\tsearcher.reset(0);\r\n\t\t} else {\r\n\t\t\tsearchText = buffer.buffer;\r\n\t\t\toffsetInBuffer = (offset: number) => offset;\r\n\t\t\tsearcher.reset(start);\r\n\t\t}\r\n\r\n\t\tdo {\r\n\t\t\tm = searcher.next(searchText);\r\n\r\n\t\t\tif (m) {\r\n\t\t\t\tif (offsetInBuffer(m.index) >= end) {\r\n\t\t\t\t\treturn resultLen;\r\n\t\t\t\t}\r\n\t\t\t\tthis.positionInBuffer(node, offsetInBuffer(m.index) - startOffsetInBuffer, ret);\r\n\t\t\t\tlet lineFeedCnt = this.getLineFeedCnt(node.piece.bufferIndex, startCursor, ret);\r\n\t\t\t\tlet retStartColumn = ret.line === startCursor.line ? ret.column - startCursor.column + startColumn : ret.column + 1;\r\n\t\t\t\tlet retEndColumn = retStartColumn + m[0].length;\r\n\t\t\t\tresult[resultLen++] = createFindMatch(new Range(startLineNumber + lineFeedCnt, retStartColumn, startLineNumber + lineFeedCnt, retEndColumn), m, captureMatches);\r\n\r\n\t\t\t\tif (offsetInBuffer(m.index) + m[0].length >= end) {\r\n\t\t\t\t\treturn resultLen;\r\n\t\t\t\t}\r\n\t\t\t\tif (resultLen >= limitResultCount) {\r\n\t\t\t\t\treturn resultLen;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t} while (m);\r\n\r\n\t\treturn resultLen;\r\n\t}\r\n\r\n\tpublic findMatchesLineByLine(searchRange: Range, searchData: SearchData, captureMatches: boolean, limitResultCount: number): FindMatch[] {\r\n\t\tconst result: FindMatch[] = [];\r\n\t\tlet resultLen = 0;\r\n\t\tconst searcher = new Searcher(searchData.wordSeparators, searchData.regex);\r\n\r\n\t\tlet startPosition = this.nodeAt2(searchRange.startLineNumber, searchRange.startColumn);\r\n\t\tif (startPosition === null) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\t\tlet endPosition = this.nodeAt2(searchRange.endLineNumber, searchRange.endColumn);\r\n\t\tif (endPosition === null) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\t\tlet start = this.positionInBuffer(startPosition.node, startPosition.remainder);\r\n\t\tlet end = this.positionInBuffer(endPosition.node, endPosition.remainder);\r\n\r\n\t\tif (startPosition.node === endPosition.node) {\r\n\t\t\tthis.findMatchesInNode(startPosition.node, searcher, searchRange.startLineNumber, searchRange.startColumn, start, end, searchData, captureMatches, limitResultCount, resultLen, result);\r\n\t\t\treturn result;\r\n\t\t}\r\n\r\n\t\tlet startLineNumber = searchRange.startLineNumber;\r\n\r\n\t\tlet currentNode = startPosition.node;\r\n\t\twhile (currentNode !== endPosition.node) {\r\n\t\t\tlet lineBreakCnt = this.getLineFeedCnt(currentNode.piece.bufferIndex, start, currentNode.piece.end);\r\n\r\n\t\t\tif (lineBreakCnt >= 1) {\r\n\t\t\t\t// last line break position\r\n\t\t\t\tlet lineStarts = this._buffers[currentNode.piece.bufferIndex].lineStarts;\r\n\t\t\t\tlet startOffsetInBuffer = this.offsetInBuffer(currentNode.piece.bufferIndex, currentNode.piece.start);\r\n\t\t\t\tlet nextLineStartOffset = lineStarts[start.line + lineBreakCnt];\r\n\t\t\t\tlet startColumn = startLineNumber === searchRange.startLineNumber ? searchRange.startColumn : 1;\r\n\t\t\t\tresultLen = this.findMatchesInNode(currentNode, searcher, startLineNumber, startColumn, start, this.positionInBuffer(currentNode, nextLineStartOffset - startOffsetInBuffer), searchData, captureMatches, limitResultCount, resultLen, result);\r\n\r\n\t\t\t\tif (resultLen >= limitResultCount) {\r\n\t\t\t\t\treturn result;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tstartLineNumber += lineBreakCnt;\r\n\t\t\t}\r\n\r\n\t\t\tlet startColumn = startLineNumber === searchRange.startLineNumber ? searchRange.startColumn - 1 : 0;\r\n\t\t\t// search for the remaining content\r\n\t\t\tif (startLineNumber === searchRange.endLineNumber) {\r\n\t\t\t\tconst text = this.getLineContent(startLineNumber).substring(startColumn, searchRange.endColumn - 1);\r\n\t\t\t\tresultLen = this._findMatchesInLine(searchData, searcher, text, searchRange.endLineNumber, startColumn, resultLen, result, captureMatches, limitResultCount);\r\n\t\t\t\treturn result;\r\n\t\t\t}\r\n\r\n\t\t\tresultLen = this._findMatchesInLine(searchData, searcher, this.getLineContent(startLineNumber).substr(startColumn), startLineNumber, startColumn, resultLen, result, captureMatches, limitResultCount);\r\n\r\n\t\t\tif (resultLen >= limitResultCount) {\r\n\t\t\t\treturn result;\r\n\t\t\t}\r\n\r\n\t\t\tstartLineNumber++;\r\n\t\t\tstartPosition = this.nodeAt2(startLineNumber, 1);\r\n\t\t\tcurrentNode = startPosition.node;\r\n\t\t\tstart = this.positionInBuffer(startPosition.node, startPosition.remainder);\r\n\t\t}\r\n\r\n\t\tif (startLineNumber === searchRange.endLineNumber) {\r\n\t\t\tlet startColumn = startLineNumber === searchRange.startLineNumber ? searchRange.startColumn - 1 : 0;\r\n\t\t\tconst text = this.getLineContent(startLineNumber).substring(startColumn, searchRange.endColumn - 1);\r\n\t\t\tresultLen = this._findMatchesInLine(searchData, searcher, text, searchRange.endLineNumber, startColumn, resultLen, result, captureMatches, limitResultCount);\r\n\t\t\treturn result;\r\n\t\t}\r\n\r\n\t\tlet startColumn = startLineNumber === searchRange.startLineNumber ? searchRange.startColumn : 1;\r\n\t\tresultLen = this.findMatchesInNode(endPosition.node, searcher, startLineNumber, startColumn, start, end, searchData, captureMatches, limitResultCount, resultLen, result);\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate _findMatchesInLine(searchData: SearchData, searcher: Searcher, text: string, lineNumber: number, deltaOffset: number, resultLen: number, result: FindMatch[], captureMatches: boolean, limitResultCount: number): number {\r\n\t\tconst wordSeparators = searchData.wordSeparators;\r\n\t\tif (!captureMatches && searchData.simpleSearch) {\r\n\t\t\tconst searchString = searchData.simpleSearch;\r\n\t\t\tconst searchStringLen = searchString.length;\r\n\t\t\tconst textLength = text.length;\r\n\r\n\t\t\tlet lastMatchIndex = -searchStringLen;\r\n\t\t\twhile ((lastMatchIndex = text.indexOf(searchString, lastMatchIndex + searchStringLen)) !== -1) {\r\n\t\t\t\tif (!wordSeparators || isValidMatch(wordSeparators, text, textLength, lastMatchIndex, searchStringLen)) {\r\n\t\t\t\t\tresult[resultLen++] = new FindMatch(new Range(lineNumber, lastMatchIndex + 1 + deltaOffset, lineNumber, lastMatchIndex + 1 + searchStringLen + deltaOffset), null);\r\n\t\t\t\t\tif (resultLen >= limitResultCount) {\r\n\t\t\t\t\t\treturn resultLen;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn resultLen;\r\n\t\t}\r\n\r\n\t\tlet m: RegExpExecArray | null;\r\n\t\t// Reset regex to search from the beginning\r\n\t\tsearcher.reset(0);\r\n\t\tdo {\r\n\t\t\tm = searcher.next(text);\r\n\t\t\tif (m) {\r\n\t\t\t\tresult[resultLen++] = createFindMatch(new Range(lineNumber, m.index + 1 + deltaOffset, lineNumber, m.index + 1 + m[0].length + deltaOffset), m, captureMatches);\r\n\t\t\t\tif (resultLen >= limitResultCount) {\r\n\t\t\t\t\treturn resultLen;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} while (m);\r\n\t\treturn resultLen;\r\n\t}\r\n\r\n\t// #endregion\r\n\r\n\t// #region Piece Table\r\n\tpublic insert(offset: number, value: string, eolNormalized: boolean = false): void {\r\n\t\tthis._EOLNormalized = this._EOLNormalized && eolNormalized;\r\n\t\tthis._lastVisitedLine.lineNumber = 0;\r\n\t\tthis._lastVisitedLine.value = '';\r\n\r\n\t\tif (this.root !== SENTINEL) {\r\n\t\t\tlet { node, remainder, nodeStartOffset } = this.nodeAt(offset);\r\n\t\t\tlet piece = node.piece;\r\n\t\t\tlet bufferIndex = piece.bufferIndex;\r\n\t\t\tlet insertPosInBuffer = this.positionInBuffer(node, remainder);\r\n\t\t\tif (node.piece.bufferIndex === 0 &&\r\n\t\t\t\tpiece.end.line === this._lastChangeBufferPos.line &&\r\n\t\t\t\tpiece.end.column === this._lastChangeBufferPos.column &&\r\n\t\t\t\t(nodeStartOffset + piece.length === offset) &&\r\n\t\t\t\tvalue.length < AverageBufferSize\r\n\t\t\t) {\r\n\t\t\t\t// changed buffer\r\n\t\t\t\tthis.appendToNode(node, value);\r\n\t\t\t\tthis.computeBufferMetadata();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (nodeStartOffset === offset) {\r\n\t\t\t\tthis.insertContentToNodeLeft(value, node);\r\n\t\t\t\tthis._searchCache.validate(offset);\r\n\t\t\t} else if (nodeStartOffset + node.piece.length > offset) {\r\n\t\t\t\t// we are inserting into the middle of a node.\r\n\t\t\t\tlet nodesToDel: TreeNode[] = [];\r\n\t\t\t\tlet newRightPiece = new Piece(\r\n\t\t\t\t\tpiece.bufferIndex,\r\n\t\t\t\t\tinsertPosInBuffer,\r\n\t\t\t\t\tpiece.end,\r\n\t\t\t\t\tthis.getLineFeedCnt(piece.bufferIndex, insertPosInBuffer, piece.end),\r\n\t\t\t\t\tthis.offsetInBuffer(bufferIndex, piece.end) - this.offsetInBuffer(bufferIndex, insertPosInBuffer)\r\n\t\t\t\t);\r\n\r\n\t\t\t\tif (this.shouldCheckCRLF() && this.endWithCR(value)) {\r\n\t\t\t\t\tlet headOfRight = this.nodeCharCodeAt(node, remainder);\r\n\r\n\t\t\t\t\tif (headOfRight === 10 /** \\n */) {\r\n\t\t\t\t\t\tlet newStart: BufferCursor = { line: newRightPiece.start.line + 1, column: 0 };\r\n\t\t\t\t\t\tnewRightPiece = new Piece(\r\n\t\t\t\t\t\t\tnewRightPiece.bufferIndex,\r\n\t\t\t\t\t\t\tnewStart,\r\n\t\t\t\t\t\t\tnewRightPiece.end,\r\n\t\t\t\t\t\t\tthis.getLineFeedCnt(newRightPiece.bufferIndex, newStart, newRightPiece.end),\r\n\t\t\t\t\t\t\tnewRightPiece.length - 1\r\n\t\t\t\t\t\t);\r\n\r\n\t\t\t\t\t\tvalue += '\\n';\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// reuse node for content before insertion point.\r\n\t\t\t\tif (this.shouldCheckCRLF() && this.startWithLF(value)) {\r\n\t\t\t\t\tlet tailOfLeft = this.nodeCharCodeAt(node, remainder - 1);\r\n\t\t\t\t\tif (tailOfLeft === 13 /** \\r */) {\r\n\t\t\t\t\t\tlet previousPos = this.positionInBuffer(node, remainder - 1);\r\n\t\t\t\t\t\tthis.deleteNodeTail(node, previousPos);\r\n\t\t\t\t\t\tvalue = '\\r' + value;\r\n\r\n\t\t\t\t\t\tif (node.piece.length === 0) {\r\n\t\t\t\t\t\t\tnodesToDel.push(node);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tthis.deleteNodeTail(node, insertPosInBuffer);\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis.deleteNodeTail(node, insertPosInBuffer);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tlet newPieces = this.createNewPieces(value);\r\n\t\t\t\tif (newRightPiece.length > 0) {\r\n\t\t\t\t\tthis.rbInsertRight(node, newRightPiece);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tlet tmpNode = node;\r\n\t\t\t\tfor (let k = 0; k < newPieces.length; k++) {\r\n\t\t\t\t\ttmpNode = this.rbInsertRight(tmpNode, newPieces[k]);\r\n\t\t\t\t}\r\n\t\t\t\tthis.deleteNodes(nodesToDel);\r\n\t\t\t} else {\r\n\t\t\t\tthis.insertContentToNodeRight(value, node);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\t// insert new node\r\n\t\t\tlet pieces = this.createNewPieces(value);\r\n\t\t\tlet node = this.rbInsertLeft(null, pieces[0]);\r\n\r\n\t\t\tfor (let k = 1; k < pieces.length; k++) {\r\n\t\t\t\tnode = this.rbInsertRight(node, pieces[k]);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// todo, this is too brutal. Total line feed count should be updated the same way as lf_left.\r\n\t\tthis.computeBufferMetadata();\r\n\t}\r\n\r\n\tpublic delete(offset: number, cnt: number): void {\r\n\t\tthis._lastVisitedLine.lineNumber = 0;\r\n\t\tthis._lastVisitedLine.value = '';\r\n\r\n\t\tif (cnt <= 0 || this.root === SENTINEL) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet startPosition = this.nodeAt(offset);\r\n\t\tlet endPosition = this.nodeAt(offset + cnt);\r\n\t\tlet startNode = startPosition.node;\r\n\t\tlet endNode = endPosition.node;\r\n\r\n\t\tif (startNode === endNode) {\r\n\t\t\tlet startSplitPosInBuffer = this.positionInBuffer(startNode, startPosition.remainder);\r\n\t\t\tlet endSplitPosInBuffer = this.positionInBuffer(startNode, endPosition.remainder);\r\n\r\n\t\t\tif (startPosition.nodeStartOffset === offset) {\r\n\t\t\t\tif (cnt === startNode.piece.length) { // delete node\r\n\t\t\t\t\tlet next = startNode.next();\r\n\t\t\t\t\trbDelete(this, startNode);\r\n\t\t\t\t\tthis.validateCRLFWithPrevNode(next);\r\n\t\t\t\t\tthis.computeBufferMetadata();\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\tthis.deleteNodeHead(startNode, endSplitPosInBuffer);\r\n\t\t\t\tthis._searchCache.validate(offset);\r\n\t\t\t\tthis.validateCRLFWithPrevNode(startNode);\r\n\t\t\t\tthis.computeBufferMetadata();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (startPosition.nodeStartOffset + startNode.piece.length === offset + cnt) {\r\n\t\t\t\tthis.deleteNodeTail(startNode, startSplitPosInBuffer);\r\n\t\t\t\tthis.validateCRLFWithNextNode(startNode);\r\n\t\t\t\tthis.computeBufferMetadata();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\t// delete content in the middle, this node will be splitted to nodes\r\n\t\t\tthis.shrinkNode(startNode, startSplitPosInBuffer, endSplitPosInBuffer);\r\n\t\t\tthis.computeBufferMetadata();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet nodesToDel: TreeNode[] = [];\r\n\r\n\t\tlet startSplitPosInBuffer = this.positionInBuffer(startNode, startPosition.remainder);\r\n\t\tthis.deleteNodeTail(startNode, startSplitPosInBuffer);\r\n\t\tthis._searchCache.validate(offset);\r\n\t\tif (startNode.piece.length === 0) {\r\n\t\t\tnodesToDel.push(startNode);\r\n\t\t}\r\n\r\n\t\t// update last touched node\r\n\t\tlet endSplitPosInBuffer = this.positionInBuffer(endNode, endPosition.remainder);\r\n\t\tthis.deleteNodeHead(endNode, endSplitPosInBuffer);\r\n\t\tif (endNode.piece.length === 0) {\r\n\t\t\tnodesToDel.push(endNode);\r\n\t\t}\r\n\r\n\t\t// delete nodes in between\r\n\t\tlet secondNode = startNode.next();\r\n\t\tfor (let node = secondNode; node !== SENTINEL && node !== endNode; node = node.next()) {\r\n\t\t\tnodesToDel.push(node);\r\n\t\t}\r\n\r\n\t\tlet prev = startNode.piece.length === 0 ? startNode.prev() : startNode;\r\n\t\tthis.deleteNodes(nodesToDel);\r\n\t\tthis.validateCRLFWithNextNode(prev);\r\n\t\tthis.computeBufferMetadata();\r\n\t}\r\n\r\n\tprivate insertContentToNodeLeft(value: string, node: TreeNode) {\r\n\t\t// we are inserting content to the beginning of node\r\n\t\tlet nodesToDel: TreeNode[] = [];\r\n\t\tif (this.shouldCheckCRLF() && this.endWithCR(value) && this.startWithLF(node)) {\r\n\t\t\t// move `\\n` to new node.\r\n\r\n\t\t\tlet piece = node.piece;\r\n\t\t\tlet newStart: BufferCursor = { line: piece.start.line + 1, column: 0 };\r\n\t\t\tlet nPiece = new Piece(\r\n\t\t\t\tpiece.bufferIndex,\r\n\t\t\t\tnewStart,\r\n\t\t\t\tpiece.end,\r\n\t\t\t\tthis.getLineFeedCnt(piece.bufferIndex, newStart, piece.end),\r\n\t\t\t\tpiece.length - 1\r\n\t\t\t);\r\n\r\n\t\t\tnode.piece = nPiece;\r\n\r\n\t\t\tvalue += '\\n';\r\n\t\t\tupdateTreeMetadata(this, node, -1, -1);\r\n\r\n\t\t\tif (node.piece.length === 0) {\r\n\t\t\t\tnodesToDel.push(node);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet newPieces = this.createNewPieces(value);\r\n\t\tlet newNode = this.rbInsertLeft(node, newPieces[newPieces.length - 1]);\r\n\t\tfor (let k = newPieces.length - 2; k >= 0; k--) {\r\n\t\t\tnewNode = this.rbInsertLeft(newNode, newPieces[k]);\r\n\t\t}\r\n\t\tthis.validateCRLFWithPrevNode(newNode);\r\n\t\tthis.deleteNodes(nodesToDel);\r\n\t}\r\n\r\n\tprivate insertContentToNodeRight(value: string, node: TreeNode) {\r\n\t\t// we are inserting to the right of this node.\r\n\t\tif (this.adjustCarriageReturnFromNext(value, node)) {\r\n\t\t\t// move \\n to the new node.\r\n\t\t\tvalue += '\\n';\r\n\t\t}\r\n\r\n\t\tlet newPieces = this.createNewPieces(value);\r\n\t\tlet newNode = this.rbInsertRight(node, newPieces[0]);\r\n\t\tlet tmpNode = newNode;\r\n\r\n\t\tfor (let k = 1; k < newPieces.length; k++) {\r\n\t\t\ttmpNode = this.rbInsertRight(tmpNode, newPieces[k]);\r\n\t\t}\r\n\r\n\t\tthis.validateCRLFWithPrevNode(newNode);\r\n\t}\r\n\r\n\tprivate positionInBuffer(node: TreeNode, remainder: number): BufferCursor;\r\n\tprivate positionInBuffer(node: TreeNode, remainder: number, ret: BufferCursor): null;\r\n\tprivate positionInBuffer(node: TreeNode, remainder: number, ret?: BufferCursor): BufferCursor | null {\r\n\t\tlet piece = node.piece;\r\n\t\tlet bufferIndex = node.piece.bufferIndex;\r\n\t\tlet lineStarts = this._buffers[bufferIndex].lineStarts;\r\n\r\n\t\tlet startOffset = lineStarts[piece.start.line] + piece.start.column;\r\n\r\n\t\tlet offset = startOffset + remainder;\r\n\r\n\t\t// binary search offset between startOffset and endOffset\r\n\t\tlet low = piece.start.line;\r\n\t\tlet high = piece.end.line;\r\n\r\n\t\tlet mid: number = 0;\r\n\t\tlet midStop: number = 0;\r\n\t\tlet midStart: number = 0;\r\n\r\n\t\twhile (low <= high) {\r\n\t\t\tmid = low + ((high - low) / 2) | 0;\r\n\t\t\tmidStart = lineStarts[mid];\r\n\r\n\t\t\tif (mid === high) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tmidStop = lineStarts[mid + 1];\r\n\r\n\t\t\tif (offset < midStart) {\r\n\t\t\t\thigh = mid - 1;\r\n\t\t\t} else if (offset >= midStop) {\r\n\t\t\t\tlow = mid + 1;\r\n\t\t\t} else {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (ret) {\r\n\t\t\tret.line = mid;\r\n\t\t\tret.column = offset - midStart;\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tline: mid,\r\n\t\t\tcolumn: offset - midStart\r\n\t\t};\r\n\t}\r\n\r\n\tprivate getLineFeedCnt(bufferIndex: number, start: BufferCursor, end: BufferCursor): number {\r\n\t\t// we don't need to worry about start: abc\\r|\\n, or abc|\\r, or abc|\\n, or abc|\\r\\n doesn't change the fact that, there is one line break after start.\r\n\t\t// now let's take care of end: abc\\r|\\n, if end is in between \\r and \\n, we need to add line feed count by 1\r\n\t\tif (end.column === 0) {\r\n\t\t\treturn end.line - start.line;\r\n\t\t}\r\n\r\n\t\tlet lineStarts = this._buffers[bufferIndex].lineStarts;\r\n\t\tif (end.line === lineStarts.length - 1) { // it means, there is no \\n after end, otherwise, there will be one more lineStart.\r\n\t\t\treturn end.line - start.line;\r\n\t\t}\r\n\r\n\t\tlet nextLineStartOffset = lineStarts[end.line + 1];\r\n\t\tlet endOffset = lineStarts[end.line] + end.column;\r\n\t\tif (nextLineStartOffset > endOffset + 1) { // there are more than 1 character after end, which means it can't be \\n\r\n\t\t\treturn end.line - start.line;\r\n\t\t}\r\n\t\t// endOffset + 1 === nextLineStartOffset\r\n\t\t// character at endOffset is \\n, so we check the character before first\r\n\t\t// if character at endOffset is \\r, end.column is 0 and we can't get here.\r\n\t\tlet previousCharOffset = endOffset - 1; // end.column > 0 so it's okay.\r\n\t\tlet buffer = this._buffers[bufferIndex].buffer;\r\n\r\n\t\tif (buffer.charCodeAt(previousCharOffset) === 13) {\r\n\t\t\treturn end.line - start.line + 1;\r\n\t\t} else {\r\n\t\t\treturn end.line - start.line;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate offsetInBuffer(bufferIndex: number, cursor: BufferCursor): number {\r\n\t\tlet lineStarts = this._buffers[bufferIndex].lineStarts;\r\n\t\treturn lineStarts[cursor.line] + cursor.column;\r\n\t}\r\n\r\n\tprivate deleteNodes(nodes: TreeNode[]): void {\r\n\t\tfor (let i = 0; i < nodes.length; i++) {\r\n\t\t\trbDelete(this, nodes[i]);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate createNewPieces(text: string): Piece[] {\r\n\t\tif (text.length > AverageBufferSize) {\r\n\t\t\t// the content is large, operations like substring, charCode becomes slow\r\n\t\t\t// so here we split it into smaller chunks, just like what we did for CR/LF normalization\r\n\t\t\tlet newPieces: Piece[] = [];\r\n\t\t\twhile (text.length > AverageBufferSize) {\r\n\t\t\t\tconst lastChar = text.charCodeAt(AverageBufferSize - 1);\r\n\t\t\t\tlet splitText;\r\n\t\t\t\tif (lastChar === CharCode.CarriageReturn || (lastChar >= 0xD800 && lastChar <= 0xDBFF)) {\r\n\t\t\t\t\t// last character is \\r or a high surrogate => keep it back\r\n\t\t\t\t\tsplitText = text.substring(0, AverageBufferSize - 1);\r\n\t\t\t\t\ttext = text.substring(AverageBufferSize - 1);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tsplitText = text.substring(0, AverageBufferSize);\r\n\t\t\t\t\ttext = text.substring(AverageBufferSize);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tlet lineStarts = createLineStartsFast(splitText);\r\n\t\t\t\tnewPieces.push(new Piece(\r\n\t\t\t\t\tthis._buffers.length, /* buffer index */\r\n\t\t\t\t\t{ line: 0, column: 0 },\r\n\t\t\t\t\t{ line: lineStarts.length - 1, column: splitText.length - lineStarts[lineStarts.length - 1] },\r\n\t\t\t\t\tlineStarts.length - 1,\r\n\t\t\t\t\tsplitText.length\r\n\t\t\t\t));\r\n\t\t\t\tthis._buffers.push(new StringBuffer(splitText, lineStarts));\r\n\t\t\t}\r\n\r\n\t\t\tlet lineStarts = createLineStartsFast(text);\r\n\t\t\tnewPieces.push(new Piece(\r\n\t\t\t\tthis._buffers.length, /* buffer index */\r\n\t\t\t\t{ line: 0, column: 0 },\r\n\t\t\t\t{ line: lineStarts.length - 1, column: text.length - lineStarts[lineStarts.length - 1] },\r\n\t\t\t\tlineStarts.length - 1,\r\n\t\t\t\ttext.length\r\n\t\t\t));\r\n\t\t\tthis._buffers.push(new StringBuffer(text, lineStarts));\r\n\r\n\t\t\treturn newPieces;\r\n\t\t}\r\n\r\n\t\tlet startOffset = this._buffers[0].buffer.length;\r\n\t\tconst lineStarts = createLineStartsFast(text, false);\r\n\r\n\t\tlet start = this._lastChangeBufferPos;\r\n\t\tif (this._buffers[0].lineStarts[this._buffers[0].lineStarts.length - 1] === startOffset\r\n\t\t\t&& startOffset !== 0\r\n\t\t\t&& this.startWithLF(text)\r\n\t\t\t&& this.endWithCR(this._buffers[0].buffer) // todo, we can check this._lastChangeBufferPos's column as it's the last one\r\n\t\t) {\r\n\t\t\tthis._lastChangeBufferPos = { line: this._lastChangeBufferPos.line, column: this._lastChangeBufferPos.column + 1 };\r\n\t\t\tstart = this._lastChangeBufferPos;\r\n\r\n\t\t\tfor (let i = 0; i < lineStarts.length; i++) {\r\n\t\t\t\tlineStarts[i] += startOffset + 1;\r\n\t\t\t}\r\n\r\n\t\t\tthis._buffers[0].lineStarts = (this._buffers[0].lineStarts).concat(lineStarts.slice(1));\r\n\t\t\tthis._buffers[0].buffer += '_' + text;\r\n\t\t\tstartOffset += 1;\r\n\t\t} else {\r\n\t\t\tif (startOffset !== 0) {\r\n\t\t\t\tfor (let i = 0; i < lineStarts.length; i++) {\r\n\t\t\t\t\tlineStarts[i] += startOffset;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tthis._buffers[0].lineStarts = (this._buffers[0].lineStarts).concat(lineStarts.slice(1));\r\n\t\t\tthis._buffers[0].buffer += text;\r\n\t\t}\r\n\r\n\t\tconst endOffset = this._buffers[0].buffer.length;\r\n\t\tlet endIndex = this._buffers[0].lineStarts.length - 1;\r\n\t\tlet endColumn = endOffset - this._buffers[0].lineStarts[endIndex];\r\n\t\tlet endPos = { line: endIndex, column: endColumn };\r\n\t\tlet newPiece = new Piece(\r\n\t\t\t0, /** todo@peng */\r\n\t\t\tstart,\r\n\t\t\tendPos,\r\n\t\t\tthis.getLineFeedCnt(0, start, endPos),\r\n\t\t\tendOffset - startOffset\r\n\t\t);\r\n\t\tthis._lastChangeBufferPos = endPos;\r\n\t\treturn [newPiece];\r\n\t}\r\n\r\n\tpublic getLineRawContent(lineNumber: number, endOffset: number = 0): string {\r\n\t\tlet x = this.root;\r\n\r\n\t\tlet ret = '';\r\n\t\tlet cache = this._searchCache.get2(lineNumber);\r\n\t\tif (cache) {\r\n\t\t\tx = cache.node;\r\n\t\t\tlet prevAccumulatedValue = this.getAccumulatedValue(x, lineNumber - cache.nodeStartLineNumber - 1);\r\n\t\t\tlet buffer = this._buffers[x.piece.bufferIndex].buffer;\r\n\t\t\tlet startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);\r\n\t\t\tif (cache.nodeStartLineNumber + x.piece.lineFeedCnt === lineNumber) {\r\n\t\t\t\tret = buffer.substring(startOffset + prevAccumulatedValue, startOffset + x.piece.length);\r\n\t\t\t} else {\r\n\t\t\t\tlet accumulatedValue = this.getAccumulatedValue(x, lineNumber - cache.nodeStartLineNumber);\r\n\t\t\t\treturn buffer.substring(startOffset + prevAccumulatedValue, startOffset + accumulatedValue - endOffset);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tlet nodeStartOffset = 0;\r\n\t\t\tconst originalLineNumber = lineNumber;\r\n\t\t\twhile (x !== SENTINEL) {\r\n\t\t\t\tif (x.left !== SENTINEL && x.lf_left >= lineNumber - 1) {\r\n\t\t\t\t\tx = x.left;\r\n\t\t\t\t} else if (x.lf_left + x.piece.lineFeedCnt > lineNumber - 1) {\r\n\t\t\t\t\tlet prevAccumulatedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);\r\n\t\t\t\t\tlet accumulatedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 1);\r\n\t\t\t\t\tlet buffer = this._buffers[x.piece.bufferIndex].buffer;\r\n\t\t\t\t\tlet startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);\r\n\t\t\t\t\tnodeStartOffset += x.size_left;\r\n\t\t\t\t\tthis._searchCache.set({\r\n\t\t\t\t\t\tnode: x,\r\n\t\t\t\t\t\tnodeStartOffset,\r\n\t\t\t\t\t\tnodeStartLineNumber: originalLineNumber - (lineNumber - 1 - x.lf_left)\r\n\t\t\t\t\t});\r\n\r\n\t\t\t\t\treturn buffer.substring(startOffset + prevAccumulatedValue, startOffset + accumulatedValue - endOffset);\r\n\t\t\t\t} else if (x.lf_left + x.piece.lineFeedCnt === lineNumber - 1) {\r\n\t\t\t\t\tlet prevAccumulatedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);\r\n\t\t\t\t\tlet buffer = this._buffers[x.piece.bufferIndex].buffer;\r\n\t\t\t\t\tlet startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);\r\n\r\n\t\t\t\t\tret = buffer.substring(startOffset + prevAccumulatedValue, startOffset + x.piece.length);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tlineNumber -= x.lf_left + x.piece.lineFeedCnt;\r\n\t\t\t\t\tnodeStartOffset += x.size_left + x.piece.length;\r\n\t\t\t\t\tx = x.right;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// search in order, to find the node contains end column\r\n\t\tx = x.next();\r\n\t\twhile (x !== SENTINEL) {\r\n\t\t\tlet buffer = this._buffers[x.piece.bufferIndex].buffer;\r\n\r\n\t\t\tif (x.piece.lineFeedCnt > 0) {\r\n\t\t\t\tlet accumulatedValue = this.getAccumulatedValue(x, 0);\r\n\t\t\t\tlet startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);\r\n\r\n\t\t\t\tret += buffer.substring(startOffset, startOffset + accumulatedValue - endOffset);\r\n\t\t\t\treturn ret;\r\n\t\t\t} else {\r\n\t\t\t\tlet startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);\r\n\t\t\t\tret += buffer.substr(startOffset, x.piece.length);\r\n\t\t\t}\r\n\r\n\t\t\tx = x.next();\r\n\t\t}\r\n\r\n\t\treturn ret;\r\n\t}\r\n\r\n\tprivate computeBufferMetadata() {\r\n\t\tlet x = this.root;\r\n\r\n\t\tlet lfCnt = 1;\r\n\t\tlet len = 0;\r\n\r\n\t\twhile (x !== SENTINEL) {\r\n\t\t\tlfCnt += x.lf_left + x.piece.lineFeedCnt;\r\n\t\t\tlen += x.size_left + x.piece.length;\r\n\t\t\tx = x.right;\r\n\t\t}\r\n\r\n\t\tthis._lineCnt = lfCnt;\r\n\t\tthis._length = len;\r\n\t\tthis._searchCache.validate(this._length);\r\n\t}\r\n\r\n\t// #region node operations\r\n\tprivate getIndexOf(node: TreeNode, accumulatedValue: number): { index: number, remainder: number } {\r\n\t\tlet piece = node.piece;\r\n\t\tlet pos = this.positionInBuffer(node, accumulatedValue);\r\n\t\tlet lineCnt = pos.line - piece.start.line;\r\n\r\n\t\tif (this.offsetInBuffer(piece.bufferIndex, piece.end) - this.offsetInBuffer(piece.bufferIndex, piece.start) === accumulatedValue) {\r\n\t\t\t// we are checking the end of this node, so a CRLF check is necessary.\r\n\t\t\tlet realLineCnt = this.getLineFeedCnt(node.piece.bufferIndex, piece.start, pos);\r\n\t\t\tif (realLineCnt !== lineCnt) {\r\n\t\t\t\t// aha yes, CRLF\r\n\t\t\t\treturn { index: realLineCnt, remainder: 0 };\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn { index: lineCnt, remainder: pos.column };\r\n\t}\r\n\r\n\tprivate getAccumulatedValue(node: TreeNode, index: number) {\r\n\t\tif (index < 0) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t\tlet piece = node.piece;\r\n\t\tlet lineStarts = this._buffers[piece.bufferIndex].lineStarts;\r\n\t\tlet expectedLineStartIndex = piece.start.line + index + 1;\r\n\t\tif (expectedLineStartIndex > piece.end.line) {\r\n\t\t\treturn lineStarts[piece.end.line] + piece.end.column - lineStarts[piece.start.line] - piece.start.column;\r\n\t\t} else {\r\n\t\t\treturn lineStarts[expectedLineStartIndex] - lineStarts[piece.start.line] - piece.start.column;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate deleteNodeTail(node: TreeNode, pos: BufferCursor) {\r\n\t\tconst piece = node.piece;\r\n\t\tconst originalLFCnt = piece.lineFeedCnt;\r\n\t\tconst originalEndOffset = this.offsetInBuffer(piece.bufferIndex, piece.end);\r\n\r\n\t\tconst newEnd = pos;\r\n\t\tconst newEndOffset = this.offsetInBuffer(piece.bufferIndex, newEnd);\r\n\t\tconst newLineFeedCnt = this.getLineFeedCnt(piece.bufferIndex, piece.start, newEnd);\r\n\r\n\t\tconst lf_delta = newLineFeedCnt - originalLFCnt;\r\n\t\tconst size_delta = newEndOffset - originalEndOffset;\r\n\t\tconst newLength = piece.length + size_delta;\r\n\r\n\t\tnode.piece = new Piece(\r\n\t\t\tpiece.bufferIndex,\r\n\t\t\tpiece.start,\r\n\t\t\tnewEnd,\r\n\t\t\tnewLineFeedCnt,\r\n\t\t\tnewLength\r\n\t\t);\r\n\r\n\t\tupdateTreeMetadata(this, node, size_delta, lf_delta);\r\n\t}\r\n\r\n\tprivate deleteNodeHead(node: TreeNode, pos: BufferCursor) {\r\n\t\tconst piece = node.piece;\r\n\t\tconst originalLFCnt = piece.lineFeedCnt;\r\n\t\tconst originalStartOffset = this.offsetInBuffer(piece.bufferIndex, piece.start);\r\n\r\n\t\tconst newStart = pos;\r\n\t\tconst newLineFeedCnt = this.getLineFeedCnt(piece.bufferIndex, newStart, piece.end);\r\n\t\tconst newStartOffset = this.offsetInBuffer(piece.bufferIndex, newStart);\r\n\t\tconst lf_delta = newLineFeedCnt - originalLFCnt;\r\n\t\tconst size_delta = originalStartOffset - newStartOffset;\r\n\t\tconst newLength = piece.length + size_delta;\r\n\t\tnode.piece = new Piece(\r\n\t\t\tpiece.bufferIndex,\r\n\t\t\tnewStart,\r\n\t\t\tpiece.end,\r\n\t\t\tnewLineFeedCnt,\r\n\t\t\tnewLength\r\n\t\t);\r\n\r\n\t\tupdateTreeMetadata(this, node, size_delta, lf_delta);\r\n\t}\r\n\r\n\tprivate shrinkNode(node: TreeNode, start: BufferCursor, end: BufferCursor) {\r\n\t\tconst piece = node.piece;\r\n\t\tconst originalStartPos = piece.start;\r\n\t\tconst originalEndPos = piece.end;\r\n\r\n\t\t// old piece, originalStartPos, start\r\n\t\tconst oldLength = piece.length;\r\n\t\tconst oldLFCnt = piece.lineFeedCnt;\r\n\t\tconst newEnd = start;\r\n\t\tconst newLineFeedCnt = this.getLineFeedCnt(piece.bufferIndex, piece.start, newEnd);\r\n\t\tconst newLength = this.offsetInBuffer(piece.bufferIndex, start) - this.offsetInBuffer(piece.bufferIndex, originalStartPos);\r\n\r\n\t\tnode.piece = new Piece(\r\n\t\t\tpiece.bufferIndex,\r\n\t\t\tpiece.start,\r\n\t\t\tnewEnd,\r\n\t\t\tnewLineFeedCnt,\r\n\t\t\tnewLength\r\n\t\t);\r\n\r\n\t\tupdateTreeMetadata(this, node, newLength - oldLength, newLineFeedCnt - oldLFCnt);\r\n\r\n\t\t// new right piece, end, originalEndPos\r\n\t\tlet newPiece = new Piece(\r\n\t\t\tpiece.bufferIndex,\r\n\t\t\tend,\r\n\t\t\toriginalEndPos,\r\n\t\t\tthis.getLineFeedCnt(piece.bufferIndex, end, originalEndPos),\r\n\t\t\tthis.offsetInBuffer(piece.bufferIndex, originalEndPos) - this.offsetInBuffer(piece.bufferIndex, end)\r\n\t\t);\r\n\r\n\t\tlet newNode = this.rbInsertRight(node, newPiece);\r\n\t\tthis.validateCRLFWithPrevNode(newNode);\r\n\t}\r\n\r\n\tprivate appendToNode(node: TreeNode, value: string): void {\r\n\t\tif (this.adjustCarriageReturnFromNext(value, node)) {\r\n\t\t\tvalue += '\\n';\r\n\t\t}\r\n\r\n\t\tconst hitCRLF = this.shouldCheckCRLF() && this.startWithLF(value) && this.endWithCR(node);\r\n\t\tconst startOffset = this._buffers[0].buffer.length;\r\n\t\tthis._buffers[0].buffer += value;\r\n\t\tconst lineStarts = createLineStartsFast(value, false);\r\n\t\tfor (let i = 0; i < lineStarts.length; i++) {\r\n\t\t\tlineStarts[i] += startOffset;\r\n\t\t}\r\n\t\tif (hitCRLF) {\r\n\t\t\tlet prevStartOffset = this._buffers[0].lineStarts[this._buffers[0].lineStarts.length - 2];\r\n\t\t\t(this._buffers[0].lineStarts).pop();\r\n\t\t\t// _lastChangeBufferPos is already wrong\r\n\t\t\tthis._lastChangeBufferPos = { line: this._lastChangeBufferPos.line - 1, column: startOffset - prevStartOffset };\r\n\t\t}\r\n\r\n\t\tthis._buffers[0].lineStarts = (this._buffers[0].lineStarts).concat(lineStarts.slice(1));\r\n\t\tconst endIndex = this._buffers[0].lineStarts.length - 1;\r\n\t\tconst endColumn = this._buffers[0].buffer.length - this._buffers[0].lineStarts[endIndex];\r\n\t\tconst newEnd = { line: endIndex, column: endColumn };\r\n\t\tconst newLength = node.piece.length + value.length;\r\n\t\tconst oldLineFeedCnt = node.piece.lineFeedCnt;\r\n\t\tconst newLineFeedCnt = this.getLineFeedCnt(0, node.piece.start, newEnd);\r\n\t\tconst lf_delta = newLineFeedCnt - oldLineFeedCnt;\r\n\r\n\t\tnode.piece = new Piece(\r\n\t\t\tnode.piece.bufferIndex,\r\n\t\t\tnode.piece.start,\r\n\t\t\tnewEnd,\r\n\t\t\tnewLineFeedCnt,\r\n\t\t\tnewLength\r\n\t\t);\r\n\r\n\t\tthis._lastChangeBufferPos = newEnd;\r\n\t\tupdateTreeMetadata(this, node, value.length, lf_delta);\r\n\t}\r\n\r\n\tprivate nodeAt(offset: number): NodePosition {\r\n\t\tlet x = this.root;\r\n\t\tlet cache = this._searchCache.get(offset);\r\n\t\tif (cache) {\r\n\t\t\treturn {\r\n\t\t\t\tnode: cache.node,\r\n\t\t\t\tnodeStartOffset: cache.nodeStartOffset,\r\n\t\t\t\tremainder: offset - cache.nodeStartOffset\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tlet nodeStartOffset = 0;\r\n\r\n\t\twhile (x !== SENTINEL) {\r\n\t\t\tif (x.size_left > offset) {\r\n\t\t\t\tx = x.left;\r\n\t\t\t} else if (x.size_left + x.piece.length >= offset) {\r\n\t\t\t\tnodeStartOffset += x.size_left;\r\n\t\t\t\tlet ret = {\r\n\t\t\t\t\tnode: x,\r\n\t\t\t\t\tremainder: offset - x.size_left,\r\n\t\t\t\t\tnodeStartOffset\r\n\t\t\t\t};\r\n\t\t\t\tthis._searchCache.set(ret);\r\n\t\t\t\treturn ret;\r\n\t\t\t} else {\r\n\t\t\t\toffset -= x.size_left + x.piece.length;\r\n\t\t\t\tnodeStartOffset += x.size_left + x.piece.length;\r\n\t\t\t\tx = x.right;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn null!;\r\n\t}\r\n\r\n\tprivate nodeAt2(lineNumber: number, column: number): NodePosition {\r\n\t\tlet x = this.root;\r\n\t\tlet nodeStartOffset = 0;\r\n\r\n\t\twhile (x !== SENTINEL) {\r\n\t\t\tif (x.left !== SENTINEL && x.lf_left >= lineNumber - 1) {\r\n\t\t\t\tx = x.left;\r\n\t\t\t} else if (x.lf_left + x.piece.lineFeedCnt > lineNumber - 1) {\r\n\t\t\t\tlet prevAccumualtedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);\r\n\t\t\t\tlet accumulatedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 1);\r\n\t\t\t\tnodeStartOffset += x.size_left;\r\n\r\n\t\t\t\treturn {\r\n\t\t\t\t\tnode: x,\r\n\t\t\t\t\tremainder: Math.min(prevAccumualtedValue + column - 1, accumulatedValue),\r\n\t\t\t\t\tnodeStartOffset\r\n\t\t\t\t};\r\n\t\t\t} else if (x.lf_left + x.piece.lineFeedCnt === lineNumber - 1) {\r\n\t\t\t\tlet prevAccumualtedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);\r\n\t\t\t\tif (prevAccumualtedValue + column - 1 <= x.piece.length) {\r\n\t\t\t\t\treturn {\r\n\t\t\t\t\t\tnode: x,\r\n\t\t\t\t\t\tremainder: prevAccumualtedValue + column - 1,\r\n\t\t\t\t\t\tnodeStartOffset\r\n\t\t\t\t\t};\r\n\t\t\t\t} else {\r\n\t\t\t\t\tcolumn -= x.piece.length - prevAccumualtedValue;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tlineNumber -= x.lf_left + x.piece.lineFeedCnt;\r\n\t\t\t\tnodeStartOffset += x.size_left + x.piece.length;\r\n\t\t\t\tx = x.right;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// search in order, to find the node contains position.column\r\n\t\tx = x.next();\r\n\t\twhile (x !== SENTINEL) {\r\n\r\n\t\t\tif (x.piece.lineFeedCnt > 0) {\r\n\t\t\t\tlet accumulatedValue = this.getAccumulatedValue(x, 0);\r\n\t\t\t\tlet nodeStartOffset = this.offsetOfNode(x);\r\n\t\t\t\treturn {\r\n\t\t\t\t\tnode: x,\r\n\t\t\t\t\tremainder: Math.min(column - 1, accumulatedValue),\r\n\t\t\t\t\tnodeStartOffset\r\n\t\t\t\t};\r\n\t\t\t} else {\r\n\t\t\t\tif (x.piece.length >= column - 1) {\r\n\t\t\t\t\tlet nodeStartOffset = this.offsetOfNode(x);\r\n\t\t\t\t\treturn {\r\n\t\t\t\t\t\tnode: x,\r\n\t\t\t\t\t\tremainder: column - 1,\r\n\t\t\t\t\t\tnodeStartOffset\r\n\t\t\t\t\t};\r\n\t\t\t\t} else {\r\n\t\t\t\t\tcolumn -= x.piece.length;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tx = x.next();\r\n\t\t}\r\n\r\n\t\treturn null!;\r\n\t}\r\n\r\n\tprivate nodeCharCodeAt(node: TreeNode, offset: number): number {\r\n\t\tif (node.piece.lineFeedCnt < 1) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\tlet buffer = this._buffers[node.piece.bufferIndex];\r\n\t\tlet newOffset = this.offsetInBuffer(node.piece.bufferIndex, node.piece.start) + offset;\r\n\t\treturn buffer.buffer.charCodeAt(newOffset);\r\n\t}\r\n\r\n\tprivate offsetOfNode(node: TreeNode): number {\r\n\t\tif (!node) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t\tlet pos = node.size_left;\r\n\t\twhile (node !== this.root) {\r\n\t\t\tif (node.parent.right === node) {\r\n\t\t\t\tpos += node.parent.size_left + node.parent.piece.length;\r\n\t\t\t}\r\n\r\n\t\t\tnode = node.parent;\r\n\t\t}\r\n\r\n\t\treturn pos;\r\n\t}\r\n\r\n\t// #endregion\r\n\r\n\t// #region CRLF\r\n\tprivate shouldCheckCRLF() {\r\n\t\treturn !(this._EOLNormalized && this._EOL === '\\n');\r\n\t}\r\n\r\n\tprivate startWithLF(val: string | TreeNode): boolean {\r\n\t\tif (typeof val === 'string') {\r\n\t\t\treturn val.charCodeAt(0) === 10;\r\n\t\t}\r\n\r\n\t\tif (val === SENTINEL || val.piece.lineFeedCnt === 0) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tlet piece = val.piece;\r\n\t\tlet lineStarts = this._buffers[piece.bufferIndex].lineStarts;\r\n\t\tlet line = piece.start.line;\r\n\t\tlet startOffset = lineStarts[line] + piece.start.column;\r\n\t\tif (line === lineStarts.length - 1) {\r\n\t\t\t// last line, so there is no line feed at the end of this line\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tlet nextLineOffset = lineStarts[line + 1];\r\n\t\tif (nextLineOffset > startOffset + 1) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn this._buffers[piece.bufferIndex].buffer.charCodeAt(startOffset) === 10;\r\n\t}\r\n\r\n\tprivate endWithCR(val: string | TreeNode): boolean {\r\n\t\tif (typeof val === 'string') {\r\n\t\t\treturn val.charCodeAt(val.length - 1) === 13;\r\n\t\t}\r\n\r\n\t\tif (val === SENTINEL || val.piece.lineFeedCnt === 0) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\treturn this.nodeCharCodeAt(val, val.piece.length - 1) === 13;\r\n\t}\r\n\r\n\tprivate validateCRLFWithPrevNode(nextNode: TreeNode) {\r\n\t\tif (this.shouldCheckCRLF() && this.startWithLF(nextNode)) {\r\n\t\t\tlet node = nextNode.prev();\r\n\t\t\tif (this.endWithCR(node)) {\r\n\t\t\t\tthis.fixCRLF(node, nextNode);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate validateCRLFWithNextNode(node: TreeNode) {\r\n\t\tif (this.shouldCheckCRLF() && this.endWithCR(node)) {\r\n\t\t\tlet nextNode = node.next();\r\n\t\t\tif (this.startWithLF(nextNode)) {\r\n\t\t\t\tthis.fixCRLF(node, nextNode);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate fixCRLF(prev: TreeNode, next: TreeNode) {\r\n\t\tlet nodesToDel: TreeNode[] = [];\r\n\t\t// update node\r\n\t\tlet lineStarts = this._buffers[prev.piece.bufferIndex].lineStarts;\r\n\t\tlet newEnd: BufferCursor;\r\n\t\tif (prev.piece.end.column === 0) {\r\n\t\t\t// it means, last line ends with \\r, not \\r\\n\r\n\t\t\tnewEnd = { line: prev.piece.end.line - 1, column: lineStarts[prev.piece.end.line] - lineStarts[prev.piece.end.line - 1] - 1 };\r\n\t\t} else {\r\n\t\t\t// \\r\\n\r\n\t\t\tnewEnd = { line: prev.piece.end.line, column: prev.piece.end.column - 1 };\r\n\t\t}\r\n\r\n\t\tconst prevNewLength = prev.piece.length - 1;\r\n\t\tconst prevNewLFCnt = prev.piece.lineFeedCnt - 1;\r\n\t\tprev.piece = new Piece(\r\n\t\t\tprev.piece.bufferIndex,\r\n\t\t\tprev.piece.start,\r\n\t\t\tnewEnd,\r\n\t\t\tprevNewLFCnt,\r\n\t\t\tprevNewLength\r\n\t\t);\r\n\r\n\t\tupdateTreeMetadata(this, prev, - 1, -1);\r\n\t\tif (prev.piece.length === 0) {\r\n\t\t\tnodesToDel.push(prev);\r\n\t\t}\r\n\r\n\t\t// update nextNode\r\n\t\tlet newStart: BufferCursor = { line: next.piece.start.line + 1, column: 0 };\r\n\t\tconst newLength = next.piece.length - 1;\r\n\t\tconst newLineFeedCnt = this.getLineFeedCnt(next.piece.bufferIndex, newStart, next.piece.end);\r\n\t\tnext.piece = new Piece(\r\n\t\t\tnext.piece.bufferIndex,\r\n\t\t\tnewStart,\r\n\t\t\tnext.piece.end,\r\n\t\t\tnewLineFeedCnt,\r\n\t\t\tnewLength\r\n\t\t);\r\n\r\n\t\tupdateTreeMetadata(this, next, - 1, -1);\r\n\t\tif (next.piece.length === 0) {\r\n\t\t\tnodesToDel.push(next);\r\n\t\t}\r\n\r\n\t\t// create new piece which contains \\r\\n\r\n\t\tlet pieces = this.createNewPieces('\\r\\n');\r\n\t\tthis.rbInsertRight(prev, pieces[0]);\r\n\t\t// delete empty nodes\r\n\r\n\t\tfor (let i = 0; i < nodesToDel.length; i++) {\r\n\t\t\trbDelete(this, nodesToDel[i]);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate adjustCarriageReturnFromNext(value: string, node: TreeNode): boolean {\r\n\t\tif (this.shouldCheckCRLF() && this.endWithCR(value)) {\r\n\t\t\tlet nextNode = node.next();\r\n\t\t\tif (this.startWithLF(nextNode)) {\r\n\t\t\t\t// move `\\n` forward\r\n\t\t\t\tvalue += '\\n';\r\n\r\n\t\t\t\tif (nextNode.piece.length === 1) {\r\n\t\t\t\t\trbDelete(this, nextNode);\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tconst piece = nextNode.piece;\r\n\t\t\t\t\tconst newStart: BufferCursor = { line: piece.start.line + 1, column: 0 };\r\n\t\t\t\t\tconst newLength = piece.length - 1;\r\n\t\t\t\t\tconst newLineFeedCnt = this.getLineFeedCnt(piece.bufferIndex, newStart, piece.end);\r\n\t\t\t\t\tnextNode.piece = new Piece(\r\n\t\t\t\t\t\tpiece.bufferIndex,\r\n\t\t\t\t\t\tnewStart,\r\n\t\t\t\t\t\tpiece.end,\r\n\t\t\t\t\t\tnewLineFeedCnt,\r\n\t\t\t\t\t\tnewLength\r\n\t\t\t\t\t);\r\n\r\n\t\t\t\t\tupdateTreeMetadata(this, nextNode, -1, -1);\r\n\t\t\t\t}\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\t}\r\n\r\n\t// #endregion\r\n\r\n\t// #endregion\r\n\r\n\t// #region Tree operations\r\n\titerate(node: TreeNode, callback: (node: TreeNode) => boolean): boolean {\r\n\t\tif (node === SENTINEL) {\r\n\t\t\treturn callback(SENTINEL);\r\n\t\t}\r\n\r\n\t\tlet leftRet = this.iterate(node.left, callback);\r\n\t\tif (!leftRet) {\r\n\t\t\treturn leftRet;\r\n\t\t}\r\n\r\n\t\treturn callback(node) && this.iterate(node.right, callback);\r\n\t}\r\n\r\n\tprivate getNodeContent(node: TreeNode) {\r\n\t\tif (node === SENTINEL) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\tlet buffer = this._buffers[node.piece.bufferIndex];\r\n\t\tlet currentContent;\r\n\t\tlet piece = node.piece;\r\n\t\tlet startOffset = this.offsetInBuffer(piece.bufferIndex, piece.start);\r\n\t\tlet endOffset = this.offsetInBuffer(piece.bufferIndex, piece.end);\r\n\t\tcurrentContent = buffer.buffer.substring(startOffset, endOffset);\r\n\t\treturn currentContent;\r\n\t}\r\n\r\n\tgetPieceContent(piece: Piece) {\r\n\t\tlet buffer = this._buffers[piece.bufferIndex];\r\n\t\tlet startOffset = this.offsetInBuffer(piece.bufferIndex, piece.start);\r\n\t\tlet endOffset = this.offsetInBuffer(piece.bufferIndex, piece.end);\r\n\t\tlet currentContent = buffer.buffer.substring(startOffset, endOffset);\r\n\t\treturn currentContent;\r\n\t}\r\n\r\n\t/**\r\n\t * node node\r\n\t * / \\ / \\\r\n\t * a b <---- a b\r\n\t * /\r\n\t * z\r\n\t */\r\n\tprivate rbInsertRight(node: TreeNode | null, p: Piece): TreeNode {\r\n\t\tlet z = new TreeNode(p, NodeColor.Red);\r\n\t\tz.left = SENTINEL;\r\n\t\tz.right = SENTINEL;\r\n\t\tz.parent = SENTINEL;\r\n\t\tz.size_left = 0;\r\n\t\tz.lf_left = 0;\r\n\r\n\t\tlet x = this.root;\r\n\t\tif (x === SENTINEL) {\r\n\t\t\tthis.root = z;\r\n\t\t\tz.color = NodeColor.Black;\r\n\t\t} else if (node!.right === SENTINEL) {\r\n\t\t\tnode!.right = z;\r\n\t\t\tz.parent = node!;\r\n\t\t} else {\r\n\t\t\tlet nextNode = leftest(node!.right);\r\n\t\t\tnextNode.left = z;\r\n\t\t\tz.parent = nextNode;\r\n\t\t}\r\n\r\n\t\tfixInsert(this, z);\r\n\t\treturn z;\r\n\t}\r\n\r\n\t/**\r\n\t * node node\r\n\t * / \\ / \\\r\n\t * a b ----> a b\r\n\t * \\\r\n\t * z\r\n\t */\r\n\tprivate rbInsertLeft(node: TreeNode | null, p: Piece): TreeNode {\r\n\t\tlet z = new TreeNode(p, NodeColor.Red);\r\n\t\tz.left = SENTINEL;\r\n\t\tz.right = SENTINEL;\r\n\t\tz.parent = SENTINEL;\r\n\t\tz.size_left = 0;\r\n\t\tz.lf_left = 0;\r\n\r\n\t\tif (this.root === SENTINEL) {\r\n\t\t\tthis.root = z;\r\n\t\t\tz.color = NodeColor.Black;\r\n\t\t} else if (node!.left === SENTINEL) {\r\n\t\t\tnode!.left = z;\r\n\t\t\tz.parent = node!;\r\n\t\t} else {\r\n\t\t\tlet prevNode = righttest(node!.left); // a\r\n\t\t\tprevNode.right = z;\r\n\t\t\tz.parent = prevNode;\r\n\t\t}\r\n\r\n\t\tfixInsert(this, z);\r\n\t\treturn z;\r\n\t}\r\n\t// #endregion\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IWordAtPosition } from 'vs/editor/common/model';\r\n\r\nexport const USUAL_WORD_SEPARATORS = '`~!@#$%^&*()-=+[{]}\\\\|;:\\'\",.<>/?';\r\n\r\n/**\r\n * Create a word definition regular expression based on default word separators.\r\n * Optionally provide allowed separators that should be included in words.\r\n *\r\n * The default would look like this:\r\n * /(-?\\d*\\.\\d\\w*)|([^\\`\\~\\!\\@\\#\\$\\%\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s]+)/g\r\n */\r\nfunction createWordRegExp(allowInWords: string = ''): RegExp {\r\n\tlet source = '(-?\\\\d*\\\\.\\\\d\\\\w*)|([^';\r\n\tfor (const sep of USUAL_WORD_SEPARATORS) {\r\n\t\tif (allowInWords.indexOf(sep) >= 0) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\t\tsource += '\\\\' + sep;\r\n\t}\r\n\tsource += '\\\\s]+)';\r\n\treturn new RegExp(source, 'g');\r\n}\r\n\r\n// catches numbers (including floating numbers) in the first group, and alphanum in the second\r\nexport const DEFAULT_WORD_REGEXP = createWordRegExp();\r\n\r\nexport function ensureValidWordDefinition(wordDefinition?: RegExp | null): RegExp {\r\n\tlet result: RegExp = DEFAULT_WORD_REGEXP;\r\n\r\n\tif (wordDefinition && (wordDefinition instanceof RegExp)) {\r\n\t\tif (!wordDefinition.global) {\r\n\t\t\tlet flags = 'g';\r\n\t\t\tif (wordDefinition.ignoreCase) {\r\n\t\t\t\tflags += 'i';\r\n\t\t\t}\r\n\t\t\tif (wordDefinition.multiline) {\r\n\t\t\t\tflags += 'm';\r\n\t\t\t}\r\n\t\t\tif ((wordDefinition as any).unicode) {\r\n\t\t\t\tflags += 'u';\r\n\t\t\t}\r\n\t\t\tresult = new RegExp(wordDefinition.source, flags);\r\n\t\t} else {\r\n\t\t\tresult = wordDefinition;\r\n\t\t}\r\n\t}\r\n\r\n\tresult.lastIndex = 0;\r\n\r\n\treturn result;\r\n}\r\n\r\nconst _defaultConfig = {\r\n\tmaxLen: 1000,\r\n\twindowSize: 15,\r\n\ttimeBudget: 150\r\n};\r\n\r\nexport function getWordAtText(column: number, wordDefinition: RegExp, text: string, textOffset: number, config = _defaultConfig): IWordAtPosition | null {\r\n\r\n\tif (text.length > config.maxLen) {\r\n\t\t// don't throw strings that long at the regexp\r\n\t\t// but use a sub-string in which a word must occur\r\n\t\tlet start = column - config.maxLen / 2;\r\n\t\tif (start < 0) {\r\n\t\t\tstart = 0;\r\n\t\t} else {\r\n\t\t\ttextOffset += start;\r\n\t\t}\r\n\t\ttext = text.substring(start, column + config.maxLen / 2);\r\n\t\treturn getWordAtText(column, wordDefinition, text, textOffset, config);\r\n\t}\r\n\r\n\tconst t1 = Date.now();\r\n\tconst pos = column - 1 - textOffset;\r\n\r\n\tlet prevRegexIndex = -1;\r\n\tlet match: RegExpMatchArray | null = null;\r\n\r\n\tfor (let i = 1; ; i++) {\r\n\t\t// check time budget\r\n\t\tif (Date.now() - t1 >= config.timeBudget) {\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\t// reset the index at which the regexp should start matching, also know where it\r\n\t\t// should stop so that subsequent search don't repeat previous searches\r\n\t\tconst regexIndex = pos - config.windowSize * i;\r\n\t\twordDefinition.lastIndex = Math.max(0, regexIndex);\r\n\t\tconst thisMatch = _findRegexMatchEnclosingPosition(wordDefinition, text, pos, prevRegexIndex);\r\n\r\n\t\tif (!thisMatch && match) {\r\n\t\t\t// stop: we have something\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tmatch = thisMatch;\r\n\r\n\t\t// stop: searched at start\r\n\t\tif (regexIndex <= 0) {\r\n\t\t\tbreak;\r\n\t\t}\r\n\t\tprevRegexIndex = regexIndex;\r\n\t}\r\n\r\n\tif (match) {\r\n\t\tlet result = {\r\n\t\t\tword: match[0],\r\n\t\t\tstartColumn: textOffset + 1 + match.index!,\r\n\t\t\tendColumn: textOffset + 1 + match.index! + match[0].length\r\n\t\t};\r\n\t\twordDefinition.lastIndex = 0;\r\n\t\treturn result;\r\n\t}\r\n\r\n\treturn null;\r\n}\r\n\r\nfunction _findRegexMatchEnclosingPosition(wordDefinition: RegExp, text: string, pos: number, stopPos: number): RegExpMatchArray | null {\r\n\tlet match: RegExpMatchArray | null;\r\n\twhile (match = wordDefinition.exec(text)) {\r\n\t\tconst matchIndex = match.index || 0;\r\n\t\tif (matchIndex <= pos && wordDefinition.lastIndex >= pos) {\r\n\t\t\treturn match;\r\n\t\t} else if (stopPos > 0 && matchIndex > stopPos) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IMode, LanguageIdentifier } from 'vs/editor/common/modes';\r\n\r\nexport class FrankensteinMode implements IMode {\r\n\r\n\tprivate readonly _languageIdentifier: LanguageIdentifier;\r\n\r\n\tconstructor(languageIdentifier: LanguageIdentifier) {\r\n\t\tthis._languageIdentifier = languageIdentifier;\r\n\t}\r\n\r\n\tpublic getId(): string {\r\n\t\treturn this._languageIdentifier.language;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { StandardTokenType } from 'vs/editor/common/modes';\r\n\r\n/**\r\n * Describes how comments for a language work.\r\n */\r\nexport interface CommentRule {\r\n\t/**\r\n\t * The line comment token, like `// this is a comment`\r\n\t */\r\n\tlineComment?: string | null;\r\n\t/**\r\n\t * The block comment character pair, like `/* block comment */`\r\n\t */\r\n\tblockComment?: CharacterPair | null;\r\n}\r\n\r\n/**\r\n * The language configuration interface defines the contract between extensions and\r\n * various editor features, like automatic bracket insertion, automatic indentation etc.\r\n */\r\nexport interface LanguageConfiguration {\r\n\t/**\r\n\t * The language's comment settings.\r\n\t */\r\n\tcomments?: CommentRule;\r\n\t/**\r\n\t * The language's brackets.\r\n\t * This configuration implicitly affects pressing Enter around these brackets.\r\n\t */\r\n\tbrackets?: CharacterPair[];\r\n\t/**\r\n\t * The language's word definition.\r\n\t * If the language supports Unicode identifiers (e.g. JavaScript), it is preferable\r\n\t * to provide a word definition that uses exclusion of known separators.\r\n\t * e.g.: A regex that matches anything except known separators (and dot is allowed to occur in a floating point number):\r\n\t * /(-?\\d*\\.\\d\\w*)|([^\\`\\~\\!\\@\\#\\%\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s]+)/g\r\n\t */\r\n\twordPattern?: RegExp;\r\n\t/**\r\n\t * The language's indentation settings.\r\n\t */\r\n\tindentationRules?: IndentationRule;\r\n\t/**\r\n\t * The language's rules to be evaluated when pressing Enter.\r\n\t */\r\n\tonEnterRules?: OnEnterRule[];\r\n\t/**\r\n\t * The language's auto closing pairs. The 'close' character is automatically inserted with the\r\n\t * 'open' character is typed. If not set, the configured brackets will be used.\r\n\t */\r\n\tautoClosingPairs?: IAutoClosingPairConditional[];\r\n\t/**\r\n\t * The language's surrounding pairs. When the 'open' character is typed on a selection, the\r\n\t * selected string is surrounded by the open and close characters. If not set, the autoclosing pairs\r\n\t * settings will be used.\r\n\t */\r\n\tsurroundingPairs?: IAutoClosingPair[];\r\n\r\n\t/**\r\n\t * Defines what characters must be after the cursor for bracket or quote autoclosing to occur when using the \\'languageDefined\\' autoclosing setting.\r\n\t *\r\n\t * This is typically the set of characters which can not start an expression, such as whitespace, closing brackets, non-unary operators, etc.\r\n\t */\r\n\tautoCloseBefore?: string;\r\n\r\n\t/**\r\n\t * The language's folding rules.\r\n\t */\r\n\tfolding?: FoldingRules;\r\n\r\n\t/**\r\n\t * **Deprecated** Do not use.\r\n\t *\r\n\t * @deprecated Will be replaced by a better API soon.\r\n\t */\r\n\t__electricCharacterSupport?: {\r\n\t\tdocComment?: IDocComment;\r\n\t};\r\n}\r\n\r\n/**\r\n * Describes indentation rules for a language.\r\n */\r\nexport interface IndentationRule {\r\n\t/**\r\n\t * If a line matches this pattern, then all the lines after it should be unindented once (until another rule matches).\r\n\t */\r\n\tdecreaseIndentPattern: RegExp;\r\n\t/**\r\n\t * If a line matches this pattern, then all the lines after it should be indented once (until another rule matches).\r\n\t */\r\n\tincreaseIndentPattern: RegExp;\r\n\t/**\r\n\t * If a line matches this pattern, then **only the next line** after it should be indented once.\r\n\t */\r\n\tindentNextLinePattern?: RegExp | null;\r\n\t/**\r\n\t * If a line matches this pattern, then its indentation should not be changed and it should not be evaluated against the other rules.\r\n\t */\r\n\tunIndentedLinePattern?: RegExp | null;\r\n\r\n}\r\n\r\n/**\r\n * Describes language specific folding markers such as '#region' and '#endregion'.\r\n * The start and end regexes will be tested against the contents of all lines and must be designed efficiently:\r\n * - the regex should start with '^'\r\n * - regexp flags (i, g) are ignored\r\n */\r\nexport interface FoldingMarkers {\r\n\tstart: RegExp;\r\n\tend: RegExp;\r\n}\r\n\r\n/**\r\n * Describes folding rules for a language.\r\n */\r\nexport interface FoldingRules {\r\n\t/**\r\n\t * Used by the indentation based strategy to decide whether empty lines belong to the previous or the next block.\r\n\t * A language adheres to the off-side rule if blocks in that language are expressed by their indentation.\r\n\t * See [wikipedia](https://en.wikipedia.org/wiki/Off-side_rule) for more information.\r\n\t * If not set, `false` is used and empty lines belong to the previous block.\r\n\t */\r\n\toffSide?: boolean;\r\n\r\n\t/**\r\n\t * Region markers used by the language.\r\n\t */\r\n\tmarkers?: FoldingMarkers;\r\n}\r\n\r\n/**\r\n * Describes a rule to be evaluated when pressing Enter.\r\n */\r\nexport interface OnEnterRule {\r\n\t/**\r\n\t * This rule will only execute if the text before the cursor matches this regular expression.\r\n\t */\r\n\tbeforeText: RegExp;\r\n\t/**\r\n\t * This rule will only execute if the text after the cursor matches this regular expression.\r\n\t */\r\n\tafterText?: RegExp;\r\n\t/**\r\n\t * This rule will only execute if the text above the this line matches this regular expression.\r\n\t */\r\n\tpreviousLineText?: RegExp;\r\n\t/**\r\n\t * The action to execute.\r\n\t */\r\n\taction: EnterAction;\r\n}\r\n\r\n/**\r\n * Definition of documentation comments (e.g. Javadoc/JSdoc)\r\n */\r\nexport interface IDocComment {\r\n\t/**\r\n\t * The string that starts a doc comment (e.g. '/**')\r\n\t */\r\n\topen: string;\r\n\t/**\r\n\t * The string that appears on the last line and closes the doc comment (e.g. ' * /').\r\n\t */\r\n\tclose?: string;\r\n}\r\n\r\n/**\r\n * A tuple of two characters, like a pair of\r\n * opening and closing brackets.\r\n */\r\nexport type CharacterPair = [string, string];\r\n\r\nexport interface IAutoClosingPair {\r\n\topen: string;\r\n\tclose: string;\r\n}\r\n\r\nexport interface IAutoClosingPairConditional extends IAutoClosingPair {\r\n\tnotIn?: string[];\r\n}\r\n\r\n/**\r\n * Describes what to do with the indentation when pressing Enter.\r\n */\r\nexport enum IndentAction {\r\n\t/**\r\n\t * Insert new line and copy the previous line's indentation.\r\n\t */\r\n\tNone = 0,\r\n\t/**\r\n\t * Insert new line and indent once (relative to the previous line's indentation).\r\n\t */\r\n\tIndent = 1,\r\n\t/**\r\n\t * Insert two new lines:\r\n\t * - the first one indented which will hold the cursor\r\n\t * - the second one at the same indentation level\r\n\t */\r\n\tIndentOutdent = 2,\r\n\t/**\r\n\t * Insert new line and outdent once (relative to the previous line's indentation).\r\n\t */\r\n\tOutdent = 3\r\n}\r\n\r\n/**\r\n * Describes what to do when pressing Enter.\r\n */\r\nexport interface EnterAction {\r\n\t/**\r\n\t * Describe what to do with the indentation.\r\n\t */\r\n\tindentAction: IndentAction;\r\n\t/**\r\n\t * Describes text to be appended after the new line and after the indentation.\r\n\t */\r\n\tappendText?: string;\r\n\t/**\r\n\t * Describes the number of characters to remove from the new line's indentation.\r\n\t */\r\n\tremoveText?: number;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface CompleteEnterAction {\r\n\t/**\r\n\t * Describe what to do with the indentation.\r\n\t */\r\n\tindentAction: IndentAction;\r\n\t/**\r\n\t * Describes text to be appended after the new line and after the indentation.\r\n\t */\r\n\tappendText: string;\r\n\t/**\r\n\t * Describes the number of characters to remove from the new line's indentation.\r\n\t */\r\n\tremoveText: number;\r\n\t/**\r\n\t * The line's indentation minus removeText\r\n\t */\r\n\tindentation: string;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport class StandardAutoClosingPairConditional {\r\n\t_standardAutoClosingPairConditionalBrand: void;\r\n\r\n\treadonly open: string;\r\n\treadonly close: string;\r\n\tprivate readonly _standardTokenMask: number;\r\n\r\n\tconstructor(source: IAutoClosingPairConditional) {\r\n\t\tthis.open = source.open;\r\n\t\tthis.close = source.close;\r\n\r\n\t\t// initially allowed in all tokens\r\n\t\tthis._standardTokenMask = 0;\r\n\r\n\t\tif (Array.isArray(source.notIn)) {\r\n\t\t\tfor (let i = 0, len = source.notIn.length; i < len; i++) {\r\n\t\t\t\tconst notIn: string = source.notIn[i];\r\n\t\t\t\tswitch (notIn) {\r\n\t\t\t\t\tcase 'string':\r\n\t\t\t\t\t\tthis._standardTokenMask |= StandardTokenType.String;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tcase 'comment':\r\n\t\t\t\t\t\tthis._standardTokenMask |= StandardTokenType.Comment;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tcase 'regex':\r\n\t\t\t\t\t\tthis._standardTokenMask |= StandardTokenType.RegEx;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic isOK(standardToken: StandardTokenType): boolean {\r\n\t\treturn (this._standardTokenMask & standardToken) === 0;\r\n\t}\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport class AutoClosingPairs {\r\n\t// it is useful to be able to get pairs using either end of open and close\r\n\r\n\t/** Key is first character of open */\r\n\tpublic readonly autoClosingPairsOpenByStart: Map;\r\n\t/** Key is last character of open */\r\n\tpublic readonly autoClosingPairsOpenByEnd: Map;\r\n\t/** Key is first character of close */\r\n\tpublic readonly autoClosingPairsCloseByStart: Map;\r\n\t/** Key is last character of close */\r\n\tpublic readonly autoClosingPairsCloseByEnd: Map;\r\n\t/** Key is close. Only has pairs that are a single character */\r\n\tpublic readonly autoClosingPairsCloseSingleChar: Map;\r\n\r\n\tconstructor(autoClosingPairs: StandardAutoClosingPairConditional[]) {\r\n\t\tthis.autoClosingPairsOpenByStart = new Map();\r\n\t\tthis.autoClosingPairsOpenByEnd = new Map();\r\n\t\tthis.autoClosingPairsCloseByStart = new Map();\r\n\t\tthis.autoClosingPairsCloseByEnd = new Map();\r\n\t\tthis.autoClosingPairsCloseSingleChar = new Map();\r\n\t\tfor (const pair of autoClosingPairs) {\r\n\t\t\tappendEntry(this.autoClosingPairsOpenByStart, pair.open.charAt(0), pair);\r\n\t\t\tappendEntry(this.autoClosingPairsOpenByEnd, pair.open.charAt(pair.open.length - 1), pair);\r\n\t\t\tappendEntry(this.autoClosingPairsCloseByStart, pair.close.charAt(0), pair);\r\n\t\t\tappendEntry(this.autoClosingPairsCloseByEnd, pair.close.charAt(pair.close.length - 1), pair);\r\n\t\t\tif (pair.close.length === 1 && pair.open.length === 1) {\r\n\t\t\t\tappendEntry(this.autoClosingPairsCloseSingleChar, pair.close, pair);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction appendEntry(target: Map, key: K, value: V): void {\r\n\tif (target.has(key)) {\r\n\t\ttarget.get(key)!.push(value);\r\n\t} else {\r\n\t\ttarget.set(key, [value]);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IRelativePattern, match as matchGlobPattern } from 'vs/base/common/glob';\r\nimport { URI } from 'vs/base/common/uri'; // TODO@Alex\r\nimport { normalize } from 'vs/base/common/path';\r\n\r\nexport interface LanguageFilter {\r\n\treadonly language?: string;\r\n\treadonly scheme?: string;\r\n\treadonly pattern?: string | IRelativePattern;\r\n\t/**\r\n\t * This provider is implemented in the UI thread.\r\n\t */\r\n\treadonly hasAccessToAllModels?: boolean;\r\n\treadonly exclusive?: boolean;\r\n}\r\n\r\nexport type LanguageSelector = string | LanguageFilter | ReadonlyArray;\r\n\r\nexport function score(selector: LanguageSelector | undefined, candidateUri: URI, candidateLanguage: string, candidateIsSynchronized: boolean): number {\r\n\r\n\tif (Array.isArray(selector)) {\r\n\t\t// array -> take max individual value\r\n\t\tlet ret = 0;\r\n\t\tfor (const filter of selector) {\r\n\t\t\tconst value = score(filter, candidateUri, candidateLanguage, candidateIsSynchronized);\r\n\t\t\tif (value === 10) {\r\n\t\t\t\treturn value; // already at the highest\r\n\t\t\t}\r\n\t\t\tif (value > ret) {\r\n\t\t\t\tret = value;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn ret;\r\n\r\n\t} else if (typeof selector === 'string') {\r\n\r\n\t\tif (!candidateIsSynchronized) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\t// short-hand notion, desugars to\r\n\t\t// 'fooLang' -> { language: 'fooLang'}\r\n\t\t// '*' -> { language: '*' }\r\n\t\tif (selector === '*') {\r\n\t\t\treturn 5;\r\n\t\t} else if (selector === candidateLanguage) {\r\n\t\t\treturn 10;\r\n\t\t} else {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t} else if (selector) {\r\n\t\t// filter -> select accordingly, use defaults for scheme\r\n\t\tconst { language, pattern, scheme, hasAccessToAllModels } = selector;\r\n\r\n\t\tif (!candidateIsSynchronized && !hasAccessToAllModels) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tlet ret = 0;\r\n\r\n\t\tif (scheme) {\r\n\t\t\tif (scheme === candidateUri.scheme) {\r\n\t\t\t\tret = 10;\r\n\t\t\t} else if (scheme === '*') {\r\n\t\t\t\tret = 5;\r\n\t\t\t} else {\r\n\t\t\t\treturn 0;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (language) {\r\n\t\t\tif (language === candidateLanguage) {\r\n\t\t\t\tret = 10;\r\n\t\t\t} else if (language === '*') {\r\n\t\t\t\tret = Math.max(ret, 5);\r\n\t\t\t} else {\r\n\t\t\t\treturn 0;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (pattern) {\r\n\t\t\tlet normalizedPattern: string | IRelativePattern;\r\n\t\t\tif (typeof pattern === 'string') {\r\n\t\t\t\tnormalizedPattern = pattern;\r\n\t\t\t} else {\r\n\t\t\t\t// Since this pattern has a `base` property, we need\r\n\t\t\t\t// to normalize this path first before passing it on\r\n\t\t\t\t// because we will compare it against `Uri.fsPath`\r\n\t\t\t\t// which uses platform specific separators.\r\n\t\t\t\t// Refs: https://github.com/microsoft/vscode/issues/99938\r\n\t\t\t\tnormalizedPattern = { ...pattern, base: normalize(pattern.base) };\r\n\t\t\t}\r\n\r\n\t\t\tif (normalizedPattern === candidateUri.fsPath || matchGlobPattern(normalizedPattern, candidateUri.fsPath)) {\r\n\t\t\t\tret = 10;\r\n\t\t\t} else {\r\n\t\t\t\treturn 0;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn ret;\r\n\r\n\t} else {\r\n\t\treturn 0;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport { CharacterClassifier } from 'vs/editor/common/core/characterClassifier';\r\nimport { ILink } from 'vs/editor/common/modes';\r\n\r\nexport interface ILinkComputerTarget {\r\n\tgetLineCount(): number;\r\n\tgetLineContent(lineNumber: number): string;\r\n}\r\n\r\nexport const enum State {\r\n\tInvalid = 0,\r\n\tStart = 1,\r\n\tH = 2,\r\n\tHT = 3,\r\n\tHTT = 4,\r\n\tHTTP = 5,\r\n\tF = 6,\r\n\tFI = 7,\r\n\tFIL = 8,\r\n\tBeforeColon = 9,\r\n\tAfterColon = 10,\r\n\tAlmostThere = 11,\r\n\tEnd = 12,\r\n\tAccept = 13,\r\n\tLastKnownState = 14 // marker, custom states may follow\r\n}\r\n\r\nexport type Edge = [State, number, State];\r\n\r\nexport class Uint8Matrix {\r\n\r\n\tprivate readonly _data: Uint8Array;\r\n\tpublic readonly rows: number;\r\n\tpublic readonly cols: number;\r\n\r\n\tconstructor(rows: number, cols: number, defaultValue: number) {\r\n\t\tconst data = new Uint8Array(rows * cols);\r\n\t\tfor (let i = 0, len = rows * cols; i < len; i++) {\r\n\t\t\tdata[i] = defaultValue;\r\n\t\t}\r\n\r\n\t\tthis._data = data;\r\n\t\tthis.rows = rows;\r\n\t\tthis.cols = cols;\r\n\t}\r\n\r\n\tpublic get(row: number, col: number): number {\r\n\t\treturn this._data[row * this.cols + col];\r\n\t}\r\n\r\n\tpublic set(row: number, col: number, value: number): void {\r\n\t\tthis._data[row * this.cols + col] = value;\r\n\t}\r\n}\r\n\r\nexport class StateMachine {\r\n\r\n\tprivate readonly _states: Uint8Matrix;\r\n\tprivate readonly _maxCharCode: number;\r\n\r\n\tconstructor(edges: Edge[]) {\r\n\t\tlet maxCharCode = 0;\r\n\t\tlet maxState = State.Invalid;\r\n\t\tfor (let i = 0, len = edges.length; i < len; i++) {\r\n\t\t\tlet [from, chCode, to] = edges[i];\r\n\t\t\tif (chCode > maxCharCode) {\r\n\t\t\t\tmaxCharCode = chCode;\r\n\t\t\t}\r\n\t\t\tif (from > maxState) {\r\n\t\t\t\tmaxState = from;\r\n\t\t\t}\r\n\t\t\tif (to > maxState) {\r\n\t\t\t\tmaxState = to;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tmaxCharCode++;\r\n\t\tmaxState++;\r\n\r\n\t\tlet states = new Uint8Matrix(maxState, maxCharCode, State.Invalid);\r\n\t\tfor (let i = 0, len = edges.length; i < len; i++) {\r\n\t\t\tlet [from, chCode, to] = edges[i];\r\n\t\t\tstates.set(from, chCode, to);\r\n\t\t}\r\n\r\n\t\tthis._states = states;\r\n\t\tthis._maxCharCode = maxCharCode;\r\n\t}\r\n\r\n\tpublic nextState(currentState: State, chCode: number): State {\r\n\t\tif (chCode < 0 || chCode >= this._maxCharCode) {\r\n\t\t\treturn State.Invalid;\r\n\t\t}\r\n\t\treturn this._states.get(currentState, chCode);\r\n\t}\r\n}\r\n\r\n// State machine for http:// or https:// or file://\r\nlet _stateMachine: StateMachine | null = null;\r\nfunction getStateMachine(): StateMachine {\r\n\tif (_stateMachine === null) {\r\n\t\t_stateMachine = new StateMachine([\r\n\t\t\t[State.Start, CharCode.h, State.H],\r\n\t\t\t[State.Start, CharCode.H, State.H],\r\n\t\t\t[State.Start, CharCode.f, State.F],\r\n\t\t\t[State.Start, CharCode.F, State.F],\r\n\r\n\t\t\t[State.H, CharCode.t, State.HT],\r\n\t\t\t[State.H, CharCode.T, State.HT],\r\n\r\n\t\t\t[State.HT, CharCode.t, State.HTT],\r\n\t\t\t[State.HT, CharCode.T, State.HTT],\r\n\r\n\t\t\t[State.HTT, CharCode.p, State.HTTP],\r\n\t\t\t[State.HTT, CharCode.P, State.HTTP],\r\n\r\n\t\t\t[State.HTTP, CharCode.s, State.BeforeColon],\r\n\t\t\t[State.HTTP, CharCode.S, State.BeforeColon],\r\n\t\t\t[State.HTTP, CharCode.Colon, State.AfterColon],\r\n\r\n\t\t\t[State.F, CharCode.i, State.FI],\r\n\t\t\t[State.F, CharCode.I, State.FI],\r\n\r\n\t\t\t[State.FI, CharCode.l, State.FIL],\r\n\t\t\t[State.FI, CharCode.L, State.FIL],\r\n\r\n\t\t\t[State.FIL, CharCode.e, State.BeforeColon],\r\n\t\t\t[State.FIL, CharCode.E, State.BeforeColon],\r\n\r\n\t\t\t[State.BeforeColon, CharCode.Colon, State.AfterColon],\r\n\r\n\t\t\t[State.AfterColon, CharCode.Slash, State.AlmostThere],\r\n\r\n\t\t\t[State.AlmostThere, CharCode.Slash, State.End],\r\n\t\t]);\r\n\t}\r\n\treturn _stateMachine;\r\n}\r\n\r\n\r\nconst enum CharacterClass {\r\n\tNone = 0,\r\n\tForceTermination = 1,\r\n\tCannotEndIn = 2\r\n}\r\n\r\nlet _classifier: CharacterClassifier | null = null;\r\nfunction getClassifier(): CharacterClassifier {\r\n\tif (_classifier === null) {\r\n\t\t_classifier = new CharacterClassifier(CharacterClass.None);\r\n\r\n\t\tconst FORCE_TERMINATION_CHARACTERS = ' \\t<>\\'\\\"、。。、,.:;‘“〈《「『【〔([{「」}])〕】』」》〉”’`~…';\r\n\t\tfor (let i = 0; i < FORCE_TERMINATION_CHARACTERS.length; i++) {\r\n\t\t\t_classifier.set(FORCE_TERMINATION_CHARACTERS.charCodeAt(i), CharacterClass.ForceTermination);\r\n\t\t}\r\n\r\n\t\tconst CANNOT_END_WITH_CHARACTERS = '.,;';\r\n\t\tfor (let i = 0; i < CANNOT_END_WITH_CHARACTERS.length; i++) {\r\n\t\t\t_classifier.set(CANNOT_END_WITH_CHARACTERS.charCodeAt(i), CharacterClass.CannotEndIn);\r\n\t\t}\r\n\t}\r\n\treturn _classifier;\r\n}\r\n\r\nexport class LinkComputer {\r\n\r\n\tprivate static _createLink(classifier: CharacterClassifier, line: string, lineNumber: number, linkBeginIndex: number, linkEndIndex: number): ILink {\r\n\t\t// Do not allow to end link in certain characters...\r\n\t\tlet lastIncludedCharIndex = linkEndIndex - 1;\r\n\t\tdo {\r\n\t\t\tconst chCode = line.charCodeAt(lastIncludedCharIndex);\r\n\t\t\tconst chClass = classifier.get(chCode);\r\n\t\t\tif (chClass !== CharacterClass.CannotEndIn) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tlastIncludedCharIndex--;\r\n\t\t} while (lastIncludedCharIndex > linkBeginIndex);\r\n\r\n\t\t// Handle links enclosed in parens, square brackets and curlys.\r\n\t\tif (linkBeginIndex > 0) {\r\n\t\t\tconst charCodeBeforeLink = line.charCodeAt(linkBeginIndex - 1);\r\n\t\t\tconst lastCharCodeInLink = line.charCodeAt(lastIncludedCharIndex);\r\n\r\n\t\t\tif (\r\n\t\t\t\t(charCodeBeforeLink === CharCode.OpenParen && lastCharCodeInLink === CharCode.CloseParen)\r\n\t\t\t\t|| (charCodeBeforeLink === CharCode.OpenSquareBracket && lastCharCodeInLink === CharCode.CloseSquareBracket)\r\n\t\t\t\t|| (charCodeBeforeLink === CharCode.OpenCurlyBrace && lastCharCodeInLink === CharCode.CloseCurlyBrace)\r\n\t\t\t) {\r\n\t\t\t\t// Do not end in ) if ( is before the link start\r\n\t\t\t\t// Do not end in ] if [ is before the link start\r\n\t\t\t\t// Do not end in } if { is before the link start\r\n\t\t\t\tlastIncludedCharIndex--;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\trange: {\r\n\t\t\t\tstartLineNumber: lineNumber,\r\n\t\t\t\tstartColumn: linkBeginIndex + 1,\r\n\t\t\t\tendLineNumber: lineNumber,\r\n\t\t\t\tendColumn: lastIncludedCharIndex + 2\r\n\t\t\t},\r\n\t\t\turl: line.substring(linkBeginIndex, lastIncludedCharIndex + 1)\r\n\t\t};\r\n\t}\r\n\r\n\tpublic static computeLinks(model: ILinkComputerTarget, stateMachine: StateMachine = getStateMachine()): ILink[] {\r\n\t\tconst classifier = getClassifier();\r\n\r\n\t\tlet result: ILink[] = [];\r\n\t\tfor (let i = 1, lineCount = model.getLineCount(); i <= lineCount; i++) {\r\n\t\t\tconst line = model.getLineContent(i);\r\n\t\t\tconst len = line.length;\r\n\r\n\t\t\tlet j = 0;\r\n\t\t\tlet linkBeginIndex = 0;\r\n\t\t\tlet linkBeginChCode = 0;\r\n\t\t\tlet state = State.Start;\r\n\t\t\tlet hasOpenParens = false;\r\n\t\t\tlet hasOpenSquareBracket = false;\r\n\t\t\tlet inSquareBrackets = false;\r\n\t\t\tlet hasOpenCurlyBracket = false;\r\n\r\n\t\t\twhile (j < len) {\r\n\r\n\t\t\t\tlet resetStateMachine = false;\r\n\t\t\t\tconst chCode = line.charCodeAt(j);\r\n\r\n\t\t\t\tif (state === State.Accept) {\r\n\t\t\t\t\tlet chClass: CharacterClass;\r\n\t\t\t\t\tswitch (chCode) {\r\n\t\t\t\t\t\tcase CharCode.OpenParen:\r\n\t\t\t\t\t\t\thasOpenParens = true;\r\n\t\t\t\t\t\t\tchClass = CharacterClass.None;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\tcase CharCode.CloseParen:\r\n\t\t\t\t\t\t\tchClass = (hasOpenParens ? CharacterClass.None : CharacterClass.ForceTermination);\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\tcase CharCode.OpenSquareBracket:\r\n\t\t\t\t\t\t\tinSquareBrackets = true;\r\n\t\t\t\t\t\t\thasOpenSquareBracket = true;\r\n\t\t\t\t\t\t\tchClass = CharacterClass.None;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\tcase CharCode.CloseSquareBracket:\r\n\t\t\t\t\t\t\tinSquareBrackets = false;\r\n\t\t\t\t\t\t\tchClass = (hasOpenSquareBracket ? CharacterClass.None : CharacterClass.ForceTermination);\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\tcase CharCode.OpenCurlyBrace:\r\n\t\t\t\t\t\t\thasOpenCurlyBracket = true;\r\n\t\t\t\t\t\t\tchClass = CharacterClass.None;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\tcase CharCode.CloseCurlyBrace:\r\n\t\t\t\t\t\t\tchClass = (hasOpenCurlyBracket ? CharacterClass.None : CharacterClass.ForceTermination);\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t/* The following three rules make it that ' or \" or ` are allowed inside links if the link began with a different one */\r\n\t\t\t\t\t\tcase CharCode.SingleQuote:\r\n\t\t\t\t\t\t\tchClass = (linkBeginChCode === CharCode.DoubleQuote || linkBeginChCode === CharCode.BackTick) ? CharacterClass.None : CharacterClass.ForceTermination;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\tcase CharCode.DoubleQuote:\r\n\t\t\t\t\t\t\tchClass = (linkBeginChCode === CharCode.SingleQuote || linkBeginChCode === CharCode.BackTick) ? CharacterClass.None : CharacterClass.ForceTermination;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\tcase CharCode.BackTick:\r\n\t\t\t\t\t\t\tchClass = (linkBeginChCode === CharCode.SingleQuote || linkBeginChCode === CharCode.DoubleQuote) ? CharacterClass.None : CharacterClass.ForceTermination;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\tcase CharCode.Asterisk:\r\n\t\t\t\t\t\t\t// `*` terminates a link if the link began with `*`\r\n\t\t\t\t\t\t\tchClass = (linkBeginChCode === CharCode.Asterisk) ? CharacterClass.ForceTermination : CharacterClass.None;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\tcase CharCode.Pipe:\r\n\t\t\t\t\t\t\t// `|` terminates a link if the link began with `|`\r\n\t\t\t\t\t\t\tchClass = (linkBeginChCode === CharCode.Pipe) ? CharacterClass.ForceTermination : CharacterClass.None;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\tcase CharCode.Space:\r\n\t\t\t\t\t\t\t// ` ` allow space in between [ and ]\r\n\t\t\t\t\t\t\tchClass = (inSquareBrackets ? CharacterClass.None : CharacterClass.ForceTermination);\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\tdefault:\r\n\t\t\t\t\t\t\tchClass = classifier.get(chCode);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t// Check if character terminates link\r\n\t\t\t\t\tif (chClass === CharacterClass.ForceTermination) {\r\n\t\t\t\t\t\tresult.push(LinkComputer._createLink(classifier, line, i, linkBeginIndex, j));\r\n\t\t\t\t\t\tresetStateMachine = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t} else if (state === State.End) {\r\n\r\n\t\t\t\t\tlet chClass: CharacterClass;\r\n\t\t\t\t\tif (chCode === CharCode.OpenSquareBracket) {\r\n\t\t\t\t\t\t// Allow for the authority part to contain ipv6 addresses which contain [ and ]\r\n\t\t\t\t\t\thasOpenSquareBracket = true;\r\n\t\t\t\t\t\tchClass = CharacterClass.None;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tchClass = classifier.get(chCode);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t// Check if character terminates link\r\n\t\t\t\t\tif (chClass === CharacterClass.ForceTermination) {\r\n\t\t\t\t\t\tresetStateMachine = true;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tstate = State.Accept;\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tstate = stateMachine.nextState(state, chCode);\r\n\t\t\t\t\tif (state === State.Invalid) {\r\n\t\t\t\t\t\tresetStateMachine = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (resetStateMachine) {\r\n\t\t\t\t\tstate = State.Start;\r\n\t\t\t\t\thasOpenParens = false;\r\n\t\t\t\t\thasOpenSquareBracket = false;\r\n\t\t\t\t\thasOpenCurlyBracket = false;\r\n\r\n\t\t\t\t\t// Record where the link started\r\n\t\t\t\t\tlinkBeginIndex = j + 1;\r\n\t\t\t\t\tlinkBeginChCode = chCode;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tj++;\r\n\t\t\t}\r\n\r\n\t\t\tif (state === State.Accept) {\r\n\t\t\t\tresult.push(LinkComputer._createLink(classifier, line, i, linkBeginIndex, len));\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n}\r\n\r\n/**\r\n * Returns an array of all links contains in the provided\r\n * document. *Note* that this operation is computational\r\n * expensive and should not run in the UI thread.\r\n */\r\nexport function computeLinks(model: ILinkComputerTarget | null): ILink[] {\r\n\tif (!model || typeof model.getLineCount !== 'function' || typeof model.getLineContent !== 'function') {\r\n\t\t// Unknown caller!\r\n\t\treturn [];\r\n\t}\r\n\treturn LinkComputer.computeLinks(model);\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { LineTokens } from 'vs/editor/common/core/lineTokens';\r\nimport * as modes from 'vs/editor/common/modes';\r\n\r\nexport function createScopedLineTokens(context: LineTokens, offset: number): ScopedLineTokens {\r\n\tlet tokenCount = context.getCount();\r\n\tlet tokenIndex = context.findTokenIndexAtOffset(offset);\r\n\tlet desiredLanguageId = context.getLanguageId(tokenIndex);\r\n\r\n\tlet lastTokenIndex = tokenIndex;\r\n\twhile (lastTokenIndex + 1 < tokenCount && context.getLanguageId(lastTokenIndex + 1) === desiredLanguageId) {\r\n\t\tlastTokenIndex++;\r\n\t}\r\n\r\n\tlet firstTokenIndex = tokenIndex;\r\n\twhile (firstTokenIndex > 0 && context.getLanguageId(firstTokenIndex - 1) === desiredLanguageId) {\r\n\t\tfirstTokenIndex--;\r\n\t}\r\n\r\n\treturn new ScopedLineTokens(\r\n\t\tcontext,\r\n\t\tdesiredLanguageId,\r\n\t\tfirstTokenIndex,\r\n\t\tlastTokenIndex + 1,\r\n\t\tcontext.getStartOffset(firstTokenIndex),\r\n\t\tcontext.getEndOffset(lastTokenIndex)\r\n\t);\r\n}\r\n\r\nexport class ScopedLineTokens {\r\n\t_scopedLineTokensBrand: void;\r\n\r\n\tpublic readonly languageId: modes.LanguageId;\r\n\tprivate readonly _actual: LineTokens;\r\n\tprivate readonly _firstTokenIndex: number;\r\n\tprivate readonly _lastTokenIndex: number;\r\n\tpublic readonly firstCharOffset: number;\r\n\tprivate readonly _lastCharOffset: number;\r\n\r\n\tconstructor(\r\n\t\tactual: LineTokens,\r\n\t\tlanguageId: modes.LanguageId,\r\n\t\tfirstTokenIndex: number,\r\n\t\tlastTokenIndex: number,\r\n\t\tfirstCharOffset: number,\r\n\t\tlastCharOffset: number\r\n\t) {\r\n\t\tthis._actual = actual;\r\n\t\tthis.languageId = languageId;\r\n\t\tthis._firstTokenIndex = firstTokenIndex;\r\n\t\tthis._lastTokenIndex = lastTokenIndex;\r\n\t\tthis.firstCharOffset = firstCharOffset;\r\n\t\tthis._lastCharOffset = lastCharOffset;\r\n\t}\r\n\r\n\tpublic getLineContent(): string {\r\n\t\tconst actualLineContent = this._actual.getLineContent();\r\n\t\treturn actualLineContent.substring(this.firstCharOffset, this._lastCharOffset);\r\n\t}\r\n\r\n\tpublic getActualLineContentBefore(offset: number): string {\r\n\t\tconst actualLineContent = this._actual.getLineContent();\r\n\t\treturn actualLineContent.substring(0, this.firstCharOffset + offset);\r\n\t}\r\n\r\n\tpublic getTokenCount(): number {\r\n\t\treturn this._lastTokenIndex - this._firstTokenIndex;\r\n\t}\r\n\r\n\tpublic findTokenIndexAtOffset(offset: number): number {\r\n\t\treturn this._actual.findTokenIndexAtOffset(offset + this.firstCharOffset) - this._firstTokenIndex;\r\n\t}\r\n\r\n\tpublic getStandardTokenType(tokenIndex: number): modes.StandardTokenType {\r\n\t\treturn this._actual.getStandardTokenType(tokenIndex + this._firstTokenIndex);\r\n\t}\r\n}\r\n\r\nconst enum IgnoreBracketsInTokens {\r\n\tvalue = modes.StandardTokenType.Comment | modes.StandardTokenType.String | modes.StandardTokenType.RegEx\r\n}\r\n\r\nexport function ignoreBracketsInToken(standardTokenType: modes.StandardTokenType): boolean {\r\n\treturn (standardTokenType & IgnoreBracketsInTokens.value) !== 0;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IAutoClosingPair, StandardAutoClosingPairConditional, LanguageConfiguration } from 'vs/editor/common/modes/languageConfiguration';\r\nimport { ScopedLineTokens } from 'vs/editor/common/modes/supports';\r\n\r\nexport class CharacterPairSupport {\r\n\r\n\tstatic readonly DEFAULT_AUTOCLOSE_BEFORE_LANGUAGE_DEFINED = ';:.,=}])> \\n\\t';\r\n\r\n\tprivate readonly _autoClosingPairs: StandardAutoClosingPairConditional[];\r\n\tprivate readonly _surroundingPairs: IAutoClosingPair[];\r\n\tprivate readonly _autoCloseBefore: string;\r\n\r\n\tconstructor(config: LanguageConfiguration) {\r\n\t\tif (config.autoClosingPairs) {\r\n\t\t\tthis._autoClosingPairs = config.autoClosingPairs.map(el => new StandardAutoClosingPairConditional(el));\r\n\t\t} else if (config.brackets) {\r\n\t\t\tthis._autoClosingPairs = config.brackets.map(b => new StandardAutoClosingPairConditional({ open: b[0], close: b[1] }));\r\n\t\t} else {\r\n\t\t\tthis._autoClosingPairs = [];\r\n\t\t}\r\n\r\n\t\tif (config.__electricCharacterSupport && config.__electricCharacterSupport.docComment) {\r\n\t\t\tconst docComment = config.__electricCharacterSupport.docComment;\r\n\t\t\t// IDocComment is legacy, only partially supported\r\n\t\t\tthis._autoClosingPairs.push(new StandardAutoClosingPairConditional({ open: docComment.open, close: docComment.close || '' }));\r\n\t\t}\r\n\r\n\t\tthis._autoCloseBefore = typeof config.autoCloseBefore === 'string' ? config.autoCloseBefore : CharacterPairSupport.DEFAULT_AUTOCLOSE_BEFORE_LANGUAGE_DEFINED;\r\n\r\n\t\tthis._surroundingPairs = config.surroundingPairs || this._autoClosingPairs;\r\n\t}\r\n\r\n\tpublic getAutoClosingPairs(): StandardAutoClosingPairConditional[] {\r\n\t\treturn this._autoClosingPairs;\r\n\t}\r\n\r\n\tpublic getAutoCloseBeforeSet(): string {\r\n\t\treturn this._autoCloseBefore;\r\n\t}\r\n\r\n\tpublic static shouldAutoClosePair(autoClosingPair: StandardAutoClosingPairConditional, context: ScopedLineTokens, column: number): boolean {\r\n\t\t// Always complete on empty line\r\n\t\tif (context.getTokenCount() === 0) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tconst tokenIndex = context.findTokenIndexAtOffset(column - 2);\r\n\t\tconst standardTokenType = context.getStandardTokenType(tokenIndex);\r\n\t\treturn autoClosingPair.isOK(standardTokenType);\r\n\t}\r\n\r\n\tpublic getSurroundingPairs(): IAutoClosingPair[] {\r\n\t\treturn this._surroundingPairs;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IndentationRule } from 'vs/editor/common/modes/languageConfiguration';\r\n\r\nexport const enum IndentConsts {\r\n\tINCREASE_MASK = 0b00000001,\r\n\tDECREASE_MASK = 0b00000010,\r\n\tINDENT_NEXTLINE_MASK = 0b00000100,\r\n\tUNINDENT_MASK = 0b00001000,\r\n}\r\n\r\nfunction resetGlobalRegex(reg: RegExp) {\r\n\tif (reg.global) {\r\n\t\treg.lastIndex = 0;\r\n\t}\r\n\r\n\treturn true;\r\n}\r\n\r\nexport class IndentRulesSupport {\r\n\r\n\tprivate readonly _indentationRules: IndentationRule;\r\n\r\n\tconstructor(indentationRules: IndentationRule) {\r\n\t\tthis._indentationRules = indentationRules;\r\n\t}\r\n\r\n\tpublic shouldIncrease(text: string): boolean {\r\n\t\tif (this._indentationRules) {\r\n\t\t\tif (this._indentationRules.increaseIndentPattern && resetGlobalRegex(this._indentationRules.increaseIndentPattern) && this._indentationRules.increaseIndentPattern.test(text)) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t\t// if (this._indentationRules.indentNextLinePattern && this._indentationRules.indentNextLinePattern.test(text)) {\r\n\t\t\t// \treturn true;\r\n\t\t\t// }\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic shouldDecrease(text: string): boolean {\r\n\t\tif (this._indentationRules && this._indentationRules.decreaseIndentPattern && resetGlobalRegex(this._indentationRules.decreaseIndentPattern) && this._indentationRules.decreaseIndentPattern.test(text)) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic shouldIndentNextLine(text: string): boolean {\r\n\t\tif (this._indentationRules && this._indentationRules.indentNextLinePattern && resetGlobalRegex(this._indentationRules.indentNextLinePattern) && this._indentationRules.indentNextLinePattern.test(text)) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic shouldIgnore(text: string): boolean {\r\n\t\t// the text matches `unIndentedLinePattern`\r\n\t\tif (this._indentationRules && this._indentationRules.unIndentedLinePattern && resetGlobalRegex(this._indentationRules.unIndentedLinePattern) && this._indentationRules.unIndentedLinePattern.test(text)) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic getIndentMetadata(text: string): number {\r\n\t\tlet ret = 0;\r\n\t\tif (this.shouldIncrease(text)) {\r\n\t\t\tret += IndentConsts.INCREASE_MASK;\r\n\t\t}\r\n\t\tif (this.shouldDecrease(text)) {\r\n\t\t\tret += IndentConsts.DECREASE_MASK;\r\n\t\t}\r\n\t\tif (this.shouldIndentNextLine(text)) {\r\n\t\t\tret += IndentConsts.INDENT_NEXTLINE_MASK;\r\n\t\t}\r\n\t\tif (this.shouldIgnore(text)) {\r\n\t\t\tret += IndentConsts.UNINDENT_MASK;\r\n\t\t}\r\n\t\treturn ret;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IRange } from 'vs/editor/common/core/range';\r\nimport { IInplaceReplaceSupportResult } from 'vs/editor/common/modes';\r\n\r\nexport class BasicInplaceReplace {\r\n\r\n\tpublic static readonly INSTANCE = new BasicInplaceReplace();\r\n\r\n\tpublic navigateValueSet(range1: IRange, text1: string, range2: IRange, text2: string | null, up: boolean): IInplaceReplaceSupportResult | null {\r\n\r\n\t\tif (range1 && text1) {\r\n\t\t\tlet result = this.doNavigateValueSet(text1, up);\r\n\t\t\tif (result) {\r\n\t\t\t\treturn {\r\n\t\t\t\t\trange: range1,\r\n\t\t\t\t\tvalue: result\r\n\t\t\t\t};\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (range2 && text2) {\r\n\t\t\tlet result = this.doNavigateValueSet(text2, up);\r\n\t\t\tif (result) {\r\n\t\t\t\treturn {\r\n\t\t\t\t\trange: range2,\r\n\t\t\t\t\tvalue: result\r\n\t\t\t\t};\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate doNavigateValueSet(text: string, up: boolean): string | null {\r\n\t\tlet numberResult = this.numberReplace(text, up);\r\n\t\tif (numberResult !== null) {\r\n\t\t\treturn numberResult;\r\n\t\t}\r\n\t\treturn this.textReplace(text, up);\r\n\t}\r\n\r\n\tprivate numberReplace(value: string, up: boolean): string | null {\r\n\t\tlet precision = Math.pow(10, value.length - (value.lastIndexOf('.') + 1));\r\n\t\tlet n1 = Number(value);\r\n\t\tlet n2 = parseFloat(value);\r\n\r\n\t\tif (!isNaN(n1) && !isNaN(n2) && n1 === n2) {\r\n\r\n\t\t\tif (n1 === 0 && !up) {\r\n\t\t\t\treturn null; // don't do negative\r\n\t\t\t\t//\t\t\t} else if(n1 === 9 && up) {\r\n\t\t\t\t//\t\t\t\treturn null; // don't insert 10 into a number\r\n\t\t\t} else {\r\n\t\t\t\tn1 = Math.floor(n1 * precision);\r\n\t\t\t\tn1 += up ? precision : -precision;\r\n\t\t\t\treturn String(n1 / precision);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate readonly _defaultValueSet: string[][] = [\r\n\t\t['true', 'false'],\r\n\t\t['True', 'False'],\r\n\t\t['Private', 'Public', 'Friend', 'ReadOnly', 'Partial', 'Protected', 'WriteOnly'],\r\n\t\t['public', 'protected', 'private'],\r\n\t];\r\n\r\n\tprivate textReplace(value: string, up: boolean): string | null {\r\n\t\treturn this.valueSetsReplace(this._defaultValueSet, value, up);\r\n\t}\r\n\r\n\tprivate valueSetsReplace(valueSets: string[][], value: string, up: boolean): string | null {\r\n\t\tlet result: string | null = null;\r\n\t\tfor (let i = 0, len = valueSets.length; result === null && i < len; i++) {\r\n\t\t\tresult = this.valueSetReplace(valueSets[i], value, up);\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate valueSetReplace(valueSet: string[], value: string, up: boolean): string | null {\r\n\t\tlet idx = valueSet.indexOf(value);\r\n\t\tif (idx >= 0) {\r\n\t\t\tidx += up ? +1 : -1;\r\n\t\t\tif (idx < 0) {\r\n\t\t\t\tidx = valueSet.length - 1;\r\n\t\t\t} else {\r\n\t\t\t\tidx %= valueSet.length;\r\n\t\t\t}\r\n\t\t\treturn valueSet[idx];\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { CharacterPair, EnterAction, IndentAction, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration';\r\nimport { EditorAutoIndentStrategy } from 'vs/editor/common/config/editorOptions';\r\n\r\nexport interface IOnEnterSupportOptions {\r\n\tbrackets?: CharacterPair[];\r\n\tonEnterRules?: OnEnterRule[];\r\n}\r\n\r\ninterface IProcessedBracketPair {\r\n\topen: string;\r\n\tclose: string;\r\n\topenRegExp: RegExp;\r\n\tcloseRegExp: RegExp;\r\n}\r\n\r\nexport class OnEnterSupport {\r\n\r\n\tprivate readonly _brackets: IProcessedBracketPair[];\r\n\tprivate readonly _regExpRules: OnEnterRule[];\r\n\r\n\tconstructor(opts: IOnEnterSupportOptions) {\r\n\t\topts = opts || {};\r\n\t\topts.brackets = opts.brackets || [\r\n\t\t\t['(', ')'],\r\n\t\t\t['{', '}'],\r\n\t\t\t['[', ']']\r\n\t\t];\r\n\r\n\t\tthis._brackets = [];\r\n\t\topts.brackets.forEach((bracket) => {\r\n\t\t\tconst openRegExp = OnEnterSupport._createOpenBracketRegExp(bracket[0]);\r\n\t\t\tconst closeRegExp = OnEnterSupport._createCloseBracketRegExp(bracket[1]);\r\n\t\t\tif (openRegExp && closeRegExp) {\r\n\t\t\t\tthis._brackets.push({\r\n\t\t\t\t\topen: bracket[0],\r\n\t\t\t\t\topenRegExp: openRegExp,\r\n\t\t\t\t\tclose: bracket[1],\r\n\t\t\t\t\tcloseRegExp: closeRegExp,\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t});\r\n\t\tthis._regExpRules = opts.onEnterRules || [];\r\n\t}\r\n\r\n\tpublic onEnter(autoIndent: EditorAutoIndentStrategy, previousLineText: string, beforeEnterText: string, afterEnterText: string): EnterAction | null {\r\n\t\t// (1): `regExpRules`\r\n\t\tif (autoIndent >= EditorAutoIndentStrategy.Advanced) {\r\n\t\t\tfor (let i = 0, len = this._regExpRules.length; i < len; i++) {\r\n\t\t\t\tlet rule = this._regExpRules[i];\r\n\t\t\t\tconst regResult = [{\r\n\t\t\t\t\treg: rule.beforeText,\r\n\t\t\t\t\ttext: beforeEnterText\r\n\t\t\t\t}, {\r\n\t\t\t\t\treg: rule.afterText,\r\n\t\t\t\t\ttext: afterEnterText\r\n\t\t\t\t}, {\r\n\t\t\t\t\treg: rule.previousLineText,\r\n\t\t\t\t\ttext: previousLineText\r\n\t\t\t\t}].every((obj): boolean => {\r\n\t\t\t\t\treturn obj.reg ? obj.reg.test(obj.text) : true;\r\n\t\t\t\t});\r\n\r\n\t\t\t\tif (regResult) {\r\n\t\t\t\t\treturn rule.action;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// (2): Special indent-outdent\r\n\t\tif (autoIndent >= EditorAutoIndentStrategy.Brackets) {\r\n\t\t\tif (beforeEnterText.length > 0 && afterEnterText.length > 0) {\r\n\t\t\t\tfor (let i = 0, len = this._brackets.length; i < len; i++) {\r\n\t\t\t\t\tlet bracket = this._brackets[i];\r\n\t\t\t\t\tif (bracket.openRegExp.test(beforeEnterText) && bracket.closeRegExp.test(afterEnterText)) {\r\n\t\t\t\t\t\treturn { indentAction: IndentAction.IndentOutdent };\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\r\n\t\t// (4): Open bracket based logic\r\n\t\tif (autoIndent >= EditorAutoIndentStrategy.Brackets) {\r\n\t\t\tif (beforeEnterText.length > 0) {\r\n\t\t\t\tfor (let i = 0, len = this._brackets.length; i < len; i++) {\r\n\t\t\t\t\tlet bracket = this._brackets[i];\r\n\t\t\t\t\tif (bracket.openRegExp.test(beforeEnterText)) {\r\n\t\t\t\t\t\treturn { indentAction: IndentAction.Indent };\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate static _createOpenBracketRegExp(bracket: string): RegExp | null {\r\n\t\tlet str = strings.escapeRegExpCharacters(bracket);\r\n\t\tif (!/\\B/.test(str.charAt(0))) {\r\n\t\t\tstr = '\\\\b' + str;\r\n\t\t}\r\n\t\tstr += '\\\\s*$';\r\n\t\treturn OnEnterSupport._safeRegExp(str);\r\n\t}\r\n\r\n\tprivate static _createCloseBracketRegExp(bracket: string): RegExp | null {\r\n\t\tlet str = strings.escapeRegExpCharacters(bracket);\r\n\t\tif (!/\\B/.test(str.charAt(str.length - 1))) {\r\n\t\t\tstr = str + '\\\\b';\r\n\t\t}\r\n\t\tstr = '^\\\\s*' + str;\r\n\t\treturn OnEnterSupport._safeRegExp(str);\r\n\t}\r\n\r\n\tprivate static _safeRegExp(def: string): RegExp | null {\r\n\t\ttry {\r\n\t\t\treturn new RegExp(def);\r\n\t\t} catch (err) {\r\n\t\t\tonUnexpectedError(err);\r\n\t\t\treturn null;\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as strings from 'vs/base/common/strings';\r\nimport * as stringBuilder from 'vs/editor/common/core/stringBuilder';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { LanguageIdentifier } from 'vs/editor/common/modes';\r\nimport { CharacterPair } from 'vs/editor/common/modes/languageConfiguration';\r\n\r\ninterface InternalBracket {\r\n\topen: string[];\r\n\tclose: string[];\r\n}\r\n\r\nexport class RichEditBracket {\r\n\t_richEditBracketBrand: void;\r\n\r\n\treadonly languageIdentifier: LanguageIdentifier;\r\n\treadonly index: number;\r\n\treadonly open: string[];\r\n\treadonly close: string[];\r\n\treadonly forwardRegex: RegExp;\r\n\treadonly reversedRegex: RegExp;\r\n\tprivate readonly _openSet: Set;\r\n\tprivate readonly _closeSet: Set;\r\n\r\n\tconstructor(languageIdentifier: LanguageIdentifier, index: number, open: string[], close: string[], forwardRegex: RegExp, reversedRegex: RegExp) {\r\n\t\tthis.languageIdentifier = languageIdentifier;\r\n\t\tthis.index = index;\r\n\t\tthis.open = open;\r\n\t\tthis.close = close;\r\n\t\tthis.forwardRegex = forwardRegex;\r\n\t\tthis.reversedRegex = reversedRegex;\r\n\t\tthis._openSet = RichEditBracket._toSet(this.open);\r\n\t\tthis._closeSet = RichEditBracket._toSet(this.close);\r\n\t}\r\n\r\n\tpublic isOpen(text: string) {\r\n\t\treturn this._openSet.has(text);\r\n\t}\r\n\r\n\tpublic isClose(text: string) {\r\n\t\treturn this._closeSet.has(text);\r\n\t}\r\n\r\n\tprivate static _toSet(arr: string[]): Set {\r\n\t\tconst result = new Set();\r\n\t\tfor (const element of arr) {\r\n\t\t\tresult.add(element);\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n}\r\n\r\nfunction groupFuzzyBrackets(brackets: CharacterPair[]): InternalBracket[] {\r\n\tconst N = brackets.length;\r\n\r\n\tbrackets = brackets.map(b => [b[0].toLowerCase(), b[1].toLowerCase()]);\r\n\r\n\tconst group: number[] = [];\r\n\tfor (let i = 0; i < N; i++) {\r\n\t\tgroup[i] = i;\r\n\t}\r\n\r\n\tconst areOverlapping = (a: CharacterPair, b: CharacterPair) => {\r\n\t\tconst [aOpen, aClose] = a;\r\n\t\tconst [bOpen, bClose] = b;\r\n\t\treturn (aOpen === bOpen || aOpen === bClose || aClose === bOpen || aClose === bClose);\r\n\t};\r\n\r\n\tconst mergeGroups = (g1: number, g2: number) => {\r\n\t\tconst newG = Math.min(g1, g2);\r\n\t\tconst oldG = Math.max(g1, g2);\r\n\t\tfor (let i = 0; i < N; i++) {\r\n\t\t\tif (group[i] === oldG) {\r\n\t\t\t\tgroup[i] = newG;\r\n\t\t\t}\r\n\t\t}\r\n\t};\r\n\r\n\t// group together brackets that have the same open or the same close sequence\r\n\tfor (let i = 0; i < N; i++) {\r\n\t\tconst a = brackets[i];\r\n\t\tfor (let j = i + 1; j < N; j++) {\r\n\t\t\tconst b = brackets[j];\r\n\t\t\tif (areOverlapping(a, b)) {\r\n\t\t\t\tmergeGroups(group[i], group[j]);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tconst result: InternalBracket[] = [];\r\n\tfor (let g = 0; g < N; g++) {\r\n\t\tlet currentOpen: string[] = [];\r\n\t\tlet currentClose: string[] = [];\r\n\t\tfor (let i = 0; i < N; i++) {\r\n\t\t\tif (group[i] === g) {\r\n\t\t\t\tconst [open, close] = brackets[i];\r\n\t\t\t\tcurrentOpen.push(open);\r\n\t\t\t\tcurrentClose.push(close);\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (currentOpen.length > 0) {\r\n\t\t\tresult.push({\r\n\t\t\t\topen: currentOpen,\r\n\t\t\t\tclose: currentClose\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\treturn result;\r\n}\r\n\r\nexport class RichEditBrackets {\r\n\t_richEditBracketsBrand: void;\r\n\r\n\tpublic readonly brackets: RichEditBracket[];\r\n\tpublic readonly forwardRegex: RegExp;\r\n\tpublic readonly reversedRegex: RegExp;\r\n\tpublic readonly maxBracketLength: number;\r\n\tpublic readonly textIsBracket: { [text: string]: RichEditBracket; };\r\n\tpublic readonly textIsOpenBracket: { [text: string]: boolean; };\r\n\r\n\tconstructor(languageIdentifier: LanguageIdentifier, _brackets: CharacterPair[]) {\r\n\t\tconst brackets = groupFuzzyBrackets(_brackets);\r\n\r\n\t\tthis.brackets = brackets.map((b, index) => {\r\n\t\t\treturn new RichEditBracket(\r\n\t\t\t\tlanguageIdentifier,\r\n\t\t\t\tindex,\r\n\t\t\t\tb.open,\r\n\t\t\t\tb.close,\r\n\t\t\t\tgetRegexForBracketPair(b.open, b.close, brackets, index),\r\n\t\t\t\tgetReversedRegexForBracketPair(b.open, b.close, brackets, index)\r\n\t\t\t);\r\n\t\t});\r\n\r\n\t\tthis.forwardRegex = getRegexForBrackets(this.brackets);\r\n\t\tthis.reversedRegex = getReversedRegexForBrackets(this.brackets);\r\n\r\n\t\tthis.textIsBracket = {};\r\n\t\tthis.textIsOpenBracket = {};\r\n\r\n\t\tthis.maxBracketLength = 0;\r\n\t\tfor (const bracket of this.brackets) {\r\n\t\t\tfor (const open of bracket.open) {\r\n\t\t\t\tthis.textIsBracket[open] = bracket;\r\n\t\t\t\tthis.textIsOpenBracket[open] = true;\r\n\t\t\t\tthis.maxBracketLength = Math.max(this.maxBracketLength, open.length);\r\n\t\t\t}\r\n\t\t\tfor (const close of bracket.close) {\r\n\t\t\t\tthis.textIsBracket[close] = bracket;\r\n\t\t\t\tthis.textIsOpenBracket[close] = false;\r\n\t\t\t\tthis.maxBracketLength = Math.max(this.maxBracketLength, close.length);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction collectSuperstrings(str: string, brackets: InternalBracket[], currentIndex: number, dest: string[]): void {\r\n\tfor (let i = 0, len = brackets.length; i < len; i++) {\r\n\t\tif (i === currentIndex) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\t\tconst bracket = brackets[i];\r\n\t\tfor (const open of bracket.open) {\r\n\t\t\tif (open.indexOf(str) >= 0) {\r\n\t\t\t\tdest.push(open);\r\n\t\t\t}\r\n\t\t}\r\n\t\tfor (const close of bracket.close) {\r\n\t\t\tif (close.indexOf(str) >= 0) {\r\n\t\t\t\tdest.push(close);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction lengthcmp(a: string, b: string) {\r\n\treturn a.length - b.length;\r\n}\r\n\r\nfunction unique(arr: string[]): string[] {\r\n\tif (arr.length <= 1) {\r\n\t\treturn arr;\r\n\t}\r\n\tconst result: string[] = [];\r\n\tconst seen = new Set();\r\n\tfor (const element of arr) {\r\n\t\tif (seen.has(element)) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\t\tresult.push(element);\r\n\t\tseen.add(element);\r\n\t}\r\n\treturn result;\r\n}\r\n\r\nfunction getRegexForBracketPair(open: string[], close: string[], brackets: InternalBracket[], currentIndex: number): RegExp {\r\n\t// search in all brackets for other brackets that are a superstring of these brackets\r\n\tlet pieces: string[] = [];\r\n\tpieces = pieces.concat(open);\r\n\tpieces = pieces.concat(close);\r\n\tfor (let i = 0, len = pieces.length; i < len; i++) {\r\n\t\tcollectSuperstrings(pieces[i], brackets, currentIndex, pieces);\r\n\t}\r\n\tpieces = unique(pieces);\r\n\tpieces.sort(lengthcmp);\r\n\tpieces.reverse();\r\n\treturn createBracketOrRegExp(pieces);\r\n}\r\n\r\nfunction getReversedRegexForBracketPair(open: string[], close: string[], brackets: InternalBracket[], currentIndex: number): RegExp {\r\n\t// search in all brackets for other brackets that are a superstring of these brackets\r\n\tlet pieces: string[] = [];\r\n\tpieces = pieces.concat(open);\r\n\tpieces = pieces.concat(close);\r\n\tfor (let i = 0, len = pieces.length; i < len; i++) {\r\n\t\tcollectSuperstrings(pieces[i], brackets, currentIndex, pieces);\r\n\t}\r\n\tpieces = unique(pieces);\r\n\tpieces.sort(lengthcmp);\r\n\tpieces.reverse();\r\n\treturn createBracketOrRegExp(pieces.map(toReversedString));\r\n}\r\n\r\nfunction getRegexForBrackets(brackets: RichEditBracket[]): RegExp {\r\n\tlet pieces: string[] = [];\r\n\tfor (const bracket of brackets) {\r\n\t\tfor (const open of bracket.open) {\r\n\t\t\tpieces.push(open);\r\n\t\t}\r\n\t\tfor (const close of bracket.close) {\r\n\t\t\tpieces.push(close);\r\n\t\t}\r\n\t}\r\n\tpieces = unique(pieces);\r\n\treturn createBracketOrRegExp(pieces);\r\n}\r\n\r\nfunction getReversedRegexForBrackets(brackets: RichEditBracket[]): RegExp {\r\n\tlet pieces: string[] = [];\r\n\tfor (const bracket of brackets) {\r\n\t\tfor (const open of bracket.open) {\r\n\t\t\tpieces.push(open);\r\n\t\t}\r\n\t\tfor (const close of bracket.close) {\r\n\t\t\tpieces.push(close);\r\n\t\t}\r\n\t}\r\n\tpieces = unique(pieces);\r\n\treturn createBracketOrRegExp(pieces.map(toReversedString));\r\n}\r\n\r\nfunction prepareBracketForRegExp(str: string): string {\r\n\t// This bracket pair uses letters like e.g. \"begin\" - \"end\"\r\n\tconst insertWordBoundaries = (/^[\\w ]+$/.test(str));\r\n\tstr = strings.escapeRegExpCharacters(str);\r\n\treturn (insertWordBoundaries ? `\\\\b${str}\\\\b` : str);\r\n}\r\n\r\nfunction createBracketOrRegExp(pieces: string[]): RegExp {\r\n\tlet regexStr = `(${pieces.map(prepareBracketForRegExp).join(')|(')})`;\r\n\treturn strings.createRegExp(regexStr, true);\r\n}\r\n\r\nconst toReversedString = (function () {\r\n\r\n\tfunction reverse(str: string): string {\r\n\t\tif (stringBuilder.hasTextDecoder) {\r\n\t\t\t// create a Uint16Array and then use a TextDecoder to create a string\r\n\t\t\tconst arr = new Uint16Array(str.length);\r\n\t\t\tlet offset = 0;\r\n\t\t\tfor (let i = str.length - 1; i >= 0; i--) {\r\n\t\t\t\tarr[offset++] = str.charCodeAt(i);\r\n\t\t\t}\r\n\t\t\treturn stringBuilder.getPlatformTextDecoder().decode(arr);\r\n\t\t} else {\r\n\t\t\tlet result: string[] = [], resultLen = 0;\r\n\t\t\tfor (let i = str.length - 1; i >= 0; i--) {\r\n\t\t\t\tresult[resultLen++] = str.charAt(i);\r\n\t\t\t}\r\n\t\t\treturn result.join('');\r\n\t\t}\r\n\t}\r\n\r\n\tlet lastInput: string | null = null;\r\n\tlet lastOutput: string | null = null;\r\n\treturn function toReversedString(str: string): string {\r\n\t\tif (lastInput !== str) {\r\n\t\t\tlastInput = str;\r\n\t\t\tlastOutput = reverse(lastInput);\r\n\t\t}\r\n\t\treturn lastOutput!;\r\n\t};\r\n})();\r\n\r\nexport class BracketsUtils {\r\n\r\n\tprivate static _findPrevBracketInText(reversedBracketRegex: RegExp, lineNumber: number, reversedText: string, offset: number): Range | null {\r\n\t\tlet m = reversedText.match(reversedBracketRegex);\r\n\r\n\t\tif (!m) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet matchOffset = reversedText.length - (m.index || 0);\r\n\t\tlet matchLength = m[0].length;\r\n\t\tlet absoluteMatchOffset = offset + matchOffset;\r\n\r\n\t\treturn new Range(lineNumber, absoluteMatchOffset - matchLength + 1, lineNumber, absoluteMatchOffset + 1);\r\n\t}\r\n\r\n\tpublic static findPrevBracketInRange(reversedBracketRegex: RegExp, lineNumber: number, lineText: string, startOffset: number, endOffset: number): Range | null {\r\n\t\t// Because JS does not support backwards regex search, we search forwards in a reversed string with a reversed regex ;)\r\n\t\tconst reversedLineText = toReversedString(lineText);\r\n\t\tconst reversedSubstr = reversedLineText.substring(lineText.length - endOffset, lineText.length - startOffset);\r\n\t\treturn this._findPrevBracketInText(reversedBracketRegex, lineNumber, reversedSubstr, startOffset);\r\n\t}\r\n\r\n\tpublic static findNextBracketInText(bracketRegex: RegExp, lineNumber: number, text: string, offset: number): Range | null {\r\n\t\tlet m = text.match(bracketRegex);\r\n\r\n\t\tif (!m) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet matchOffset = m.index || 0;\r\n\t\tlet matchLength = m[0].length;\r\n\t\tif (matchLength === 0) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tlet absoluteMatchOffset = offset + matchOffset;\r\n\r\n\t\treturn new Range(lineNumber, absoluteMatchOffset + 1, lineNumber, absoluteMatchOffset + 1 + matchLength);\r\n\t}\r\n\r\n\tpublic static findNextBracketInRange(bracketRegex: RegExp, lineNumber: number, lineText: string, startOffset: number, endOffset: number): Range | null {\r\n\t\tconst substr = lineText.substring(startOffset, endOffset);\r\n\t\treturn this.findNextBracketInText(bracketRegex, lineNumber, substr, startOffset);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { ScopedLineTokens, ignoreBracketsInToken } from 'vs/editor/common/modes/supports';\r\nimport { BracketsUtils, RichEditBrackets } from 'vs/editor/common/modes/supports/richEditBrackets';\r\n\r\n/**\r\n * Interface used to support electric characters\r\n * @internal\r\n */\r\nexport interface IElectricAction {\r\n\t// The line will be indented at the same level of the line\r\n\t// which contains the matching given bracket type.\r\n\tmatchOpenBracket: string;\r\n}\r\n\r\nexport class BracketElectricCharacterSupport {\r\n\r\n\tprivate readonly _richEditBrackets: RichEditBrackets | null;\r\n\r\n\tconstructor(richEditBrackets: RichEditBrackets | null) {\r\n\t\tthis._richEditBrackets = richEditBrackets;\r\n\t}\r\n\r\n\tpublic getElectricCharacters(): string[] {\r\n\t\tlet result: string[] = [];\r\n\r\n\t\tif (this._richEditBrackets) {\r\n\t\t\tfor (const bracket of this._richEditBrackets.brackets) {\r\n\t\t\t\tfor (const close of bracket.close) {\r\n\t\t\t\t\tconst lastChar = close.charAt(close.length - 1);\r\n\t\t\t\t\tresult.push(lastChar);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Filter duplicate entries\r\n\t\tresult = result.filter((item, pos, array) => {\r\n\t\t\treturn array.indexOf(item) === pos;\r\n\t\t});\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic onElectricCharacter(character: string, context: ScopedLineTokens, column: number): IElectricAction | null {\r\n\t\tif (!this._richEditBrackets || this._richEditBrackets.brackets.length === 0) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst tokenIndex = context.findTokenIndexAtOffset(column - 1);\r\n\t\tif (ignoreBracketsInToken(context.getStandardTokenType(tokenIndex))) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst reversedBracketRegex = this._richEditBrackets.reversedRegex;\r\n\t\tconst text = context.getLineContent().substring(0, column - 1) + character;\r\n\r\n\t\tconst r = BracketsUtils.findPrevBracketInRange(reversedBracketRegex, 1, text, 0, text.length);\r\n\t\tif (!r) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst bracketText = text.substring(r.startColumn - 1, r.endColumn - 1).toLowerCase();\r\n\r\n\t\tconst isOpen = this._richEditBrackets.textIsOpenBracket[bracketText];\r\n\t\tif (isOpen) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst textBeforeBracket = context.getActualLineContentBefore(r.startColumn - 1);\r\n\t\tif (!/^\\s*$/.test(textBeforeBracket)) {\r\n\t\t\t// There is other text on the line before the bracket\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tmatchOpenBracket: bracketText\r\n\t\t};\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { IDisposable, toDisposable } from 'vs/base/common/lifecycle';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { LineTokens } from 'vs/editor/common/core/lineTokens';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { DEFAULT_WORD_REGEXP, ensureValidWordDefinition } from 'vs/editor/common/model/wordHelper';\r\nimport { LanguageId, LanguageIdentifier } from 'vs/editor/common/modes';\r\nimport { EnterAction, FoldingRules, IAutoClosingPair, IndentAction, IndentationRule, LanguageConfiguration, StandardAutoClosingPairConditional, CompleteEnterAction, AutoClosingPairs } from 'vs/editor/common/modes/languageConfiguration';\r\nimport { createScopedLineTokens, ScopedLineTokens } from 'vs/editor/common/modes/supports';\r\nimport { CharacterPairSupport } from 'vs/editor/common/modes/supports/characterPair';\r\nimport { BracketElectricCharacterSupport, IElectricAction } from 'vs/editor/common/modes/supports/electricCharacter';\r\nimport { IndentConsts, IndentRulesSupport } from 'vs/editor/common/modes/supports/indentRules';\r\nimport { OnEnterSupport } from 'vs/editor/common/modes/supports/onEnter';\r\nimport { RichEditBrackets } from 'vs/editor/common/modes/supports/richEditBrackets';\r\nimport { EditorAutoIndentStrategy } from 'vs/editor/common/config/editorOptions';\r\n\r\n/**\r\n * Interface used to support insertion of mode specific comments.\r\n */\r\nexport interface ICommentsConfiguration {\r\n\tlineCommentToken?: string;\r\n\tblockCommentStartToken?: string;\r\n\tblockCommentEndToken?: string;\r\n}\r\n\r\nexport interface IVirtualModel {\r\n\tgetLineTokens(lineNumber: number): LineTokens;\r\n\tgetLanguageIdentifier(): LanguageIdentifier;\r\n\tgetLanguageIdAtPosition(lineNumber: number, column: number): LanguageId;\r\n\tgetLineContent(lineNumber: number): string;\r\n}\r\n\r\nexport interface IIndentConverter {\r\n\tshiftIndent(indentation: string): string;\r\n\tunshiftIndent(indentation: string): string;\r\n\tnormalizeIndentation?(indentation: string): string;\r\n}\r\n\r\nexport class RichEditSupport {\r\n\r\n\tprivate readonly _conf: LanguageConfiguration;\r\n\tprivate readonly _languageIdentifier: LanguageIdentifier;\r\n\tprivate _brackets: RichEditBrackets | null;\r\n\tprivate _electricCharacter: BracketElectricCharacterSupport | null;\r\n\tprivate readonly _onEnterSupport: OnEnterSupport | null;\r\n\r\n\tpublic readonly comments: ICommentsConfiguration | null;\r\n\tpublic readonly characterPair: CharacterPairSupport;\r\n\tpublic readonly wordDefinition: RegExp;\r\n\tpublic readonly indentRulesSupport: IndentRulesSupport | null;\r\n\tpublic readonly indentationRules: IndentationRule | undefined;\r\n\tpublic readonly foldingRules: FoldingRules;\r\n\r\n\tconstructor(languageIdentifier: LanguageIdentifier, previous: RichEditSupport | undefined, rawConf: LanguageConfiguration) {\r\n\t\tthis._languageIdentifier = languageIdentifier;\r\n\r\n\t\tthis._brackets = null;\r\n\t\tthis._electricCharacter = null;\r\n\r\n\t\tlet prev: LanguageConfiguration | null = null;\r\n\t\tif (previous) {\r\n\t\t\tprev = previous._conf;\r\n\t\t}\r\n\r\n\t\tthis._conf = RichEditSupport._mergeConf(prev, rawConf);\r\n\r\n\t\tthis._onEnterSupport = (this._conf.brackets || this._conf.indentationRules || this._conf.onEnterRules ? new OnEnterSupport(this._conf) : null);\r\n\t\tthis.comments = RichEditSupport._handleComments(this._conf);\r\n\r\n\t\tthis.characterPair = new CharacterPairSupport(this._conf);\r\n\r\n\t\tthis.wordDefinition = this._conf.wordPattern || DEFAULT_WORD_REGEXP;\r\n\r\n\t\tthis.indentationRules = this._conf.indentationRules;\r\n\t\tif (this._conf.indentationRules) {\r\n\t\t\tthis.indentRulesSupport = new IndentRulesSupport(this._conf.indentationRules);\r\n\t\t} else {\r\n\t\t\tthis.indentRulesSupport = null;\r\n\t\t}\r\n\r\n\t\tthis.foldingRules = this._conf.folding || {};\r\n\t}\r\n\r\n\tpublic get brackets(): RichEditBrackets | null {\r\n\t\tif (!this._brackets && this._conf.brackets) {\r\n\t\t\tthis._brackets = new RichEditBrackets(this._languageIdentifier, this._conf.brackets);\r\n\t\t}\r\n\t\treturn this._brackets;\r\n\t}\r\n\r\n\tpublic get electricCharacter(): BracketElectricCharacterSupport | null {\r\n\t\tif (!this._electricCharacter) {\r\n\t\t\tthis._electricCharacter = new BracketElectricCharacterSupport(this.brackets);\r\n\t\t}\r\n\t\treturn this._electricCharacter;\r\n\t}\r\n\r\n\tpublic onEnter(autoIndent: EditorAutoIndentStrategy, previousLineText: string, beforeEnterText: string, afterEnterText: string): EnterAction | null {\r\n\t\tif (!this._onEnterSupport) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn this._onEnterSupport.onEnter(autoIndent, previousLineText, beforeEnterText, afterEnterText);\r\n\t}\r\n\r\n\tprivate static _mergeConf(prev: LanguageConfiguration | null, current: LanguageConfiguration): LanguageConfiguration {\r\n\t\treturn {\r\n\t\t\tcomments: (prev ? current.comments || prev.comments : current.comments),\r\n\t\t\tbrackets: (prev ? current.brackets || prev.brackets : current.brackets),\r\n\t\t\twordPattern: (prev ? current.wordPattern || prev.wordPattern : current.wordPattern),\r\n\t\t\tindentationRules: (prev ? current.indentationRules || prev.indentationRules : current.indentationRules),\r\n\t\t\tonEnterRules: (prev ? current.onEnterRules || prev.onEnterRules : current.onEnterRules),\r\n\t\t\tautoClosingPairs: (prev ? current.autoClosingPairs || prev.autoClosingPairs : current.autoClosingPairs),\r\n\t\t\tsurroundingPairs: (prev ? current.surroundingPairs || prev.surroundingPairs : current.surroundingPairs),\r\n\t\t\tautoCloseBefore: (prev ? current.autoCloseBefore || prev.autoCloseBefore : current.autoCloseBefore),\r\n\t\t\tfolding: (prev ? current.folding || prev.folding : current.folding),\r\n\t\t\t__electricCharacterSupport: (prev ? current.__electricCharacterSupport || prev.__electricCharacterSupport : current.__electricCharacterSupport),\r\n\t\t};\r\n\t}\r\n\r\n\tprivate static _handleComments(conf: LanguageConfiguration): ICommentsConfiguration | null {\r\n\t\tlet commentRule = conf.comments;\r\n\t\tif (!commentRule) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\t// comment configuration\r\n\t\tlet comments: ICommentsConfiguration = {};\r\n\r\n\t\tif (commentRule.lineComment) {\r\n\t\t\tcomments.lineCommentToken = commentRule.lineComment;\r\n\t\t}\r\n\t\tif (commentRule.blockComment) {\r\n\t\t\tlet [blockStart, blockEnd] = commentRule.blockComment;\r\n\t\t\tcomments.blockCommentStartToken = blockStart;\r\n\t\t\tcomments.blockCommentEndToken = blockEnd;\r\n\t\t}\r\n\r\n\t\treturn comments;\r\n\t}\r\n}\r\n\r\nexport class LanguageConfigurationChangeEvent {\r\n\tconstructor(\r\n\t\tpublic readonly languageIdentifier: LanguageIdentifier\r\n\t) { }\r\n}\r\n\r\nexport class LanguageConfigurationRegistryImpl {\r\n\r\n\tprivate readonly _entries = new Map();\r\n\r\n\tprivate readonly _onDidChange = new Emitter();\r\n\tpublic readonly onDidChange: Event = this._onDidChange.event;\r\n\r\n\tpublic register(languageIdentifier: LanguageIdentifier, configuration: LanguageConfiguration): IDisposable {\r\n\t\tlet previous = this._getRichEditSupport(languageIdentifier.id);\r\n\t\tlet current = new RichEditSupport(languageIdentifier, previous, configuration);\r\n\t\tthis._entries.set(languageIdentifier.id, current);\r\n\t\tthis._onDidChange.fire(new LanguageConfigurationChangeEvent(languageIdentifier));\r\n\t\treturn toDisposable(() => {\r\n\t\t\tif (this._entries.get(languageIdentifier.id) === current) {\r\n\t\t\t\tthis._entries.set(languageIdentifier.id, previous);\r\n\t\t\t\tthis._onDidChange.fire(new LanguageConfigurationChangeEvent(languageIdentifier));\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _getRichEditSupport(languageId: LanguageId): RichEditSupport | undefined {\r\n\t\treturn this._entries.get(languageId);\r\n\t}\r\n\r\n\tpublic getIndentationRules(languageId: LanguageId) {\r\n\t\tconst value = this._entries.get(languageId);\r\n\r\n\t\tif (!value) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\treturn value.indentationRules || null;\r\n\t}\r\n\r\n\t// begin electricCharacter\r\n\r\n\tprivate _getElectricCharacterSupport(languageId: LanguageId): BracketElectricCharacterSupport | null {\r\n\t\tlet value = this._getRichEditSupport(languageId);\r\n\t\tif (!value) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn value.electricCharacter || null;\r\n\t}\r\n\r\n\tpublic getElectricCharacters(languageId: LanguageId): string[] {\r\n\t\tlet electricCharacterSupport = this._getElectricCharacterSupport(languageId);\r\n\t\tif (!electricCharacterSupport) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\t\treturn electricCharacterSupport.getElectricCharacters();\r\n\t}\r\n\r\n\t/**\r\n\t * Should return opening bracket type to match indentation with\r\n\t */\r\n\tpublic onElectricCharacter(character: string, context: LineTokens, column: number): IElectricAction | null {\r\n\t\tlet scopedLineTokens = createScopedLineTokens(context, column - 1);\r\n\t\tlet electricCharacterSupport = this._getElectricCharacterSupport(scopedLineTokens.languageId);\r\n\t\tif (!electricCharacterSupport) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn electricCharacterSupport.onElectricCharacter(character, scopedLineTokens, column - scopedLineTokens.firstCharOffset);\r\n\t}\r\n\r\n\t// end electricCharacter\r\n\r\n\tpublic getComments(languageId: LanguageId): ICommentsConfiguration | null {\r\n\t\tlet value = this._getRichEditSupport(languageId);\r\n\t\tif (!value) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn value.comments || null;\r\n\t}\r\n\r\n\t// begin characterPair\r\n\r\n\tprivate _getCharacterPairSupport(languageId: LanguageId): CharacterPairSupport | null {\r\n\t\tlet value = this._getRichEditSupport(languageId);\r\n\t\tif (!value) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn value.characterPair || null;\r\n\t}\r\n\r\n\tpublic getAutoClosingPairs(languageId: LanguageId): AutoClosingPairs {\r\n\t\tconst characterPairSupport = this._getCharacterPairSupport(languageId);\r\n\t\treturn new AutoClosingPairs(characterPairSupport ? characterPairSupport.getAutoClosingPairs() : []);\r\n\t}\r\n\r\n\tpublic getAutoCloseBeforeSet(languageId: LanguageId): string {\r\n\t\tlet characterPairSupport = this._getCharacterPairSupport(languageId);\r\n\t\tif (!characterPairSupport) {\r\n\t\t\treturn CharacterPairSupport.DEFAULT_AUTOCLOSE_BEFORE_LANGUAGE_DEFINED;\r\n\t\t}\r\n\t\treturn characterPairSupport.getAutoCloseBeforeSet();\r\n\t}\r\n\r\n\tpublic getSurroundingPairs(languageId: LanguageId): IAutoClosingPair[] {\r\n\t\tlet characterPairSupport = this._getCharacterPairSupport(languageId);\r\n\t\tif (!characterPairSupport) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\t\treturn characterPairSupport.getSurroundingPairs();\r\n\t}\r\n\r\n\tpublic shouldAutoClosePair(autoClosingPair: StandardAutoClosingPairConditional, context: LineTokens, column: number): boolean {\r\n\t\tconst scopedLineTokens = createScopedLineTokens(context, column - 1);\r\n\t\treturn CharacterPairSupport.shouldAutoClosePair(autoClosingPair, scopedLineTokens, column - scopedLineTokens.firstCharOffset);\r\n\t}\r\n\r\n\t// end characterPair\r\n\r\n\tpublic getWordDefinition(languageId: LanguageId): RegExp {\r\n\t\tlet value = this._getRichEditSupport(languageId);\r\n\t\tif (!value) {\r\n\t\t\treturn ensureValidWordDefinition(null);\r\n\t\t}\r\n\t\treturn ensureValidWordDefinition(value.wordDefinition || null);\r\n\t}\r\n\r\n\tpublic getFoldingRules(languageId: LanguageId): FoldingRules {\r\n\t\tlet value = this._getRichEditSupport(languageId);\r\n\t\tif (!value) {\r\n\t\t\treturn {};\r\n\t\t}\r\n\t\treturn value.foldingRules;\r\n\t}\r\n\r\n\t// begin Indent Rules\r\n\r\n\tpublic getIndentRulesSupport(languageId: LanguageId): IndentRulesSupport | null {\r\n\t\tlet value = this._getRichEditSupport(languageId);\r\n\t\tif (!value) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn value.indentRulesSupport || null;\r\n\t}\r\n\r\n\t/**\r\n\t * Get nearest preceiding line which doesn't match unIndentPattern or contains all whitespace.\r\n\t * Result:\r\n\t * -1: run into the boundary of embedded languages\r\n\t * 0: every line above are invalid\r\n\t * else: nearest preceding line of the same language\r\n\t */\r\n\tprivate getPrecedingValidLine(model: IVirtualModel, lineNumber: number, indentRulesSupport: IndentRulesSupport) {\r\n\t\tlet languageID = model.getLanguageIdAtPosition(lineNumber, 0);\r\n\t\tif (lineNumber > 1) {\r\n\t\t\tlet lastLineNumber: number;\r\n\t\t\tlet resultLineNumber = -1;\r\n\r\n\t\t\tfor (lastLineNumber = lineNumber - 1; lastLineNumber >= 1; lastLineNumber--) {\r\n\t\t\t\tif (model.getLanguageIdAtPosition(lastLineNumber, 0) !== languageID) {\r\n\t\t\t\t\treturn resultLineNumber;\r\n\t\t\t\t}\r\n\t\t\t\tlet text = model.getLineContent(lastLineNumber);\r\n\t\t\t\tif (indentRulesSupport.shouldIgnore(text) || /^\\s+$/.test(text) || text === '') {\r\n\t\t\t\t\tresultLineNumber = lastLineNumber;\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn lastLineNumber;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn -1;\r\n\t}\r\n\r\n\t/**\r\n\t * Get inherited indentation from above lines.\r\n\t * 1. Find the nearest preceding line which doesn't match unIndentedLinePattern.\r\n\t * 2. If this line matches indentNextLinePattern or increaseIndentPattern, it means that the indent level of `lineNumber` should be 1 greater than this line.\r\n\t * 3. If this line doesn't match any indent rules\r\n\t * a. check whether the line above it matches indentNextLinePattern\r\n\t * b. If not, the indent level of this line is the result\r\n\t * c. If so, it means the indent of this line is *temporary*, go upward utill we find a line whose indent is not temporary (the same workflow a -> b -> c).\r\n\t * 4. Otherwise, we fail to get an inherited indent from aboves. Return null and we should not touch the indent of `lineNumber`\r\n\t *\r\n\t * This function only return the inherited indent based on above lines, it doesn't check whether current line should decrease or not.\r\n\t */\r\n\tpublic getInheritIndentForLine(autoIndent: EditorAutoIndentStrategy, model: IVirtualModel, lineNumber: number, honorIntentialIndent: boolean = true): { indentation: string; action: IndentAction | null; line?: number; } | null {\r\n\t\tif (autoIndent < EditorAutoIndentStrategy.Full) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst indentRulesSupport = this.getIndentRulesSupport(model.getLanguageIdentifier().id);\r\n\t\tif (!indentRulesSupport) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (lineNumber <= 1) {\r\n\t\t\treturn {\r\n\t\t\t\tindentation: '',\r\n\t\t\t\taction: null\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tconst precedingUnIgnoredLine = this.getPrecedingValidLine(model, lineNumber, indentRulesSupport);\r\n\t\tif (precedingUnIgnoredLine < 0) {\r\n\t\t\treturn null;\r\n\t\t} else if (precedingUnIgnoredLine < 1) {\r\n\t\t\treturn {\r\n\t\t\t\tindentation: '',\r\n\t\t\t\taction: null\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tconst precedingUnIgnoredLineContent = model.getLineContent(precedingUnIgnoredLine);\r\n\t\tif (indentRulesSupport.shouldIncrease(precedingUnIgnoredLineContent) || indentRulesSupport.shouldIndentNextLine(precedingUnIgnoredLineContent)) {\r\n\t\t\treturn {\r\n\t\t\t\tindentation: strings.getLeadingWhitespace(precedingUnIgnoredLineContent),\r\n\t\t\t\taction: IndentAction.Indent,\r\n\t\t\t\tline: precedingUnIgnoredLine\r\n\t\t\t};\r\n\t\t} else if (indentRulesSupport.shouldDecrease(precedingUnIgnoredLineContent)) {\r\n\t\t\treturn {\r\n\t\t\t\tindentation: strings.getLeadingWhitespace(precedingUnIgnoredLineContent),\r\n\t\t\t\taction: null,\r\n\t\t\t\tline: precedingUnIgnoredLine\r\n\t\t\t};\r\n\t\t} else {\r\n\t\t\t// precedingUnIgnoredLine can not be ignored.\r\n\t\t\t// it doesn't increase indent of following lines\r\n\t\t\t// it doesn't increase just next line\r\n\t\t\t// so current line is not affect by precedingUnIgnoredLine\r\n\t\t\t// and then we should get a correct inheritted indentation from above lines\r\n\t\t\tif (precedingUnIgnoredLine === 1) {\r\n\t\t\t\treturn {\r\n\t\t\t\t\tindentation: strings.getLeadingWhitespace(model.getLineContent(precedingUnIgnoredLine)),\r\n\t\t\t\t\taction: null,\r\n\t\t\t\t\tline: precedingUnIgnoredLine\r\n\t\t\t\t};\r\n\t\t\t}\r\n\r\n\t\t\tconst previousLine = precedingUnIgnoredLine - 1;\r\n\r\n\t\t\tconst previousLineIndentMetadata = indentRulesSupport.getIndentMetadata(model.getLineContent(previousLine));\r\n\t\t\tif (!(previousLineIndentMetadata & (IndentConsts.INCREASE_MASK | IndentConsts.DECREASE_MASK)) &&\r\n\t\t\t\t(previousLineIndentMetadata & IndentConsts.INDENT_NEXTLINE_MASK)) {\r\n\t\t\t\tlet stopLine = 0;\r\n\t\t\t\tfor (let i = previousLine - 1; i > 0; i--) {\r\n\t\t\t\t\tif (indentRulesSupport.shouldIndentNextLine(model.getLineContent(i))) {\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tstopLine = i;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn {\r\n\t\t\t\t\tindentation: strings.getLeadingWhitespace(model.getLineContent(stopLine + 1)),\r\n\t\t\t\t\taction: null,\r\n\t\t\t\t\tline: stopLine + 1\r\n\t\t\t\t};\r\n\t\t\t}\r\n\r\n\t\t\tif (honorIntentialIndent) {\r\n\t\t\t\treturn {\r\n\t\t\t\t\tindentation: strings.getLeadingWhitespace(model.getLineContent(precedingUnIgnoredLine)),\r\n\t\t\t\t\taction: null,\r\n\t\t\t\t\tline: precedingUnIgnoredLine\r\n\t\t\t\t};\r\n\t\t\t} else {\r\n\t\t\t\t// search from precedingUnIgnoredLine until we find one whose indent is not temporary\r\n\t\t\t\tfor (let i = precedingUnIgnoredLine; i > 0; i--) {\r\n\t\t\t\t\tconst lineContent = model.getLineContent(i);\r\n\t\t\t\t\tif (indentRulesSupport.shouldIncrease(lineContent)) {\r\n\t\t\t\t\t\treturn {\r\n\t\t\t\t\t\t\tindentation: strings.getLeadingWhitespace(lineContent),\r\n\t\t\t\t\t\t\taction: IndentAction.Indent,\r\n\t\t\t\t\t\t\tline: i\r\n\t\t\t\t\t\t};\r\n\t\t\t\t\t} else if (indentRulesSupport.shouldIndentNextLine(lineContent)) {\r\n\t\t\t\t\t\tlet stopLine = 0;\r\n\t\t\t\t\t\tfor (let j = i - 1; j > 0; j--) {\r\n\t\t\t\t\t\t\tif (indentRulesSupport.shouldIndentNextLine(model.getLineContent(i))) {\r\n\t\t\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tstopLine = j;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\treturn {\r\n\t\t\t\t\t\t\tindentation: strings.getLeadingWhitespace(model.getLineContent(stopLine + 1)),\r\n\t\t\t\t\t\t\taction: null,\r\n\t\t\t\t\t\t\tline: stopLine + 1\r\n\t\t\t\t\t\t};\r\n\t\t\t\t\t} else if (indentRulesSupport.shouldDecrease(lineContent)) {\r\n\t\t\t\t\t\treturn {\r\n\t\t\t\t\t\t\tindentation: strings.getLeadingWhitespace(lineContent),\r\n\t\t\t\t\t\t\taction: null,\r\n\t\t\t\t\t\t\tline: i\r\n\t\t\t\t\t\t};\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn {\r\n\t\t\t\t\tindentation: strings.getLeadingWhitespace(model.getLineContent(1)),\r\n\t\t\t\t\taction: null,\r\n\t\t\t\t\tline: 1\r\n\t\t\t\t};\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getGoodIndentForLine(autoIndent: EditorAutoIndentStrategy, virtualModel: IVirtualModel, languageId: LanguageId, lineNumber: number, indentConverter: IIndentConverter): string | null {\r\n\t\tif (autoIndent < EditorAutoIndentStrategy.Full) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst richEditSupport = this._getRichEditSupport(languageId);\r\n\t\tif (!richEditSupport) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst indentRulesSupport = this.getIndentRulesSupport(languageId);\r\n\t\tif (!indentRulesSupport) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst indent = this.getInheritIndentForLine(autoIndent, virtualModel, lineNumber);\r\n\t\tconst lineContent = virtualModel.getLineContent(lineNumber);\r\n\r\n\t\tif (indent) {\r\n\t\t\tconst inheritLine = indent.line;\r\n\t\t\tif (inheritLine !== undefined) {\r\n\t\t\t\tconst enterResult = richEditSupport.onEnter(autoIndent, '', virtualModel.getLineContent(inheritLine), '');\r\n\r\n\t\t\t\tif (enterResult) {\r\n\t\t\t\t\tlet indentation = strings.getLeadingWhitespace(virtualModel.getLineContent(inheritLine));\r\n\r\n\t\t\t\t\tif (enterResult.removeText) {\r\n\t\t\t\t\t\tindentation = indentation.substring(0, indentation.length - enterResult.removeText);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (\r\n\t\t\t\t\t\t(enterResult.indentAction === IndentAction.Indent) ||\r\n\t\t\t\t\t\t(enterResult.indentAction === IndentAction.IndentOutdent)\r\n\t\t\t\t\t) {\r\n\t\t\t\t\t\tindentation = indentConverter.shiftIndent(indentation);\r\n\t\t\t\t\t} else if (enterResult.indentAction === IndentAction.Outdent) {\r\n\t\t\t\t\t\tindentation = indentConverter.unshiftIndent(indentation);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (indentRulesSupport.shouldDecrease(lineContent)) {\r\n\t\t\t\t\t\tindentation = indentConverter.unshiftIndent(indentation);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (enterResult.appendText) {\r\n\t\t\t\t\t\tindentation += enterResult.appendText;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\treturn strings.getLeadingWhitespace(indentation);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (indentRulesSupport.shouldDecrease(lineContent)) {\r\n\t\t\t\tif (indent.action === IndentAction.Indent) {\r\n\t\t\t\t\treturn indent.indentation;\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn indentConverter.unshiftIndent(indent.indentation);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tif (indent.action === IndentAction.Indent) {\r\n\t\t\t\t\treturn indentConverter.shiftIndent(indent.indentation);\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn indent.indentation;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic getIndentForEnter(autoIndent: EditorAutoIndentStrategy, model: ITextModel, range: Range, indentConverter: IIndentConverter): { beforeEnter: string, afterEnter: string } | null {\r\n\t\tif (autoIndent < EditorAutoIndentStrategy.Full) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tmodel.forceTokenization(range.startLineNumber);\r\n\t\tconst lineTokens = model.getLineTokens(range.startLineNumber);\r\n\t\tconst scopedLineTokens = createScopedLineTokens(lineTokens, range.startColumn - 1);\r\n\t\tconst scopedLineText = scopedLineTokens.getLineContent();\r\n\r\n\t\tlet embeddedLanguage = false;\r\n\t\tlet beforeEnterText: string;\r\n\t\tif (scopedLineTokens.firstCharOffset > 0 && lineTokens.getLanguageId(0) !== scopedLineTokens.languageId) {\r\n\t\t\t// we are in the embeded language content\r\n\t\t\tembeddedLanguage = true; // if embeddedLanguage is true, then we don't touch the indentation of current line\r\n\t\t\tbeforeEnterText = scopedLineText.substr(0, range.startColumn - 1 - scopedLineTokens.firstCharOffset);\r\n\t\t} else {\r\n\t\t\tbeforeEnterText = lineTokens.getLineContent().substring(0, range.startColumn - 1);\r\n\t\t}\r\n\r\n\t\tlet afterEnterText: string;\r\n\t\tif (range.isEmpty()) {\r\n\t\t\tafterEnterText = scopedLineText.substr(range.startColumn - 1 - scopedLineTokens.firstCharOffset);\r\n\t\t} else {\r\n\t\t\tconst endScopedLineTokens = this.getScopedLineTokens(model, range.endLineNumber, range.endColumn);\r\n\t\t\tafterEnterText = endScopedLineTokens.getLineContent().substr(range.endColumn - 1 - scopedLineTokens.firstCharOffset);\r\n\t\t}\r\n\r\n\t\tconst indentRulesSupport = this.getIndentRulesSupport(scopedLineTokens.languageId);\r\n\t\tif (!indentRulesSupport) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst beforeEnterResult = beforeEnterText;\r\n\t\tconst beforeEnterIndent = strings.getLeadingWhitespace(beforeEnterText);\r\n\r\n\t\tconst virtualModel: IVirtualModel = {\r\n\t\t\tgetLineTokens: (lineNumber: number) => {\r\n\t\t\t\treturn model.getLineTokens(lineNumber);\r\n\t\t\t},\r\n\t\t\tgetLanguageIdentifier: () => {\r\n\t\t\t\treturn model.getLanguageIdentifier();\r\n\t\t\t},\r\n\t\t\tgetLanguageIdAtPosition: (lineNumber: number, column: number) => {\r\n\t\t\t\treturn model.getLanguageIdAtPosition(lineNumber, column);\r\n\t\t\t},\r\n\t\t\tgetLineContent: (lineNumber: number) => {\r\n\t\t\t\tif (lineNumber === range.startLineNumber) {\r\n\t\t\t\t\treturn beforeEnterResult;\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn model.getLineContent(lineNumber);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tconst currentLineIndent = strings.getLeadingWhitespace(lineTokens.getLineContent());\r\n\t\tconst afterEnterAction = this.getInheritIndentForLine(autoIndent, virtualModel, range.startLineNumber + 1);\r\n\t\tif (!afterEnterAction) {\r\n\t\t\tconst beforeEnter = embeddedLanguage ? currentLineIndent : beforeEnterIndent;\r\n\t\t\treturn {\r\n\t\t\t\tbeforeEnter: beforeEnter,\r\n\t\t\t\tafterEnter: beforeEnter\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tlet afterEnterIndent = embeddedLanguage ? currentLineIndent : afterEnterAction.indentation;\r\n\r\n\t\tif (afterEnterAction.action === IndentAction.Indent) {\r\n\t\t\tafterEnterIndent = indentConverter.shiftIndent(afterEnterIndent);\r\n\t\t}\r\n\r\n\t\tif (indentRulesSupport.shouldDecrease(afterEnterText)) {\r\n\t\t\tafterEnterIndent = indentConverter.unshiftIndent(afterEnterIndent);\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tbeforeEnter: embeddedLanguage ? currentLineIndent : beforeEnterIndent,\r\n\t\t\tafterEnter: afterEnterIndent\r\n\t\t};\r\n\t}\r\n\r\n\t/**\r\n\t * We should always allow intentional indentation. It means, if users change the indentation of `lineNumber` and the content of\r\n\t * this line doesn't match decreaseIndentPattern, we should not adjust the indentation.\r\n\t */\r\n\tpublic getIndentActionForType(autoIndent: EditorAutoIndentStrategy, model: ITextModel, range: Range, ch: string, indentConverter: IIndentConverter): string | null {\r\n\t\tif (autoIndent < EditorAutoIndentStrategy.Full) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tconst scopedLineTokens = this.getScopedLineTokens(model, range.startLineNumber, range.startColumn);\r\n\r\n\t\tif (scopedLineTokens.firstCharOffset) {\r\n\t\t\t// this line has mixed languages and indentation rules will not work\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst indentRulesSupport = this.getIndentRulesSupport(scopedLineTokens.languageId);\r\n\t\tif (!indentRulesSupport) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst scopedLineText = scopedLineTokens.getLineContent();\r\n\t\tconst beforeTypeText = scopedLineText.substr(0, range.startColumn - 1 - scopedLineTokens.firstCharOffset);\r\n\r\n\t\t// selection support\r\n\t\tlet afterTypeText: string;\r\n\t\tif (range.isEmpty()) {\r\n\t\t\tafterTypeText = scopedLineText.substr(range.startColumn - 1 - scopedLineTokens.firstCharOffset);\r\n\t\t} else {\r\n\t\t\tconst endScopedLineTokens = this.getScopedLineTokens(model, range.endLineNumber, range.endColumn);\r\n\t\t\tafterTypeText = endScopedLineTokens.getLineContent().substr(range.endColumn - 1 - scopedLineTokens.firstCharOffset);\r\n\t\t}\r\n\r\n\t\t// If previous content already matches decreaseIndentPattern, it means indentation of this line should already be adjusted\r\n\t\t// Users might change the indentation by purpose and we should honor that instead of readjusting.\r\n\t\tif (!indentRulesSupport.shouldDecrease(beforeTypeText + afterTypeText) && indentRulesSupport.shouldDecrease(beforeTypeText + ch + afterTypeText)) {\r\n\t\t\t// after typing `ch`, the content matches decreaseIndentPattern, we should adjust the indent to a good manner.\r\n\t\t\t// 1. Get inherited indent action\r\n\t\t\tconst r = this.getInheritIndentForLine(autoIndent, model, range.startLineNumber, false);\r\n\t\t\tif (!r) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\r\n\t\t\tlet indentation = r.indentation;\r\n\t\t\tif (r.action !== IndentAction.Indent) {\r\n\t\t\t\tindentation = indentConverter.unshiftIndent(indentation);\r\n\t\t\t}\r\n\r\n\t\t\treturn indentation;\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic getIndentMetadata(model: ITextModel, lineNumber: number): number | null {\r\n\t\tconst indentRulesSupport = this.getIndentRulesSupport(model.getLanguageIdentifier().id);\r\n\t\tif (!indentRulesSupport) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tif (lineNumber < 1 || lineNumber > model.getLineCount()) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn indentRulesSupport.getIndentMetadata(model.getLineContent(lineNumber));\r\n\t}\r\n\r\n\t// end Indent Rules\r\n\r\n\t// begin onEnter\r\n\r\n\tpublic getEnterAction(autoIndent: EditorAutoIndentStrategy, model: ITextModel, range: Range): CompleteEnterAction | null {\r\n\t\tconst scopedLineTokens = this.getScopedLineTokens(model, range.startLineNumber, range.startColumn);\r\n\t\tconst richEditSupport = this._getRichEditSupport(scopedLineTokens.languageId);\r\n\t\tif (!richEditSupport) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst scopedLineText = scopedLineTokens.getLineContent();\r\n\t\tconst beforeEnterText = scopedLineText.substr(0, range.startColumn - 1 - scopedLineTokens.firstCharOffset);\r\n\r\n\t\t// selection support\r\n\t\tlet afterEnterText: string;\r\n\t\tif (range.isEmpty()) {\r\n\t\t\tafterEnterText = scopedLineText.substr(range.startColumn - 1 - scopedLineTokens.firstCharOffset);\r\n\t\t} else {\r\n\t\t\tconst endScopedLineTokens = this.getScopedLineTokens(model, range.endLineNumber, range.endColumn);\r\n\t\t\tafterEnterText = endScopedLineTokens.getLineContent().substr(range.endColumn - 1 - scopedLineTokens.firstCharOffset);\r\n\t\t}\r\n\r\n\t\tlet previousLineText = '';\r\n\t\tif (range.startLineNumber > 1 && scopedLineTokens.firstCharOffset === 0) {\r\n\t\t\t// This is not the first line and the entire line belongs to this mode\r\n\t\t\tconst oneLineAboveScopedLineTokens = this.getScopedLineTokens(model, range.startLineNumber - 1);\r\n\t\t\tif (oneLineAboveScopedLineTokens.languageId === scopedLineTokens.languageId) {\r\n\t\t\t\t// The line above ends with text belonging to the same mode\r\n\t\t\t\tpreviousLineText = oneLineAboveScopedLineTokens.getLineContent();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst enterResult = richEditSupport.onEnter(autoIndent, previousLineText, beforeEnterText, afterEnterText);\r\n\t\tif (!enterResult) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst indentAction = enterResult.indentAction;\r\n\t\tlet appendText = enterResult.appendText;\r\n\t\tconst removeText = enterResult.removeText || 0;\r\n\r\n\t\t// Here we add `\\t` to appendText first because enterAction is leveraging appendText and removeText to change indentation.\r\n\t\tif (!appendText) {\r\n\t\t\tif (\r\n\t\t\t\t(indentAction === IndentAction.Indent) ||\r\n\t\t\t\t(indentAction === IndentAction.IndentOutdent)\r\n\t\t\t) {\r\n\t\t\t\tappendText = '\\t';\r\n\t\t\t} else {\r\n\t\t\t\tappendText = '';\r\n\t\t\t}\r\n\t\t} else if (indentAction === IndentAction.Indent) {\r\n\t\t\tappendText = '\\t' + appendText;\r\n\t\t}\r\n\r\n\t\tlet indentation = this.getIndentationAtPosition(model, range.startLineNumber, range.startColumn);\r\n\t\tif (removeText) {\r\n\t\t\tindentation = indentation.substring(0, indentation.length - removeText);\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tindentAction: indentAction,\r\n\t\t\tappendText: appendText,\r\n\t\t\tremoveText: removeText,\r\n\t\t\tindentation: indentation\r\n\t\t};\r\n\t}\r\n\r\n\tpublic getIndentationAtPosition(model: ITextModel, lineNumber: number, column: number): string {\r\n\t\tconst lineText = model.getLineContent(lineNumber);\r\n\t\tlet indentation = strings.getLeadingWhitespace(lineText);\r\n\t\tif (indentation.length > column - 1) {\r\n\t\t\tindentation = indentation.substring(0, column - 1);\r\n\t\t}\r\n\t\treturn indentation;\r\n\t}\r\n\r\n\tprivate getScopedLineTokens(model: ITextModel, lineNumber: number, columnNumber?: number): ScopedLineTokens {\r\n\t\tmodel.forceTokenization(lineNumber);\r\n\t\tconst lineTokens = model.getLineTokens(lineNumber);\r\n\t\tconst column = (typeof columnNumber === 'undefined' ? model.getLineMaxColumn(lineNumber) - 1 : columnNumber - 1);\r\n\t\treturn createScopedLineTokens(lineTokens, column);\r\n\t}\r\n\r\n\t// end onEnter\r\n\r\n\tpublic getBracketsSupport(languageId: LanguageId): RichEditBrackets | null {\r\n\t\tconst value = this._getRichEditSupport(languageId);\r\n\t\tif (!value) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn value.brackets || null;\r\n\t}\r\n}\r\n\r\nexport const LanguageConfigurationRegistry = new LanguageConfigurationRegistryImpl();\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Color } from 'vs/base/common/color';\r\nimport { ColorId, FontStyle, LanguageId, MetadataConsts, StandardTokenType } from 'vs/editor/common/modes';\r\n\r\nexport interface ITokenThemeRule {\r\n\ttoken: string;\r\n\tforeground?: string;\r\n\tbackground?: string;\r\n\tfontStyle?: string;\r\n}\r\n\r\nexport class ParsedTokenThemeRule {\r\n\t_parsedThemeRuleBrand: void;\r\n\r\n\treadonly token: string;\r\n\treadonly index: number;\r\n\r\n\t/**\r\n\t * -1 if not set. An or mask of `FontStyle` otherwise.\r\n\t */\r\n\treadonly fontStyle: FontStyle;\r\n\treadonly foreground: string | null;\r\n\treadonly background: string | null;\r\n\r\n\tconstructor(\r\n\t\ttoken: string,\r\n\t\tindex: number,\r\n\t\tfontStyle: number,\r\n\t\tforeground: string | null,\r\n\t\tbackground: string | null,\r\n\t) {\r\n\t\tthis.token = token;\r\n\t\tthis.index = index;\r\n\t\tthis.fontStyle = fontStyle;\r\n\t\tthis.foreground = foreground;\r\n\t\tthis.background = background;\r\n\t}\r\n}\r\n\r\n/**\r\n * Parse a raw theme into rules.\r\n */\r\nexport function parseTokenTheme(source: ITokenThemeRule[]): ParsedTokenThemeRule[] {\r\n\tif (!source || !Array.isArray(source)) {\r\n\t\treturn [];\r\n\t}\r\n\tlet result: ParsedTokenThemeRule[] = [], resultLen = 0;\r\n\tfor (let i = 0, len = source.length; i < len; i++) {\r\n\t\tlet entry = source[i];\r\n\r\n\t\tlet fontStyle: number = FontStyle.NotSet;\r\n\t\tif (typeof entry.fontStyle === 'string') {\r\n\t\t\tfontStyle = FontStyle.None;\r\n\r\n\t\t\tlet segments = entry.fontStyle.split(' ');\r\n\t\t\tfor (let j = 0, lenJ = segments.length; j < lenJ; j++) {\r\n\t\t\t\tlet segment = segments[j];\r\n\t\t\t\tswitch (segment) {\r\n\t\t\t\t\tcase 'italic':\r\n\t\t\t\t\t\tfontStyle = fontStyle | FontStyle.Italic;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tcase 'bold':\r\n\t\t\t\t\t\tfontStyle = fontStyle | FontStyle.Bold;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tcase 'underline':\r\n\t\t\t\t\t\tfontStyle = fontStyle | FontStyle.Underline;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet foreground: string | null = null;\r\n\t\tif (typeof entry.foreground === 'string') {\r\n\t\t\tforeground = entry.foreground;\r\n\t\t}\r\n\r\n\t\tlet background: string | null = null;\r\n\t\tif (typeof entry.background === 'string') {\r\n\t\t\tbackground = entry.background;\r\n\t\t}\r\n\r\n\t\tresult[resultLen++] = new ParsedTokenThemeRule(\r\n\t\t\tentry.token || '',\r\n\t\t\ti,\r\n\t\t\tfontStyle,\r\n\t\t\tforeground,\r\n\t\t\tbackground\r\n\t\t);\r\n\t}\r\n\r\n\treturn result;\r\n}\r\n\r\n/**\r\n * Resolve rules (i.e. inheritance).\r\n */\r\nfunction resolveParsedTokenThemeRules(parsedThemeRules: ParsedTokenThemeRule[], customTokenColors: string[]): TokenTheme {\r\n\r\n\t// Sort rules lexicographically, and then by index if necessary\r\n\tparsedThemeRules.sort((a, b) => {\r\n\t\tlet r = strcmp(a.token, b.token);\r\n\t\tif (r !== 0) {\r\n\t\t\treturn r;\r\n\t\t}\r\n\t\treturn a.index - b.index;\r\n\t});\r\n\r\n\t// Determine defaults\r\n\tlet defaultFontStyle = FontStyle.None;\r\n\tlet defaultForeground = '000000';\r\n\tlet defaultBackground = 'ffffff';\r\n\twhile (parsedThemeRules.length >= 1 && parsedThemeRules[0].token === '') {\r\n\t\tlet incomingDefaults = parsedThemeRules.shift()!;\r\n\t\tif (incomingDefaults.fontStyle !== FontStyle.NotSet) {\r\n\t\t\tdefaultFontStyle = incomingDefaults.fontStyle;\r\n\t\t}\r\n\t\tif (incomingDefaults.foreground !== null) {\r\n\t\t\tdefaultForeground = incomingDefaults.foreground;\r\n\t\t}\r\n\t\tif (incomingDefaults.background !== null) {\r\n\t\t\tdefaultBackground = incomingDefaults.background;\r\n\t\t}\r\n\t}\r\n\tlet colorMap = new ColorMap();\r\n\r\n\t// start with token colors from custom token themes\r\n\tfor (let color of customTokenColors) {\r\n\t\tcolorMap.getId(color);\r\n\t}\r\n\r\n\r\n\tlet foregroundColorId = colorMap.getId(defaultForeground);\r\n\tlet backgroundColorId = colorMap.getId(defaultBackground);\r\n\r\n\tlet defaults = new ThemeTrieElementRule(defaultFontStyle, foregroundColorId, backgroundColorId);\r\n\tlet root = new ThemeTrieElement(defaults);\r\n\tfor (let i = 0, len = parsedThemeRules.length; i < len; i++) {\r\n\t\tlet rule = parsedThemeRules[i];\r\n\t\troot.insert(rule.token, rule.fontStyle, colorMap.getId(rule.foreground), colorMap.getId(rule.background));\r\n\t}\r\n\r\n\treturn new TokenTheme(colorMap, root);\r\n}\r\n\r\nconst colorRegExp = /^#?([0-9A-Fa-f]{6})([0-9A-Fa-f]{2})?$/;\r\n\r\nexport class ColorMap {\r\n\r\n\tprivate _lastColorId: number;\r\n\tprivate readonly _id2color: Color[];\r\n\tprivate readonly _color2id: Map;\r\n\r\n\tconstructor() {\r\n\t\tthis._lastColorId = 0;\r\n\t\tthis._id2color = [];\r\n\t\tthis._color2id = new Map();\r\n\t}\r\n\r\n\tpublic getId(color: string | null): ColorId {\r\n\t\tif (color === null) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t\tconst match = color.match(colorRegExp);\r\n\t\tif (!match) {\r\n\t\t\tthrow new Error('Illegal value for token color: ' + color);\r\n\t\t}\r\n\t\tcolor = match[1].toUpperCase();\r\n\t\tlet value = this._color2id.get(color);\r\n\t\tif (value) {\r\n\t\t\treturn value;\r\n\t\t}\r\n\t\tvalue = ++this._lastColorId;\r\n\t\tthis._color2id.set(color, value);\r\n\t\tthis._id2color[value] = Color.fromHex('#' + color);\r\n\t\treturn value;\r\n\t}\r\n\r\n\tpublic getColorMap(): Color[] {\r\n\t\treturn this._id2color.slice(0);\r\n\t}\r\n\r\n}\r\n\r\nexport class TokenTheme {\r\n\r\n\tpublic static createFromRawTokenTheme(source: ITokenThemeRule[], customTokenColors: string[]): TokenTheme {\r\n\t\treturn this.createFromParsedTokenTheme(parseTokenTheme(source), customTokenColors);\r\n\t}\r\n\r\n\tpublic static createFromParsedTokenTheme(source: ParsedTokenThemeRule[], customTokenColors: string[]): TokenTheme {\r\n\t\treturn resolveParsedTokenThemeRules(source, customTokenColors);\r\n\t}\r\n\r\n\tprivate readonly _colorMap: ColorMap;\r\n\tprivate readonly _root: ThemeTrieElement;\r\n\tprivate readonly _cache: Map;\r\n\r\n\tconstructor(colorMap: ColorMap, root: ThemeTrieElement) {\r\n\t\tthis._colorMap = colorMap;\r\n\t\tthis._root = root;\r\n\t\tthis._cache = new Map();\r\n\t}\r\n\r\n\tpublic getColorMap(): Color[] {\r\n\t\treturn this._colorMap.getColorMap();\r\n\t}\r\n\r\n\tpublic _match(token: string): ThemeTrieElementRule {\r\n\t\treturn this._root.match(token);\r\n\t}\r\n\r\n\tpublic match(languageId: LanguageId, token: string): number {\r\n\t\t// The cache contains the metadata without the language bits set.\r\n\t\tlet result = this._cache.get(token);\r\n\t\tif (typeof result === 'undefined') {\r\n\t\t\tlet rule = this._match(token);\r\n\t\t\tlet standardToken = toStandardTokenType(token);\r\n\t\t\tresult = (\r\n\t\t\t\trule.metadata\r\n\t\t\t\t| (standardToken << MetadataConsts.TOKEN_TYPE_OFFSET)\r\n\t\t\t) >>> 0;\r\n\t\t\tthis._cache.set(token, result);\r\n\t\t}\r\n\r\n\t\treturn (\r\n\t\t\tresult\r\n\t\t\t| (languageId << MetadataConsts.LANGUAGEID_OFFSET)\r\n\t\t) >>> 0;\r\n\t}\r\n}\r\n\r\nconst STANDARD_TOKEN_TYPE_REGEXP = /\\b(comment|string|regex|regexp)\\b/;\r\nexport function toStandardTokenType(tokenType: string): StandardTokenType {\r\n\tlet m = tokenType.match(STANDARD_TOKEN_TYPE_REGEXP);\r\n\tif (!m) {\r\n\t\treturn StandardTokenType.Other;\r\n\t}\r\n\tswitch (m[1]) {\r\n\t\tcase 'comment':\r\n\t\t\treturn StandardTokenType.Comment;\r\n\t\tcase 'string':\r\n\t\t\treturn StandardTokenType.String;\r\n\t\tcase 'regex':\r\n\t\t\treturn StandardTokenType.RegEx;\r\n\t\tcase 'regexp':\r\n\t\t\treturn StandardTokenType.RegEx;\r\n\t}\r\n\tthrow new Error('Unexpected match for standard token type!');\r\n}\r\n\r\nexport function strcmp(a: string, b: string): number {\r\n\tif (a < b) {\r\n\t\treturn -1;\r\n\t}\r\n\tif (a > b) {\r\n\t\treturn 1;\r\n\t}\r\n\treturn 0;\r\n}\r\n\r\nexport class ThemeTrieElementRule {\r\n\t_themeTrieElementRuleBrand: void;\r\n\r\n\tprivate _fontStyle: FontStyle;\r\n\tprivate _foreground: ColorId;\r\n\tprivate _background: ColorId;\r\n\tpublic metadata: number;\r\n\r\n\tconstructor(fontStyle: FontStyle, foreground: ColorId, background: ColorId) {\r\n\t\tthis._fontStyle = fontStyle;\r\n\t\tthis._foreground = foreground;\r\n\t\tthis._background = background;\r\n\t\tthis.metadata = (\r\n\t\t\t(this._fontStyle << MetadataConsts.FONT_STYLE_OFFSET)\r\n\t\t\t| (this._foreground << MetadataConsts.FOREGROUND_OFFSET)\r\n\t\t\t| (this._background << MetadataConsts.BACKGROUND_OFFSET)\r\n\t\t) >>> 0;\r\n\t}\r\n\r\n\tpublic clone(): ThemeTrieElementRule {\r\n\t\treturn new ThemeTrieElementRule(this._fontStyle, this._foreground, this._background);\r\n\t}\r\n\r\n\tpublic acceptOverwrite(fontStyle: FontStyle, foreground: ColorId, background: ColorId): void {\r\n\t\tif (fontStyle !== FontStyle.NotSet) {\r\n\t\t\tthis._fontStyle = fontStyle;\r\n\t\t}\r\n\t\tif (foreground !== ColorId.None) {\r\n\t\t\tthis._foreground = foreground;\r\n\t\t}\r\n\t\tif (background !== ColorId.None) {\r\n\t\t\tthis._background = background;\r\n\t\t}\r\n\t\tthis.metadata = (\r\n\t\t\t(this._fontStyle << MetadataConsts.FONT_STYLE_OFFSET)\r\n\t\t\t| (this._foreground << MetadataConsts.FOREGROUND_OFFSET)\r\n\t\t\t| (this._background << MetadataConsts.BACKGROUND_OFFSET)\r\n\t\t) >>> 0;\r\n\t}\r\n}\r\n\r\nexport class ThemeTrieElement {\r\n\t_themeTrieElementBrand: void;\r\n\r\n\tprivate readonly _mainRule: ThemeTrieElementRule;\r\n\tprivate readonly _children: Map;\r\n\r\n\tconstructor(mainRule: ThemeTrieElementRule) {\r\n\t\tthis._mainRule = mainRule;\r\n\t\tthis._children = new Map();\r\n\t}\r\n\r\n\tpublic match(token: string): ThemeTrieElementRule {\r\n\t\tif (token === '') {\r\n\t\t\treturn this._mainRule;\r\n\t\t}\r\n\r\n\t\tlet dotIndex = token.indexOf('.');\r\n\t\tlet head: string;\r\n\t\tlet tail: string;\r\n\t\tif (dotIndex === -1) {\r\n\t\t\thead = token;\r\n\t\t\ttail = '';\r\n\t\t} else {\r\n\t\t\thead = token.substring(0, dotIndex);\r\n\t\t\ttail = token.substring(dotIndex + 1);\r\n\t\t}\r\n\r\n\t\tlet child = this._children.get(head);\r\n\t\tif (typeof child !== 'undefined') {\r\n\t\t\treturn child.match(tail);\r\n\t\t}\r\n\r\n\t\treturn this._mainRule;\r\n\t}\r\n\r\n\tpublic insert(token: string, fontStyle: FontStyle, foreground: ColorId, background: ColorId): void {\r\n\t\tif (token === '') {\r\n\t\t\t// Merge into the main rule\r\n\t\t\tthis._mainRule.acceptOverwrite(fontStyle, foreground, background);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet dotIndex = token.indexOf('.');\r\n\t\tlet head: string;\r\n\t\tlet tail: string;\r\n\t\tif (dotIndex === -1) {\r\n\t\t\thead = token;\r\n\t\t\ttail = '';\r\n\t\t} else {\r\n\t\t\thead = token.substring(0, dotIndex);\r\n\t\t\ttail = token.substring(dotIndex + 1);\r\n\t\t}\r\n\r\n\t\tlet child = this._children.get(head);\r\n\t\tif (typeof child === 'undefined') {\r\n\t\t\tchild = new ThemeTrieElement(this._mainRule.clone());\r\n\t\t\tthis._children.set(head, child);\r\n\t\t}\r\n\r\n\t\tchild.insert(tail, fontStyle, foreground, background);\r\n\t}\r\n}\r\n\r\nexport function generateTokensCSSForColorMap(colorMap: readonly Color[]): string {\r\n\tlet rules: string[] = [];\r\n\tfor (let i = 1, len = colorMap.length; i < len; i++) {\r\n\t\tlet color = colorMap[i];\r\n\t\trules[i] = `.mtk${i} { color: ${color}; }`;\r\n\t}\r\n\trules.push('.mtki { font-style: italic; }');\r\n\trules.push('.mtkb { font-weight: bold; }');\r\n\trules.push('.mtku { text-decoration: underline; text-underline-position: under; }');\r\n\treturn rules.join('\\n');\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Color } from 'vs/base/common/color';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { IDisposable, toDisposable } from 'vs/base/common/lifecycle';\r\nimport { ColorId, ITokenizationRegistry, ITokenizationSupport, ITokenizationSupportChangedEvent } from 'vs/editor/common/modes';\r\n\r\nexport class TokenizationRegistryImpl implements ITokenizationRegistry {\r\n\r\n\tprivate readonly _map = new Map();\r\n\tprivate readonly _promises = new Map>();\r\n\r\n\tprivate readonly _onDidChange = new Emitter();\r\n\tpublic readonly onDidChange: Event = this._onDidChange.event;\r\n\r\n\tprivate _colorMap: Color[] | null;\r\n\r\n\tconstructor() {\r\n\t\tthis._colorMap = null;\r\n\t}\r\n\r\n\tpublic fire(languages: string[]): void {\r\n\t\tthis._onDidChange.fire({\r\n\t\t\tchangedLanguages: languages,\r\n\t\t\tchangedColorMap: false\r\n\t\t});\r\n\t}\r\n\r\n\tpublic register(language: string, support: ITokenizationSupport) {\r\n\t\tthis._map.set(language, support);\r\n\t\tthis.fire([language]);\r\n\t\treturn toDisposable(() => {\r\n\t\t\tif (this._map.get(language) !== support) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tthis._map.delete(language);\r\n\t\t\tthis.fire([language]);\r\n\t\t});\r\n\t}\r\n\r\n\tpublic registerPromise(language: string, supportPromise: Thenable): IDisposable {\r\n\r\n\t\tlet registration: IDisposable | null = null;\r\n\t\tlet isDisposed: boolean = false;\r\n\r\n\t\tthis._promises.set(language, supportPromise.then(support => {\r\n\t\t\tthis._promises.delete(language);\r\n\t\t\tif (isDisposed || !support) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tregistration = this.register(language, support);\r\n\t\t}));\r\n\r\n\t\treturn toDisposable(() => {\r\n\t\t\tisDisposed = true;\r\n\t\t\tif (registration) {\r\n\t\t\t\tregistration.dispose();\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic getPromise(language: string): Thenable | null {\r\n\t\tconst support = this.get(language);\r\n\t\tif (support) {\r\n\t\t\treturn Promise.resolve(support);\r\n\t\t}\r\n\t\tconst promise = this._promises.get(language);\r\n\t\tif (promise) {\r\n\t\t\treturn promise.then(_ => this.get(language)!);\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic get(language: string): ITokenizationSupport | null {\r\n\t\treturn (this._map.get(language) || null);\r\n\t}\r\n\r\n\tpublic setColorMap(colorMap: Color[]): void {\r\n\t\tthis._colorMap = colorMap;\r\n\t\tthis._onDidChange.fire({\r\n\t\t\tchangedLanguages: Array.from(this._map.keys()),\r\n\t\t\tchangedColorMap: true\r\n\t\t});\r\n\t}\r\n\r\n\tpublic getColorMap(): Color[] | null {\r\n\t\treturn this._colorMap;\r\n\t}\r\n\r\n\tpublic getDefaultBackground(): Color | null {\r\n\t\tif (this._colorMap && this._colorMap.length > ColorId.DefaultBackground) {\r\n\t\t\treturn this._colorMap[ColorId.DefaultBackground];\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { VSBuffer } from 'vs/base/common/buffer';\r\nimport * as platform from 'vs/base/common/platform';\r\n\r\nexport interface IFullSemanticTokensDto {\r\n\tid: number;\r\n\ttype: 'full';\r\n\tdata: Uint32Array;\r\n}\r\n\r\nexport interface IDeltaSemanticTokensDto {\r\n\tid: number;\r\n\ttype: 'delta';\r\n\tdeltas: { start: number; deleteCount: number; data?: Uint32Array; }[];\r\n}\r\n\r\nexport type ISemanticTokensDto = IFullSemanticTokensDto | IDeltaSemanticTokensDto;\r\n\r\nconst enum EncodedSemanticTokensType {\r\n\tFull = 1,\r\n\tDelta = 2\r\n}\r\n\r\nfunction reverseEndianness(arr: Uint8Array): void {\r\n\tfor (let i = 0, len = arr.length; i < len; i += 4) {\r\n\t\t// flip bytes 0<->3 and 1<->2\r\n\t\tconst b0 = arr[i + 0];\r\n\t\tconst b1 = arr[i + 1];\r\n\t\tconst b2 = arr[i + 2];\r\n\t\tconst b3 = arr[i + 3];\r\n\t\tarr[i + 0] = b3;\r\n\t\tarr[i + 1] = b2;\r\n\t\tarr[i + 2] = b1;\r\n\t\tarr[i + 3] = b0;\r\n\t}\r\n}\r\n\r\nfunction toLittleEndianBuffer(arr: Uint32Array): VSBuffer {\r\n\tconst uint8Arr = new Uint8Array(arr.buffer, arr.byteOffset, arr.length * 4);\r\n\tif (!platform.isLittleEndian()) {\r\n\t\t// the byte order must be changed\r\n\t\treverseEndianness(uint8Arr);\r\n\t}\r\n\treturn VSBuffer.wrap(uint8Arr);\r\n}\r\n\r\nexport function encodeSemanticTokensDto(semanticTokens: ISemanticTokensDto): VSBuffer {\r\n\tconst dest = new Uint32Array(encodeSemanticTokensDtoSize(semanticTokens));\r\n\tlet offset = 0;\r\n\tdest[offset++] = semanticTokens.id;\r\n\tif (semanticTokens.type === 'full') {\r\n\t\tdest[offset++] = EncodedSemanticTokensType.Full;\r\n\t\tdest[offset++] = semanticTokens.data.length;\r\n\t\tdest.set(semanticTokens.data, offset); offset += semanticTokens.data.length;\r\n\t} else {\r\n\t\tdest[offset++] = EncodedSemanticTokensType.Delta;\r\n\t\tdest[offset++] = semanticTokens.deltas.length;\r\n\t\tfor (const delta of semanticTokens.deltas) {\r\n\t\t\tdest[offset++] = delta.start;\r\n\t\t\tdest[offset++] = delta.deleteCount;\r\n\t\t\tif (delta.data) {\r\n\t\t\t\tdest[offset++] = delta.data.length;\r\n\t\t\t\tdest.set(delta.data, offset); offset += delta.data.length;\r\n\t\t\t} else {\r\n\t\t\t\tdest[offset++] = 0;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn toLittleEndianBuffer(dest);\r\n}\r\n\r\nfunction encodeSemanticTokensDtoSize(semanticTokens: ISemanticTokensDto): number {\r\n\tlet result = 0;\r\n\tresult += (\r\n\t\t+ 1 // id\r\n\t\t+ 1 // type\r\n\t);\r\n\tif (semanticTokens.type === 'full') {\r\n\t\tresult += (\r\n\t\t\t+ 1 // data length\r\n\t\t\t+ semanticTokens.data.length\r\n\t\t);\r\n\t} else {\r\n\t\tresult += (\r\n\t\t\t+ 1 // delta count\r\n\t\t);\r\n\t\tresult += (\r\n\t\t\t+ 1 // start\r\n\t\t\t+ 1 // deleteCount\r\n\t\t\t+ 1 // data length\r\n\t\t) * semanticTokens.deltas.length;\r\n\t\tfor (const delta of semanticTokens.deltas) {\r\n\t\t\tif (delta.data) {\r\n\t\t\t\tresult += delta.data.length;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn result;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\n// THIS IS A GENERATED FILE. DO NOT EDIT DIRECTLY.\n\n\nexport enum AccessibilitySupport {\n\t/**\n\t * This should be the browser case where it is not known if a screen reader is attached or no.\n\t */\n\tUnknown = 0,\n\tDisabled = 1,\n\tEnabled = 2\n}\n\nexport enum CompletionItemInsertTextRule {\n\t/**\n\t * Adjust whitespace/indentation of multiline insert texts to\n\t * match the current line indentation.\n\t */\n\tKeepWhitespace = 1,\n\t/**\n\t * `insertText` is a snippet.\n\t */\n\tInsertAsSnippet = 4\n}\n\nexport enum CompletionItemKind {\n\tMethod = 0,\n\tFunction = 1,\n\tConstructor = 2,\n\tField = 3,\n\tVariable = 4,\n\tClass = 5,\n\tStruct = 6,\n\tInterface = 7,\n\tModule = 8,\n\tProperty = 9,\n\tEvent = 10,\n\tOperator = 11,\n\tUnit = 12,\n\tValue = 13,\n\tConstant = 14,\n\tEnum = 15,\n\tEnumMember = 16,\n\tKeyword = 17,\n\tText = 18,\n\tColor = 19,\n\tFile = 20,\n\tReference = 21,\n\tCustomcolor = 22,\n\tFolder = 23,\n\tTypeParameter = 24,\n\tUser = 25,\n\tIssue = 26,\n\tSnippet = 27\n}\n\nexport enum CompletionItemTag {\n\tDeprecated = 1\n}\n\n/**\n * How a suggest provider was triggered.\n */\nexport enum CompletionTriggerKind {\n\tInvoke = 0,\n\tTriggerCharacter = 1,\n\tTriggerForIncompleteCompletions = 2\n}\n\n/**\n * A positioning preference for rendering content widgets.\n */\nexport enum ContentWidgetPositionPreference {\n\t/**\n\t * Place the content widget exactly at a position\n\t */\n\tEXACT = 0,\n\t/**\n\t * Place the content widget above a position\n\t */\n\tABOVE = 1,\n\t/**\n\t * Place the content widget below a position\n\t */\n\tBELOW = 2\n}\n\n/**\n * Describes the reason the cursor has changed its position.\n */\nexport enum CursorChangeReason {\n\t/**\n\t * Unknown or not set.\n\t */\n\tNotSet = 0,\n\t/**\n\t * A `model.setValue()` was called.\n\t */\n\tContentFlush = 1,\n\t/**\n\t * The `model` has been changed outside of this cursor and the cursor recovers its position from associated markers.\n\t */\n\tRecoverFromMarkers = 2,\n\t/**\n\t * There was an explicit user gesture.\n\t */\n\tExplicit = 3,\n\t/**\n\t * There was a Paste.\n\t */\n\tPaste = 4,\n\t/**\n\t * There was an Undo.\n\t */\n\tUndo = 5,\n\t/**\n\t * There was a Redo.\n\t */\n\tRedo = 6\n}\n\n/**\n * The default end of line to use when instantiating models.\n */\nexport enum DefaultEndOfLine {\n\t/**\n\t * Use line feed (\\n) as the end of line character.\n\t */\n\tLF = 1,\n\t/**\n\t * Use carriage return and line feed (\\r\\n) as the end of line character.\n\t */\n\tCRLF = 2\n}\n\n/**\n * A document highlight kind.\n */\nexport enum DocumentHighlightKind {\n\t/**\n\t * A textual occurrence.\n\t */\n\tText = 0,\n\t/**\n\t * Read-access of a symbol, like reading a variable.\n\t */\n\tRead = 1,\n\t/**\n\t * Write-access of a symbol, like writing to a variable.\n\t */\n\tWrite = 2\n}\n\n/**\n * Configuration options for auto indentation in the editor\n */\nexport enum EditorAutoIndentStrategy {\n\tNone = 0,\n\tKeep = 1,\n\tBrackets = 2,\n\tAdvanced = 3,\n\tFull = 4\n}\n\nexport enum EditorOption {\n\tacceptSuggestionOnCommitCharacter = 0,\n\tacceptSuggestionOnEnter = 1,\n\taccessibilitySupport = 2,\n\taccessibilityPageSize = 3,\n\tariaLabel = 4,\n\tautoClosingBrackets = 5,\n\tautoClosingOvertype = 6,\n\tautoClosingQuotes = 7,\n\tautoIndent = 8,\n\tautomaticLayout = 9,\n\tautoSurround = 10,\n\tcodeLens = 11,\n\tcodeLensFontFamily = 12,\n\tcodeLensFontSize = 13,\n\tcolorDecorators = 14,\n\tcolumnSelection = 15,\n\tcomments = 16,\n\tcontextmenu = 17,\n\tcopyWithSyntaxHighlighting = 18,\n\tcursorBlinking = 19,\n\tcursorSmoothCaretAnimation = 20,\n\tcursorStyle = 21,\n\tcursorSurroundingLines = 22,\n\tcursorSurroundingLinesStyle = 23,\n\tcursorWidth = 24,\n\tdisableLayerHinting = 25,\n\tdisableMonospaceOptimizations = 26,\n\tdragAndDrop = 27,\n\temptySelectionClipboard = 28,\n\textraEditorClassName = 29,\n\tfastScrollSensitivity = 30,\n\tfind = 31,\n\tfixedOverflowWidgets = 32,\n\tfolding = 33,\n\tfoldingStrategy = 34,\n\tfoldingHighlight = 35,\n\tunfoldOnClickAfterEndOfLine = 36,\n\tfontFamily = 37,\n\tfontInfo = 38,\n\tfontLigatures = 39,\n\tfontSize = 40,\n\tfontWeight = 41,\n\tformatOnPaste = 42,\n\tformatOnType = 43,\n\tglyphMargin = 44,\n\tgotoLocation = 45,\n\thideCursorInOverviewRuler = 46,\n\thighlightActiveIndentGuide = 47,\n\thover = 48,\n\tinDiffEditor = 49,\n\tletterSpacing = 50,\n\tlightbulb = 51,\n\tlineDecorationsWidth = 52,\n\tlineHeight = 53,\n\tlineNumbers = 54,\n\tlineNumbersMinChars = 55,\n\tlinkedEditing = 56,\n\tlinks = 57,\n\tmatchBrackets = 58,\n\tminimap = 59,\n\tmouseStyle = 60,\n\tmouseWheelScrollSensitivity = 61,\n\tmouseWheelZoom = 62,\n\tmultiCursorMergeOverlapping = 63,\n\tmultiCursorModifier = 64,\n\tmultiCursorPaste = 65,\n\toccurrencesHighlight = 66,\n\toverviewRulerBorder = 67,\n\toverviewRulerLanes = 68,\n\tpadding = 69,\n\tparameterHints = 70,\n\tpeekWidgetDefaultFocus = 71,\n\tdefinitionLinkOpensInPeek = 72,\n\tquickSuggestions = 73,\n\tquickSuggestionsDelay = 74,\n\treadOnly = 75,\n\trenameOnType = 76,\n\trenderControlCharacters = 77,\n\trenderIndentGuides = 78,\n\trenderFinalNewline = 79,\n\trenderLineHighlight = 80,\n\trenderLineHighlightOnlyWhenFocus = 81,\n\trenderValidationDecorations = 82,\n\trenderWhitespace = 83,\n\trevealHorizontalRightPadding = 84,\n\troundedSelection = 85,\n\trulers = 86,\n\tscrollbar = 87,\n\tscrollBeyondLastColumn = 88,\n\tscrollBeyondLastLine = 89,\n\tscrollPredominantAxis = 90,\n\tselectionClipboard = 91,\n\tselectionHighlight = 92,\n\tselectOnLineNumbers = 93,\n\tshowFoldingControls = 94,\n\tshowUnused = 95,\n\tsnippetSuggestions = 96,\n\tsmartSelect = 97,\n\tsmoothScrolling = 98,\n\tstickyTabStops = 99,\n\tstopRenderingLineAfter = 100,\n\tsuggest = 101,\n\tsuggestFontSize = 102,\n\tsuggestLineHeight = 103,\n\tsuggestOnTriggerCharacters = 104,\n\tsuggestSelection = 105,\n\ttabCompletion = 106,\n\ttabIndex = 107,\n\tunusualLineTerminators = 108,\n\tuseTabStops = 109,\n\twordSeparators = 110,\n\twordWrap = 111,\n\twordWrapBreakAfterCharacters = 112,\n\twordWrapBreakBeforeCharacters = 113,\n\twordWrapColumn = 114,\n\twordWrapOverride1 = 115,\n\twordWrapOverride2 = 116,\n\twrappingIndent = 117,\n\twrappingStrategy = 118,\n\tshowDeprecated = 119,\n\tinlineHints = 120,\n\teditorClassName = 121,\n\tpixelRatio = 122,\n\ttabFocusMode = 123,\n\tlayoutInfo = 124,\n\twrappingInfo = 125\n}\n\n/**\n * End of line character preference.\n */\nexport enum EndOfLinePreference {\n\t/**\n\t * Use the end of line character identified in the text buffer.\n\t */\n\tTextDefined = 0,\n\t/**\n\t * Use line feed (\\n) as the end of line character.\n\t */\n\tLF = 1,\n\t/**\n\t * Use carriage return and line feed (\\r\\n) as the end of line character.\n\t */\n\tCRLF = 2\n}\n\n/**\n * End of line character preference.\n */\nexport enum EndOfLineSequence {\n\t/**\n\t * Use line feed (\\n) as the end of line character.\n\t */\n\tLF = 0,\n\t/**\n\t * Use carriage return and line feed (\\r\\n) as the end of line character.\n\t */\n\tCRLF = 1\n}\n\n/**\n * Describes what to do with the indentation when pressing Enter.\n */\nexport enum IndentAction {\n\t/**\n\t * Insert new line and copy the previous line's indentation.\n\t */\n\tNone = 0,\n\t/**\n\t * Insert new line and indent once (relative to the previous line's indentation).\n\t */\n\tIndent = 1,\n\t/**\n\t * Insert two new lines:\n\t * - the first one indented which will hold the cursor\n\t * - the second one at the same indentation level\n\t */\n\tIndentOutdent = 2,\n\t/**\n\t * Insert new line and outdent once (relative to the previous line's indentation).\n\t */\n\tOutdent = 3\n}\n\n/**\n * Virtual Key Codes, the value does not hold any inherent meaning.\n * Inspired somewhat from https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx\n * But these are \"more general\", as they should work across browsers & OS`s.\n */\nexport enum KeyCode {\n\t/**\n\t * Placed first to cover the 0 value of the enum.\n\t */\n\tUnknown = 0,\n\tBackspace = 1,\n\tTab = 2,\n\tEnter = 3,\n\tShift = 4,\n\tCtrl = 5,\n\tAlt = 6,\n\tPauseBreak = 7,\n\tCapsLock = 8,\n\tEscape = 9,\n\tSpace = 10,\n\tPageUp = 11,\n\tPageDown = 12,\n\tEnd = 13,\n\tHome = 14,\n\tLeftArrow = 15,\n\tUpArrow = 16,\n\tRightArrow = 17,\n\tDownArrow = 18,\n\tInsert = 19,\n\tDelete = 20,\n\tKEY_0 = 21,\n\tKEY_1 = 22,\n\tKEY_2 = 23,\n\tKEY_3 = 24,\n\tKEY_4 = 25,\n\tKEY_5 = 26,\n\tKEY_6 = 27,\n\tKEY_7 = 28,\n\tKEY_8 = 29,\n\tKEY_9 = 30,\n\tKEY_A = 31,\n\tKEY_B = 32,\n\tKEY_C = 33,\n\tKEY_D = 34,\n\tKEY_E = 35,\n\tKEY_F = 36,\n\tKEY_G = 37,\n\tKEY_H = 38,\n\tKEY_I = 39,\n\tKEY_J = 40,\n\tKEY_K = 41,\n\tKEY_L = 42,\n\tKEY_M = 43,\n\tKEY_N = 44,\n\tKEY_O = 45,\n\tKEY_P = 46,\n\tKEY_Q = 47,\n\tKEY_R = 48,\n\tKEY_S = 49,\n\tKEY_T = 50,\n\tKEY_U = 51,\n\tKEY_V = 52,\n\tKEY_W = 53,\n\tKEY_X = 54,\n\tKEY_Y = 55,\n\tKEY_Z = 56,\n\tMeta = 57,\n\tContextMenu = 58,\n\tF1 = 59,\n\tF2 = 60,\n\tF3 = 61,\n\tF4 = 62,\n\tF5 = 63,\n\tF6 = 64,\n\tF7 = 65,\n\tF8 = 66,\n\tF9 = 67,\n\tF10 = 68,\n\tF11 = 69,\n\tF12 = 70,\n\tF13 = 71,\n\tF14 = 72,\n\tF15 = 73,\n\tF16 = 74,\n\tF17 = 75,\n\tF18 = 76,\n\tF19 = 77,\n\tNumLock = 78,\n\tScrollLock = 79,\n\t/**\n\t * Used for miscellaneous characters; it can vary by keyboard.\n\t * For the US standard keyboard, the ';:' key\n\t */\n\tUS_SEMICOLON = 80,\n\t/**\n\t * For any country/region, the '+' key\n\t * For the US standard keyboard, the '=+' key\n\t */\n\tUS_EQUAL = 81,\n\t/**\n\t * For any country/region, the ',' key\n\t * For the US standard keyboard, the ',<' key\n\t */\n\tUS_COMMA = 82,\n\t/**\n\t * For any country/region, the '-' key\n\t * For the US standard keyboard, the '-_' key\n\t */\n\tUS_MINUS = 83,\n\t/**\n\t * For any country/region, the '.' key\n\t * For the US standard keyboard, the '.>' key\n\t */\n\tUS_DOT = 84,\n\t/**\n\t * Used for miscellaneous characters; it can vary by keyboard.\n\t * For the US standard keyboard, the '/?' key\n\t */\n\tUS_SLASH = 85,\n\t/**\n\t * Used for miscellaneous characters; it can vary by keyboard.\n\t * For the US standard keyboard, the '`~' key\n\t */\n\tUS_BACKTICK = 86,\n\t/**\n\t * Used for miscellaneous characters; it can vary by keyboard.\n\t * For the US standard keyboard, the '[{' key\n\t */\n\tUS_OPEN_SQUARE_BRACKET = 87,\n\t/**\n\t * Used for miscellaneous characters; it can vary by keyboard.\n\t * For the US standard keyboard, the '\\|' key\n\t */\n\tUS_BACKSLASH = 88,\n\t/**\n\t * Used for miscellaneous characters; it can vary by keyboard.\n\t * For the US standard keyboard, the ']}' key\n\t */\n\tUS_CLOSE_SQUARE_BRACKET = 89,\n\t/**\n\t * Used for miscellaneous characters; it can vary by keyboard.\n\t * For the US standard keyboard, the ''\"' key\n\t */\n\tUS_QUOTE = 90,\n\t/**\n\t * Used for miscellaneous characters; it can vary by keyboard.\n\t */\n\tOEM_8 = 91,\n\t/**\n\t * Either the angle bracket key or the backslash key on the RT 102-key keyboard.\n\t */\n\tOEM_102 = 92,\n\tNUMPAD_0 = 93,\n\tNUMPAD_1 = 94,\n\tNUMPAD_2 = 95,\n\tNUMPAD_3 = 96,\n\tNUMPAD_4 = 97,\n\tNUMPAD_5 = 98,\n\tNUMPAD_6 = 99,\n\tNUMPAD_7 = 100,\n\tNUMPAD_8 = 101,\n\tNUMPAD_9 = 102,\n\tNUMPAD_MULTIPLY = 103,\n\tNUMPAD_ADD = 104,\n\tNUMPAD_SEPARATOR = 105,\n\tNUMPAD_SUBTRACT = 106,\n\tNUMPAD_DECIMAL = 107,\n\tNUMPAD_DIVIDE = 108,\n\t/**\n\t * Cover all key codes when IME is processing input.\n\t */\n\tKEY_IN_COMPOSITION = 109,\n\tABNT_C1 = 110,\n\tABNT_C2 = 111,\n\t/**\n\t * Placed last to cover the length of the enum.\n\t * Please do not depend on this value!\n\t */\n\tMAX_VALUE = 112\n}\n\nexport enum MarkerSeverity {\n\tHint = 1,\n\tInfo = 2,\n\tWarning = 4,\n\tError = 8\n}\n\nexport enum MarkerTag {\n\tUnnecessary = 1,\n\tDeprecated = 2\n}\n\n/**\n * Position in the minimap to render the decoration.\n */\nexport enum MinimapPosition {\n\tInline = 1,\n\tGutter = 2\n}\n\n/**\n * Type of hit element with the mouse in the editor.\n */\nexport enum MouseTargetType {\n\t/**\n\t * Mouse is on top of an unknown element.\n\t */\n\tUNKNOWN = 0,\n\t/**\n\t * Mouse is on top of the textarea used for input.\n\t */\n\tTEXTAREA = 1,\n\t/**\n\t * Mouse is on top of the glyph margin\n\t */\n\tGUTTER_GLYPH_MARGIN = 2,\n\t/**\n\t * Mouse is on top of the line numbers\n\t */\n\tGUTTER_LINE_NUMBERS = 3,\n\t/**\n\t * Mouse is on top of the line decorations\n\t */\n\tGUTTER_LINE_DECORATIONS = 4,\n\t/**\n\t * Mouse is on top of the whitespace left in the gutter by a view zone.\n\t */\n\tGUTTER_VIEW_ZONE = 5,\n\t/**\n\t * Mouse is on top of text in the content.\n\t */\n\tCONTENT_TEXT = 6,\n\t/**\n\t * Mouse is on top of empty space in the content (e.g. after line text or below last line)\n\t */\n\tCONTENT_EMPTY = 7,\n\t/**\n\t * Mouse is on top of a view zone in the content.\n\t */\n\tCONTENT_VIEW_ZONE = 8,\n\t/**\n\t * Mouse is on top of a content widget.\n\t */\n\tCONTENT_WIDGET = 9,\n\t/**\n\t * Mouse is on top of the decorations overview ruler.\n\t */\n\tOVERVIEW_RULER = 10,\n\t/**\n\t * Mouse is on top of a scrollbar.\n\t */\n\tSCROLLBAR = 11,\n\t/**\n\t * Mouse is on top of an overlay widget.\n\t */\n\tOVERLAY_WIDGET = 12,\n\t/**\n\t * Mouse is outside of the editor.\n\t */\n\tOUTSIDE_EDITOR = 13\n}\n\n/**\n * A positioning preference for rendering overlay widgets.\n */\nexport enum OverlayWidgetPositionPreference {\n\t/**\n\t * Position the overlay widget in the top right corner\n\t */\n\tTOP_RIGHT_CORNER = 0,\n\t/**\n\t * Position the overlay widget in the bottom right corner\n\t */\n\tBOTTOM_RIGHT_CORNER = 1,\n\t/**\n\t * Position the overlay widget in the top center\n\t */\n\tTOP_CENTER = 2\n}\n\n/**\n * Vertical Lane in the overview ruler of the editor.\n */\nexport enum OverviewRulerLane {\n\tLeft = 1,\n\tCenter = 2,\n\tRight = 4,\n\tFull = 7\n}\n\nexport enum RenderLineNumbersType {\n\tOff = 0,\n\tOn = 1,\n\tRelative = 2,\n\tInterval = 3,\n\tCustom = 4\n}\n\nexport enum RenderMinimap {\n\tNone = 0,\n\tText = 1,\n\tBlocks = 2\n}\n\nexport enum ScrollType {\n\tSmooth = 0,\n\tImmediate = 1\n}\n\nexport enum ScrollbarVisibility {\n\tAuto = 1,\n\tHidden = 2,\n\tVisible = 3\n}\n\n/**\n * The direction of a selection.\n */\nexport enum SelectionDirection {\n\t/**\n\t * The selection starts above where it ends.\n\t */\n\tLTR = 0,\n\t/**\n\t * The selection starts below where it ends.\n\t */\n\tRTL = 1\n}\n\nexport enum SignatureHelpTriggerKind {\n\tInvoke = 1,\n\tTriggerCharacter = 2,\n\tContentChange = 3\n}\n\n/**\n * A symbol kind.\n */\nexport enum SymbolKind {\n\tFile = 0,\n\tModule = 1,\n\tNamespace = 2,\n\tPackage = 3,\n\tClass = 4,\n\tMethod = 5,\n\tProperty = 6,\n\tField = 7,\n\tConstructor = 8,\n\tEnum = 9,\n\tInterface = 10,\n\tFunction = 11,\n\tVariable = 12,\n\tConstant = 13,\n\tString = 14,\n\tNumber = 15,\n\tBoolean = 16,\n\tArray = 17,\n\tObject = 18,\n\tKey = 19,\n\tNull = 20,\n\tEnumMember = 21,\n\tStruct = 22,\n\tEvent = 23,\n\tOperator = 24,\n\tTypeParameter = 25\n}\n\nexport enum SymbolTag {\n\tDeprecated = 1\n}\n\n/**\n * The kind of animation in which the editor's cursor should be rendered.\n */\nexport enum TextEditorCursorBlinkingStyle {\n\t/**\n\t * Hidden\n\t */\n\tHidden = 0,\n\t/**\n\t * Blinking\n\t */\n\tBlink = 1,\n\t/**\n\t * Blinking with smooth fading\n\t */\n\tSmooth = 2,\n\t/**\n\t * Blinking with prolonged filled state and smooth fading\n\t */\n\tPhase = 3,\n\t/**\n\t * Expand collapse animation on the y axis\n\t */\n\tExpand = 4,\n\t/**\n\t * No-Blinking\n\t */\n\tSolid = 5\n}\n\n/**\n * The style in which the editor's cursor should be rendered.\n */\nexport enum TextEditorCursorStyle {\n\t/**\n\t * As a vertical line (sitting between two characters).\n\t */\n\tLine = 1,\n\t/**\n\t * As a block (sitting on top of a character).\n\t */\n\tBlock = 2,\n\t/**\n\t * As a horizontal line (sitting under a character).\n\t */\n\tUnderline = 3,\n\t/**\n\t * As a thin vertical line (sitting between two characters).\n\t */\n\tLineThin = 4,\n\t/**\n\t * As an outlined block (sitting on top of a character).\n\t */\n\tBlockOutline = 5,\n\t/**\n\t * As a thin horizontal line (sitting under a character).\n\t */\n\tUnderlineThin = 6\n}\n\n/**\n * Describes the behavior of decorations when typing/editing near their edges.\n * Note: Please do not edit the values, as they very carefully match `DecorationRangeBehavior`\n */\nexport enum TrackedRangeStickiness {\n\tAlwaysGrowsWhenTypingAtEdges = 0,\n\tNeverGrowsWhenTypingAtEdges = 1,\n\tGrowsOnlyWhenTypingBefore = 2,\n\tGrowsOnlyWhenTypingAfter = 3\n}\n\n/**\n * Describes how to indent wrapped lines.\n */\nexport enum WrappingIndent {\n\t/**\n\t * No indentation => wrapped lines begin at column 1.\n\t */\n\tNone = 0,\n\t/**\n\t * Same => wrapped lines get the same indentation as the parent.\n\t */\n\tSame = 1,\n\t/**\n\t * Indent => wrapped lines get +1 indentation toward the parent.\n\t */\n\tIndent = 2,\n\t/**\n\t * DeepIndent => wrapped lines get +2 indentation toward the parent.\n\t */\n\tDeepIndent = 3\n}","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CancellationTokenSource } from 'vs/base/common/cancellation';\r\nimport { Emitter } from 'vs/base/common/event';\r\nimport { KeyChord, KeyMod as ConstKeyMod } from 'vs/base/common/keyCodes';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { Token } from 'vs/editor/common/core/token';\r\nimport * as standaloneEnums from 'vs/editor/common/standalone/standaloneEnums';\r\n\r\nexport class KeyMod {\r\n\tpublic static readonly CtrlCmd: number = ConstKeyMod.CtrlCmd;\r\n\tpublic static readonly Shift: number = ConstKeyMod.Shift;\r\n\tpublic static readonly Alt: number = ConstKeyMod.Alt;\r\n\tpublic static readonly WinCtrl: number = ConstKeyMod.WinCtrl;\r\n\r\n\tpublic static chord(firstPart: number, secondPart: number): number {\r\n\t\treturn KeyChord(firstPart, secondPart);\r\n\t}\r\n}\r\n\r\nexport function createMonacoBaseAPI(): typeof monaco {\r\n\treturn {\r\n\t\teditor: undefined!, // undefined override expected here\r\n\t\tlanguages: undefined!, // undefined override expected here\r\n\t\tCancellationTokenSource: CancellationTokenSource,\r\n\t\tEmitter: Emitter,\r\n\t\tKeyCode: standaloneEnums.KeyCode,\r\n\t\tKeyMod: KeyMod,\r\n\t\tPosition: Position,\r\n\t\tRange: Range,\r\n\t\tSelection: Selection,\r\n\t\tSelectionDirection: standaloneEnums.SelectionDirection,\r\n\t\tMarkerSeverity: standaloneEnums.MarkerSeverity,\r\n\t\tMarkerTag: standaloneEnums.MarkerTag,\r\n\t\tUri: URI,\r\n\t\tToken: Token\r\n\t};\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nconst enum Constants {\r\n\tMINIMUM_HEIGHT = 4\r\n}\r\n\r\nexport class ColorZone {\r\n\t_colorZoneBrand: void;\r\n\r\n\tpublic readonly from: number;\r\n\tpublic readonly to: number;\r\n\tpublic readonly colorId: number;\r\n\r\n\tconstructor(from: number, to: number, colorId: number) {\r\n\t\tthis.from = from | 0;\r\n\t\tthis.to = to | 0;\r\n\t\tthis.colorId = colorId | 0;\r\n\t}\r\n\r\n\tpublic static compare(a: ColorZone, b: ColorZone): number {\r\n\t\tif (a.colorId === b.colorId) {\r\n\t\t\tif (a.from === b.from) {\r\n\t\t\t\treturn a.to - b.to;\r\n\t\t\t}\r\n\t\t\treturn a.from - b.from;\r\n\t\t}\r\n\t\treturn a.colorId - b.colorId;\r\n\t}\r\n}\r\n\r\n/**\r\n * A zone in the overview ruler\r\n */\r\nexport class OverviewRulerZone {\r\n\t_overviewRulerZoneBrand: void;\r\n\r\n\tpublic readonly startLineNumber: number;\r\n\tpublic readonly endLineNumber: number;\r\n\tpublic readonly color: string;\r\n\r\n\tprivate _colorZone: ColorZone | null;\r\n\r\n\tconstructor(\r\n\t\tstartLineNumber: number,\r\n\t\tendLineNumber: number,\r\n\t\tcolor: string\r\n\t) {\r\n\t\tthis.startLineNumber = startLineNumber;\r\n\t\tthis.endLineNumber = endLineNumber;\r\n\t\tthis.color = color;\r\n\t\tthis._colorZone = null;\r\n\t}\r\n\r\n\tpublic static compare(a: OverviewRulerZone, b: OverviewRulerZone): number {\r\n\t\tif (a.color === b.color) {\r\n\t\t\tif (a.startLineNumber === b.startLineNumber) {\r\n\t\t\t\treturn a.endLineNumber - b.endLineNumber;\r\n\t\t\t}\r\n\t\t\treturn a.startLineNumber - b.startLineNumber;\r\n\t\t}\r\n\t\treturn a.color < b.color ? -1 : 1;\r\n\t}\r\n\r\n\tpublic setColorZone(colorZone: ColorZone): void {\r\n\t\tthis._colorZone = colorZone;\r\n\t}\r\n\r\n\tpublic getColorZones(): ColorZone | null {\r\n\t\treturn this._colorZone;\r\n\t}\r\n}\r\n\r\nexport class OverviewZoneManager {\r\n\r\n\tprivate readonly _getVerticalOffsetForLine: (lineNumber: number) => number;\r\n\tprivate _zones: OverviewRulerZone[];\r\n\tprivate _colorZonesInvalid: boolean;\r\n\tprivate _lineHeight: number;\r\n\tprivate _domWidth: number;\r\n\tprivate _domHeight: number;\r\n\tprivate _outerHeight: number;\r\n\tprivate _pixelRatio: number;\r\n\r\n\tprivate _lastAssignedId: number;\r\n\tprivate readonly _color2Id: { [color: string]: number; };\r\n\tprivate readonly _id2Color: string[];\r\n\r\n\tconstructor(getVerticalOffsetForLine: (lineNumber: number) => number) {\r\n\t\tthis._getVerticalOffsetForLine = getVerticalOffsetForLine;\r\n\t\tthis._zones = [];\r\n\t\tthis._colorZonesInvalid = false;\r\n\t\tthis._lineHeight = 0;\r\n\t\tthis._domWidth = 0;\r\n\t\tthis._domHeight = 0;\r\n\t\tthis._outerHeight = 0;\r\n\t\tthis._pixelRatio = 1;\r\n\r\n\t\tthis._lastAssignedId = 0;\r\n\t\tthis._color2Id = Object.create(null);\r\n\t\tthis._id2Color = [];\r\n\t}\r\n\r\n\tpublic getId2Color(): string[] {\r\n\t\treturn this._id2Color;\r\n\t}\r\n\r\n\tpublic setZones(newZones: OverviewRulerZone[]): void {\r\n\t\tthis._zones = newZones;\r\n\t\tthis._zones.sort(OverviewRulerZone.compare);\r\n\t}\r\n\r\n\tpublic setLineHeight(lineHeight: number): boolean {\r\n\t\tif (this._lineHeight === lineHeight) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tthis._lineHeight = lineHeight;\r\n\t\tthis._colorZonesInvalid = true;\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic setPixelRatio(pixelRatio: number): void {\r\n\t\tthis._pixelRatio = pixelRatio;\r\n\t\tthis._colorZonesInvalid = true;\r\n\t}\r\n\r\n\tpublic getDOMWidth(): number {\r\n\t\treturn this._domWidth;\r\n\t}\r\n\r\n\tpublic getCanvasWidth(): number {\r\n\t\treturn this._domWidth * this._pixelRatio;\r\n\t}\r\n\r\n\tpublic setDOMWidth(width: number): boolean {\r\n\t\tif (this._domWidth === width) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tthis._domWidth = width;\r\n\t\tthis._colorZonesInvalid = true;\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic getDOMHeight(): number {\r\n\t\treturn this._domHeight;\r\n\t}\r\n\r\n\tpublic getCanvasHeight(): number {\r\n\t\treturn this._domHeight * this._pixelRatio;\r\n\t}\r\n\r\n\tpublic setDOMHeight(height: number): boolean {\r\n\t\tif (this._domHeight === height) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tthis._domHeight = height;\r\n\t\tthis._colorZonesInvalid = true;\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic getOuterHeight(): number {\r\n\t\treturn this._outerHeight;\r\n\t}\r\n\r\n\tpublic setOuterHeight(outerHeight: number): boolean {\r\n\t\tif (this._outerHeight === outerHeight) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tthis._outerHeight = outerHeight;\r\n\t\tthis._colorZonesInvalid = true;\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic resolveColorZones(): ColorZone[] {\r\n\t\tconst colorZonesInvalid = this._colorZonesInvalid;\r\n\t\tconst lineHeight = Math.floor(this._lineHeight); // @perf\r\n\t\tconst totalHeight = Math.floor(this.getCanvasHeight()); // @perf\r\n\t\tconst outerHeight = Math.floor(this._outerHeight); // @perf\r\n\t\tconst heightRatio = totalHeight / outerHeight;\r\n\t\tconst halfMinimumHeight = Math.floor(Constants.MINIMUM_HEIGHT * this._pixelRatio / 2);\r\n\r\n\t\tlet allColorZones: ColorZone[] = [];\r\n\t\tfor (let i = 0, len = this._zones.length; i < len; i++) {\r\n\t\t\tconst zone = this._zones[i];\r\n\r\n\t\t\tif (!colorZonesInvalid) {\r\n\t\t\t\tconst colorZone = zone.getColorZones();\r\n\t\t\t\tif (colorZone) {\r\n\t\t\t\t\tallColorZones.push(colorZone);\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tconst y1 = Math.floor(heightRatio * (this._getVerticalOffsetForLine(zone.startLineNumber)));\r\n\t\t\tconst y2 = Math.floor(heightRatio * (this._getVerticalOffsetForLine(zone.endLineNumber) + lineHeight));\r\n\r\n\t\t\tlet ycenter = Math.floor((y1 + y2) / 2);\r\n\t\t\tlet halfHeight = (y2 - ycenter);\r\n\r\n\t\t\tif (halfHeight < halfMinimumHeight) {\r\n\t\t\t\thalfHeight = halfMinimumHeight;\r\n\t\t\t}\r\n\r\n\t\t\tif (ycenter - halfHeight < 0) {\r\n\t\t\t\tycenter = halfHeight;\r\n\t\t\t}\r\n\t\t\tif (ycenter + halfHeight > totalHeight) {\r\n\t\t\t\tycenter = totalHeight - halfHeight;\r\n\t\t\t}\r\n\r\n\t\t\tconst color = zone.color;\r\n\t\t\tlet colorId = this._color2Id[color];\r\n\t\t\tif (!colorId) {\r\n\t\t\t\tcolorId = (++this._lastAssignedId);\r\n\t\t\t\tthis._color2Id[color] = colorId;\r\n\t\t\t\tthis._id2Color[colorId] = color;\r\n\t\t\t}\r\n\t\t\tconst colorZone = new ColorZone(ycenter - halfHeight, ycenter + halfHeight, colorId);\r\n\r\n\t\t\tzone.setColorZone(colorZone);\r\n\t\t\tallColorZones.push(colorZone);\r\n\t\t}\r\n\r\n\t\tthis._colorZonesInvalid = false;\r\n\r\n\t\tallColorZones.sort(ColorZone.compare);\r\n\t\treturn allColorZones;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';\r\nimport { IViewLayout, ViewModelDecoration } from 'vs/editor/common/viewModel/viewModel';\r\n\r\nexport interface IViewLines {\r\n\tlinesVisibleRangesForRange(range: Range, includeNewLines: boolean): LineVisibleRanges[] | null;\r\n\tvisibleRangeForPosition(position: Position): HorizontalPosition | null;\r\n}\r\n\r\nexport abstract class RestrictedRenderingContext {\r\n\t_restrictedRenderingContextBrand: void;\r\n\r\n\tpublic readonly viewportData: ViewportData;\r\n\r\n\tpublic readonly scrollWidth: number;\r\n\tpublic readonly scrollHeight: number;\r\n\r\n\tpublic readonly visibleRange: Range;\r\n\tpublic readonly bigNumbersDelta: number;\r\n\r\n\tpublic readonly scrollTop: number;\r\n\tpublic readonly scrollLeft: number;\r\n\r\n\tpublic readonly viewportWidth: number;\r\n\tpublic readonly viewportHeight: number;\r\n\r\n\tprivate readonly _viewLayout: IViewLayout;\r\n\r\n\tconstructor(viewLayout: IViewLayout, viewportData: ViewportData) {\r\n\t\tthis._viewLayout = viewLayout;\r\n\t\tthis.viewportData = viewportData;\r\n\r\n\t\tthis.scrollWidth = this._viewLayout.getScrollWidth();\r\n\t\tthis.scrollHeight = this._viewLayout.getScrollHeight();\r\n\r\n\t\tthis.visibleRange = this.viewportData.visibleRange;\r\n\t\tthis.bigNumbersDelta = this.viewportData.bigNumbersDelta;\r\n\r\n\t\tconst vInfo = this._viewLayout.getCurrentViewport();\r\n\t\tthis.scrollTop = vInfo.top;\r\n\t\tthis.scrollLeft = vInfo.left;\r\n\t\tthis.viewportWidth = vInfo.width;\r\n\t\tthis.viewportHeight = vInfo.height;\r\n\t}\r\n\r\n\tpublic getScrolledTopFromAbsoluteTop(absoluteTop: number): number {\r\n\t\treturn absoluteTop - this.scrollTop;\r\n\t}\r\n\r\n\tpublic getVerticalOffsetForLineNumber(lineNumber: number): number {\r\n\t\treturn this._viewLayout.getVerticalOffsetForLineNumber(lineNumber);\r\n\t}\r\n\r\n\tpublic getDecorationsInViewport(): ViewModelDecoration[] {\r\n\t\treturn this.viewportData.getDecorationsInViewport();\r\n\t}\r\n\r\n}\r\n\r\nexport class RenderingContext extends RestrictedRenderingContext {\r\n\t_renderingContextBrand: void;\r\n\r\n\tprivate readonly _viewLines: IViewLines;\r\n\r\n\tconstructor(viewLayout: IViewLayout, viewportData: ViewportData, viewLines: IViewLines) {\r\n\t\tsuper(viewLayout, viewportData);\r\n\t\tthis._viewLines = viewLines;\r\n\t}\r\n\r\n\tpublic linesVisibleRangesForRange(range: Range, includeNewLines: boolean): LineVisibleRanges[] | null {\r\n\t\treturn this._viewLines.linesVisibleRangesForRange(range, includeNewLines);\r\n\t}\r\n\r\n\tpublic visibleRangeForPosition(position: Position): HorizontalPosition | null {\r\n\t\treturn this._viewLines.visibleRangeForPosition(position);\r\n\t}\r\n}\r\n\r\nexport class LineVisibleRanges {\r\n\tconstructor(\r\n\t\tpublic readonly outsideRenderedLine: boolean,\r\n\t\tpublic readonly lineNumber: number,\r\n\t\tpublic readonly ranges: HorizontalRange[]\r\n\t) { }\r\n}\r\n\r\nexport class HorizontalRange {\r\n\tpublic left: number;\r\n\tpublic width: number;\r\n\r\n\tconstructor(left: number, width: number) {\r\n\t\tthis.left = Math.round(left);\r\n\t\tthis.width = Math.round(width);\r\n\t}\r\n\r\n\tpublic toString(): string {\r\n\t\treturn `[${this.left},${this.width}]`;\r\n\t}\r\n}\r\n\r\nexport class HorizontalPosition {\r\n\tpublic outsideRenderedLine: boolean;\r\n\tpublic left: number;\r\n\r\n\tconstructor(outsideRenderedLine: boolean, left: number) {\r\n\t\tthis.outsideRenderedLine = outsideRenderedLine;\r\n\t\tthis.left = Math.round(left);\r\n\t}\r\n}\r\n\r\nexport class VisibleRanges {\r\n\tconstructor(\r\n\t\tpublic readonly outsideRenderedLine: boolean,\r\n\t\tpublic readonly ranges: HorizontalRange[]\r\n\t) {\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Constants } from 'vs/base/common/uint';\r\nimport { HorizontalRange } from 'vs/editor/common/view/renderingContext';\r\n\r\nclass FloatHorizontalRange {\r\n\t_floatHorizontalRangeBrand: void;\r\n\r\n\tpublic readonly left: number;\r\n\tpublic readonly width: number;\r\n\r\n\tconstructor(left: number, width: number) {\r\n\t\tthis.left = left;\r\n\t\tthis.width = width;\r\n\t}\r\n\r\n\tpublic toString(): string {\r\n\t\treturn `[${this.left},${this.width}]`;\r\n\t}\r\n\r\n\tpublic static compare(a: FloatHorizontalRange, b: FloatHorizontalRange): number {\r\n\t\treturn a.left - b.left;\r\n\t}\r\n}\r\n\r\nexport class RangeUtil {\r\n\r\n\t/**\r\n\t * Reusing the same range here\r\n\t * because IE is buggy and constantly freezes when using a large number\r\n\t * of ranges and calling .detach on them\r\n\t */\r\n\tprivate static _handyReadyRange: Range;\r\n\r\n\tprivate static _createRange(): Range {\r\n\t\tif (!this._handyReadyRange) {\r\n\t\t\tthis._handyReadyRange = document.createRange();\r\n\t\t}\r\n\t\treturn this._handyReadyRange;\r\n\t}\r\n\r\n\tprivate static _detachRange(range: Range, endNode: HTMLElement): void {\r\n\t\t// Move range out of the span node, IE doesn't like having many ranges in\r\n\t\t// the same spot and will act badly for lines containing dashes ('-')\r\n\t\trange.selectNodeContents(endNode);\r\n\t}\r\n\r\n\tprivate static _readClientRects(startElement: Node, startOffset: number, endElement: Node, endOffset: number, endNode: HTMLElement): ClientRectList | DOMRectList | null {\r\n\t\tconst range = this._createRange();\r\n\t\ttry {\r\n\t\t\trange.setStart(startElement, startOffset);\r\n\t\t\trange.setEnd(endElement, endOffset);\r\n\r\n\t\t\treturn range.getClientRects();\r\n\t\t} catch (e) {\r\n\t\t\t// This is life ...\r\n\t\t\treturn null;\r\n\t\t} finally {\r\n\t\t\tthis._detachRange(range, endNode);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static _mergeAdjacentRanges(ranges: FloatHorizontalRange[]): HorizontalRange[] {\r\n\t\tif (ranges.length === 1) {\r\n\t\t\t// There is nothing to merge\r\n\t\t\treturn [new HorizontalRange(ranges[0].left, ranges[0].width)];\r\n\t\t}\r\n\r\n\t\tranges.sort(FloatHorizontalRange.compare);\r\n\r\n\t\tlet result: HorizontalRange[] = [], resultLen = 0;\r\n\t\tlet prevLeft = ranges[0].left;\r\n\t\tlet prevWidth = ranges[0].width;\r\n\r\n\t\tfor (let i = 1, len = ranges.length; i < len; i++) {\r\n\t\t\tconst range = ranges[i];\r\n\t\t\tconst myLeft = range.left;\r\n\t\t\tconst myWidth = range.width;\r\n\r\n\t\t\tif (prevLeft + prevWidth + 0.9 /* account for browser's rounding errors*/ >= myLeft) {\r\n\t\t\t\tprevWidth = Math.max(prevWidth, myLeft + myWidth - prevLeft);\r\n\t\t\t} else {\r\n\t\t\t\tresult[resultLen++] = new HorizontalRange(prevLeft, prevWidth);\r\n\t\t\t\tprevLeft = myLeft;\r\n\t\t\t\tprevWidth = myWidth;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tresult[resultLen++] = new HorizontalRange(prevLeft, prevWidth);\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _createHorizontalRangesFromClientRects(clientRects: ClientRectList | DOMRectList | null, clientRectDeltaLeft: number): HorizontalRange[] | null {\r\n\t\tif (!clientRects || clientRects.length === 0) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\t// We go through FloatHorizontalRange because it has been observed in bi-di text\r\n\t\t// that the clientRects are not coming in sorted from the browser\r\n\r\n\t\tconst result: FloatHorizontalRange[] = [];\r\n\t\tfor (let i = 0, len = clientRects.length; i < len; i++) {\r\n\t\t\tconst clientRect = clientRects[i];\r\n\t\t\tresult[i] = new FloatHorizontalRange(Math.max(0, clientRect.left - clientRectDeltaLeft), clientRect.width);\r\n\t\t}\r\n\r\n\t\treturn this._mergeAdjacentRanges(result);\r\n\t}\r\n\r\n\tpublic static readHorizontalRanges(domNode: HTMLElement, startChildIndex: number, startOffset: number, endChildIndex: number, endOffset: number, clientRectDeltaLeft: number, endNode: HTMLElement): HorizontalRange[] | null {\r\n\t\t// Panic check\r\n\t\tconst min = 0;\r\n\t\tconst max = domNode.children.length - 1;\r\n\t\tif (min > max) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tstartChildIndex = Math.min(max, Math.max(min, startChildIndex));\r\n\t\tendChildIndex = Math.min(max, Math.max(min, endChildIndex));\r\n\r\n\t\tif (startChildIndex === endChildIndex && startOffset === endOffset && startOffset === 0) {\r\n\t\t\t// We must find the position at the beginning of a \r\n\t\t\t// To cover cases of empty s, aboid using a range and use the 's bounding box\r\n\t\t\tconst clientRects = domNode.children[startChildIndex].getClientRects();\r\n\t\t\treturn this._createHorizontalRangesFromClientRects(clientRects, clientRectDeltaLeft);\r\n\t\t}\r\n\r\n\t\t// If crossing over to a span only to select offset 0, then use the previous span's maximum offset\r\n\t\t// Chrome is buggy and doesn't handle 0 offsets well sometimes.\r\n\t\tif (startChildIndex !== endChildIndex) {\r\n\t\t\tif (endChildIndex > 0 && endOffset === 0) {\r\n\t\t\t\tendChildIndex--;\r\n\t\t\t\tendOffset = Constants.MAX_SAFE_SMALL_INTEGER;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet startElement = domNode.children[startChildIndex].firstChild;\r\n\t\tlet endElement = domNode.children[endChildIndex].firstChild;\r\n\r\n\t\tif (!startElement || !endElement) {\r\n\t\t\t// When having an empty (without any text content), try to move to the previous \r\n\t\t\tif (!startElement && startOffset === 0 && startChildIndex > 0) {\r\n\t\t\t\tstartElement = domNode.children[startChildIndex - 1].firstChild;\r\n\t\t\t\tstartOffset = Constants.MAX_SAFE_SMALL_INTEGER;\r\n\t\t\t}\r\n\t\t\tif (!endElement && endOffset === 0 && endChildIndex > 0) {\r\n\t\t\t\tendElement = domNode.children[endChildIndex - 1].firstChild;\r\n\t\t\t\tendOffset = Constants.MAX_SAFE_SMALL_INTEGER;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!startElement || !endElement) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tstartOffset = Math.min(startElement.textContent!.length, Math.max(0, startOffset));\r\n\t\tendOffset = Math.min(endElement.textContent!.length, Math.max(0, endOffset));\r\n\r\n\t\tconst clientRects = this._readClientRects(startElement, startOffset, endElement, endOffset, endNode);\r\n\t\treturn this._createHorizontalRangesFromClientRects(clientRects, clientRectDeltaLeft);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IConfiguration } from 'vs/editor/common/editorCommon';\r\nimport { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler';\r\nimport { IViewLayout, IViewModel } from 'vs/editor/common/viewModel/viewModel';\r\nimport { IColorTheme } from 'vs/platform/theme/common/themeService';\r\nimport { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { ColorScheme } from 'vs/platform/theme/common/theme';\r\n\r\nexport class EditorTheme {\r\n\r\n\tprivate _theme: IColorTheme;\r\n\r\n\tpublic get type(): ColorScheme {\r\n\t\treturn this._theme.type;\r\n\t}\r\n\r\n\tconstructor(theme: IColorTheme) {\r\n\t\tthis._theme = theme;\r\n\t}\r\n\r\n\tpublic update(theme: IColorTheme): void {\r\n\t\tthis._theme = theme;\r\n\t}\r\n\r\n\tpublic getColor(color: ColorIdentifier): Color | undefined {\r\n\t\treturn this._theme.getColor(color);\r\n\t}\r\n}\r\n\r\nexport class ViewContext {\r\n\r\n\tpublic readonly configuration: IConfiguration;\r\n\tpublic readonly model: IViewModel;\r\n\tpublic readonly viewLayout: IViewLayout;\r\n\tpublic readonly theme: EditorTheme;\r\n\r\n\tconstructor(\r\n\t\tconfiguration: IConfiguration,\r\n\t\ttheme: IColorTheme,\r\n\t\tmodel: IViewModel\r\n\t) {\r\n\t\tthis.configuration = configuration;\r\n\t\tthis.theme = new EditorTheme(theme);\r\n\t\tthis.model = model;\r\n\t\tthis.viewLayout = model.viewLayout;\r\n\t}\r\n\r\n\tpublic addEventHandler(eventHandler: ViewEventHandler): void {\r\n\t\tthis.model.addViewEventHandler(eventHandler);\r\n\t}\r\n\r\n\tpublic removeEventHandler(eventHandler: ViewEventHandler): void {\r\n\t\tthis.model.removeViewEventHandler(eventHandler);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { ScrollEvent } from 'vs/base/common/scrollable';\r\nimport { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { ScrollType } from 'vs/editor/common/editorCommon';\r\nimport { IModelDecorationsChangedEvent } from 'vs/editor/common/model/textModelEvents';\r\n\r\nexport const enum ViewEventType {\r\n\tViewCompositionStart,\r\n\tViewCompositionEnd,\r\n\tViewConfigurationChanged,\r\n\tViewCursorStateChanged,\r\n\tViewDecorationsChanged,\r\n\tViewFlushed,\r\n\tViewFocusChanged,\r\n\tViewLanguageConfigurationChanged,\r\n\tViewLineMappingChanged,\r\n\tViewLinesChanged,\r\n\tViewLinesDeleted,\r\n\tViewLinesInserted,\r\n\tViewRevealRangeRequest,\r\n\tViewScrollChanged,\r\n\tViewThemeChanged,\r\n\tViewTokensChanged,\r\n\tViewTokensColorsChanged,\r\n\tViewZonesChanged,\r\n}\r\n\r\nexport class ViewCompositionStartEvent {\r\n\tpublic readonly type = ViewEventType.ViewCompositionStart;\r\n\tconstructor() { }\r\n}\r\n\r\nexport class ViewCompositionEndEvent {\r\n\tpublic readonly type = ViewEventType.ViewCompositionEnd;\r\n\tconstructor() { }\r\n}\r\n\r\nexport class ViewConfigurationChangedEvent {\r\n\r\n\tpublic readonly type = ViewEventType.ViewConfigurationChanged;\r\n\r\n\tpublic readonly _source: ConfigurationChangedEvent;\r\n\r\n\tconstructor(source: ConfigurationChangedEvent) {\r\n\t\tthis._source = source;\r\n\t}\r\n\r\n\tpublic hasChanged(id: EditorOption): boolean {\r\n\t\treturn this._source.hasChanged(id);\r\n\t}\r\n}\r\n\r\nexport class ViewCursorStateChangedEvent {\r\n\r\n\tpublic readonly type = ViewEventType.ViewCursorStateChanged;\r\n\r\n\tpublic readonly selections: Selection[];\r\n\tpublic readonly modelSelections: Selection[];\r\n\r\n\tconstructor(selections: Selection[], modelSelections: Selection[]) {\r\n\t\tthis.selections = selections;\r\n\t\tthis.modelSelections = modelSelections;\r\n\t}\r\n}\r\n\r\nexport class ViewDecorationsChangedEvent {\r\n\r\n\tpublic readonly type = ViewEventType.ViewDecorationsChanged;\r\n\r\n\treadonly affectsMinimap: boolean;\r\n\treadonly affectsOverviewRuler: boolean;\r\n\r\n\tconstructor(source: IModelDecorationsChangedEvent | null) {\r\n\t\tif (source) {\r\n\t\t\tthis.affectsMinimap = source.affectsMinimap;\r\n\t\t\tthis.affectsOverviewRuler = source.affectsOverviewRuler;\r\n\t\t} else {\r\n\t\t\tthis.affectsMinimap = true;\r\n\t\t\tthis.affectsOverviewRuler = true;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class ViewFlushedEvent {\r\n\r\n\tpublic readonly type = ViewEventType.ViewFlushed;\r\n\r\n\tconstructor() {\r\n\t\t// Nothing to do\r\n\t}\r\n}\r\n\r\nexport class ViewFocusChangedEvent {\r\n\r\n\tpublic readonly type = ViewEventType.ViewFocusChanged;\r\n\r\n\tpublic readonly isFocused: boolean;\r\n\r\n\tconstructor(isFocused: boolean) {\r\n\t\tthis.isFocused = isFocused;\r\n\t}\r\n}\r\n\r\nexport class ViewLanguageConfigurationEvent {\r\n\r\n\tpublic readonly type = ViewEventType.ViewLanguageConfigurationChanged;\r\n}\r\n\r\nexport class ViewLineMappingChangedEvent {\r\n\r\n\tpublic readonly type = ViewEventType.ViewLineMappingChanged;\r\n\r\n\tconstructor() {\r\n\t\t// Nothing to do\r\n\t}\r\n}\r\n\r\nexport class ViewLinesChangedEvent {\r\n\r\n\tpublic readonly type = ViewEventType.ViewLinesChanged;\r\n\r\n\t/**\r\n\t * The first line that has changed.\r\n\t */\r\n\tpublic readonly fromLineNumber: number;\r\n\t/**\r\n\t * The last line that has changed.\r\n\t */\r\n\tpublic readonly toLineNumber: number;\r\n\r\n\tconstructor(fromLineNumber: number, toLineNumber: number) {\r\n\t\tthis.fromLineNumber = fromLineNumber;\r\n\t\tthis.toLineNumber = toLineNumber;\r\n\t}\r\n}\r\n\r\nexport class ViewLinesDeletedEvent {\r\n\r\n\tpublic readonly type = ViewEventType.ViewLinesDeleted;\r\n\r\n\t/**\r\n\t * At what line the deletion began (inclusive).\r\n\t */\r\n\tpublic readonly fromLineNumber: number;\r\n\t/**\r\n\t * At what line the deletion stopped (inclusive).\r\n\t */\r\n\tpublic readonly toLineNumber: number;\r\n\r\n\tconstructor(fromLineNumber: number, toLineNumber: number) {\r\n\t\tthis.fromLineNumber = fromLineNumber;\r\n\t\tthis.toLineNumber = toLineNumber;\r\n\t}\r\n}\r\n\r\nexport class ViewLinesInsertedEvent {\r\n\r\n\tpublic readonly type = ViewEventType.ViewLinesInserted;\r\n\r\n\t/**\r\n\t * Before what line did the insertion begin\r\n\t */\r\n\tpublic readonly fromLineNumber: number;\r\n\t/**\r\n\t * `toLineNumber` - `fromLineNumber` + 1 denotes the number of lines that were inserted\r\n\t */\r\n\tpublic readonly toLineNumber: number;\r\n\r\n\tconstructor(fromLineNumber: number, toLineNumber: number) {\r\n\t\tthis.fromLineNumber = fromLineNumber;\r\n\t\tthis.toLineNumber = toLineNumber;\r\n\t}\r\n}\r\n\r\nexport const enum VerticalRevealType {\r\n\tSimple = 0,\r\n\tCenter = 1,\r\n\tCenterIfOutsideViewport = 2,\r\n\tTop = 3,\r\n\tBottom = 4,\r\n\tNearTop = 5,\r\n\tNearTopIfOutsideViewport = 6,\r\n}\r\n\r\nexport class ViewRevealRangeRequestEvent {\r\n\r\n\tpublic readonly type = ViewEventType.ViewRevealRangeRequest;\r\n\r\n\t/**\r\n\t * Range to be reavealed.\r\n\t */\r\n\tpublic readonly range: Range | null;\r\n\r\n\t/**\r\n\t * Selections to be revealed.\r\n\t */\r\n\tpublic readonly selections: Selection[] | null;\r\n\r\n\tpublic readonly verticalType: VerticalRevealType;\r\n\t/**\r\n\t * If true: there should be a horizontal & vertical revealing\r\n\t * If false: there should be just a vertical revealing\r\n\t */\r\n\tpublic readonly revealHorizontal: boolean;\r\n\r\n\tpublic readonly scrollType: ScrollType;\r\n\r\n\t/**\r\n\t * Source of the call that caused the event.\r\n\t */\r\n\treadonly source: string | null | undefined;\r\n\r\n\tconstructor(source: string | null | undefined, range: Range | null, selections: Selection[] | null, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: ScrollType) {\r\n\t\tthis.source = source;\r\n\t\tthis.range = range;\r\n\t\tthis.selections = selections;\r\n\t\tthis.verticalType = verticalType;\r\n\t\tthis.revealHorizontal = revealHorizontal;\r\n\t\tthis.scrollType = scrollType;\r\n\t}\r\n}\r\n\r\nexport class ViewScrollChangedEvent {\r\n\r\n\tpublic readonly type = ViewEventType.ViewScrollChanged;\r\n\r\n\tpublic readonly scrollWidth: number;\r\n\tpublic readonly scrollLeft: number;\r\n\tpublic readonly scrollHeight: number;\r\n\tpublic readonly scrollTop: number;\r\n\r\n\tpublic readonly scrollWidthChanged: boolean;\r\n\tpublic readonly scrollLeftChanged: boolean;\r\n\tpublic readonly scrollHeightChanged: boolean;\r\n\tpublic readonly scrollTopChanged: boolean;\r\n\r\n\tconstructor(source: ScrollEvent) {\r\n\t\tthis.scrollWidth = source.scrollWidth;\r\n\t\tthis.scrollLeft = source.scrollLeft;\r\n\t\tthis.scrollHeight = source.scrollHeight;\r\n\t\tthis.scrollTop = source.scrollTop;\r\n\r\n\t\tthis.scrollWidthChanged = source.scrollWidthChanged;\r\n\t\tthis.scrollLeftChanged = source.scrollLeftChanged;\r\n\t\tthis.scrollHeightChanged = source.scrollHeightChanged;\r\n\t\tthis.scrollTopChanged = source.scrollTopChanged;\r\n\t}\r\n}\r\n\r\nexport class ViewThemeChangedEvent {\r\n\r\n\tpublic readonly type = ViewEventType.ViewThemeChanged;\r\n}\r\n\r\nexport class ViewTokensChangedEvent {\r\n\r\n\tpublic readonly type = ViewEventType.ViewTokensChanged;\r\n\r\n\tpublic readonly ranges: {\r\n\t\t/**\r\n\t\t * Start line number of range\r\n\t\t */\r\n\t\treadonly fromLineNumber: number;\r\n\t\t/**\r\n\t\t * End line number of range\r\n\t\t */\r\n\t\treadonly toLineNumber: number;\r\n\t}[];\r\n\r\n\tconstructor(ranges: { fromLineNumber: number; toLineNumber: number; }[]) {\r\n\t\tthis.ranges = ranges;\r\n\t}\r\n}\r\n\r\nexport class ViewTokensColorsChangedEvent {\r\n\r\n\tpublic readonly type = ViewEventType.ViewTokensColorsChanged;\r\n\r\n\tconstructor() {\r\n\t\t// Nothing to do\r\n\t}\r\n}\r\n\r\nexport class ViewZonesChangedEvent {\r\n\r\n\tpublic readonly type = ViewEventType.ViewZonesChanged;\r\n\r\n\tconstructor() {\r\n\t\t// Nothing to do\r\n\t}\r\n}\r\n\r\nexport type ViewEvent = (\r\n\tViewCompositionStartEvent\r\n\t| ViewCompositionEndEvent\r\n\t| ViewConfigurationChangedEvent\r\n\t| ViewCursorStateChangedEvent\r\n\t| ViewDecorationsChangedEvent\r\n\t| ViewFlushedEvent\r\n\t| ViewFocusChangedEvent\r\n\t| ViewLanguageConfigurationEvent\r\n\t| ViewLineMappingChangedEvent\r\n\t| ViewLinesChangedEvent\r\n\t| ViewLinesDeletedEvent\r\n\t| ViewLinesInsertedEvent\r\n\t| ViewRevealRangeRequestEvent\r\n\t| ViewScrollChangedEvent\r\n\t| ViewThemeChangedEvent\r\n\t| ViewTokensChangedEvent\r\n\t| ViewTokensColorsChangedEvent\r\n\t| ViewZonesChangedEvent\r\n);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { Constants } from 'vs/base/common/uint';\r\nimport { InlineDecoration, InlineDecorationType } from 'vs/editor/common/viewModel/viewModel';\r\nimport { LinePartMetadata } from 'vs/editor/common/viewLayout/viewLineRenderer';\r\n\r\nexport class LineDecoration {\r\n\t_lineDecorationBrand: void;\r\n\r\n\tconstructor(\r\n\t\tpublic readonly startColumn: number,\r\n\t\tpublic readonly endColumn: number,\r\n\t\tpublic readonly className: string,\r\n\t\tpublic readonly type: InlineDecorationType\r\n\t) {\r\n\t}\r\n\r\n\tprivate static _equals(a: LineDecoration, b: LineDecoration): boolean {\r\n\t\treturn (\r\n\t\t\ta.startColumn === b.startColumn\r\n\t\t\t&& a.endColumn === b.endColumn\r\n\t\t\t&& a.className === b.className\r\n\t\t\t&& a.type === b.type\r\n\t\t);\r\n\t}\r\n\r\n\tpublic static equalsArr(a: LineDecoration[], b: LineDecoration[]): boolean {\r\n\t\tconst aLen = a.length;\r\n\t\tconst bLen = b.length;\r\n\t\tif (aLen !== bLen) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tfor (let i = 0; i < aLen; i++) {\r\n\t\t\tif (!LineDecoration._equals(a[i], b[i])) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic static extractWrapped(arr: LineDecoration[], startOffset: number, endOffset: number): LineDecoration[] {\r\n\t\tif (arr.length === 0) {\r\n\t\t\treturn arr;\r\n\t\t}\r\n\t\tconst startColumn = startOffset + 1;\r\n\t\tconst endColumn = endOffset + 1;\r\n\t\tconst lineLength = endOffset - startOffset;\r\n\t\tconst r = [];\r\n\t\tlet rLength = 0;\r\n\t\tfor (const dec of arr) {\r\n\t\t\tif (dec.endColumn <= startColumn || dec.startColumn >= endColumn) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tr[rLength++] = new LineDecoration(Math.max(1, dec.startColumn - startColumn + 1), Math.min(lineLength + 1, dec.endColumn - startColumn + 1), dec.className, dec.type);\r\n\t\t}\r\n\t\treturn r;\r\n\t}\r\n\r\n\tpublic static filter(lineDecorations: InlineDecoration[], lineNumber: number, minLineColumn: number, maxLineColumn: number): LineDecoration[] {\r\n\t\tif (lineDecorations.length === 0) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tlet result: LineDecoration[] = [], resultLen = 0;\r\n\r\n\t\tfor (let i = 0, len = lineDecorations.length; i < len; i++) {\r\n\t\t\tconst d = lineDecorations[i];\r\n\t\t\tconst range = d.range;\r\n\r\n\t\t\tif (range.endLineNumber < lineNumber || range.startLineNumber > lineNumber) {\r\n\t\t\t\t// Ignore decorations that sit outside this line\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (range.isEmpty() && (d.type === InlineDecorationType.Regular || d.type === InlineDecorationType.RegularAffectingLetterSpacing)) {\r\n\t\t\t\t// Ignore empty range decorations\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tconst startColumn = (range.startLineNumber === lineNumber ? range.startColumn : minLineColumn);\r\n\t\t\tconst endColumn = (range.endLineNumber === lineNumber ? range.endColumn : maxLineColumn);\r\n\r\n\t\t\tresult[resultLen++] = new LineDecoration(startColumn, endColumn, d.inlineClassName, d.type);\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _typeCompare(a: InlineDecorationType, b: InlineDecorationType): number {\r\n\t\tconst ORDER = [2, 0, 1, 3];\r\n\t\treturn ORDER[a] - ORDER[b];\r\n\t}\r\n\r\n\tpublic static compare(a: LineDecoration, b: LineDecoration): number {\r\n\t\tif (a.startColumn === b.startColumn) {\r\n\t\t\tif (a.endColumn === b.endColumn) {\r\n\t\t\t\tconst typeCmp = LineDecoration._typeCompare(a.type, b.type);\r\n\t\t\t\tif (typeCmp === 0) {\r\n\t\t\t\t\tif (a.className < b.className) {\r\n\t\t\t\t\t\treturn -1;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (a.className > b.className) {\r\n\t\t\t\t\t\treturn 1;\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn 0;\r\n\t\t\t\t}\r\n\t\t\t\treturn typeCmp;\r\n\t\t\t}\r\n\t\t\treturn a.endColumn - b.endColumn;\r\n\t\t}\r\n\t\treturn a.startColumn - b.startColumn;\r\n\t}\r\n}\r\n\r\nexport class DecorationSegment {\r\n\tstartOffset: number;\r\n\tendOffset: number;\r\n\tclassName: string;\r\n\tmetadata: number;\r\n\r\n\tconstructor(startOffset: number, endOffset: number, className: string, metadata: number) {\r\n\t\tthis.startOffset = startOffset;\r\n\t\tthis.endOffset = endOffset;\r\n\t\tthis.className = className;\r\n\t\tthis.metadata = metadata;\r\n\t}\r\n}\r\n\r\nclass Stack {\r\n\tpublic count: number;\r\n\tprivate readonly stopOffsets: number[];\r\n\tprivate readonly classNames: string[];\r\n\tprivate readonly metadata: number[];\r\n\r\n\tconstructor() {\r\n\t\tthis.stopOffsets = [];\r\n\t\tthis.classNames = [];\r\n\t\tthis.metadata = [];\r\n\t\tthis.count = 0;\r\n\t}\r\n\r\n\tprivate static _metadata(metadata: number[]): number {\r\n\t\tlet result = 0;\r\n\t\tfor (let i = 0, len = metadata.length; i < len; i++) {\r\n\t\t\tresult |= metadata[i];\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic consumeLowerThan(maxStopOffset: number, nextStartOffset: number, result: DecorationSegment[]): number {\r\n\r\n\t\twhile (this.count > 0 && this.stopOffsets[0] < maxStopOffset) {\r\n\t\t\tlet i = 0;\r\n\r\n\t\t\t// Take all equal stopping offsets\r\n\t\t\twhile (i + 1 < this.count && this.stopOffsets[i] === this.stopOffsets[i + 1]) {\r\n\t\t\t\ti++;\r\n\t\t\t}\r\n\r\n\t\t\t// Basically we are consuming the first i + 1 elements of the stack\r\n\t\t\tresult.push(new DecorationSegment(nextStartOffset, this.stopOffsets[i], this.classNames.join(' '), Stack._metadata(this.metadata)));\r\n\t\t\tnextStartOffset = this.stopOffsets[i] + 1;\r\n\r\n\t\t\t// Consume them\r\n\t\t\tthis.stopOffsets.splice(0, i + 1);\r\n\t\t\tthis.classNames.splice(0, i + 1);\r\n\t\t\tthis.metadata.splice(0, i + 1);\r\n\t\t\tthis.count -= (i + 1);\r\n\t\t}\r\n\r\n\t\tif (this.count > 0 && nextStartOffset < maxStopOffset) {\r\n\t\t\tresult.push(new DecorationSegment(nextStartOffset, maxStopOffset - 1, this.classNames.join(' '), Stack._metadata(this.metadata)));\r\n\t\t\tnextStartOffset = maxStopOffset;\r\n\t\t}\r\n\r\n\t\treturn nextStartOffset;\r\n\t}\r\n\r\n\tpublic insert(stopOffset: number, className: string, metadata: number): void {\r\n\t\tif (this.count === 0 || this.stopOffsets[this.count - 1] <= stopOffset) {\r\n\t\t\t// Insert at the end\r\n\t\t\tthis.stopOffsets.push(stopOffset);\r\n\t\t\tthis.classNames.push(className);\r\n\t\t\tthis.metadata.push(metadata);\r\n\t\t} else {\r\n\t\t\t// Find the insertion position for `stopOffset`\r\n\t\t\tfor (let i = 0; i < this.count; i++) {\r\n\t\t\t\tif (this.stopOffsets[i] >= stopOffset) {\r\n\t\t\t\t\tthis.stopOffsets.splice(i, 0, stopOffset);\r\n\t\t\t\t\tthis.classNames.splice(i, 0, className);\r\n\t\t\t\t\tthis.metadata.splice(i, 0, metadata);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis.count++;\r\n\t\treturn;\r\n\t}\r\n}\r\n\r\nexport class LineDecorationsNormalizer {\r\n\t/**\r\n\t * Normalize line decorations. Overlapping decorations will generate multiple segments\r\n\t */\r\n\tpublic static normalize(lineContent: string, lineDecorations: LineDecoration[]): DecorationSegment[] {\r\n\t\tif (lineDecorations.length === 0) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tlet result: DecorationSegment[] = [];\r\n\r\n\t\tconst stack = new Stack();\r\n\t\tlet nextStartOffset = 0;\r\n\r\n\t\tfor (let i = 0, len = lineDecorations.length; i < len; i++) {\r\n\t\t\tconst d = lineDecorations[i];\r\n\t\t\tlet startColumn = d.startColumn;\r\n\t\t\tlet endColumn = d.endColumn;\r\n\t\t\tconst className = d.className;\r\n\t\t\tconst metadata = (\r\n\t\t\t\td.type === InlineDecorationType.Before\r\n\t\t\t\t\t? LinePartMetadata.PSEUDO_BEFORE\r\n\t\t\t\t\t: d.type === InlineDecorationType.After\r\n\t\t\t\t\t\t? LinePartMetadata.PSEUDO_AFTER\r\n\t\t\t\t\t\t: 0\r\n\t\t\t);\r\n\r\n\t\t\t// If the position would end up in the middle of a high-low surrogate pair, we move it to before the pair\r\n\t\t\tif (startColumn > 1) {\r\n\t\t\t\tconst charCodeBefore = lineContent.charCodeAt(startColumn - 2);\r\n\t\t\t\tif (strings.isHighSurrogate(charCodeBefore)) {\r\n\t\t\t\t\tstartColumn--;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (endColumn > 1) {\r\n\t\t\t\tconst charCodeBefore = lineContent.charCodeAt(endColumn - 2);\r\n\t\t\t\tif (strings.isHighSurrogate(charCodeBefore)) {\r\n\t\t\t\t\tendColumn--;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tconst currentStartOffset = startColumn - 1;\r\n\t\t\tconst currentEndOffset = endColumn - 2;\r\n\r\n\t\t\tnextStartOffset = stack.consumeLowerThan(currentStartOffset, nextStartOffset, result);\r\n\r\n\t\t\tif (stack.count === 0) {\r\n\t\t\t\tnextStartOffset = currentStartOffset;\r\n\t\t\t}\r\n\t\t\tstack.insert(currentEndOffset, className, metadata);\r\n\t\t}\r\n\r\n\t\tstack.consumeLowerThan(Constants.MAX_SAFE_SMALL_INTEGER, nextStartOffset, result);\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';\r\nimport { IViewWhitespaceViewportData } from 'vs/editor/common/viewModel/viewModel';\r\nimport * as strings from 'vs/base/common/strings';\r\n\r\nexport interface IEditorWhitespace {\r\n\treadonly id: string;\r\n\treadonly afterLineNumber: number;\r\n\treadonly height: number;\r\n}\r\n\r\n/**\r\n * An accessor that allows for whtiespace to be added, removed or changed in bulk.\r\n */\r\nexport interface IWhitespaceChangeAccessor {\r\n\tinsertWhitespace(afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): string;\r\n\tchangeOneWhitespace(id: string, newAfterLineNumber: number, newHeight: number): void;\r\n\tremoveWhitespace(id: string): void;\r\n}\r\n\r\ninterface IPendingChange { id: string; newAfterLineNumber: number; newHeight: number; }\r\ninterface IPendingRemove { id: string; }\r\n\r\nclass PendingChanges {\r\n\tprivate _hasPending: boolean;\r\n\tprivate _inserts: EditorWhitespace[];\r\n\tprivate _changes: IPendingChange[];\r\n\tprivate _removes: IPendingRemove[];\r\n\r\n\tconstructor() {\r\n\t\tthis._hasPending = false;\r\n\t\tthis._inserts = [];\r\n\t\tthis._changes = [];\r\n\t\tthis._removes = [];\r\n\t}\r\n\r\n\tpublic insert(x: EditorWhitespace): void {\r\n\t\tthis._hasPending = true;\r\n\t\tthis._inserts.push(x);\r\n\t}\r\n\r\n\tpublic change(x: IPendingChange): void {\r\n\t\tthis._hasPending = true;\r\n\t\tthis._changes.push(x);\r\n\t}\r\n\r\n\tpublic remove(x: IPendingRemove): void {\r\n\t\tthis._hasPending = true;\r\n\t\tthis._removes.push(x);\r\n\t}\r\n\r\n\tpublic mustCommit(): boolean {\r\n\t\treturn this._hasPending;\r\n\t}\r\n\r\n\tpublic commit(linesLayout: LinesLayout): void {\r\n\t\tif (!this._hasPending) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst inserts = this._inserts;\r\n\t\tconst changes = this._changes;\r\n\t\tconst removes = this._removes;\r\n\r\n\t\tthis._hasPending = false;\r\n\t\tthis._inserts = [];\r\n\t\tthis._changes = [];\r\n\t\tthis._removes = [];\r\n\r\n\t\tlinesLayout._commitPendingChanges(inserts, changes, removes);\r\n\t}\r\n}\r\n\r\nexport class EditorWhitespace implements IEditorWhitespace {\r\n\tpublic id: string;\r\n\tpublic afterLineNumber: number;\r\n\tpublic ordinal: number;\r\n\tpublic height: number;\r\n\tpublic minWidth: number;\r\n\tpublic prefixSum: number;\r\n\r\n\tconstructor(id: string, afterLineNumber: number, ordinal: number, height: number, minWidth: number) {\r\n\t\tthis.id = id;\r\n\t\tthis.afterLineNumber = afterLineNumber;\r\n\t\tthis.ordinal = ordinal;\r\n\t\tthis.height = height;\r\n\t\tthis.minWidth = minWidth;\r\n\t\tthis.prefixSum = 0;\r\n\t}\r\n}\r\n\r\n/**\r\n * Layouting of objects that take vertical space (by having a height) and push down other objects.\r\n *\r\n * These objects are basically either text (lines) or spaces between those lines (whitespaces).\r\n * This provides commodity operations for working with lines that contain whitespace that pushes lines lower (vertically).\r\n */\r\nexport class LinesLayout {\r\n\r\n\tprivate static INSTANCE_COUNT = 0;\r\n\r\n\tprivate readonly _instanceId: string;\r\n\tprivate readonly _pendingChanges: PendingChanges;\r\n\tprivate _lastWhitespaceId: number;\r\n\tprivate _arr: EditorWhitespace[];\r\n\tprivate _prefixSumValidIndex: number;\r\n\tprivate _minWidth: number;\r\n\tprivate _lineCount: number;\r\n\tprivate _lineHeight: number;\r\n\tprivate _paddingTop: number;\r\n\tprivate _paddingBottom: number;\r\n\r\n\tconstructor(lineCount: number, lineHeight: number, paddingTop: number, paddingBottom: number) {\r\n\t\tthis._instanceId = strings.singleLetterHash(++LinesLayout.INSTANCE_COUNT);\r\n\t\tthis._pendingChanges = new PendingChanges();\r\n\t\tthis._lastWhitespaceId = 0;\r\n\t\tthis._arr = [];\r\n\t\tthis._prefixSumValidIndex = -1;\r\n\t\tthis._minWidth = -1; /* marker for not being computed */\r\n\t\tthis._lineCount = lineCount;\r\n\t\tthis._lineHeight = lineHeight;\r\n\t\tthis._paddingTop = paddingTop;\r\n\t\tthis._paddingBottom = paddingBottom;\r\n\t}\r\n\r\n\t/**\r\n\t * Find the insertion index for a new value inside a sorted array of values.\r\n\t * If the value is already present in the sorted array, the insertion index will be after the already existing value.\r\n\t */\r\n\tpublic static findInsertionIndex(arr: EditorWhitespace[], afterLineNumber: number, ordinal: number): number {\r\n\t\tlet low = 0;\r\n\t\tlet high = arr.length;\r\n\r\n\t\twhile (low < high) {\r\n\t\t\tconst mid = ((low + high) >>> 1);\r\n\r\n\t\t\tif (afterLineNumber === arr[mid].afterLineNumber) {\r\n\t\t\t\tif (ordinal < arr[mid].ordinal) {\r\n\t\t\t\t\thigh = mid;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tlow = mid + 1;\r\n\t\t\t\t}\r\n\t\t\t} else if (afterLineNumber < arr[mid].afterLineNumber) {\r\n\t\t\t\thigh = mid;\r\n\t\t\t} else {\r\n\t\t\t\tlow = mid + 1;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn low;\r\n\t}\r\n\r\n\t/**\r\n\t * Change the height of a line in pixels.\r\n\t */\r\n\tpublic setLineHeight(lineHeight: number): void {\r\n\t\tthis._checkPendingChanges();\r\n\t\tthis._lineHeight = lineHeight;\r\n\t}\r\n\r\n\t/**\r\n\t * Changes the padding used to calculate vertical offsets.\r\n\t */\r\n\tpublic setPadding(paddingTop: number, paddingBottom: number): void {\r\n\t\tthis._paddingTop = paddingTop;\r\n\t\tthis._paddingBottom = paddingBottom;\r\n\t}\r\n\r\n\t/**\r\n\t * Set the number of lines.\r\n\t *\r\n\t * @param lineCount New number of lines.\r\n\t */\r\n\tpublic onFlushed(lineCount: number): void {\r\n\t\tthis._checkPendingChanges();\r\n\t\tthis._lineCount = lineCount;\r\n\t}\r\n\r\n\tpublic changeWhitespace(callback: (accessor: IWhitespaceChangeAccessor) => void): boolean {\r\n\t\tlet hadAChange = false;\r\n\t\ttry {\r\n\t\t\tconst accessor: IWhitespaceChangeAccessor = {\r\n\t\t\t\tinsertWhitespace: (afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): string => {\r\n\t\t\t\t\thadAChange = true;\r\n\t\t\t\t\tafterLineNumber = afterLineNumber | 0;\r\n\t\t\t\t\tordinal = ordinal | 0;\r\n\t\t\t\t\theightInPx = heightInPx | 0;\r\n\t\t\t\t\tminWidth = minWidth | 0;\r\n\t\t\t\t\tconst id = this._instanceId + (++this._lastWhitespaceId);\r\n\t\t\t\t\tthis._pendingChanges.insert(new EditorWhitespace(id, afterLineNumber, ordinal, heightInPx, minWidth));\r\n\t\t\t\t\treturn id;\r\n\t\t\t\t},\r\n\t\t\t\tchangeOneWhitespace: (id: string, newAfterLineNumber: number, newHeight: number): void => {\r\n\t\t\t\t\thadAChange = true;\r\n\t\t\t\t\tnewAfterLineNumber = newAfterLineNumber | 0;\r\n\t\t\t\t\tnewHeight = newHeight | 0;\r\n\t\t\t\t\tthis._pendingChanges.change({ id, newAfterLineNumber, newHeight });\r\n\t\t\t\t},\r\n\t\t\t\tremoveWhitespace: (id: string): void => {\r\n\t\t\t\t\thadAChange = true;\r\n\t\t\t\t\tthis._pendingChanges.remove({ id });\r\n\t\t\t\t}\r\n\t\t\t};\r\n\t\t\tcallback(accessor);\r\n\t\t} finally {\r\n\t\t\tthis._pendingChanges.commit(this);\r\n\t\t}\r\n\t\treturn hadAChange;\r\n\t}\r\n\r\n\tpublic _commitPendingChanges(inserts: EditorWhitespace[], changes: IPendingChange[], removes: IPendingRemove[]): void {\r\n\t\tif (inserts.length > 0 || removes.length > 0) {\r\n\t\t\tthis._minWidth = -1; /* marker for not being computed */\r\n\t\t}\r\n\r\n\t\tif (inserts.length + changes.length + removes.length <= 1) {\r\n\t\t\t// when only one thing happened, handle it \"delicately\"\r\n\t\t\tfor (const insert of inserts) {\r\n\t\t\t\tthis._insertWhitespace(insert);\r\n\t\t\t}\r\n\t\t\tfor (const change of changes) {\r\n\t\t\t\tthis._changeOneWhitespace(change.id, change.newAfterLineNumber, change.newHeight);\r\n\t\t\t}\r\n\t\t\tfor (const remove of removes) {\r\n\t\t\t\tconst index = this._findWhitespaceIndex(remove.id);\r\n\t\t\t\tif (index === -1) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\tthis._removeWhitespace(index);\r\n\t\t\t}\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// simply rebuild the entire datastructure\r\n\r\n\t\tconst toRemove = new Set();\r\n\t\tfor (const remove of removes) {\r\n\t\t\ttoRemove.add(remove.id);\r\n\t\t}\r\n\r\n\t\tconst toChange = new Map();\r\n\t\tfor (const change of changes) {\r\n\t\t\ttoChange.set(change.id, change);\r\n\t\t}\r\n\r\n\t\tconst applyRemoveAndChange = (whitespaces: EditorWhitespace[]): EditorWhitespace[] => {\r\n\t\t\tlet result: EditorWhitespace[] = [];\r\n\t\t\tfor (const whitespace of whitespaces) {\r\n\t\t\t\tif (toRemove.has(whitespace.id)) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\tif (toChange.has(whitespace.id)) {\r\n\t\t\t\t\tconst change = toChange.get(whitespace.id)!;\r\n\t\t\t\t\twhitespace.afterLineNumber = change.newAfterLineNumber;\r\n\t\t\t\t\twhitespace.height = change.newHeight;\r\n\t\t\t\t}\r\n\t\t\t\tresult.push(whitespace);\r\n\t\t\t}\r\n\t\t\treturn result;\r\n\t\t};\r\n\r\n\t\tconst result = applyRemoveAndChange(this._arr).concat(applyRemoveAndChange(inserts));\r\n\t\tresult.sort((a, b) => {\r\n\t\t\tif (a.afterLineNumber === b.afterLineNumber) {\r\n\t\t\t\treturn a.ordinal - b.ordinal;\r\n\t\t\t}\r\n\t\t\treturn a.afterLineNumber - b.afterLineNumber;\r\n\t\t});\r\n\r\n\t\tthis._arr = result;\r\n\t\tthis._prefixSumValidIndex = -1;\r\n\t}\r\n\r\n\tprivate _checkPendingChanges(): void {\r\n\t\tif (this._pendingChanges.mustCommit()) {\r\n\t\t\tthis._pendingChanges.commit(this);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _insertWhitespace(whitespace: EditorWhitespace): void {\r\n\t\tconst insertIndex = LinesLayout.findInsertionIndex(this._arr, whitespace.afterLineNumber, whitespace.ordinal);\r\n\t\tthis._arr.splice(insertIndex, 0, whitespace);\r\n\t\tthis._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, insertIndex - 1);\r\n\t}\r\n\r\n\tprivate _findWhitespaceIndex(id: string): number {\r\n\t\tconst arr = this._arr;\r\n\t\tfor (let i = 0, len = arr.length; i < len; i++) {\r\n\t\t\tif (arr[i].id === id) {\r\n\t\t\t\treturn i;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn -1;\r\n\t}\r\n\r\n\tprivate _changeOneWhitespace(id: string, newAfterLineNumber: number, newHeight: number): void {\r\n\t\tconst index = this._findWhitespaceIndex(id);\r\n\t\tif (index === -1) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (this._arr[index].height !== newHeight) {\r\n\t\t\tthis._arr[index].height = newHeight;\r\n\t\t\tthis._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, index - 1);\r\n\t\t}\r\n\t\tif (this._arr[index].afterLineNumber !== newAfterLineNumber) {\r\n\t\t\t// `afterLineNumber` changed for this whitespace\r\n\r\n\t\t\t// Record old whitespace\r\n\t\t\tconst whitespace = this._arr[index];\r\n\r\n\t\t\t// Since changing `afterLineNumber` can trigger a reordering, we're gonna remove this whitespace\r\n\t\t\tthis._removeWhitespace(index);\r\n\r\n\t\t\twhitespace.afterLineNumber = newAfterLineNumber;\r\n\r\n\t\t\t// And add it again\r\n\t\t\tthis._insertWhitespace(whitespace);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _removeWhitespace(removeIndex: number): void {\r\n\t\tthis._arr.splice(removeIndex, 1);\r\n\t\tthis._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, removeIndex - 1);\r\n\t}\r\n\r\n\t/**\r\n\t * Notify the layouter that lines have been deleted (a continuous zone of lines).\r\n\t *\r\n\t * @param fromLineNumber The line number at which the deletion started, inclusive\r\n\t * @param toLineNumber The line number at which the deletion ended, inclusive\r\n\t */\r\n\tpublic onLinesDeleted(fromLineNumber: number, toLineNumber: number): void {\r\n\t\tthis._checkPendingChanges();\r\n\t\tfromLineNumber = fromLineNumber | 0;\r\n\t\ttoLineNumber = toLineNumber | 0;\r\n\r\n\t\tthis._lineCount -= (toLineNumber - fromLineNumber + 1);\r\n\t\tfor (let i = 0, len = this._arr.length; i < len; i++) {\r\n\t\t\tconst afterLineNumber = this._arr[i].afterLineNumber;\r\n\r\n\t\t\tif (fromLineNumber <= afterLineNumber && afterLineNumber <= toLineNumber) {\r\n\t\t\t\t// The line this whitespace was after has been deleted\r\n\t\t\t\t// => move whitespace to before first deleted line\r\n\t\t\t\tthis._arr[i].afterLineNumber = fromLineNumber - 1;\r\n\t\t\t} else if (afterLineNumber > toLineNumber) {\r\n\t\t\t\t// The line this whitespace was after has been moved up\r\n\t\t\t\t// => move whitespace up\r\n\t\t\t\tthis._arr[i].afterLineNumber -= (toLineNumber - fromLineNumber + 1);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Notify the layouter that lines have been inserted (a continuous zone of lines).\r\n\t *\r\n\t * @param fromLineNumber The line number at which the insertion started, inclusive\r\n\t * @param toLineNumber The line number at which the insertion ended, inclusive.\r\n\t */\r\n\tpublic onLinesInserted(fromLineNumber: number, toLineNumber: number): void {\r\n\t\tthis._checkPendingChanges();\r\n\t\tfromLineNumber = fromLineNumber | 0;\r\n\t\ttoLineNumber = toLineNumber | 0;\r\n\r\n\t\tthis._lineCount += (toLineNumber - fromLineNumber + 1);\r\n\t\tfor (let i = 0, len = this._arr.length; i < len; i++) {\r\n\t\t\tconst afterLineNumber = this._arr[i].afterLineNumber;\r\n\r\n\t\t\tif (fromLineNumber <= afterLineNumber) {\r\n\t\t\t\tthis._arr[i].afterLineNumber += (toLineNumber - fromLineNumber + 1);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Get the sum of all the whitespaces.\r\n\t */\r\n\tpublic getWhitespacesTotalHeight(): number {\r\n\t\tthis._checkPendingChanges();\r\n\t\tif (this._arr.length === 0) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t\treturn this.getWhitespacesAccumulatedHeight(this._arr.length - 1);\r\n\t}\r\n\r\n\t/**\r\n\t * Return the sum of the heights of the whitespaces at [0..index].\r\n\t * This includes the whitespace at `index`.\r\n\t *\r\n\t * @param index The index of the whitespace.\r\n\t * @return The sum of the heights of all whitespaces before the one at `index`, including the one at `index`.\r\n\t */\r\n\tpublic getWhitespacesAccumulatedHeight(index: number): number {\r\n\t\tthis._checkPendingChanges();\r\n\t\tindex = index | 0;\r\n\r\n\t\tlet startIndex = Math.max(0, this._prefixSumValidIndex + 1);\r\n\t\tif (startIndex === 0) {\r\n\t\t\tthis._arr[0].prefixSum = this._arr[0].height;\r\n\t\t\tstartIndex++;\r\n\t\t}\r\n\r\n\t\tfor (let i = startIndex; i <= index; i++) {\r\n\t\t\tthis._arr[i].prefixSum = this._arr[i - 1].prefixSum + this._arr[i].height;\r\n\t\t}\r\n\t\tthis._prefixSumValidIndex = Math.max(this._prefixSumValidIndex, index);\r\n\t\treturn this._arr[index].prefixSum;\r\n\t}\r\n\r\n\t/**\r\n\t * Get the sum of heights for all objects.\r\n\t *\r\n\t * @return The sum of heights for all objects.\r\n\t */\r\n\tpublic getLinesTotalHeight(): number {\r\n\t\tthis._checkPendingChanges();\r\n\t\tconst linesHeight = this._lineHeight * this._lineCount;\r\n\t\tconst whitespacesHeight = this.getWhitespacesTotalHeight();\r\n\r\n\t\treturn linesHeight + whitespacesHeight + this._paddingTop + this._paddingBottom;\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the accumulated height of whitespaces before the given line number.\r\n\t *\r\n\t * @param lineNumber The line number\r\n\t */\r\n\tpublic getWhitespaceAccumulatedHeightBeforeLineNumber(lineNumber: number): number {\r\n\t\tthis._checkPendingChanges();\r\n\t\tlineNumber = lineNumber | 0;\r\n\r\n\t\tconst lastWhitespaceBeforeLineNumber = this._findLastWhitespaceBeforeLineNumber(lineNumber);\r\n\r\n\t\tif (lastWhitespaceBeforeLineNumber === -1) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\treturn this.getWhitespacesAccumulatedHeight(lastWhitespaceBeforeLineNumber);\r\n\t}\r\n\r\n\tprivate _findLastWhitespaceBeforeLineNumber(lineNumber: number): number {\r\n\t\tlineNumber = lineNumber | 0;\r\n\r\n\t\t// Find the whitespace before line number\r\n\t\tconst arr = this._arr;\r\n\t\tlet low = 0;\r\n\t\tlet high = arr.length - 1;\r\n\r\n\t\twhile (low <= high) {\r\n\t\t\tconst delta = (high - low) | 0;\r\n\t\t\tconst halfDelta = (delta / 2) | 0;\r\n\t\t\tconst mid = (low + halfDelta) | 0;\r\n\r\n\t\t\tif (arr[mid].afterLineNumber < lineNumber) {\r\n\t\t\t\tif (mid + 1 >= arr.length || arr[mid + 1].afterLineNumber >= lineNumber) {\r\n\t\t\t\t\treturn mid;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tlow = (mid + 1) | 0;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\thigh = (mid - 1) | 0;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn -1;\r\n\t}\r\n\r\n\tprivate _findFirstWhitespaceAfterLineNumber(lineNumber: number): number {\r\n\t\tlineNumber = lineNumber | 0;\r\n\r\n\t\tconst lastWhitespaceBeforeLineNumber = this._findLastWhitespaceBeforeLineNumber(lineNumber);\r\n\t\tconst firstWhitespaceAfterLineNumber = lastWhitespaceBeforeLineNumber + 1;\r\n\r\n\t\tif (firstWhitespaceAfterLineNumber < this._arr.length) {\r\n\t\t\treturn firstWhitespaceAfterLineNumber;\r\n\t\t}\r\n\r\n\t\treturn -1;\r\n\t}\r\n\r\n\t/**\r\n\t * Find the index of the first whitespace which has `afterLineNumber` >= `lineNumber`.\r\n\t * @return The index of the first whitespace with `afterLineNumber` >= `lineNumber` or -1 if no whitespace is found.\r\n\t */\r\n\tpublic getFirstWhitespaceIndexAfterLineNumber(lineNumber: number): number {\r\n\t\tthis._checkPendingChanges();\r\n\t\tlineNumber = lineNumber | 0;\r\n\r\n\t\treturn this._findFirstWhitespaceAfterLineNumber(lineNumber);\r\n\t}\r\n\r\n\t/**\r\n\t * Get the vertical offset (the sum of heights for all objects above) a certain line number.\r\n\t *\r\n\t * @param lineNumber The line number\r\n\t * @return The sum of heights for all objects above `lineNumber`.\r\n\t */\r\n\tpublic getVerticalOffsetForLineNumber(lineNumber: number): number {\r\n\t\tthis._checkPendingChanges();\r\n\t\tlineNumber = lineNumber | 0;\r\n\r\n\t\tlet previousLinesHeight: number;\r\n\t\tif (lineNumber > 1) {\r\n\t\t\tpreviousLinesHeight = this._lineHeight * (lineNumber - 1);\r\n\t\t} else {\r\n\t\t\tpreviousLinesHeight = 0;\r\n\t\t}\r\n\r\n\t\tconst previousWhitespacesHeight = this.getWhitespaceAccumulatedHeightBeforeLineNumber(lineNumber);\r\n\r\n\t\treturn previousLinesHeight + previousWhitespacesHeight + this._paddingTop;\r\n\t}\r\n\r\n\t/**\r\n\t * The maximum min width for all whitespaces.\r\n\t */\r\n\tpublic getWhitespaceMinWidth(): number {\r\n\t\tthis._checkPendingChanges();\r\n\t\tif (this._minWidth === -1) {\r\n\t\t\tlet minWidth = 0;\r\n\t\t\tfor (let i = 0, len = this._arr.length; i < len; i++) {\r\n\t\t\t\tminWidth = Math.max(minWidth, this._arr[i].minWidth);\r\n\t\t\t}\r\n\t\t\tthis._minWidth = minWidth;\r\n\t\t}\r\n\t\treturn this._minWidth;\r\n\t}\r\n\r\n\t/**\r\n\t * Check if `verticalOffset` is below all lines.\r\n\t */\r\n\tpublic isAfterLines(verticalOffset: number): boolean {\r\n\t\tthis._checkPendingChanges();\r\n\t\tconst totalHeight = this.getLinesTotalHeight();\r\n\t\treturn verticalOffset > totalHeight;\r\n\t}\r\n\r\n\tpublic isInTopPadding(verticalOffset: number): boolean {\r\n\t\tif (this._paddingTop === 0) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tthis._checkPendingChanges();\r\n\t\treturn (verticalOffset < this._paddingTop);\r\n\t}\r\n\r\n\tpublic isInBottomPadding(verticalOffset: number): boolean {\r\n\t\tif (this._paddingBottom === 0) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tthis._checkPendingChanges();\r\n\t\tconst totalHeight = this.getLinesTotalHeight();\r\n\t\treturn (verticalOffset >= totalHeight - this._paddingBottom);\r\n\t}\r\n\r\n\t/**\r\n\t * Find the first line number that is at or after vertical offset `verticalOffset`.\r\n\t * i.e. if getVerticalOffsetForLine(line) is x and getVerticalOffsetForLine(line + 1) is y, then\r\n\t * getLineNumberAtOrAfterVerticalOffset(i) = line, x <= i < y.\r\n\t *\r\n\t * @param verticalOffset The vertical offset to search at.\r\n\t * @return The line number at or after vertical offset `verticalOffset`.\r\n\t */\r\n\tpublic getLineNumberAtOrAfterVerticalOffset(verticalOffset: number): number {\r\n\t\tthis._checkPendingChanges();\r\n\t\tverticalOffset = verticalOffset | 0;\r\n\r\n\t\tif (verticalOffset < 0) {\r\n\t\t\treturn 1;\r\n\t\t}\r\n\r\n\t\tconst linesCount = this._lineCount | 0;\r\n\t\tconst lineHeight = this._lineHeight;\r\n\t\tlet minLineNumber = 1;\r\n\t\tlet maxLineNumber = linesCount;\r\n\r\n\t\twhile (minLineNumber < maxLineNumber) {\r\n\t\t\tconst midLineNumber = ((minLineNumber + maxLineNumber) / 2) | 0;\r\n\r\n\t\t\tconst midLineNumberVerticalOffset = this.getVerticalOffsetForLineNumber(midLineNumber) | 0;\r\n\r\n\t\t\tif (verticalOffset >= midLineNumberVerticalOffset + lineHeight) {\r\n\t\t\t\t// vertical offset is after mid line number\r\n\t\t\t\tminLineNumber = midLineNumber + 1;\r\n\t\t\t} else if (verticalOffset >= midLineNumberVerticalOffset) {\r\n\t\t\t\t// Hit\r\n\t\t\t\treturn midLineNumber;\r\n\t\t\t} else {\r\n\t\t\t\t// vertical offset is before mid line number, but mid line number could still be what we're searching for\r\n\t\t\t\tmaxLineNumber = midLineNumber;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (minLineNumber > linesCount) {\r\n\t\t\treturn linesCount;\r\n\t\t}\r\n\r\n\t\treturn minLineNumber;\r\n\t}\r\n\r\n\t/**\r\n\t * Get all the lines and their relative vertical offsets that are positioned between `verticalOffset1` and `verticalOffset2`.\r\n\t *\r\n\t * @param verticalOffset1 The beginning of the viewport.\r\n\t * @param verticalOffset2 The end of the viewport.\r\n\t * @return A structure describing the lines positioned between `verticalOffset1` and `verticalOffset2`.\r\n\t */\r\n\tpublic getLinesViewportData(verticalOffset1: number, verticalOffset2: number): IPartialViewLinesViewportData {\r\n\t\tthis._checkPendingChanges();\r\n\t\tverticalOffset1 = verticalOffset1 | 0;\r\n\t\tverticalOffset2 = verticalOffset2 | 0;\r\n\t\tconst lineHeight = this._lineHeight;\r\n\r\n\t\t// Find first line number\r\n\t\t// We don't live in a perfect world, so the line number might start before or after verticalOffset1\r\n\t\tconst startLineNumber = this.getLineNumberAtOrAfterVerticalOffset(verticalOffset1) | 0;\r\n\t\tconst startLineNumberVerticalOffset = this.getVerticalOffsetForLineNumber(startLineNumber) | 0;\r\n\r\n\t\tlet endLineNumber = this._lineCount | 0;\r\n\r\n\t\t// Also keep track of what whitespace we've got\r\n\t\tlet whitespaceIndex = this.getFirstWhitespaceIndexAfterLineNumber(startLineNumber) | 0;\r\n\t\tconst whitespaceCount = this.getWhitespacesCount() | 0;\r\n\t\tlet currentWhitespaceHeight: number;\r\n\t\tlet currentWhitespaceAfterLineNumber: number;\r\n\r\n\t\tif (whitespaceIndex === -1) {\r\n\t\t\twhitespaceIndex = whitespaceCount;\r\n\t\t\tcurrentWhitespaceAfterLineNumber = endLineNumber + 1;\r\n\t\t\tcurrentWhitespaceHeight = 0;\r\n\t\t} else {\r\n\t\t\tcurrentWhitespaceAfterLineNumber = this.getAfterLineNumberForWhitespaceIndex(whitespaceIndex) | 0;\r\n\t\t\tcurrentWhitespaceHeight = this.getHeightForWhitespaceIndex(whitespaceIndex) | 0;\r\n\t\t}\r\n\r\n\t\tlet currentVerticalOffset = startLineNumberVerticalOffset;\r\n\t\tlet currentLineRelativeOffset = currentVerticalOffset;\r\n\r\n\t\t// IE (all versions) cannot handle units above about 1,533,908 px, so every 500k pixels bring numbers down\r\n\t\tconst STEP_SIZE = 500000;\r\n\t\tlet bigNumbersDelta = 0;\r\n\t\tif (startLineNumberVerticalOffset >= STEP_SIZE) {\r\n\t\t\t// Compute a delta that guarantees that lines are positioned at `lineHeight` increments\r\n\t\t\tbigNumbersDelta = Math.floor(startLineNumberVerticalOffset / STEP_SIZE) * STEP_SIZE;\r\n\t\t\tbigNumbersDelta = Math.floor(bigNumbersDelta / lineHeight) * lineHeight;\r\n\r\n\t\t\tcurrentLineRelativeOffset -= bigNumbersDelta;\r\n\t\t}\r\n\r\n\t\tconst linesOffsets: number[] = [];\r\n\r\n\t\tconst verticalCenter = verticalOffset1 + (verticalOffset2 - verticalOffset1) / 2;\r\n\t\tlet centeredLineNumber = -1;\r\n\r\n\t\t// Figure out how far the lines go\r\n\t\tfor (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {\r\n\r\n\t\t\tif (centeredLineNumber === -1) {\r\n\t\t\t\tconst currentLineTop = currentVerticalOffset;\r\n\t\t\t\tconst currentLineBottom = currentVerticalOffset + lineHeight;\r\n\t\t\t\tif ((currentLineTop <= verticalCenter && verticalCenter < currentLineBottom) || currentLineTop > verticalCenter) {\r\n\t\t\t\t\tcenteredLineNumber = lineNumber;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// Count current line height in the vertical offsets\r\n\t\t\tcurrentVerticalOffset += lineHeight;\r\n\t\t\tlinesOffsets[lineNumber - startLineNumber] = currentLineRelativeOffset;\r\n\r\n\t\t\t// Next line starts immediately after this one\r\n\t\t\tcurrentLineRelativeOffset += lineHeight;\r\n\t\t\twhile (currentWhitespaceAfterLineNumber === lineNumber) {\r\n\t\t\t\t// Push down next line with the height of the current whitespace\r\n\t\t\t\tcurrentLineRelativeOffset += currentWhitespaceHeight;\r\n\r\n\t\t\t\t// Count current whitespace in the vertical offsets\r\n\t\t\t\tcurrentVerticalOffset += currentWhitespaceHeight;\r\n\t\t\t\twhitespaceIndex++;\r\n\r\n\t\t\t\tif (whitespaceIndex >= whitespaceCount) {\r\n\t\t\t\t\tcurrentWhitespaceAfterLineNumber = endLineNumber + 1;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tcurrentWhitespaceAfterLineNumber = this.getAfterLineNumberForWhitespaceIndex(whitespaceIndex) | 0;\r\n\t\t\t\t\tcurrentWhitespaceHeight = this.getHeightForWhitespaceIndex(whitespaceIndex) | 0;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (currentVerticalOffset >= verticalOffset2) {\r\n\t\t\t\t// We have covered the entire viewport area, time to stop\r\n\t\t\t\tendLineNumber = lineNumber;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (centeredLineNumber === -1) {\r\n\t\t\tcenteredLineNumber = endLineNumber;\r\n\t\t}\r\n\r\n\t\tconst endLineNumberVerticalOffset = this.getVerticalOffsetForLineNumber(endLineNumber) | 0;\r\n\r\n\t\tlet completelyVisibleStartLineNumber = startLineNumber;\r\n\t\tlet completelyVisibleEndLineNumber = endLineNumber;\r\n\r\n\t\tif (completelyVisibleStartLineNumber < completelyVisibleEndLineNumber) {\r\n\t\t\tif (startLineNumberVerticalOffset < verticalOffset1) {\r\n\t\t\t\tcompletelyVisibleStartLineNumber++;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (completelyVisibleStartLineNumber < completelyVisibleEndLineNumber) {\r\n\t\t\tif (endLineNumberVerticalOffset + lineHeight > verticalOffset2) {\r\n\t\t\t\tcompletelyVisibleEndLineNumber--;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tbigNumbersDelta: bigNumbersDelta,\r\n\t\t\tstartLineNumber: startLineNumber,\r\n\t\t\tendLineNumber: endLineNumber,\r\n\t\t\trelativeVerticalOffset: linesOffsets,\r\n\t\t\tcenteredLineNumber: centeredLineNumber,\r\n\t\t\tcompletelyVisibleStartLineNumber: completelyVisibleStartLineNumber,\r\n\t\t\tcompletelyVisibleEndLineNumber: completelyVisibleEndLineNumber\r\n\t\t};\r\n\t}\r\n\r\n\tpublic getVerticalOffsetForWhitespaceIndex(whitespaceIndex: number): number {\r\n\t\tthis._checkPendingChanges();\r\n\t\twhitespaceIndex = whitespaceIndex | 0;\r\n\r\n\t\tconst afterLineNumber = this.getAfterLineNumberForWhitespaceIndex(whitespaceIndex);\r\n\r\n\t\tlet previousLinesHeight: number;\r\n\t\tif (afterLineNumber >= 1) {\r\n\t\t\tpreviousLinesHeight = this._lineHeight * afterLineNumber;\r\n\t\t} else {\r\n\t\t\tpreviousLinesHeight = 0;\r\n\t\t}\r\n\r\n\t\tlet previousWhitespacesHeight: number;\r\n\t\tif (whitespaceIndex > 0) {\r\n\t\t\tpreviousWhitespacesHeight = this.getWhitespacesAccumulatedHeight(whitespaceIndex - 1);\r\n\t\t} else {\r\n\t\t\tpreviousWhitespacesHeight = 0;\r\n\t\t}\r\n\t\treturn previousLinesHeight + previousWhitespacesHeight + this._paddingTop;\r\n\t}\r\n\r\n\tpublic getWhitespaceIndexAtOrAfterVerticallOffset(verticalOffset: number): number {\r\n\t\tthis._checkPendingChanges();\r\n\t\tverticalOffset = verticalOffset | 0;\r\n\r\n\t\tlet minWhitespaceIndex = 0;\r\n\t\tlet maxWhitespaceIndex = this.getWhitespacesCount() - 1;\r\n\r\n\t\tif (maxWhitespaceIndex < 0) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\r\n\t\t// Special case: nothing to be found\r\n\t\tconst maxWhitespaceVerticalOffset = this.getVerticalOffsetForWhitespaceIndex(maxWhitespaceIndex);\r\n\t\tconst maxWhitespaceHeight = this.getHeightForWhitespaceIndex(maxWhitespaceIndex);\r\n\t\tif (verticalOffset >= maxWhitespaceVerticalOffset + maxWhitespaceHeight) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\r\n\t\twhile (minWhitespaceIndex < maxWhitespaceIndex) {\r\n\t\t\tconst midWhitespaceIndex = Math.floor((minWhitespaceIndex + maxWhitespaceIndex) / 2);\r\n\r\n\t\t\tconst midWhitespaceVerticalOffset = this.getVerticalOffsetForWhitespaceIndex(midWhitespaceIndex);\r\n\t\t\tconst midWhitespaceHeight = this.getHeightForWhitespaceIndex(midWhitespaceIndex);\r\n\r\n\t\t\tif (verticalOffset >= midWhitespaceVerticalOffset + midWhitespaceHeight) {\r\n\t\t\t\t// vertical offset is after whitespace\r\n\t\t\t\tminWhitespaceIndex = midWhitespaceIndex + 1;\r\n\t\t\t} else if (verticalOffset >= midWhitespaceVerticalOffset) {\r\n\t\t\t\t// Hit\r\n\t\t\t\treturn midWhitespaceIndex;\r\n\t\t\t} else {\r\n\t\t\t\t// vertical offset is before whitespace, but midWhitespaceIndex might still be what we're searching for\r\n\t\t\t\tmaxWhitespaceIndex = midWhitespaceIndex;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn minWhitespaceIndex;\r\n\t}\r\n\r\n\t/**\r\n\t * Get exactly the whitespace that is layouted at `verticalOffset`.\r\n\t *\r\n\t * @param verticalOffset The vertical offset.\r\n\t * @return Precisely the whitespace that is layouted at `verticaloffset` or null.\r\n\t */\r\n\tpublic getWhitespaceAtVerticalOffset(verticalOffset: number): IViewWhitespaceViewportData | null {\r\n\t\tthis._checkPendingChanges();\r\n\t\tverticalOffset = verticalOffset | 0;\r\n\r\n\t\tconst candidateIndex = this.getWhitespaceIndexAtOrAfterVerticallOffset(verticalOffset);\r\n\r\n\t\tif (candidateIndex < 0) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (candidateIndex >= this.getWhitespacesCount()) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst candidateTop = this.getVerticalOffsetForWhitespaceIndex(candidateIndex);\r\n\r\n\t\tif (candidateTop > verticalOffset) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst candidateHeight = this.getHeightForWhitespaceIndex(candidateIndex);\r\n\t\tconst candidateId = this.getIdForWhitespaceIndex(candidateIndex);\r\n\t\tconst candidateAfterLineNumber = this.getAfterLineNumberForWhitespaceIndex(candidateIndex);\r\n\r\n\t\treturn {\r\n\t\t\tid: candidateId,\r\n\t\t\tafterLineNumber: candidateAfterLineNumber,\r\n\t\t\tverticalOffset: candidateTop,\r\n\t\t\theight: candidateHeight\r\n\t\t};\r\n\t}\r\n\r\n\t/**\r\n\t * Get a list of whitespaces that are positioned between `verticalOffset1` and `verticalOffset2`.\r\n\t *\r\n\t * @param verticalOffset1 The beginning of the viewport.\r\n\t * @param verticalOffset2 The end of the viewport.\r\n\t * @return An array with all the whitespaces in the viewport. If no whitespace is in viewport, the array is empty.\r\n\t */\r\n\tpublic getWhitespaceViewportData(verticalOffset1: number, verticalOffset2: number): IViewWhitespaceViewportData[] {\r\n\t\tthis._checkPendingChanges();\r\n\t\tverticalOffset1 = verticalOffset1 | 0;\r\n\t\tverticalOffset2 = verticalOffset2 | 0;\r\n\r\n\t\tconst startIndex = this.getWhitespaceIndexAtOrAfterVerticallOffset(verticalOffset1);\r\n\t\tconst endIndex = this.getWhitespacesCount() - 1;\r\n\r\n\t\tif (startIndex < 0) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tlet result: IViewWhitespaceViewportData[] = [];\r\n\t\tfor (let i = startIndex; i <= endIndex; i++) {\r\n\t\t\tconst top = this.getVerticalOffsetForWhitespaceIndex(i);\r\n\t\t\tconst height = this.getHeightForWhitespaceIndex(i);\r\n\t\t\tif (top >= verticalOffset2) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tresult.push({\r\n\t\t\t\tid: this.getIdForWhitespaceIndex(i),\r\n\t\t\t\tafterLineNumber: this.getAfterLineNumberForWhitespaceIndex(i),\r\n\t\t\t\tverticalOffset: top,\r\n\t\t\t\theight: height\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\t/**\r\n\t * Get all whitespaces.\r\n\t */\r\n\tpublic getWhitespaces(): IEditorWhitespace[] {\r\n\t\tthis._checkPendingChanges();\r\n\t\treturn this._arr.slice(0);\r\n\t}\r\n\r\n\t/**\r\n\t * The number of whitespaces.\r\n\t */\r\n\tpublic getWhitespacesCount(): number {\r\n\t\tthis._checkPendingChanges();\r\n\t\treturn this._arr.length;\r\n\t}\r\n\r\n\t/**\r\n\t * Get the `id` for whitespace at index `index`.\r\n\t *\r\n\t * @param index The index of the whitespace.\r\n\t * @return `id` of whitespace at `index`.\r\n\t */\r\n\tpublic getIdForWhitespaceIndex(index: number): string {\r\n\t\tthis._checkPendingChanges();\r\n\t\tindex = index | 0;\r\n\r\n\t\treturn this._arr[index].id;\r\n\t}\r\n\r\n\t/**\r\n\t * Get the `afterLineNumber` for whitespace at index `index`.\r\n\t *\r\n\t * @param index The index of the whitespace.\r\n\t * @return `afterLineNumber` of whitespace at `index`.\r\n\t */\r\n\tpublic getAfterLineNumberForWhitespaceIndex(index: number): number {\r\n\t\tthis._checkPendingChanges();\r\n\t\tindex = index | 0;\r\n\r\n\t\treturn this._arr[index].afterLineNumber;\r\n\t}\r\n\r\n\t/**\r\n\t * Get the `height` for whitespace at index `index`.\r\n\t *\r\n\t * @param index The index of the whitespace.\r\n\t * @return `height` of whitespace at `index`.\r\n\t */\r\n\tpublic getHeightForWhitespaceIndex(index: number): number {\r\n\t\tthis._checkPendingChanges();\r\n\t\tindex = index | 0;\r\n\r\n\t\treturn this._arr[index].height;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { IViewLineTokens } from 'vs/editor/common/core/lineTokens';\r\nimport { IStringBuilder, createStringBuilder } from 'vs/editor/common/core/stringBuilder';\r\nimport { LineDecoration, LineDecorationsNormalizer } from 'vs/editor/common/viewLayout/lineDecorations';\r\nimport { InlineDecorationType } from 'vs/editor/common/viewModel/viewModel';\r\n\r\nexport const enum RenderWhitespace {\r\n\tNone = 0,\r\n\tBoundary = 1,\r\n\tSelection = 2,\r\n\tTrailing = 3,\r\n\tAll = 4\r\n}\r\n\r\nexport const enum LinePartMetadata {\r\n\tIS_WHITESPACE = 1,\r\n\tPSEUDO_BEFORE = 2,\r\n\tPSEUDO_AFTER = 4,\r\n\r\n\tIS_WHITESPACE_MASK = 0b001,\r\n\tPSEUDO_BEFORE_MASK = 0b010,\r\n\tPSEUDO_AFTER_MASK = 0b100,\r\n}\r\n\r\nclass LinePart {\r\n\t_linePartBrand: void;\r\n\r\n\t/**\r\n\t * last char index of this token (not inclusive).\r\n\t */\r\n\tpublic readonly endIndex: number;\r\n\tpublic readonly type: string;\r\n\tpublic readonly metadata: number;\r\n\r\n\tconstructor(endIndex: number, type: string, metadata: number) {\r\n\t\tthis.endIndex = endIndex;\r\n\t\tthis.type = type;\r\n\t\tthis.metadata = metadata;\r\n\t}\r\n\r\n\tpublic isWhitespace(): boolean {\r\n\t\treturn (this.metadata & LinePartMetadata.IS_WHITESPACE_MASK ? true : false);\r\n\t}\r\n}\r\n\r\nexport class LineRange {\r\n\t/**\r\n\t * Zero-based offset on which the range starts, inclusive.\r\n\t */\r\n\tpublic readonly startOffset: number;\r\n\r\n\t/**\r\n\t * Zero-based offset on which the range ends, inclusive.\r\n\t */\r\n\tpublic readonly endOffset: number;\r\n\r\n\tconstructor(startIndex: number, endIndex: number) {\r\n\t\tthis.startOffset = startIndex;\r\n\t\tthis.endOffset = endIndex;\r\n\t}\r\n\r\n\tpublic equals(otherLineRange: LineRange) {\r\n\t\treturn this.startOffset === otherLineRange.startOffset\r\n\t\t\t&& this.endOffset === otherLineRange.endOffset;\r\n\t}\r\n}\r\n\r\nexport class RenderLineInput {\r\n\r\n\tpublic readonly useMonospaceOptimizations: boolean;\r\n\tpublic readonly canUseHalfwidthRightwardsArrow: boolean;\r\n\tpublic readonly lineContent: string;\r\n\tpublic readonly continuesWithWrappedLine: boolean;\r\n\tpublic readonly isBasicASCII: boolean;\r\n\tpublic readonly containsRTL: boolean;\r\n\tpublic readonly fauxIndentLength: number;\r\n\tpublic readonly lineTokens: IViewLineTokens;\r\n\tpublic readonly lineDecorations: LineDecoration[];\r\n\tpublic readonly tabSize: number;\r\n\tpublic readonly startVisibleColumn: number;\r\n\tpublic readonly spaceWidth: number;\r\n\tpublic readonly renderSpaceWidth: number;\r\n\tpublic readonly renderSpaceCharCode: number;\r\n\tpublic readonly stopRenderingLineAfter: number;\r\n\tpublic readonly renderWhitespace: RenderWhitespace;\r\n\tpublic readonly renderControlCharacters: boolean;\r\n\tpublic readonly fontLigatures: boolean;\r\n\r\n\t/**\r\n\t * Defined only when renderWhitespace is 'selection'. Selections are non-overlapping,\r\n\t * and ordered by position within the line.\r\n\t */\r\n\tpublic readonly selectionsOnLine: LineRange[] | null;\r\n\r\n\tconstructor(\r\n\t\tuseMonospaceOptimizations: boolean,\r\n\t\tcanUseHalfwidthRightwardsArrow: boolean,\r\n\t\tlineContent: string,\r\n\t\tcontinuesWithWrappedLine: boolean,\r\n\t\tisBasicASCII: boolean,\r\n\t\tcontainsRTL: boolean,\r\n\t\tfauxIndentLength: number,\r\n\t\tlineTokens: IViewLineTokens,\r\n\t\tlineDecorations: LineDecoration[],\r\n\t\ttabSize: number,\r\n\t\tstartVisibleColumn: number,\r\n\t\tspaceWidth: number,\r\n\t\tmiddotWidth: number,\r\n\t\twsmiddotWidth: number,\r\n\t\tstopRenderingLineAfter: number,\r\n\t\trenderWhitespace: 'none' | 'boundary' | 'selection' | 'trailing' | 'all',\r\n\t\trenderControlCharacters: boolean,\r\n\t\tfontLigatures: boolean,\r\n\t\tselectionsOnLine: LineRange[] | null\r\n\t) {\r\n\t\tthis.useMonospaceOptimizations = useMonospaceOptimizations;\r\n\t\tthis.canUseHalfwidthRightwardsArrow = canUseHalfwidthRightwardsArrow;\r\n\t\tthis.lineContent = lineContent;\r\n\t\tthis.continuesWithWrappedLine = continuesWithWrappedLine;\r\n\t\tthis.isBasicASCII = isBasicASCII;\r\n\t\tthis.containsRTL = containsRTL;\r\n\t\tthis.fauxIndentLength = fauxIndentLength;\r\n\t\tthis.lineTokens = lineTokens;\r\n\t\tthis.lineDecorations = lineDecorations.sort(LineDecoration.compare);\r\n\t\tthis.tabSize = tabSize;\r\n\t\tthis.startVisibleColumn = startVisibleColumn;\r\n\t\tthis.spaceWidth = spaceWidth;\r\n\t\tthis.stopRenderingLineAfter = stopRenderingLineAfter;\r\n\t\tthis.renderWhitespace = (\r\n\t\t\trenderWhitespace === 'all'\r\n\t\t\t\t? RenderWhitespace.All\r\n\t\t\t\t: renderWhitespace === 'boundary'\r\n\t\t\t\t\t? RenderWhitespace.Boundary\r\n\t\t\t\t\t: renderWhitespace === 'selection'\r\n\t\t\t\t\t\t? RenderWhitespace.Selection\r\n\t\t\t\t\t\t: renderWhitespace === 'trailing'\r\n\t\t\t\t\t\t\t? RenderWhitespace.Trailing\r\n\t\t\t\t\t\t\t: RenderWhitespace.None\r\n\t\t);\r\n\t\tthis.renderControlCharacters = renderControlCharacters;\r\n\t\tthis.fontLigatures = fontLigatures;\r\n\t\tthis.selectionsOnLine = selectionsOnLine && selectionsOnLine.sort((a, b) => a.startOffset < b.startOffset ? -1 : 1);\r\n\r\n\t\tconst wsmiddotDiff = Math.abs(wsmiddotWidth - spaceWidth);\r\n\t\tconst middotDiff = Math.abs(middotWidth - spaceWidth);\r\n\t\tif (wsmiddotDiff < middotDiff) {\r\n\t\t\tthis.renderSpaceWidth = wsmiddotWidth;\r\n\t\t\tthis.renderSpaceCharCode = 0x2E31; // U+2E31 - WORD SEPARATOR MIDDLE DOT\r\n\t\t} else {\r\n\t\t\tthis.renderSpaceWidth = middotWidth;\r\n\t\t\tthis.renderSpaceCharCode = 0xB7; // U+00B7 - MIDDLE DOT\r\n\t\t}\r\n\t}\r\n\r\n\tprivate sameSelection(otherSelections: LineRange[] | null): boolean {\r\n\t\tif (this.selectionsOnLine === null) {\r\n\t\t\treturn otherSelections === null;\r\n\t\t}\r\n\r\n\t\tif (otherSelections === null) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tif (otherSelections.length !== this.selectionsOnLine.length) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tfor (let i = 0; i < this.selectionsOnLine.length; i++) {\r\n\t\t\tif (!this.selectionsOnLine[i].equals(otherSelections[i])) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic equals(other: RenderLineInput): boolean {\r\n\t\treturn (\r\n\t\t\tthis.useMonospaceOptimizations === other.useMonospaceOptimizations\r\n\t\t\t&& this.canUseHalfwidthRightwardsArrow === other.canUseHalfwidthRightwardsArrow\r\n\t\t\t&& this.lineContent === other.lineContent\r\n\t\t\t&& this.continuesWithWrappedLine === other.continuesWithWrappedLine\r\n\t\t\t&& this.isBasicASCII === other.isBasicASCII\r\n\t\t\t&& this.containsRTL === other.containsRTL\r\n\t\t\t&& this.fauxIndentLength === other.fauxIndentLength\r\n\t\t\t&& this.tabSize === other.tabSize\r\n\t\t\t&& this.startVisibleColumn === other.startVisibleColumn\r\n\t\t\t&& this.spaceWidth === other.spaceWidth\r\n\t\t\t&& this.renderSpaceWidth === other.renderSpaceWidth\r\n\t\t\t&& this.renderSpaceCharCode === other.renderSpaceCharCode\r\n\t\t\t&& this.stopRenderingLineAfter === other.stopRenderingLineAfter\r\n\t\t\t&& this.renderWhitespace === other.renderWhitespace\r\n\t\t\t&& this.renderControlCharacters === other.renderControlCharacters\r\n\t\t\t&& this.fontLigatures === other.fontLigatures\r\n\t\t\t&& LineDecoration.equalsArr(this.lineDecorations, other.lineDecorations)\r\n\t\t\t&& this.lineTokens.equals(other.lineTokens)\r\n\t\t\t&& this.sameSelection(other.selectionsOnLine)\r\n\t\t);\r\n\t}\r\n}\r\n\r\nexport const enum CharacterMappingConstants {\r\n\tPART_INDEX_MASK = 0b11111111111111110000000000000000,\r\n\tCHAR_INDEX_MASK = 0b00000000000000001111111111111111,\r\n\r\n\tCHAR_INDEX_OFFSET = 0,\r\n\tPART_INDEX_OFFSET = 16\r\n}\r\n\r\n/**\r\n * Provides a both direction mapping between a line's character and its rendered position.\r\n */\r\nexport class CharacterMapping {\r\n\r\n\tpublic static getPartIndex(partData: number): number {\r\n\t\treturn (partData & CharacterMappingConstants.PART_INDEX_MASK) >>> CharacterMappingConstants.PART_INDEX_OFFSET;\r\n\t}\r\n\r\n\tpublic static getCharIndex(partData: number): number {\r\n\t\treturn (partData & CharacterMappingConstants.CHAR_INDEX_MASK) >>> CharacterMappingConstants.CHAR_INDEX_OFFSET;\r\n\t}\r\n\r\n\tpublic readonly length: number;\r\n\tprivate readonly _data: Uint32Array;\r\n\tprivate readonly _absoluteOffsets: Uint32Array;\r\n\r\n\tconstructor(length: number, partCount: number) {\r\n\t\tthis.length = length;\r\n\t\tthis._data = new Uint32Array(this.length);\r\n\t\tthis._absoluteOffsets = new Uint32Array(this.length);\r\n\t}\r\n\r\n\tpublic setPartData(charOffset: number, partIndex: number, charIndex: number, partAbsoluteOffset: number): void {\r\n\t\tlet partData = (\r\n\t\t\t(partIndex << CharacterMappingConstants.PART_INDEX_OFFSET)\r\n\t\t\t| (charIndex << CharacterMappingConstants.CHAR_INDEX_OFFSET)\r\n\t\t) >>> 0;\r\n\t\tthis._data[charOffset] = partData;\r\n\t\tthis._absoluteOffsets[charOffset] = partAbsoluteOffset + charIndex;\r\n\t}\r\n\r\n\tpublic getAbsoluteOffsets(): Uint32Array {\r\n\t\treturn this._absoluteOffsets;\r\n\t}\r\n\r\n\tpublic charOffsetToPartData(charOffset: number): number {\r\n\t\tif (this.length === 0) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t\tif (charOffset < 0) {\r\n\t\t\treturn this._data[0];\r\n\t\t}\r\n\t\tif (charOffset >= this.length) {\r\n\t\t\treturn this._data[this.length - 1];\r\n\t\t}\r\n\t\treturn this._data[charOffset];\r\n\t}\r\n\r\n\tpublic partDataToCharOffset(partIndex: number, partLength: number, charIndex: number): number {\r\n\t\tif (this.length === 0) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tlet searchEntry = (\r\n\t\t\t(partIndex << CharacterMappingConstants.PART_INDEX_OFFSET)\r\n\t\t\t| (charIndex << CharacterMappingConstants.CHAR_INDEX_OFFSET)\r\n\t\t) >>> 0;\r\n\r\n\t\tlet min = 0;\r\n\t\tlet max = this.length - 1;\r\n\t\twhile (min + 1 < max) {\r\n\t\t\tlet mid = ((min + max) >>> 1);\r\n\t\t\tlet midEntry = this._data[mid];\r\n\t\t\tif (midEntry === searchEntry) {\r\n\t\t\t\treturn mid;\r\n\t\t\t} else if (midEntry > searchEntry) {\r\n\t\t\t\tmax = mid;\r\n\t\t\t} else {\r\n\t\t\t\tmin = mid;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (min === max) {\r\n\t\t\treturn min;\r\n\t\t}\r\n\r\n\t\tlet minEntry = this._data[min];\r\n\t\tlet maxEntry = this._data[max];\r\n\r\n\t\tif (minEntry === searchEntry) {\r\n\t\t\treturn min;\r\n\t\t}\r\n\t\tif (maxEntry === searchEntry) {\r\n\t\t\treturn max;\r\n\t\t}\r\n\r\n\t\tlet minPartIndex = CharacterMapping.getPartIndex(minEntry);\r\n\t\tlet minCharIndex = CharacterMapping.getCharIndex(minEntry);\r\n\r\n\t\tlet maxPartIndex = CharacterMapping.getPartIndex(maxEntry);\r\n\t\tlet maxCharIndex: number;\r\n\r\n\t\tif (minPartIndex !== maxPartIndex) {\r\n\t\t\t// sitting between parts\r\n\t\t\tmaxCharIndex = partLength;\r\n\t\t} else {\r\n\t\t\tmaxCharIndex = CharacterMapping.getCharIndex(maxEntry);\r\n\t\t}\r\n\r\n\t\tlet minEntryDistance = charIndex - minCharIndex;\r\n\t\tlet maxEntryDistance = maxCharIndex - charIndex;\r\n\r\n\t\tif (minEntryDistance <= maxEntryDistance) {\r\n\t\t\treturn min;\r\n\t\t}\r\n\t\treturn max;\r\n\t}\r\n}\r\n\r\nexport const enum ForeignElementType {\r\n\tNone = 0,\r\n\tBefore = 1,\r\n\tAfter = 2\r\n}\r\n\r\nexport class RenderLineOutput {\r\n\t_renderLineOutputBrand: void;\r\n\r\n\treadonly characterMapping: CharacterMapping;\r\n\treadonly containsRTL: boolean;\r\n\treadonly containsForeignElements: ForeignElementType;\r\n\r\n\tconstructor(characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: ForeignElementType) {\r\n\t\tthis.characterMapping = characterMapping;\r\n\t\tthis.containsRTL = containsRTL;\r\n\t\tthis.containsForeignElements = containsForeignElements;\r\n\t}\r\n}\r\n\r\nexport function renderViewLine(input: RenderLineInput, sb: IStringBuilder): RenderLineOutput {\r\n\tif (input.lineContent.length === 0) {\r\n\r\n\t\tlet containsForeignElements = ForeignElementType.None;\r\n\r\n\t\tlet content: string = '';\r\n\r\n\t\tif (input.lineDecorations.length > 0) {\r\n\t\t\t// This line is empty, but it contains inline decorations\r\n\t\t\tconst beforeClassNames: string[] = [];\r\n\t\t\tconst afterClassNames: string[] = [];\r\n\t\t\tfor (let i = 0, len = input.lineDecorations.length; i < len; i++) {\r\n\t\t\t\tconst lineDecoration = input.lineDecorations[i];\r\n\t\t\t\tif (lineDecoration.type === InlineDecorationType.Before) {\r\n\t\t\t\t\tbeforeClassNames.push(input.lineDecorations[i].className);\r\n\t\t\t\t\tcontainsForeignElements |= ForeignElementType.Before;\r\n\t\t\t\t}\r\n\t\t\t\tif (lineDecoration.type === InlineDecorationType.After) {\r\n\t\t\t\t\tafterClassNames.push(input.lineDecorations[i].className);\r\n\t\t\t\t\tcontainsForeignElements |= ForeignElementType.After;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (containsForeignElements !== ForeignElementType.None) {\r\n\t\t\t\tconst beforeSpan = (beforeClassNames.length > 0 ? `` : ``);\r\n\t\t\t\tconst afterSpan = (afterClassNames.length > 0 ? `` : ``);\r\n\t\t\t\tcontent = `${beforeSpan}${afterSpan}`;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tsb.appendASCIIString(content);\r\n\t\treturn new RenderLineOutput(\r\n\t\t\tnew CharacterMapping(0, 0),\r\n\t\t\tfalse,\r\n\t\t\tcontainsForeignElements\r\n\t\t);\r\n\t}\r\n\r\n\treturn _renderLine(resolveRenderLineInput(input), sb);\r\n}\r\n\r\nexport class RenderLineOutput2 {\r\n\tconstructor(\r\n\t\tpublic readonly characterMapping: CharacterMapping,\r\n\t\tpublic readonly html: string,\r\n\t\tpublic readonly containsRTL: boolean,\r\n\t\tpublic readonly containsForeignElements: ForeignElementType\r\n\t) {\r\n\t}\r\n}\r\n\r\nexport function renderViewLine2(input: RenderLineInput): RenderLineOutput2 {\r\n\tlet sb = createStringBuilder(10000);\r\n\tlet out = renderViewLine(input, sb);\r\n\treturn new RenderLineOutput2(out.characterMapping, sb.build(), out.containsRTL, out.containsForeignElements);\r\n}\r\n\r\nclass ResolvedRenderLineInput {\r\n\tconstructor(\r\n\t\tpublic readonly fontIsMonospace: boolean,\r\n\t\tpublic readonly canUseHalfwidthRightwardsArrow: boolean,\r\n\t\tpublic readonly lineContent: string,\r\n\t\tpublic readonly len: number,\r\n\t\tpublic readonly isOverflowing: boolean,\r\n\t\tpublic readonly parts: LinePart[],\r\n\t\tpublic readonly containsForeignElements: ForeignElementType,\r\n\t\tpublic readonly fauxIndentLength: number,\r\n\t\tpublic readonly tabSize: number,\r\n\t\tpublic readonly startVisibleColumn: number,\r\n\t\tpublic readonly containsRTL: boolean,\r\n\t\tpublic readonly spaceWidth: number,\r\n\t\tpublic readonly renderSpaceCharCode: number,\r\n\t\tpublic readonly renderWhitespace: RenderWhitespace,\r\n\t\tpublic readonly renderControlCharacters: boolean,\r\n\t) {\r\n\t\t//\r\n\t}\r\n}\r\n\r\nfunction resolveRenderLineInput(input: RenderLineInput): ResolvedRenderLineInput {\r\n\tconst lineContent = input.lineContent;\r\n\r\n\tlet isOverflowing: boolean;\r\n\tlet len: number;\r\n\r\n\tif (input.stopRenderingLineAfter !== -1 && input.stopRenderingLineAfter < lineContent.length) {\r\n\t\tisOverflowing = true;\r\n\t\tlen = input.stopRenderingLineAfter;\r\n\t} else {\r\n\t\tisOverflowing = false;\r\n\t\tlen = lineContent.length;\r\n\t}\r\n\r\n\tlet tokens = transformAndRemoveOverflowing(input.lineTokens, input.fauxIndentLength, len);\r\n\tif (input.renderWhitespace === RenderWhitespace.All ||\r\n\t\tinput.renderWhitespace === RenderWhitespace.Boundary ||\r\n\t\t(input.renderWhitespace === RenderWhitespace.Selection && !!input.selectionsOnLine) ||\r\n\t\tinput.renderWhitespace === RenderWhitespace.Trailing) {\r\n\r\n\t\ttokens = _applyRenderWhitespace(input, lineContent, len, tokens);\r\n\t}\r\n\tlet containsForeignElements = ForeignElementType.None;\r\n\tif (input.lineDecorations.length > 0) {\r\n\t\tfor (let i = 0, len = input.lineDecorations.length; i < len; i++) {\r\n\t\t\tconst lineDecoration = input.lineDecorations[i];\r\n\t\t\tif (lineDecoration.type === InlineDecorationType.RegularAffectingLetterSpacing) {\r\n\t\t\t\t// Pretend there are foreign elements... although not 100% accurate.\r\n\t\t\t\tcontainsForeignElements |= ForeignElementType.Before;\r\n\t\t\t} else if (lineDecoration.type === InlineDecorationType.Before) {\r\n\t\t\t\tcontainsForeignElements |= ForeignElementType.Before;\r\n\t\t\t} else if (lineDecoration.type === InlineDecorationType.After) {\r\n\t\t\t\tcontainsForeignElements |= ForeignElementType.After;\r\n\t\t\t}\r\n\t\t}\r\n\t\ttokens = _applyInlineDecorations(lineContent, len, tokens, input.lineDecorations);\r\n\t}\r\n\tif (!input.containsRTL) {\r\n\t\t// We can never split RTL text, as it ruins the rendering\r\n\t\ttokens = splitLargeTokens(lineContent, tokens, !input.isBasicASCII || input.fontLigatures);\r\n\t}\r\n\r\n\treturn new ResolvedRenderLineInput(\r\n\t\tinput.useMonospaceOptimizations,\r\n\t\tinput.canUseHalfwidthRightwardsArrow,\r\n\t\tlineContent,\r\n\t\tlen,\r\n\t\tisOverflowing,\r\n\t\ttokens,\r\n\t\tcontainsForeignElements,\r\n\t\tinput.fauxIndentLength,\r\n\t\tinput.tabSize,\r\n\t\tinput.startVisibleColumn,\r\n\t\tinput.containsRTL,\r\n\t\tinput.spaceWidth,\r\n\t\tinput.renderSpaceCharCode,\r\n\t\tinput.renderWhitespace,\r\n\t\tinput.renderControlCharacters\r\n\t);\r\n}\r\n\r\n/**\r\n * In the rendering phase, characters are always looped until token.endIndex.\r\n * Ensure that all tokens end before `len` and the last one ends precisely at `len`.\r\n */\r\nfunction transformAndRemoveOverflowing(tokens: IViewLineTokens, fauxIndentLength: number, len: number): LinePart[] {\r\n\tlet result: LinePart[] = [], resultLen = 0;\r\n\r\n\t// The faux indent part of the line should have no token type\r\n\tif (fauxIndentLength > 0) {\r\n\t\tresult[resultLen++] = new LinePart(fauxIndentLength, '', 0);\r\n\t}\r\n\r\n\tfor (let tokenIndex = 0, tokensLen = tokens.getCount(); tokenIndex < tokensLen; tokenIndex++) {\r\n\t\tconst endIndex = tokens.getEndOffset(tokenIndex);\r\n\t\tif (endIndex <= fauxIndentLength) {\r\n\t\t\t// The faux indent part of the line should have no token type\r\n\t\t\tcontinue;\r\n\t\t}\r\n\t\tconst type = tokens.getClassName(tokenIndex);\r\n\t\tif (endIndex >= len) {\r\n\t\t\tresult[resultLen++] = new LinePart(len, type, 0);\r\n\t\t\tbreak;\r\n\t\t}\r\n\t\tresult[resultLen++] = new LinePart(endIndex, type, 0);\r\n\t}\r\n\r\n\treturn result;\r\n}\r\n\r\n/**\r\n * written as a const enum to get value inlining.\r\n */\r\nconst enum Constants {\r\n\tLongToken = 50\r\n}\r\n\r\n/**\r\n * See https://github.com/microsoft/vscode/issues/6885.\r\n * It appears that having very large spans causes very slow reading of character positions.\r\n * So here we try to avoid that.\r\n */\r\nfunction splitLargeTokens(lineContent: string, tokens: LinePart[], onlyAtSpaces: boolean): LinePart[] {\r\n\tlet lastTokenEndIndex = 0;\r\n\tlet result: LinePart[] = [], resultLen = 0;\r\n\r\n\tif (onlyAtSpaces) {\r\n\t\t// Split only at spaces => we need to walk each character\r\n\t\tfor (let i = 0, len = tokens.length; i < len; i++) {\r\n\t\t\tconst token = tokens[i];\r\n\t\t\tconst tokenEndIndex = token.endIndex;\r\n\t\t\tif (lastTokenEndIndex + Constants.LongToken < tokenEndIndex) {\r\n\t\t\t\tconst tokenType = token.type;\r\n\t\t\t\tconst tokenMetadata = token.metadata;\r\n\r\n\t\t\t\tlet lastSpaceOffset = -1;\r\n\t\t\t\tlet currTokenStart = lastTokenEndIndex;\r\n\t\t\t\tfor (let j = lastTokenEndIndex; j < tokenEndIndex; j++) {\r\n\t\t\t\t\tif (lineContent.charCodeAt(j) === CharCode.Space) {\r\n\t\t\t\t\t\tlastSpaceOffset = j;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (lastSpaceOffset !== -1 && j - currTokenStart >= Constants.LongToken) {\r\n\t\t\t\t\t\t// Split at `lastSpaceOffset` + 1\r\n\t\t\t\t\t\tresult[resultLen++] = new LinePart(lastSpaceOffset + 1, tokenType, tokenMetadata);\r\n\t\t\t\t\t\tcurrTokenStart = lastSpaceOffset + 1;\r\n\t\t\t\t\t\tlastSpaceOffset = -1;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tif (currTokenStart !== tokenEndIndex) {\r\n\t\t\t\t\tresult[resultLen++] = new LinePart(tokenEndIndex, tokenType, tokenMetadata);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tresult[resultLen++] = token;\r\n\t\t\t}\r\n\r\n\t\t\tlastTokenEndIndex = tokenEndIndex;\r\n\t\t}\r\n\t} else {\r\n\t\t// Split anywhere => we don't need to walk each character\r\n\t\tfor (let i = 0, len = tokens.length; i < len; i++) {\r\n\t\t\tconst token = tokens[i];\r\n\t\t\tconst tokenEndIndex = token.endIndex;\r\n\t\t\tlet diff = (tokenEndIndex - lastTokenEndIndex);\r\n\t\t\tif (diff > Constants.LongToken) {\r\n\t\t\t\tconst tokenType = token.type;\r\n\t\t\t\tconst tokenMetadata = token.metadata;\r\n\t\t\t\tconst piecesCount = Math.ceil(diff / Constants.LongToken);\r\n\t\t\t\tfor (let j = 1; j < piecesCount; j++) {\r\n\t\t\t\t\tlet pieceEndIndex = lastTokenEndIndex + (j * Constants.LongToken);\r\n\t\t\t\t\tresult[resultLen++] = new LinePart(pieceEndIndex, tokenType, tokenMetadata);\r\n\t\t\t\t}\r\n\t\t\t\tresult[resultLen++] = new LinePart(tokenEndIndex, tokenType, tokenMetadata);\r\n\t\t\t} else {\r\n\t\t\t\tresult[resultLen++] = token;\r\n\t\t\t}\r\n\t\t\tlastTokenEndIndex = tokenEndIndex;\r\n\t\t}\r\n\t}\r\n\r\n\treturn result;\r\n}\r\n\r\n/**\r\n * Whitespace is rendered by \"replacing\" tokens with a special-purpose `mtkw` type that is later recognized in the rendering phase.\r\n * Moreover, a token is created for every visual indent because on some fonts the glyphs used for rendering whitespace (→ or ·) do not have the same width as  .\r\n * The rendering phase will generate `style=\"width:...\"` for these tokens.\r\n */\r\nfunction _applyRenderWhitespace(input: RenderLineInput, lineContent: string, len: number, tokens: LinePart[]): LinePart[] {\r\n\r\n\tconst continuesWithWrappedLine = input.continuesWithWrappedLine;\r\n\tconst fauxIndentLength = input.fauxIndentLength;\r\n\tconst tabSize = input.tabSize;\r\n\tconst startVisibleColumn = input.startVisibleColumn;\r\n\tconst useMonospaceOptimizations = input.useMonospaceOptimizations;\r\n\tconst selections = input.selectionsOnLine;\r\n\tconst onlyBoundary = (input.renderWhitespace === RenderWhitespace.Boundary);\r\n\tconst onlyTrailing = (input.renderWhitespace === RenderWhitespace.Trailing);\r\n\tconst generateLinePartForEachWhitespace = (input.renderSpaceWidth !== input.spaceWidth);\r\n\r\n\tlet result: LinePart[] = [], resultLen = 0;\r\n\tlet tokenIndex = 0;\r\n\tlet tokenType = tokens[tokenIndex].type;\r\n\tlet tokenEndIndex = tokens[tokenIndex].endIndex;\r\n\tconst tokensLength = tokens.length;\r\n\r\n\tlet lineIsEmptyOrWhitespace = false;\r\n\tlet firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(lineContent);\r\n\tlet lastNonWhitespaceIndex: number;\r\n\tif (firstNonWhitespaceIndex === -1) {\r\n\t\tlineIsEmptyOrWhitespace = true;\r\n\t\tfirstNonWhitespaceIndex = len;\r\n\t\tlastNonWhitespaceIndex = len;\r\n\t} else {\r\n\t\tlastNonWhitespaceIndex = strings.lastNonWhitespaceIndex(lineContent);\r\n\t}\r\n\r\n\tlet wasInWhitespace = false;\r\n\tlet currentSelectionIndex = 0;\r\n\tlet currentSelection = selections && selections[currentSelectionIndex];\r\n\tlet tmpIndent = startVisibleColumn % tabSize;\r\n\tfor (let charIndex = fauxIndentLength; charIndex < len; charIndex++) {\r\n\t\tconst chCode = lineContent.charCodeAt(charIndex);\r\n\r\n\t\tif (currentSelection && charIndex >= currentSelection.endOffset) {\r\n\t\t\tcurrentSelectionIndex++;\r\n\t\t\tcurrentSelection = selections && selections[currentSelectionIndex];\r\n\t\t}\r\n\r\n\t\tlet isInWhitespace: boolean;\r\n\t\tif (charIndex < firstNonWhitespaceIndex || charIndex > lastNonWhitespaceIndex) {\r\n\t\t\t// in leading or trailing whitespace\r\n\t\t\tisInWhitespace = true;\r\n\t\t} else if (chCode === CharCode.Tab) {\r\n\t\t\t// a tab character is rendered both in all and boundary cases\r\n\t\t\tisInWhitespace = true;\r\n\t\t} else if (chCode === CharCode.Space) {\r\n\t\t\t// hit a space character\r\n\t\t\tif (onlyBoundary) {\r\n\t\t\t\t// rendering only boundary whitespace\r\n\t\t\t\tif (wasInWhitespace) {\r\n\t\t\t\t\tisInWhitespace = true;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tconst nextChCode = (charIndex + 1 < len ? lineContent.charCodeAt(charIndex + 1) : CharCode.Null);\r\n\t\t\t\t\tisInWhitespace = (nextChCode === CharCode.Space || nextChCode === CharCode.Tab);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tisInWhitespace = true;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tisInWhitespace = false;\r\n\t\t}\r\n\r\n\t\t// If rendering whitespace on selection, check that the charIndex falls within a selection\r\n\t\tif (isInWhitespace && selections) {\r\n\t\t\tisInWhitespace = !!currentSelection && currentSelection.startOffset <= charIndex && currentSelection.endOffset > charIndex;\r\n\t\t}\r\n\r\n\t\t// If rendering only trailing whitespace, check that the charIndex points to trailing whitespace.\r\n\t\tif (isInWhitespace && onlyTrailing) {\r\n\t\t\tisInWhitespace = lineIsEmptyOrWhitespace || charIndex > lastNonWhitespaceIndex;\r\n\t\t}\r\n\r\n\t\tif (wasInWhitespace) {\r\n\t\t\t// was in whitespace token\r\n\t\t\tif (!isInWhitespace || (!useMonospaceOptimizations && tmpIndent >= tabSize)) {\r\n\t\t\t\t// leaving whitespace token or entering a new indent\r\n\t\t\t\tif (generateLinePartForEachWhitespace) {\r\n\t\t\t\t\tconst lastEndIndex = (resultLen > 0 ? result[resultLen - 1].endIndex : fauxIndentLength);\r\n\t\t\t\t\tfor (let i = lastEndIndex + 1; i <= charIndex; i++) {\r\n\t\t\t\t\t\tresult[resultLen++] = new LinePart(i, 'mtkw', LinePartMetadata.IS_WHITESPACE);\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tresult[resultLen++] = new LinePart(charIndex, 'mtkw', LinePartMetadata.IS_WHITESPACE);\r\n\t\t\t\t}\r\n\t\t\t\ttmpIndent = tmpIndent % tabSize;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\t// was in regular token\r\n\t\t\tif (charIndex === tokenEndIndex || (isInWhitespace && charIndex > fauxIndentLength)) {\r\n\t\t\t\tresult[resultLen++] = new LinePart(charIndex, tokenType, 0);\r\n\t\t\t\ttmpIndent = tmpIndent % tabSize;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (chCode === CharCode.Tab) {\r\n\t\t\ttmpIndent = tabSize;\r\n\t\t} else if (strings.isFullWidthCharacter(chCode)) {\r\n\t\t\ttmpIndent += 2;\r\n\t\t} else {\r\n\t\t\ttmpIndent++;\r\n\t\t}\r\n\r\n\t\twasInWhitespace = isInWhitespace;\r\n\r\n\t\twhile (charIndex === tokenEndIndex) {\r\n\t\t\ttokenIndex++;\r\n\t\t\tif (tokenIndex < tokensLength) {\r\n\t\t\t\ttokenType = tokens[tokenIndex].type;\r\n\t\t\t\ttokenEndIndex = tokens[tokenIndex].endIndex;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tlet generateWhitespace = false;\r\n\tif (wasInWhitespace) {\r\n\t\t// was in whitespace token\r\n\t\tif (continuesWithWrappedLine && onlyBoundary) {\r\n\t\t\tlet lastCharCode = (len > 0 ? lineContent.charCodeAt(len - 1) : CharCode.Null);\r\n\t\t\tlet prevCharCode = (len > 1 ? lineContent.charCodeAt(len - 2) : CharCode.Null);\r\n\t\t\tlet isSingleTrailingSpace = (lastCharCode === CharCode.Space && (prevCharCode !== CharCode.Space && prevCharCode !== CharCode.Tab));\r\n\t\t\tif (!isSingleTrailingSpace) {\r\n\t\t\t\tgenerateWhitespace = true;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tgenerateWhitespace = true;\r\n\t\t}\r\n\t}\r\n\r\n\tif (generateWhitespace) {\r\n\t\tif (generateLinePartForEachWhitespace) {\r\n\t\t\tconst lastEndIndex = (resultLen > 0 ? result[resultLen - 1].endIndex : fauxIndentLength);\r\n\t\t\tfor (let i = lastEndIndex + 1; i <= len; i++) {\r\n\t\t\t\tresult[resultLen++] = new LinePart(i, 'mtkw', LinePartMetadata.IS_WHITESPACE);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tresult[resultLen++] = new LinePart(len, 'mtkw', LinePartMetadata.IS_WHITESPACE);\r\n\t\t}\r\n\t} else {\r\n\t\tresult[resultLen++] = new LinePart(len, tokenType, 0);\r\n\t}\r\n\r\n\treturn result;\r\n}\r\n\r\n/**\r\n * Inline decorations are \"merged\" on top of tokens.\r\n * Special care must be taken when multiple inline decorations are at play and they overlap.\r\n */\r\nfunction _applyInlineDecorations(lineContent: string, len: number, tokens: LinePart[], _lineDecorations: LineDecoration[]): LinePart[] {\r\n\t_lineDecorations.sort(LineDecoration.compare);\r\n\tconst lineDecorations = LineDecorationsNormalizer.normalize(lineContent, _lineDecorations);\r\n\tconst lineDecorationsLen = lineDecorations.length;\r\n\r\n\tlet lineDecorationIndex = 0;\r\n\tlet result: LinePart[] = [], resultLen = 0, lastResultEndIndex = 0;\r\n\tfor (let tokenIndex = 0, len = tokens.length; tokenIndex < len; tokenIndex++) {\r\n\t\tconst token = tokens[tokenIndex];\r\n\t\tconst tokenEndIndex = token.endIndex;\r\n\t\tconst tokenType = token.type;\r\n\t\tconst tokenMetadata = token.metadata;\r\n\r\n\t\twhile (lineDecorationIndex < lineDecorationsLen && lineDecorations[lineDecorationIndex].startOffset < tokenEndIndex) {\r\n\t\t\tconst lineDecoration = lineDecorations[lineDecorationIndex];\r\n\r\n\t\t\tif (lineDecoration.startOffset > lastResultEndIndex) {\r\n\t\t\t\tlastResultEndIndex = lineDecoration.startOffset;\r\n\t\t\t\tresult[resultLen++] = new LinePart(lastResultEndIndex, tokenType, tokenMetadata);\r\n\t\t\t}\r\n\r\n\t\t\tif (lineDecoration.endOffset + 1 <= tokenEndIndex) {\r\n\t\t\t\t// This line decoration ends before this token ends\r\n\t\t\t\tlastResultEndIndex = lineDecoration.endOffset + 1;\r\n\t\t\t\tresult[resultLen++] = new LinePart(lastResultEndIndex, tokenType + ' ' + lineDecoration.className, tokenMetadata | lineDecoration.metadata);\r\n\t\t\t\tlineDecorationIndex++;\r\n\t\t\t} else {\r\n\t\t\t\t// This line decoration continues on to the next token\r\n\t\t\t\tlastResultEndIndex = tokenEndIndex;\r\n\t\t\t\tresult[resultLen++] = new LinePart(lastResultEndIndex, tokenType + ' ' + lineDecoration.className, tokenMetadata | lineDecoration.metadata);\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (tokenEndIndex > lastResultEndIndex) {\r\n\t\t\tlastResultEndIndex = tokenEndIndex;\r\n\t\t\tresult[resultLen++] = new LinePart(lastResultEndIndex, tokenType, tokenMetadata);\r\n\t\t}\r\n\t}\r\n\r\n\tconst lastTokenEndIndex = tokens[tokens.length - 1].endIndex;\r\n\tif (lineDecorationIndex < lineDecorationsLen && lineDecorations[lineDecorationIndex].startOffset === lastTokenEndIndex) {\r\n\t\tlet classNames: string[] = [];\r\n\t\tlet metadata = 0;\r\n\t\twhile (lineDecorationIndex < lineDecorationsLen && lineDecorations[lineDecorationIndex].startOffset === lastTokenEndIndex) {\r\n\t\t\tclassNames.push(lineDecorations[lineDecorationIndex].className);\r\n\t\t\tmetadata |= lineDecorations[lineDecorationIndex].metadata;\r\n\t\t\tlineDecorationIndex++;\r\n\t\t}\r\n\t\tresult[resultLen++] = new LinePart(lastResultEndIndex, classNames.join(' '), metadata);\r\n\t}\r\n\r\n\treturn result;\r\n}\r\n\r\n/**\r\n * This function is on purpose not split up into multiple functions to allow runtime type inference (i.e. performance reasons).\r\n * Notice how all the needed data is fully resolved and passed in (i.e. no other calls).\r\n */\r\nfunction _renderLine(input: ResolvedRenderLineInput, sb: IStringBuilder): RenderLineOutput {\r\n\tconst fontIsMonospace = input.fontIsMonospace;\r\n\tconst canUseHalfwidthRightwardsArrow = input.canUseHalfwidthRightwardsArrow;\r\n\tconst containsForeignElements = input.containsForeignElements;\r\n\tconst lineContent = input.lineContent;\r\n\tconst len = input.len;\r\n\tconst isOverflowing = input.isOverflowing;\r\n\tconst parts = input.parts;\r\n\tconst fauxIndentLength = input.fauxIndentLength;\r\n\tconst tabSize = input.tabSize;\r\n\tconst startVisibleColumn = input.startVisibleColumn;\r\n\tconst containsRTL = input.containsRTL;\r\n\tconst spaceWidth = input.spaceWidth;\r\n\tconst renderSpaceCharCode = input.renderSpaceCharCode;\r\n\tconst renderWhitespace = input.renderWhitespace;\r\n\tconst renderControlCharacters = input.renderControlCharacters;\r\n\r\n\tconst characterMapping = new CharacterMapping(len + 1, parts.length);\r\n\r\n\tlet charIndex = 0;\r\n\tlet visibleColumn = startVisibleColumn;\r\n\tlet charOffsetInPart = 0;\r\n\r\n\tlet partDisplacement = 0;\r\n\tlet prevPartContentCnt = 0;\r\n\tlet partAbsoluteOffset = 0;\r\n\r\n\tif (containsRTL) {\r\n\t\tsb.appendASCIIString('');\r\n\t} else {\r\n\t\tsb.appendASCIIString('');\r\n\t}\r\n\r\n\tfor (let partIndex = 0, tokensLen = parts.length; partIndex < tokensLen; partIndex++) {\r\n\t\tpartAbsoluteOffset += prevPartContentCnt;\r\n\r\n\t\tconst part = parts[partIndex];\r\n\t\tconst partEndIndex = part.endIndex;\r\n\t\tconst partType = part.type;\r\n\t\tconst partRendersWhitespace = (renderWhitespace !== RenderWhitespace.None && part.isWhitespace());\r\n\t\tconst partRendersWhitespaceWithWidth = partRendersWhitespace && !fontIsMonospace && (partType === 'mtkw'/*only whitespace*/ || !containsForeignElements);\r\n\t\tconst partIsEmptyAndHasPseudoAfter = (charIndex === partEndIndex && part.metadata === LinePartMetadata.PSEUDO_AFTER);\r\n\t\tcharOffsetInPart = 0;\r\n\r\n\t\tsb.appendASCIIString('= fauxIndentLength) {\r\n\t\t\t\t\t\t_visibleColumn += charWidth;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (partRendersWhitespaceWithWidth) {\r\n\t\t\t\tsb.appendASCIIString(' style=\"width:');\r\n\t\t\t\tsb.appendASCIIString(String(spaceWidth * partContentCnt));\r\n\t\t\t\tsb.appendASCIIString('px\"');\r\n\t\t\t}\r\n\t\t\tsb.appendASCII(CharCode.GreaterThan);\r\n\r\n\t\t\tfor (; charIndex < partEndIndex; charIndex++) {\r\n\t\t\t\tcharacterMapping.setPartData(charIndex, partIndex - partDisplacement, charOffsetInPart, partAbsoluteOffset);\r\n\t\t\t\tpartDisplacement = 0;\r\n\t\t\t\tconst charCode = lineContent.charCodeAt(charIndex);\r\n\t\t\t\tlet charWidth: number;\r\n\r\n\t\t\t\tif (charCode === CharCode.Tab) {\r\n\t\t\t\t\tcharWidth = (tabSize - (visibleColumn % tabSize)) | 0;\r\n\r\n\t\t\t\t\tif (!canUseHalfwidthRightwardsArrow || charWidth > 1) {\r\n\t\t\t\t\t\tsb.write1(0x2192); // RIGHTWARDS ARROW\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tsb.write1(0xFFEB); // HALFWIDTH RIGHTWARDS ARROW\r\n\t\t\t\t\t}\r\n\t\t\t\t\tfor (let space = 2; space <= charWidth; space++) {\r\n\t\t\t\t\t\tsb.write1(0xA0); //  \r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t} else { // must be CharCode.Space\r\n\t\t\t\t\tcharWidth = 1;\r\n\r\n\t\t\t\t\tsb.write1(renderSpaceCharCode); // · or word separator middle dot\r\n\t\t\t\t}\r\n\r\n\t\t\t\tcharOffsetInPart += charWidth;\r\n\t\t\t\tif (charIndex >= fauxIndentLength) {\r\n\t\t\t\t\tvisibleColumn += charWidth;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tprevPartContentCnt = partContentCnt;\r\n\r\n\t\t} else {\r\n\r\n\t\t\tlet partContentCnt = 0;\r\n\r\n\t\t\tsb.appendASCII(CharCode.GreaterThan);\r\n\r\n\t\t\tfor (; charIndex < partEndIndex; charIndex++) {\r\n\t\t\t\tcharacterMapping.setPartData(charIndex, partIndex - partDisplacement, charOffsetInPart, partAbsoluteOffset);\r\n\t\t\t\tpartDisplacement = 0;\r\n\t\t\t\tconst charCode = lineContent.charCodeAt(charIndex);\r\n\r\n\t\t\t\tlet producedCharacters = 1;\r\n\t\t\t\tlet charWidth = 1;\r\n\r\n\t\t\t\tswitch (charCode) {\r\n\t\t\t\t\tcase CharCode.Tab:\r\n\t\t\t\t\t\tproducedCharacters = (tabSize - (visibleColumn % tabSize));\r\n\t\t\t\t\t\tcharWidth = producedCharacters;\r\n\t\t\t\t\t\tfor (let space = 1; space <= producedCharacters; space++) {\r\n\t\t\t\t\t\t\tsb.write1(0xA0); //  \r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\tcase CharCode.Space:\r\n\t\t\t\t\t\tsb.write1(0xA0); //  \r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\tcase CharCode.LessThan:\r\n\t\t\t\t\t\tsb.appendASCIIString('<');\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\tcase CharCode.GreaterThan:\r\n\t\t\t\t\t\tsb.appendASCIIString('>');\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\tcase CharCode.Ampersand:\r\n\t\t\t\t\t\tsb.appendASCIIString('&');\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\tcase CharCode.Null:\r\n\t\t\t\t\t\tsb.appendASCIIString('�');\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\tcase CharCode.UTF8_BOM:\r\n\t\t\t\t\tcase CharCode.LINE_SEPARATOR:\r\n\t\t\t\t\tcase CharCode.PARAGRAPH_SEPARATOR:\r\n\t\t\t\t\tcase CharCode.NEXT_LINE:\r\n\t\t\t\t\t\tsb.write1(0xFFFD);\r\n\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\tdefault:\r\n\t\t\t\t\t\tif (strings.isFullWidthCharacter(charCode)) {\r\n\t\t\t\t\t\t\tcharWidth++;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (renderControlCharacters && charCode < 32) {\r\n\t\t\t\t\t\t\tsb.write1(9216 + charCode);\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tsb.write1(charCode);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tcharOffsetInPart += producedCharacters;\r\n\t\t\t\tpartContentCnt += producedCharacters;\r\n\t\t\t\tif (charIndex >= fauxIndentLength) {\r\n\t\t\t\t\tvisibleColumn += charWidth;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tprevPartContentCnt = partContentCnt;\r\n\t\t}\r\n\r\n\t\tif (partIsEmptyAndHasPseudoAfter) {\r\n\t\t\tpartDisplacement++;\r\n\t\t} else {\r\n\t\t\tpartDisplacement = 0;\r\n\t\t}\r\n\r\n\t\tsb.appendASCIIString('');\r\n\r\n\t}\r\n\r\n\t// When getting client rects for the last character, we will position the\r\n\t// text range at the end of the span, insteaf of at the beginning of next span\r\n\tcharacterMapping.setPartData(len, parts.length - 1, charOffsetInPart, partAbsoluteOffset);\r\n\r\n\tif (isOverflowing) {\r\n\t\tsb.appendASCIIString('');\r\n\t}\r\n\r\n\tsb.appendASCIIString('');\r\n\r\n\treturn new RenderLineOutput(characterMapping, containsRTL, containsForeignElements);\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { IViewModel, IViewWhitespaceViewportData, ViewLineRenderingData, ViewModelDecoration } from 'vs/editor/common/viewModel/viewModel';\r\n\r\nexport interface IPartialViewLinesViewportData {\r\n\t/**\r\n\t * Value to be substracted from `scrollTop` (in order to vertical offset numbers < 1MM)\r\n\t */\r\n\treadonly bigNumbersDelta: number;\r\n\t/**\r\n\t * The first (partially) visible line number.\r\n\t */\r\n\treadonly startLineNumber: number;\r\n\t/**\r\n\t * The last (partially) visible line number.\r\n\t */\r\n\treadonly endLineNumber: number;\r\n\t/**\r\n\t * relativeVerticalOffset[i] is the `top` position for line at `i` + `startLineNumber`.\r\n\t */\r\n\treadonly relativeVerticalOffset: number[];\r\n\t/**\r\n\t * The centered line in the viewport.\r\n\t */\r\n\treadonly centeredLineNumber: number;\r\n\t/**\r\n\t * The first completely visible line number.\r\n\t */\r\n\treadonly completelyVisibleStartLineNumber: number;\r\n\t/**\r\n\t * The last completely visible line number.\r\n\t */\r\n\treadonly completelyVisibleEndLineNumber: number;\r\n}\r\n\r\n/**\r\n * Contains all data needed to render at a specific viewport.\r\n */\r\nexport class ViewportData {\r\n\r\n\tpublic readonly selections: Selection[];\r\n\r\n\t/**\r\n\t * The line number at which to start rendering (inclusive).\r\n\t */\r\n\tpublic readonly startLineNumber: number;\r\n\r\n\t/**\r\n\t * The line number at which to end rendering (inclusive).\r\n\t */\r\n\tpublic readonly endLineNumber: number;\r\n\r\n\t/**\r\n\t * relativeVerticalOffset[i] is the `top` position for line at `i` + `startLineNumber`.\r\n\t */\r\n\tpublic readonly relativeVerticalOffset: number[];\r\n\r\n\t/**\r\n\t * The viewport as a range (startLineNumber,1) -> (endLineNumber,maxColumn(endLineNumber)).\r\n\t */\r\n\tpublic readonly visibleRange: Range;\r\n\r\n\t/**\r\n\t * Value to be substracted from `scrollTop` (in order to vertical offset numbers < 1MM)\r\n\t */\r\n\tpublic readonly bigNumbersDelta: number;\r\n\r\n\t/**\r\n\t * Positioning information about gaps whitespace.\r\n\t */\r\n\tpublic readonly whitespaceViewportData: IViewWhitespaceViewportData[];\r\n\r\n\tprivate readonly _model: IViewModel;\r\n\r\n\tconstructor(\r\n\t\tselections: Selection[],\r\n\t\tpartialData: IPartialViewLinesViewportData,\r\n\t\twhitespaceViewportData: IViewWhitespaceViewportData[],\r\n\t\tmodel: IViewModel\r\n\t) {\r\n\t\tthis.selections = selections;\r\n\t\tthis.startLineNumber = partialData.startLineNumber | 0;\r\n\t\tthis.endLineNumber = partialData.endLineNumber | 0;\r\n\t\tthis.relativeVerticalOffset = partialData.relativeVerticalOffset;\r\n\t\tthis.bigNumbersDelta = partialData.bigNumbersDelta | 0;\r\n\t\tthis.whitespaceViewportData = whitespaceViewportData;\r\n\r\n\t\tthis._model = model;\r\n\r\n\t\tthis.visibleRange = new Range(\r\n\t\t\tpartialData.startLineNumber,\r\n\t\t\tthis._model.getLineMinColumn(partialData.startLineNumber),\r\n\t\t\tpartialData.endLineNumber,\r\n\t\t\tthis._model.getLineMaxColumn(partialData.endLineNumber)\r\n\t\t);\r\n\t}\r\n\r\n\tpublic getViewLineRenderingData(lineNumber: number): ViewLineRenderingData {\r\n\t\treturn this._model.getViewLineRenderingData(this.visibleRange, lineNumber);\r\n\t}\r\n\r\n\tpublic getDecorationsInViewport(): ViewModelDecoration[] {\r\n\t\treturn this._model.getDecorationsInViewport(this.visibleRange);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { toUint32 } from 'vs/base/common/uint';\r\n\r\nexport class PrefixSumIndexOfResult {\r\n\t_prefixSumIndexOfResultBrand: void;\r\n\r\n\tindex: number;\r\n\tremainder: number;\r\n\r\n\tconstructor(index: number, remainder: number) {\r\n\t\tthis.index = index;\r\n\t\tthis.remainder = remainder;\r\n\t}\r\n}\r\n\r\nexport class PrefixSumComputer {\r\n\r\n\t/**\r\n\t * values[i] is the value at index i\r\n\t */\r\n\tprivate values: Uint32Array;\r\n\r\n\t/**\r\n\t * prefixSum[i] = SUM(heights[j]), 0 <= j <= i\r\n\t */\r\n\tprivate prefixSum: Uint32Array;\r\n\r\n\t/**\r\n\t * prefixSum[i], 0 <= i <= prefixSumValidIndex can be trusted\r\n\t */\r\n\tprivate readonly prefixSumValidIndex: Int32Array;\r\n\r\n\tconstructor(values: Uint32Array) {\r\n\t\tthis.values = values;\r\n\t\tthis.prefixSum = new Uint32Array(values.length);\r\n\t\tthis.prefixSumValidIndex = new Int32Array(1);\r\n\t\tthis.prefixSumValidIndex[0] = -1;\r\n\t}\r\n\r\n\tpublic insertValues(insertIndex: number, insertValues: Uint32Array): boolean {\r\n\t\tinsertIndex = toUint32(insertIndex);\r\n\t\tconst oldValues = this.values;\r\n\t\tconst oldPrefixSum = this.prefixSum;\r\n\t\tconst insertValuesLen = insertValues.length;\r\n\r\n\t\tif (insertValuesLen === 0) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tthis.values = new Uint32Array(oldValues.length + insertValuesLen);\r\n\t\tthis.values.set(oldValues.subarray(0, insertIndex), 0);\r\n\t\tthis.values.set(oldValues.subarray(insertIndex), insertIndex + insertValuesLen);\r\n\t\tthis.values.set(insertValues, insertIndex);\r\n\r\n\t\tif (insertIndex - 1 < this.prefixSumValidIndex[0]) {\r\n\t\t\tthis.prefixSumValidIndex[0] = insertIndex - 1;\r\n\t\t}\r\n\r\n\t\tthis.prefixSum = new Uint32Array(this.values.length);\r\n\t\tif (this.prefixSumValidIndex[0] >= 0) {\r\n\t\t\tthis.prefixSum.set(oldPrefixSum.subarray(0, this.prefixSumValidIndex[0] + 1));\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic changeValue(index: number, value: number): boolean {\r\n\t\tindex = toUint32(index);\r\n\t\tvalue = toUint32(value);\r\n\r\n\t\tif (this.values[index] === value) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tthis.values[index] = value;\r\n\t\tif (index - 1 < this.prefixSumValidIndex[0]) {\r\n\t\t\tthis.prefixSumValidIndex[0] = index - 1;\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic removeValues(startIndex: number, cnt: number): boolean {\r\n\t\tstartIndex = toUint32(startIndex);\r\n\t\tcnt = toUint32(cnt);\r\n\r\n\t\tconst oldValues = this.values;\r\n\t\tconst oldPrefixSum = this.prefixSum;\r\n\r\n\t\tif (startIndex >= oldValues.length) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tlet maxCnt = oldValues.length - startIndex;\r\n\t\tif (cnt >= maxCnt) {\r\n\t\t\tcnt = maxCnt;\r\n\t\t}\r\n\r\n\t\tif (cnt === 0) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tthis.values = new Uint32Array(oldValues.length - cnt);\r\n\t\tthis.values.set(oldValues.subarray(0, startIndex), 0);\r\n\t\tthis.values.set(oldValues.subarray(startIndex + cnt), startIndex);\r\n\r\n\t\tthis.prefixSum = new Uint32Array(this.values.length);\r\n\t\tif (startIndex - 1 < this.prefixSumValidIndex[0]) {\r\n\t\t\tthis.prefixSumValidIndex[0] = startIndex - 1;\r\n\t\t}\r\n\t\tif (this.prefixSumValidIndex[0] >= 0) {\r\n\t\t\tthis.prefixSum.set(oldPrefixSum.subarray(0, this.prefixSumValidIndex[0] + 1));\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic getTotalValue(): number {\r\n\t\tif (this.values.length === 0) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t\treturn this._getAccumulatedValue(this.values.length - 1);\r\n\t}\r\n\r\n\tpublic getAccumulatedValue(index: number): number {\r\n\t\tif (index < 0) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tindex = toUint32(index);\r\n\t\treturn this._getAccumulatedValue(index);\r\n\t}\r\n\r\n\tprivate _getAccumulatedValue(index: number): number {\r\n\t\tif (index <= this.prefixSumValidIndex[0]) {\r\n\t\t\treturn this.prefixSum[index];\r\n\t\t}\r\n\r\n\t\tlet startIndex = this.prefixSumValidIndex[0] + 1;\r\n\t\tif (startIndex === 0) {\r\n\t\t\tthis.prefixSum[0] = this.values[0];\r\n\t\t\tstartIndex++;\r\n\t\t}\r\n\r\n\t\tif (index >= this.values.length) {\r\n\t\t\tindex = this.values.length - 1;\r\n\t\t}\r\n\r\n\t\tfor (let i = startIndex; i <= index; i++) {\r\n\t\t\tthis.prefixSum[i] = this.prefixSum[i - 1] + this.values[i];\r\n\t\t}\r\n\t\tthis.prefixSumValidIndex[0] = Math.max(this.prefixSumValidIndex[0], index);\r\n\t\treturn this.prefixSum[index];\r\n\t}\r\n\r\n\tpublic getIndexOf(accumulatedValue: number): PrefixSumIndexOfResult {\r\n\t\taccumulatedValue = Math.floor(accumulatedValue); //@perf\r\n\r\n\t\t// Compute all sums (to get a fully valid prefixSum)\r\n\t\tthis.getTotalValue();\r\n\r\n\t\tlet low = 0;\r\n\t\tlet high = this.values.length - 1;\r\n\t\tlet mid = 0;\r\n\t\tlet midStop = 0;\r\n\t\tlet midStart = 0;\r\n\r\n\t\twhile (low <= high) {\r\n\t\t\tmid = low + ((high - low) / 2) | 0;\r\n\r\n\t\t\tmidStop = this.prefixSum[mid];\r\n\t\t\tmidStart = midStop - this.values[mid];\r\n\r\n\t\t\tif (accumulatedValue < midStart) {\r\n\t\t\t\thigh = mid - 1;\r\n\t\t\t} else if (accumulatedValue >= midStop) {\r\n\t\t\t\tlow = mid + 1;\r\n\t\t\t} else {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn new PrefixSumIndexOfResult(mid, accumulatedValue - midStart);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { splitLines } from 'vs/base/common/strings';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { IRange } from 'vs/editor/common/core/range';\r\nimport { IModelContentChange } from 'vs/editor/common/model/textModelEvents';\r\nimport { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer';\r\n\r\nexport interface IModelChangedEvent {\r\n\t/**\r\n\t * The actual changes.\r\n\t */\r\n\treadonly changes: IModelContentChange[];\r\n\t/**\r\n\t * The (new) end-of-line character.\r\n\t */\r\n\treadonly eol: string;\r\n\t/**\r\n\t * The new version id the model has transitioned to.\r\n\t */\r\n\treadonly versionId: number;\r\n}\r\n\r\nexport class MirrorTextModel {\r\n\r\n\tprotected _uri: URI;\r\n\tprotected _lines: string[];\r\n\tprotected _eol: string;\r\n\tprotected _versionId: number;\r\n\tprotected _lineStarts: PrefixSumComputer | null;\r\n\tprivate _cachedTextValue: string | null;\r\n\r\n\tconstructor(uri: URI, lines: string[], eol: string, versionId: number) {\r\n\t\tthis._uri = uri;\r\n\t\tthis._lines = lines;\r\n\t\tthis._eol = eol;\r\n\t\tthis._versionId = versionId;\r\n\t\tthis._lineStarts = null;\r\n\t\tthis._cachedTextValue = null;\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._lines.length = 0;\r\n\t}\r\n\r\n\tgetText(): string {\r\n\t\tif (this._cachedTextValue === null) {\r\n\t\t\tthis._cachedTextValue = this._lines.join(this._eol);\r\n\t\t}\r\n\t\treturn this._cachedTextValue;\r\n\t}\r\n\r\n\tonEvents(e: IModelChangedEvent): void {\r\n\t\tif (e.eol && e.eol !== this._eol) {\r\n\t\t\tthis._eol = e.eol;\r\n\t\t\tthis._lineStarts = null;\r\n\t\t}\r\n\r\n\t\t// Update my lines\r\n\t\tconst changes = e.changes;\r\n\t\tfor (const change of changes) {\r\n\t\t\tthis._acceptDeleteRange(change.range);\r\n\t\t\tthis._acceptInsertText(new Position(change.range.startLineNumber, change.range.startColumn), change.text);\r\n\t\t}\r\n\r\n\t\tthis._versionId = e.versionId;\r\n\t\tthis._cachedTextValue = null;\r\n\t}\r\n\r\n\tprotected _ensureLineStarts(): void {\r\n\t\tif (!this._lineStarts) {\r\n\t\t\tconst eolLength = this._eol.length;\r\n\t\t\tconst linesLength = this._lines.length;\r\n\t\t\tconst lineStartValues = new Uint32Array(linesLength);\r\n\t\t\tfor (let i = 0; i < linesLength; i++) {\r\n\t\t\t\tlineStartValues[i] = this._lines[i].length + eolLength;\r\n\t\t\t}\r\n\t\t\tthis._lineStarts = new PrefixSumComputer(lineStartValues);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * All changes to a line's text go through this method\r\n\t */\r\n\tprivate _setLineText(lineIndex: number, newValue: string): void {\r\n\t\tthis._lines[lineIndex] = newValue;\r\n\t\tif (this._lineStarts) {\r\n\t\t\t// update prefix sum\r\n\t\t\tthis._lineStarts.changeValue(lineIndex, this._lines[lineIndex].length + this._eol.length);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _acceptDeleteRange(range: IRange): void {\r\n\r\n\t\tif (range.startLineNumber === range.endLineNumber) {\r\n\t\t\tif (range.startColumn === range.endColumn) {\r\n\t\t\t\t// Nothing to delete\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t// Delete text on the affected line\r\n\t\t\tthis._setLineText(range.startLineNumber - 1,\r\n\t\t\t\tthis._lines[range.startLineNumber - 1].substring(0, range.startColumn - 1)\r\n\t\t\t\t+ this._lines[range.startLineNumber - 1].substring(range.endColumn - 1)\r\n\t\t\t);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// Take remaining text on last line and append it to remaining text on first line\r\n\t\tthis._setLineText(range.startLineNumber - 1,\r\n\t\t\tthis._lines[range.startLineNumber - 1].substring(0, range.startColumn - 1)\r\n\t\t\t+ this._lines[range.endLineNumber - 1].substring(range.endColumn - 1)\r\n\t\t);\r\n\r\n\t\t// Delete middle lines\r\n\t\tthis._lines.splice(range.startLineNumber, range.endLineNumber - range.startLineNumber);\r\n\t\tif (this._lineStarts) {\r\n\t\t\t// update prefix sum\r\n\t\t\tthis._lineStarts.removeValues(range.startLineNumber, range.endLineNumber - range.startLineNumber);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _acceptInsertText(position: Position, insertText: string): void {\r\n\t\tif (insertText.length === 0) {\r\n\t\t\t// Nothing to insert\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tlet insertLines = splitLines(insertText);\r\n\t\tif (insertLines.length === 1) {\r\n\t\t\t// Inserting text on one line\r\n\t\t\tthis._setLineText(position.lineNumber - 1,\r\n\t\t\t\tthis._lines[position.lineNumber - 1].substring(0, position.column - 1)\r\n\t\t\t\t+ insertLines[0]\r\n\t\t\t\t+ this._lines[position.lineNumber - 1].substring(position.column - 1)\r\n\t\t\t);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// Append overflowing text from first line to the end of text to insert\r\n\t\tinsertLines[insertLines.length - 1] += this._lines[position.lineNumber - 1].substring(position.column - 1);\r\n\r\n\t\t// Delete overflowing text from first line and insert text on first line\r\n\t\tthis._setLineText(position.lineNumber - 1,\r\n\t\t\tthis._lines[position.lineNumber - 1].substring(0, position.column - 1)\r\n\t\t\t+ insertLines[0]\r\n\t\t);\r\n\r\n\t\t// Insert new lines & store lengths\r\n\t\tlet newLengths = new Uint32Array(insertLines.length - 1);\r\n\t\tfor (let i = 1; i < insertLines.length; i++) {\r\n\t\t\tthis._lines.splice(position.lineNumber + i - 1, 0, insertLines[i]);\r\n\t\t\tnewLengths[i - 1] = insertLines[i].length + this._eol.length;\r\n\t\t}\r\n\r\n\t\tif (this._lineStarts) {\r\n\t\t\t// update prefix sum\r\n\t\t\tthis._lineStarts.insertValues(position.lineNumber, newLengths);\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { mergeSort } from 'vs/base/common/arrays';\r\nimport { stringDiff } from 'vs/base/common/diff/diff';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { globals } from 'vs/base/common/platform';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { IRequestHandler } from 'vs/base/common/worker/simpleWorker';\r\nimport { IPosition, Position } from 'vs/editor/common/core/position';\r\nimport { IRange, Range } from 'vs/editor/common/core/range';\r\nimport { DiffComputer } from 'vs/editor/common/diff/diffComputer';\r\nimport { EndOfLineSequence, IWordAtPosition } from 'vs/editor/common/model';\r\nimport { IModelChangedEvent, MirrorTextModel as BaseMirrorModel } from 'vs/editor/common/model/mirrorTextModel';\r\nimport { ensureValidWordDefinition, getWordAtText } from 'vs/editor/common/model/wordHelper';\r\nimport { IInplaceReplaceSupportResult, ILink, TextEdit } from 'vs/editor/common/modes';\r\nimport { ILinkComputerTarget, computeLinks } from 'vs/editor/common/modes/linkComputer';\r\nimport { BasicInplaceReplace } from 'vs/editor/common/modes/supports/inplaceReplaceSupport';\r\nimport { IDiffComputationResult } from 'vs/editor/common/services/editorWorkerService';\r\nimport { createMonacoBaseAPI } from 'vs/editor/common/standalone/standaloneBase';\r\nimport * as types from 'vs/base/common/types';\r\nimport { EditorWorkerHost } from 'vs/editor/common/services/editorWorkerServiceImpl';\r\nimport { StopWatch } from 'vs/base/common/stopwatch';\r\n\r\nexport interface IMirrorModel {\r\n\treadonly uri: URI;\r\n\treadonly version: number;\r\n\tgetValue(): string;\r\n}\r\n\r\nexport interface IWorkerContext {\r\n\t/**\r\n\t * A proxy to the main thread host object.\r\n\t */\r\n\thost: H;\r\n\t/**\r\n\t * Get all available mirror models in this worker.\r\n\t */\r\n\tgetMirrorModels(): IMirrorModel[];\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface IRawModelData {\r\n\turl: string;\r\n\tversionId: number;\r\n\tlines: string[];\r\n\tEOL: string;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface ICommonModel extends ILinkComputerTarget, IMirrorModel {\r\n\teol: string;\r\n\r\n\tgetLinesContent(): string[];\r\n\tgetLineCount(): number;\r\n\tgetLineContent(lineNumber: number): string;\r\n\tgetLineWords(lineNumber: number, wordDefinition: RegExp): IWordAtPosition[];\r\n\twords(wordDefinition: RegExp): Iterable;\r\n\tgetValueInRange(range: IRange): string;\r\n\tgetWordAtPosition(position: IPosition, wordDefinition: RegExp): Range | null;\r\n\toffsetAt(position: IPosition): number;\r\n\tpositionAt(offset: number): IPosition;\r\n}\r\n\r\n/**\r\n * Range of a word inside a model.\r\n * @internal\r\n */\r\ninterface IWordRange {\r\n\t/**\r\n\t * The index where the word starts.\r\n\t */\r\n\treadonly start: number;\r\n\t/**\r\n\t * The index where the word ends.\r\n\t */\r\n\treadonly end: number;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nclass MirrorModel extends BaseMirrorModel implements ICommonModel {\r\n\r\n\tpublic get uri(): URI {\r\n\t\treturn this._uri;\r\n\t}\r\n\r\n\tpublic get version(): number {\r\n\t\treturn this._versionId;\r\n\t}\r\n\r\n\tpublic get eol(): string {\r\n\t\treturn this._eol;\r\n\t}\r\n\r\n\tpublic getValue(): string {\r\n\t\treturn this.getText();\r\n\t}\r\n\r\n\tpublic getLinesContent(): string[] {\r\n\t\treturn this._lines.slice(0);\r\n\t}\r\n\r\n\tpublic getLineCount(): number {\r\n\t\treturn this._lines.length;\r\n\t}\r\n\r\n\tpublic getLineContent(lineNumber: number): string {\r\n\t\treturn this._lines[lineNumber - 1];\r\n\t}\r\n\r\n\tpublic getWordAtPosition(position: IPosition, wordDefinition: RegExp): Range | null {\r\n\r\n\t\tlet wordAtText = getWordAtText(\r\n\t\t\tposition.column,\r\n\t\t\tensureValidWordDefinition(wordDefinition),\r\n\t\t\tthis._lines[position.lineNumber - 1],\r\n\t\t\t0\r\n\t\t);\r\n\r\n\t\tif (wordAtText) {\r\n\t\t\treturn new Range(position.lineNumber, wordAtText.startColumn, position.lineNumber, wordAtText.endColumn);\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\r\n\tpublic words(wordDefinition: RegExp): Iterable {\r\n\r\n\t\tconst lines = this._lines;\r\n\t\tconst wordenize = this._wordenize.bind(this);\r\n\r\n\t\tlet lineNumber = 0;\r\n\t\tlet lineText = '';\r\n\t\tlet wordRangesIdx = 0;\r\n\t\tlet wordRanges: IWordRange[] = [];\r\n\r\n\t\treturn {\r\n\t\t\t*[Symbol.iterator]() {\r\n\t\t\t\twhile (true) {\r\n\t\t\t\t\tif (wordRangesIdx < wordRanges.length) {\r\n\t\t\t\t\t\tconst value = lineText.substring(wordRanges[wordRangesIdx].start, wordRanges[wordRangesIdx].end);\r\n\t\t\t\t\t\twordRangesIdx += 1;\r\n\t\t\t\t\t\tyield value;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tif (lineNumber < lines.length) {\r\n\t\t\t\t\t\t\tlineText = lines[lineNumber];\r\n\t\t\t\t\t\t\twordRanges = wordenize(lineText, wordDefinition);\r\n\t\t\t\t\t\t\twordRangesIdx = 0;\r\n\t\t\t\t\t\t\tlineNumber += 1;\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\tpublic getLineWords(lineNumber: number, wordDefinition: RegExp): IWordAtPosition[] {\r\n\t\tlet content = this._lines[lineNumber - 1];\r\n\t\tlet ranges = this._wordenize(content, wordDefinition);\r\n\t\tlet words: IWordAtPosition[] = [];\r\n\t\tfor (const range of ranges) {\r\n\t\t\twords.push({\r\n\t\t\t\tword: content.substring(range.start, range.end),\r\n\t\t\t\tstartColumn: range.start + 1,\r\n\t\t\t\tendColumn: range.end + 1\r\n\t\t\t});\r\n\t\t}\r\n\t\treturn words;\r\n\t}\r\n\r\n\tprivate _wordenize(content: string, wordDefinition: RegExp): IWordRange[] {\r\n\t\tconst result: IWordRange[] = [];\r\n\t\tlet match: RegExpExecArray | null;\r\n\r\n\t\twordDefinition.lastIndex = 0; // reset lastIndex just to be sure\r\n\r\n\t\twhile (match = wordDefinition.exec(content)) {\r\n\t\t\tif (match[0].length === 0) {\r\n\t\t\t\t// it did match the empty string\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tresult.push({ start: match.index, end: match.index + match[0].length });\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic getValueInRange(range: IRange): string {\r\n\t\trange = this._validateRange(range);\r\n\r\n\t\tif (range.startLineNumber === range.endLineNumber) {\r\n\t\t\treturn this._lines[range.startLineNumber - 1].substring(range.startColumn - 1, range.endColumn - 1);\r\n\t\t}\r\n\r\n\t\tlet lineEnding = this._eol;\r\n\t\tlet startLineIndex = range.startLineNumber - 1;\r\n\t\tlet endLineIndex = range.endLineNumber - 1;\r\n\t\tlet resultLines: string[] = [];\r\n\r\n\t\tresultLines.push(this._lines[startLineIndex].substring(range.startColumn - 1));\r\n\t\tfor (let i = startLineIndex + 1; i < endLineIndex; i++) {\r\n\t\t\tresultLines.push(this._lines[i]);\r\n\t\t}\r\n\t\tresultLines.push(this._lines[endLineIndex].substring(0, range.endColumn - 1));\r\n\r\n\t\treturn resultLines.join(lineEnding);\r\n\t}\r\n\r\n\tpublic offsetAt(position: IPosition): number {\r\n\t\tposition = this._validatePosition(position);\r\n\t\tthis._ensureLineStarts();\r\n\t\treturn this._lineStarts!.getAccumulatedValue(position.lineNumber - 2) + (position.column - 1);\r\n\t}\r\n\r\n\tpublic positionAt(offset: number): IPosition {\r\n\t\toffset = Math.floor(offset);\r\n\t\toffset = Math.max(0, offset);\r\n\r\n\t\tthis._ensureLineStarts();\r\n\t\tlet out = this._lineStarts!.getIndexOf(offset);\r\n\t\tlet lineLength = this._lines[out.index].length;\r\n\r\n\t\t// Ensure we return a valid position\r\n\t\treturn {\r\n\t\t\tlineNumber: 1 + out.index,\r\n\t\t\tcolumn: 1 + Math.min(out.remainder, lineLength)\r\n\t\t};\r\n\t}\r\n\r\n\tprivate _validateRange(range: IRange): IRange {\r\n\r\n\t\tconst start = this._validatePosition({ lineNumber: range.startLineNumber, column: range.startColumn });\r\n\t\tconst end = this._validatePosition({ lineNumber: range.endLineNumber, column: range.endColumn });\r\n\r\n\t\tif (start.lineNumber !== range.startLineNumber\r\n\t\t\t|| start.column !== range.startColumn\r\n\t\t\t|| end.lineNumber !== range.endLineNumber\r\n\t\t\t|| end.column !== range.endColumn) {\r\n\r\n\t\t\treturn {\r\n\t\t\t\tstartLineNumber: start.lineNumber,\r\n\t\t\t\tstartColumn: start.column,\r\n\t\t\t\tendLineNumber: end.lineNumber,\r\n\t\t\t\tendColumn: end.column\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\treturn range;\r\n\t}\r\n\r\n\tprivate _validatePosition(position: IPosition): IPosition {\r\n\t\tif (!Position.isIPosition(position)) {\r\n\t\t\tthrow new Error('bad position');\r\n\t\t}\r\n\t\tlet { lineNumber, column } = position;\r\n\t\tlet hasChanged = false;\r\n\r\n\t\tif (lineNumber < 1) {\r\n\t\t\tlineNumber = 1;\r\n\t\t\tcolumn = 1;\r\n\t\t\thasChanged = true;\r\n\r\n\t\t} else if (lineNumber > this._lines.length) {\r\n\t\t\tlineNumber = this._lines.length;\r\n\t\t\tcolumn = this._lines[lineNumber - 1].length + 1;\r\n\t\t\thasChanged = true;\r\n\r\n\t\t} else {\r\n\t\t\tlet maxCharacter = this._lines[lineNumber - 1].length + 1;\r\n\t\t\tif (column < 1) {\r\n\t\t\t\tcolumn = 1;\r\n\t\t\t\thasChanged = true;\r\n\t\t\t}\r\n\t\t\telse if (column > maxCharacter) {\r\n\t\t\t\tcolumn = maxCharacter;\r\n\t\t\t\thasChanged = true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!hasChanged) {\r\n\t\t\treturn position;\r\n\t\t} else {\r\n\t\t\treturn { lineNumber, column };\r\n\t\t}\r\n\t}\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface IForeignModuleFactory {\r\n\t(ctx: IWorkerContext, createData: any): any;\r\n}\r\n\r\ndeclare const require: any;\r\n\r\n/**\r\n * @internal\r\n */\r\nexport class EditorSimpleWorker implements IRequestHandler, IDisposable {\r\n\t_requestHandlerBrand: any;\r\n\r\n\tprivate readonly _host: EditorWorkerHost;\r\n\tprivate _models: { [uri: string]: MirrorModel; };\r\n\tprivate readonly _foreignModuleFactory: IForeignModuleFactory | null;\r\n\tprivate _foreignModule: any;\r\n\r\n\tconstructor(host: EditorWorkerHost, foreignModuleFactory: IForeignModuleFactory | null) {\r\n\t\tthis._host = host;\r\n\t\tthis._models = Object.create(null);\r\n\t\tthis._foreignModuleFactory = foreignModuleFactory;\r\n\t\tthis._foreignModule = null;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._models = Object.create(null);\r\n\t}\r\n\r\n\tprotected _getModel(uri: string): ICommonModel {\r\n\t\treturn this._models[uri];\r\n\t}\r\n\r\n\tprivate _getModels(): ICommonModel[] {\r\n\t\tlet all: MirrorModel[] = [];\r\n\t\tObject.keys(this._models).forEach((key) => all.push(this._models[key]));\r\n\t\treturn all;\r\n\t}\r\n\r\n\tpublic acceptNewModel(data: IRawModelData): void {\r\n\t\tthis._models[data.url] = new MirrorModel(URI.parse(data.url), data.lines, data.EOL, data.versionId);\r\n\t}\r\n\r\n\tpublic acceptModelChanged(strURL: string, e: IModelChangedEvent): void {\r\n\t\tif (!this._models[strURL]) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tlet model = this._models[strURL];\r\n\t\tmodel.onEvents(e);\r\n\t}\r\n\r\n\tpublic acceptRemovedModel(strURL: string): void {\r\n\t\tif (!this._models[strURL]) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tdelete this._models[strURL];\r\n\t}\r\n\r\n\t// ---- BEGIN diff --------------------------------------------------------------------------\r\n\r\n\tpublic async computeDiff(originalUrl: string, modifiedUrl: string, ignoreTrimWhitespace: boolean, maxComputationTime: number): Promise {\r\n\t\tconst original = this._getModel(originalUrl);\r\n\t\tconst modified = this._getModel(modifiedUrl);\r\n\t\tif (!original || !modified) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst originalLines = original.getLinesContent();\r\n\t\tconst modifiedLines = modified.getLinesContent();\r\n\t\tconst diffComputer = new DiffComputer(originalLines, modifiedLines, {\r\n\t\t\tshouldComputeCharChanges: true,\r\n\t\t\tshouldPostProcessCharChanges: true,\r\n\t\t\tshouldIgnoreTrimWhitespace: ignoreTrimWhitespace,\r\n\t\t\tshouldMakePrettyDiff: true,\r\n\t\t\tmaxComputationTime: maxComputationTime\r\n\t\t});\r\n\r\n\t\tconst diffResult = diffComputer.computeDiff();\r\n\t\tconst identical = (diffResult.changes.length > 0 ? false : this._modelsAreIdentical(original, modified));\r\n\t\treturn {\r\n\t\t\tquitEarly: diffResult.quitEarly,\r\n\t\t\tidentical: identical,\r\n\t\t\tchanges: diffResult.changes\r\n\t\t};\r\n\t}\r\n\r\n\tprivate _modelsAreIdentical(original: ICommonModel, modified: ICommonModel): boolean {\r\n\t\tconst originalLineCount = original.getLineCount();\r\n\t\tconst modifiedLineCount = modified.getLineCount();\r\n\t\tif (originalLineCount !== modifiedLineCount) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tfor (let line = 1; line <= originalLineCount; line++) {\r\n\t\t\tconst originalLine = original.getLineContent(line);\r\n\t\t\tconst modifiedLine = modified.getLineContent(line);\r\n\t\t\tif (originalLine !== modifiedLine) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// ---- END diff --------------------------------------------------------------------------\r\n\r\n\r\n\t// ---- BEGIN minimal edits ---------------------------------------------------------------\r\n\r\n\tprivate static readonly _diffLimit = 100000;\r\n\r\n\tpublic async computeMoreMinimalEdits(modelUrl: string, edits: TextEdit[]): Promise {\r\n\t\tconst model = this._getModel(modelUrl);\r\n\t\tif (!model) {\r\n\t\t\treturn edits;\r\n\t\t}\r\n\r\n\t\tconst result: TextEdit[] = [];\r\n\t\tlet lastEol: EndOfLineSequence | undefined = undefined;\r\n\r\n\t\tedits = mergeSort(edits, (a, b) => {\r\n\t\t\tif (a.range && b.range) {\r\n\t\t\t\treturn Range.compareRangesUsingStarts(a.range, b.range);\r\n\t\t\t}\r\n\t\t\t// eol only changes should go to the end\r\n\t\t\tlet aRng = a.range ? 0 : 1;\r\n\t\t\tlet bRng = b.range ? 0 : 1;\r\n\t\t\treturn aRng - bRng;\r\n\t\t});\r\n\r\n\t\tfor (let { range, text, eol } of edits) {\r\n\r\n\t\t\tif (typeof eol === 'number') {\r\n\t\t\t\tlastEol = eol;\r\n\t\t\t}\r\n\r\n\t\t\tif (Range.isEmpty(range) && !text) {\r\n\t\t\t\t// empty change\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tconst original = model.getValueInRange(range);\r\n\t\t\ttext = text.replace(/\\r\\n|\\n|\\r/g, model.eol);\r\n\r\n\t\t\tif (original === text) {\r\n\t\t\t\t// noop\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\t// make sure diff won't take too long\r\n\t\t\tif (Math.max(text.length, original.length) > EditorSimpleWorker._diffLimit) {\r\n\t\t\t\tresult.push({ range, text });\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\t// compute diff between original and edit.text\r\n\t\t\tconst changes = stringDiff(original, text, false);\r\n\t\t\tconst editOffset = model.offsetAt(Range.lift(range).getStartPosition());\r\n\r\n\t\t\tfor (const change of changes) {\r\n\t\t\t\tconst start = model.positionAt(editOffset + change.originalStart);\r\n\t\t\t\tconst end = model.positionAt(editOffset + change.originalStart + change.originalLength);\r\n\t\t\t\tconst newEdit: TextEdit = {\r\n\t\t\t\t\ttext: text.substr(change.modifiedStart, change.modifiedLength),\r\n\t\t\t\t\trange: { startLineNumber: start.lineNumber, startColumn: start.column, endLineNumber: end.lineNumber, endColumn: end.column }\r\n\t\t\t\t};\r\n\r\n\t\t\t\tif (model.getValueInRange(newEdit.range) !== newEdit.text) {\r\n\t\t\t\t\tresult.push(newEdit);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (typeof lastEol === 'number') {\r\n\t\t\tresult.push({ eol: lastEol, text: '', range: { startLineNumber: 0, startColumn: 0, endLineNumber: 0, endColumn: 0 } });\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\t// ---- END minimal edits ---------------------------------------------------------------\r\n\r\n\tpublic async computeLinks(modelUrl: string): Promise {\r\n\t\tlet model = this._getModel(modelUrl);\r\n\t\tif (!model) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\treturn computeLinks(model);\r\n\t}\r\n\r\n\t// ---- BEGIN suggest --------------------------------------------------------------------------\r\n\r\n\tprivate static readonly _suggestionsLimit = 10000;\r\n\r\n\tpublic async textualSuggest(modelUrls: string[], leadingWord: string | undefined, wordDef: string, wordDefFlags: string): Promise<{ words: string[], duration: number } | null> {\r\n\r\n\t\tconst sw = new StopWatch(true);\r\n\t\tconst wordDefRegExp = new RegExp(wordDef, wordDefFlags);\r\n\t\tconst seen = new Set();\r\n\r\n\t\touter: for (let url of modelUrls) {\r\n\t\t\tconst model = this._getModel(url);\r\n\t\t\tif (!model) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tfor (let word of model.words(wordDefRegExp)) {\r\n\t\t\t\tif (word === leadingWord || !isNaN(Number(word))) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\tseen.add(word);\r\n\t\t\t\tif (seen.size > EditorSimpleWorker._suggestionsLimit) {\r\n\t\t\t\t\tbreak outer;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn { words: Array.from(seen), duration: sw.elapsed() };\r\n\t}\r\n\r\n\r\n\t// ---- END suggest --------------------------------------------------------------------------\r\n\r\n\t//#region -- word ranges --\r\n\r\n\tpublic async computeWordRanges(modelUrl: string, range: IRange, wordDef: string, wordDefFlags: string): Promise<{ [word: string]: IRange[] }> {\r\n\t\tlet model = this._getModel(modelUrl);\r\n\t\tif (!model) {\r\n\t\t\treturn Object.create(null);\r\n\t\t}\r\n\t\tconst wordDefRegExp = new RegExp(wordDef, wordDefFlags);\r\n\t\tconst result: { [word: string]: IRange[] } = Object.create(null);\r\n\t\tfor (let line = range.startLineNumber; line < range.endLineNumber; line++) {\r\n\t\t\tlet words = model.getLineWords(line, wordDefRegExp);\r\n\t\t\tfor (const word of words) {\r\n\t\t\t\tif (!isNaN(Number(word.word))) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\tlet array = result[word.word];\r\n\t\t\t\tif (!array) {\r\n\t\t\t\t\tarray = [];\r\n\t\t\t\t\tresult[word.word] = array;\r\n\t\t\t\t}\r\n\t\t\t\tarray.push({\r\n\t\t\t\t\tstartLineNumber: line,\r\n\t\t\t\t\tstartColumn: word.startColumn,\r\n\t\t\t\t\tendLineNumber: line,\r\n\t\t\t\t\tendColumn: word.endColumn\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\t//#endregion\r\n\r\n\tpublic async navigateValueSet(modelUrl: string, range: IRange, up: boolean, wordDef: string, wordDefFlags: string): Promise {\r\n\t\tlet model = this._getModel(modelUrl);\r\n\t\tif (!model) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet wordDefRegExp = new RegExp(wordDef, wordDefFlags);\r\n\r\n\t\tif (range.startColumn === range.endColumn) {\r\n\t\t\trange = {\r\n\t\t\t\tstartLineNumber: range.startLineNumber,\r\n\t\t\t\tstartColumn: range.startColumn,\r\n\t\t\t\tendLineNumber: range.endLineNumber,\r\n\t\t\t\tendColumn: range.endColumn + 1\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tlet selectionText = model.getValueInRange(range);\r\n\r\n\t\tlet wordRange = model.getWordAtPosition({ lineNumber: range.startLineNumber, column: range.startColumn }, wordDefRegExp);\r\n\t\tif (!wordRange) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tlet word = model.getValueInRange(wordRange);\r\n\t\tlet result = BasicInplaceReplace.INSTANCE.navigateValueSet(range, selectionText, wordRange, word, up);\r\n\t\treturn result;\r\n\t}\r\n\r\n\t// ---- BEGIN foreign module support --------------------------------------------------------------------------\r\n\r\n\tpublic loadForeignModule(moduleId: string, createData: any, foreignHostMethods: string[]): Promise {\r\n\t\tconst proxyMethodRequest = (method: string, args: any[]): Promise => {\r\n\t\t\treturn this._host.fhr(method, args);\r\n\t\t};\r\n\r\n\t\tconst foreignHost = types.createProxyObject(foreignHostMethods, proxyMethodRequest);\r\n\r\n\t\tlet ctx: IWorkerContext = {\r\n\t\t\thost: foreignHost,\r\n\t\t\tgetMirrorModels: (): IMirrorModel[] => {\r\n\t\t\t\treturn this._getModels();\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tif (this._foreignModuleFactory) {\r\n\t\t\tthis._foreignModule = this._foreignModuleFactory(ctx, createData);\r\n\t\t\t// static foreing module\r\n\t\t\treturn Promise.resolve(types.getAllMethodNames(this._foreignModule));\r\n\t\t}\r\n\t\t// ESM-comment-begin\r\n\t\treturn new Promise((resolve, reject) => {\r\n\t\t\trequire([moduleId], (foreignModule: { create: IForeignModuleFactory }) => {\r\n\t\t\t\tthis._foreignModule = foreignModule.create(ctx, createData);\r\n\r\n\t\t\t\tresolve(types.getAllMethodNames(this._foreignModule));\r\n\r\n\t\t\t}, reject);\r\n\t\t});\r\n\t\t// ESM-comment-end\r\n\r\n\t\t// ESM-uncomment-begin\r\n\t\t// return Promise.reject(new Error(`Unexpected usage`));\r\n\t\t// ESM-uncomment-end\r\n\t}\r\n\r\n\t// foreign method request\r\n\tpublic fmr(method: string, args: any[]): Promise {\r\n\t\tif (!this._foreignModule || typeof this._foreignModule[method] !== 'function') {\r\n\t\t\treturn Promise.reject(new Error('Missing requestHandler or method: ' + method));\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\treturn Promise.resolve(this._foreignModule[method].apply(this._foreignModule, args));\r\n\t\t} catch (e) {\r\n\t\t\treturn Promise.reject(e);\r\n\t\t}\r\n\t}\r\n\r\n\t// ---- END foreign module support --------------------------------------------------------------------------\r\n}\r\n\r\n/**\r\n * Called on the worker side\r\n * @internal\r\n */\r\nexport function create(host: EditorWorkerHost): IRequestHandler {\r\n\treturn new EditorSimpleWorker(host, null);\r\n}\r\n\r\n// This is only available in a Web Worker\r\ndeclare function importScripts(...urls: string[]): void;\r\n\r\nif (typeof importScripts === 'function') {\r\n\t// Running in a web worker\r\n\tglobals.monaco = createMonacoBaseAPI();\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\n\r\nexport class ViewEventHandler extends Disposable {\r\n\r\n\tprivate _shouldRender: boolean;\r\n\r\n\tconstructor() {\r\n\t\tsuper();\r\n\t\tthis._shouldRender = true;\r\n\t}\r\n\r\n\tpublic shouldRender(): boolean {\r\n\t\treturn this._shouldRender;\r\n\t}\r\n\r\n\tpublic forceShouldRender(): void {\r\n\t\tthis._shouldRender = true;\r\n\t}\r\n\r\n\tprotected setShouldRender(): void {\r\n\t\tthis._shouldRender = true;\r\n\t}\r\n\r\n\tpublic onDidRender(): void {\r\n\t\tthis._shouldRender = false;\r\n\t}\r\n\r\n\t// --- begin event handlers\r\n\r\n\tpublic onCompositionStart(e: viewEvents.ViewCompositionStartEvent): boolean {\r\n\t\treturn false;\r\n\t}\r\n\tpublic onCompositionEnd(e: viewEvents.ViewCompositionEndEvent): boolean {\r\n\t\treturn false;\r\n\t}\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\treturn false;\r\n\t}\r\n\tpublic onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {\r\n\t\treturn false;\r\n\t}\r\n\tpublic onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {\r\n\t\treturn false;\r\n\t}\r\n\tpublic onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\r\n\t\treturn false;\r\n\t}\r\n\tpublic onFocusChanged(e: viewEvents.ViewFocusChangedEvent): boolean {\r\n\t\treturn false;\r\n\t}\r\n\tpublic onLanguageConfigurationChanged(e: viewEvents.ViewLanguageConfigurationEvent): boolean {\r\n\t\treturn false;\r\n\t}\r\n\tpublic onLineMappingChanged(e: viewEvents.ViewLineMappingChangedEvent): boolean {\r\n\t\treturn false;\r\n\t}\r\n\tpublic onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\r\n\t\treturn false;\r\n\t}\r\n\tpublic onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\r\n\t\treturn false;\r\n\t}\r\n\tpublic onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\r\n\t\treturn false;\r\n\t}\r\n\tpublic onRevealRangeRequest(e: viewEvents.ViewRevealRangeRequestEvent): boolean {\r\n\t\treturn false;\r\n\t}\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\treturn false;\r\n\t}\r\n\tpublic onThemeChanged(e: viewEvents.ViewThemeChangedEvent): boolean {\r\n\t\treturn false;\r\n\t}\r\n\tpublic onTokensChanged(e: viewEvents.ViewTokensChangedEvent): boolean {\r\n\t\treturn false;\r\n\t}\r\n\tpublic onTokensColorsChanged(e: viewEvents.ViewTokensColorsChangedEvent): boolean {\r\n\t\treturn false;\r\n\t}\r\n\tpublic onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\r\n\t\treturn false;\r\n\t}\r\n\r\n\t// --- end event handlers\r\n\r\n\tpublic handleEvents(events: viewEvents.ViewEvent[]): void {\r\n\r\n\t\tlet shouldRender = false;\r\n\r\n\t\tfor (let i = 0, len = events.length; i < len; i++) {\r\n\t\t\tlet e = events[i];\r\n\r\n\t\t\tswitch (e.type) {\r\n\r\n\t\t\t\tcase viewEvents.ViewEventType.ViewCompositionStart:\r\n\t\t\t\t\tif (this.onCompositionStart(e)) {\r\n\t\t\t\t\t\tshouldRender = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase viewEvents.ViewEventType.ViewCompositionEnd:\r\n\t\t\t\t\tif (this.onCompositionEnd(e)) {\r\n\t\t\t\t\t\tshouldRender = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase viewEvents.ViewEventType.ViewConfigurationChanged:\r\n\t\t\t\t\tif (this.onConfigurationChanged(e)) {\r\n\t\t\t\t\t\tshouldRender = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase viewEvents.ViewEventType.ViewCursorStateChanged:\r\n\t\t\t\t\tif (this.onCursorStateChanged(e)) {\r\n\t\t\t\t\t\tshouldRender = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase viewEvents.ViewEventType.ViewDecorationsChanged:\r\n\t\t\t\t\tif (this.onDecorationsChanged(e)) {\r\n\t\t\t\t\t\tshouldRender = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase viewEvents.ViewEventType.ViewFlushed:\r\n\t\t\t\t\tif (this.onFlushed(e)) {\r\n\t\t\t\t\t\tshouldRender = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase viewEvents.ViewEventType.ViewFocusChanged:\r\n\t\t\t\t\tif (this.onFocusChanged(e)) {\r\n\t\t\t\t\t\tshouldRender = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase viewEvents.ViewEventType.ViewLanguageConfigurationChanged:\r\n\t\t\t\t\tif (this.onLanguageConfigurationChanged(e)) {\r\n\t\t\t\t\t\tshouldRender = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase viewEvents.ViewEventType.ViewLineMappingChanged:\r\n\t\t\t\t\tif (this.onLineMappingChanged(e)) {\r\n\t\t\t\t\t\tshouldRender = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase viewEvents.ViewEventType.ViewLinesChanged:\r\n\t\t\t\t\tif (this.onLinesChanged(e)) {\r\n\t\t\t\t\t\tshouldRender = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase viewEvents.ViewEventType.ViewLinesDeleted:\r\n\t\t\t\t\tif (this.onLinesDeleted(e)) {\r\n\t\t\t\t\t\tshouldRender = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase viewEvents.ViewEventType.ViewLinesInserted:\r\n\t\t\t\t\tif (this.onLinesInserted(e)) {\r\n\t\t\t\t\t\tshouldRender = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase viewEvents.ViewEventType.ViewRevealRangeRequest:\r\n\t\t\t\t\tif (this.onRevealRangeRequest(e)) {\r\n\t\t\t\t\t\tshouldRender = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase viewEvents.ViewEventType.ViewScrollChanged:\r\n\t\t\t\t\tif (this.onScrollChanged(e)) {\r\n\t\t\t\t\t\tshouldRender = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase viewEvents.ViewEventType.ViewTokensChanged:\r\n\t\t\t\t\tif (this.onTokensChanged(e)) {\r\n\t\t\t\t\t\tshouldRender = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase viewEvents.ViewEventType.ViewThemeChanged:\r\n\t\t\t\t\tif (this.onThemeChanged(e)) {\r\n\t\t\t\t\t\tshouldRender = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase viewEvents.ViewEventType.ViewTokensColorsChanged:\r\n\t\t\t\t\tif (this.onTokensColorsChanged(e)) {\r\n\t\t\t\t\t\tshouldRender = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase viewEvents.ViewEventType.ViewZonesChanged:\r\n\t\t\t\t\tif (this.onZonesChanged(e)) {\r\n\t\t\t\t\t\tshouldRender = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tdefault:\r\n\t\t\t\t\tconsole.info('View received unknown event: ');\r\n\t\t\t\t\tconsole.info(e);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (shouldRender) {\r\n\t\t\tthis._shouldRender = true;\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { RenderingContext } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler';\r\n\r\nexport abstract class DynamicViewOverlay extends ViewEventHandler {\r\n\r\n\tpublic abstract prepareRender(ctx: RenderingContext): void;\r\n\r\n\tpublic abstract render(startLineNumber: number, lineNumber: number): string;\r\n\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { FastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler';\r\n\r\nexport abstract class ViewPart extends ViewEventHandler {\r\n\r\n\t_context: ViewContext;\r\n\r\n\tconstructor(context: ViewContext) {\r\n\t\tsuper();\r\n\t\tthis._context = context;\r\n\t\tthis._context.addEventHandler(this);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._context.removeEventHandler(this);\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tpublic abstract prepareRender(ctx: RenderingContext): void;\r\n\tpublic abstract render(ctx: RestrictedRenderingContext): void;\r\n}\r\n\r\nexport const enum PartFingerprint {\r\n\tNone,\r\n\tContentWidgets,\r\n\tOverflowingContentWidgets,\r\n\tOverflowGuard,\r\n\tOverlayWidgets,\r\n\tScrollableElement,\r\n\tTextArea,\r\n\tViewLines,\r\n\tMinimap\r\n}\r\n\r\nexport class PartFingerprints {\r\n\r\n\tpublic static write(target: Element | FastDomNode, partId: PartFingerprint) {\r\n\t\tif (target instanceof FastDomNode) {\r\n\t\t\ttarget.setAttribute('data-mprt', String(partId));\r\n\t\t} else {\r\n\t\t\ttarget.setAttribute('data-mprt', String(partId));\r\n\t\t}\r\n\t}\r\n\r\n\tpublic static read(target: Element): PartFingerprint {\r\n\t\tconst r = target.getAttribute('data-mprt');\r\n\t\tif (r === null) {\r\n\t\t\treturn PartFingerprint.None;\r\n\t\t}\r\n\t\treturn parseInt(r, 10);\r\n\t}\r\n\r\n\tpublic static collect(child: Element | null, stopAt: Element): Uint8Array {\r\n\t\tlet result: PartFingerprint[] = [], resultLen = 0;\r\n\r\n\t\twhile (child && child !== document.body) {\r\n\t\t\tif (child === stopAt) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tif (child.nodeType === child.ELEMENT_NODE) {\r\n\t\t\t\tresult[resultLen++] = this.read(child);\r\n\t\t\t}\r\n\t\t\tchild = child.parentElement;\r\n\t\t}\r\n\r\n\t\tconst r = new Uint8Array(resultLen);\r\n\t\tfor (let i = 0; i < resultLen; i++) {\r\n\t\t\tr[i] = result[resultLen - i - 1];\r\n\t\t}\r\n\t\treturn r;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { ContentWidgetPositionPreference, IContentWidget } from 'vs/editor/browser/editorBrowser';\r\nimport { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/view/viewPart';\r\nimport { IRange, Range } from 'vs/editor/common/core/range';\r\nimport { Constants } from 'vs/base/common/uint';\r\nimport { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { IDimension } from 'vs/editor/common/editorCommon';\r\n\r\n\r\nclass Coordinate {\r\n\t_coordinateBrand: void;\r\n\r\n\tpublic readonly top: number;\r\n\tpublic readonly left: number;\r\n\r\n\tconstructor(top: number, left: number) {\r\n\t\tthis.top = top;\r\n\t\tthis.left = left;\r\n\t}\r\n}\r\n\r\nexport class ViewContentWidgets extends ViewPart {\r\n\r\n\tprivate readonly _viewDomNode: FastDomNode;\r\n\tprivate _widgets: { [key: string]: Widget; };\r\n\r\n\tpublic domNode: FastDomNode;\r\n\tpublic overflowingContentWidgetsDomNode: FastDomNode;\r\n\r\n\tconstructor(context: ViewContext, viewDomNode: FastDomNode) {\r\n\t\tsuper(context);\r\n\t\tthis._viewDomNode = viewDomNode;\r\n\t\tthis._widgets = {};\r\n\r\n\t\tthis.domNode = createFastDomNode(document.createElement('div'));\r\n\t\tPartFingerprints.write(this.domNode, PartFingerprint.ContentWidgets);\r\n\t\tthis.domNode.setClassName('contentWidgets');\r\n\t\tthis.domNode.setPosition('absolute');\r\n\t\tthis.domNode.setTop(0);\r\n\r\n\t\tthis.overflowingContentWidgetsDomNode = createFastDomNode(document.createElement('div'));\r\n\t\tPartFingerprints.write(this.overflowingContentWidgetsDomNode, PartFingerprint.OverflowingContentWidgets);\r\n\t\tthis.overflowingContentWidgetsDomNode.setClassName('overflowingContentWidgets');\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tsuper.dispose();\r\n\t\tthis._widgets = {};\r\n\t}\r\n\r\n\t// --- begin event handlers\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tconst keys = Object.keys(this._widgets);\r\n\t\tfor (const widgetId of keys) {\r\n\t\t\tthis._widgets[widgetId].onConfigurationChanged(e);\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\tpublic onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {\r\n\t\t// true for inline decorations that can end up relayouting text\r\n\t\treturn true;\r\n\t}\r\n\tpublic onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLineMappingChanged(e: viewEvents.ViewLineMappingChangedEvent): boolean {\r\n\t\tconst keys = Object.keys(this._widgets);\r\n\t\tfor (const widgetId of keys) {\r\n\t\t\tthis._widgets[widgetId].onLineMappingChanged(e);\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// ---- end view event handlers\r\n\r\n\tpublic addWidget(_widget: IContentWidget): void {\r\n\t\tconst myWidget = new Widget(this._context, this._viewDomNode, _widget);\r\n\t\tthis._widgets[myWidget.id] = myWidget;\r\n\r\n\t\tif (myWidget.allowEditorOverflow) {\r\n\t\t\tthis.overflowingContentWidgetsDomNode.appendChild(myWidget.domNode);\r\n\t\t} else {\r\n\t\t\tthis.domNode.appendChild(myWidget.domNode);\r\n\t\t}\r\n\r\n\t\tthis.setShouldRender();\r\n\t}\r\n\r\n\tpublic setWidgetPosition(widget: IContentWidget, range: IRange | null, preference: ContentWidgetPositionPreference[] | null): void {\r\n\t\tconst myWidget = this._widgets[widget.getId()];\r\n\t\tmyWidget.setPosition(range, preference);\r\n\r\n\t\tthis.setShouldRender();\r\n\t}\r\n\r\n\tpublic removeWidget(widget: IContentWidget): void {\r\n\t\tconst widgetId = widget.getId();\r\n\t\tif (this._widgets.hasOwnProperty(widgetId)) {\r\n\t\t\tconst myWidget = this._widgets[widgetId];\r\n\t\t\tdelete this._widgets[widgetId];\r\n\r\n\t\t\tconst domNode = myWidget.domNode.domNode;\r\n\t\t\tdomNode.parentNode!.removeChild(domNode);\r\n\t\t\tdomNode.removeAttribute('monaco-visible-content-widget');\r\n\r\n\t\t\tthis.setShouldRender();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic shouldSuppressMouseDownOnWidget(widgetId: string): boolean {\r\n\t\tif (this._widgets.hasOwnProperty(widgetId)) {\r\n\t\t\treturn this._widgets[widgetId].suppressMouseDown;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic onBeforeRender(viewportData: ViewportData): void {\r\n\t\tconst keys = Object.keys(this._widgets);\r\n\t\tfor (const widgetId of keys) {\r\n\t\t\tthis._widgets[widgetId].onBeforeRender(viewportData);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic prepareRender(ctx: RenderingContext): void {\r\n\t\tconst keys = Object.keys(this._widgets);\r\n\t\tfor (const widgetId of keys) {\r\n\t\t\tthis._widgets[widgetId].prepareRender(ctx);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic render(ctx: RestrictedRenderingContext): void {\r\n\t\tconst keys = Object.keys(this._widgets);\r\n\t\tfor (const widgetId of keys) {\r\n\t\t\tthis._widgets[widgetId].render(ctx);\r\n\t\t}\r\n\t}\r\n}\r\n\r\ninterface IBoxLayoutResult {\r\n\tfitsAbove: boolean;\r\n\taboveTop: number;\r\n\taboveLeft: number;\r\n\r\n\tfitsBelow: boolean;\r\n\tbelowTop: number;\r\n\tbelowLeft: number;\r\n}\r\n\r\ninterface IRenderData {\r\n\tcoordinate: Coordinate,\r\n\tposition: ContentWidgetPositionPreference\r\n}\r\n\r\nclass Widget {\r\n\tprivate readonly _context: ViewContext;\r\n\tprivate readonly _viewDomNode: FastDomNode;\r\n\tprivate readonly _actual: IContentWidget;\r\n\r\n\tpublic readonly domNode: FastDomNode;\r\n\tpublic readonly id: string;\r\n\tpublic readonly allowEditorOverflow: boolean;\r\n\tpublic readonly suppressMouseDown: boolean;\r\n\r\n\tprivate readonly _fixedOverflowWidgets: boolean;\r\n\tprivate _contentWidth: number;\r\n\tprivate _contentLeft: number;\r\n\tprivate _lineHeight: number;\r\n\r\n\tprivate _range: IRange | null;\r\n\tprivate _viewRange: Range | null;\r\n\tprivate _preference: ContentWidgetPositionPreference[] | null;\r\n\tprivate _cachedDomNodeClientWidth: number;\r\n\tprivate _cachedDomNodeClientHeight: number;\r\n\tprivate _maxWidth: number;\r\n\tprivate _isVisible: boolean;\r\n\r\n\tprivate _renderData: IRenderData | null;\r\n\r\n\tconstructor(context: ViewContext, viewDomNode: FastDomNode, actual: IContentWidget) {\r\n\t\tthis._context = context;\r\n\t\tthis._viewDomNode = viewDomNode;\r\n\t\tthis._actual = actual;\r\n\r\n\t\tthis.domNode = createFastDomNode(this._actual.getDomNode());\r\n\t\tthis.id = this._actual.getId();\r\n\t\tthis.allowEditorOverflow = this._actual.allowEditorOverflow || false;\r\n\t\tthis.suppressMouseDown = this._actual.suppressMouseDown || false;\r\n\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\r\n\t\tthis._fixedOverflowWidgets = options.get(EditorOption.fixedOverflowWidgets);\r\n\t\tthis._contentWidth = layoutInfo.contentWidth;\r\n\t\tthis._contentLeft = layoutInfo.contentLeft;\r\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\r\n\r\n\t\tthis._range = null;\r\n\t\tthis._viewRange = null;\r\n\t\tthis._preference = [];\r\n\t\tthis._cachedDomNodeClientWidth = -1;\r\n\t\tthis._cachedDomNodeClientHeight = -1;\r\n\t\tthis._maxWidth = this._getMaxWidth();\r\n\t\tthis._isVisible = false;\r\n\t\tthis._renderData = null;\r\n\r\n\t\tthis.domNode.setPosition((this._fixedOverflowWidgets && this.allowEditorOverflow) ? 'fixed' : 'absolute');\r\n\t\tthis.domNode.setVisibility('hidden');\r\n\t\tthis.domNode.setAttribute('widgetId', this.id);\r\n\t\tthis.domNode.setMaxWidth(this._maxWidth);\r\n\t}\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): void {\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tif (e.hasChanged(EditorOption.layoutInfo)) {\r\n\t\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\t\t\tthis._contentLeft = layoutInfo.contentLeft;\r\n\t\t\tthis._contentWidth = layoutInfo.contentWidth;\r\n\t\t\tthis._maxWidth = this._getMaxWidth();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic onLineMappingChanged(e: viewEvents.ViewLineMappingChangedEvent): void {\r\n\t\tthis._setPosition(this._range);\r\n\t}\r\n\r\n\tprivate _setPosition(range: IRange | null): void {\r\n\t\tthis._range = range;\r\n\t\tthis._viewRange = null;\r\n\r\n\t\tif (this._range) {\r\n\t\t\t// Do not trust that widgets give a valid position\r\n\t\t\tconst validModelRange = this._context.model.validateModelRange(this._range);\r\n\t\t\tif (this._context.model.coordinatesConverter.modelPositionIsVisible(validModelRange.getStartPosition()) || this._context.model.coordinatesConverter.modelPositionIsVisible(validModelRange.getEndPosition())) {\r\n\t\t\t\tthis._viewRange = this._context.model.coordinatesConverter.convertModelRangeToViewRange(validModelRange);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _getMaxWidth(): number {\r\n\t\treturn (\r\n\t\t\tthis.allowEditorOverflow\r\n\t\t\t\t? window.innerWidth || document.documentElement!.clientWidth || document.body.clientWidth\r\n\t\t\t\t: this._contentWidth\r\n\t\t);\r\n\t}\r\n\r\n\tpublic setPosition(range: IRange | null, preference: ContentWidgetPositionPreference[] | null): void {\r\n\t\tthis._setPosition(range);\r\n\t\tthis._preference = preference;\r\n\t\tthis._cachedDomNodeClientWidth = -1;\r\n\t\tthis._cachedDomNodeClientHeight = -1;\r\n\t}\r\n\r\n\tprivate _layoutBoxInViewport(topLeft: Coordinate, bottomLeft: Coordinate, width: number, height: number, ctx: RenderingContext): IBoxLayoutResult {\r\n\t\t// Our visible box is split horizontally by the current line => 2 boxes\r\n\r\n\t\t// a) the box above the line\r\n\t\tconst aboveLineTop = topLeft.top;\r\n\t\tconst heightAboveLine = aboveLineTop;\r\n\r\n\t\t// b) the box under the line\r\n\t\tconst underLineTop = bottomLeft.top + this._lineHeight;\r\n\t\tconst heightUnderLine = ctx.viewportHeight - underLineTop;\r\n\r\n\t\tconst aboveTop = aboveLineTop - height;\r\n\t\tconst fitsAbove = (heightAboveLine >= height);\r\n\t\tconst belowTop = underLineTop;\r\n\t\tconst fitsBelow = (heightUnderLine >= height);\r\n\r\n\t\t// And its left\r\n\t\tlet actualAboveLeft = topLeft.left;\r\n\t\tlet actualBelowLeft = bottomLeft.left;\r\n\t\tif (actualAboveLeft + width > ctx.scrollLeft + ctx.viewportWidth) {\r\n\t\t\tactualAboveLeft = ctx.scrollLeft + ctx.viewportWidth - width;\r\n\t\t}\r\n\t\tif (actualBelowLeft + width > ctx.scrollLeft + ctx.viewportWidth) {\r\n\t\t\tactualBelowLeft = ctx.scrollLeft + ctx.viewportWidth - width;\r\n\t\t}\r\n\t\tif (actualAboveLeft < ctx.scrollLeft) {\r\n\t\t\tactualAboveLeft = ctx.scrollLeft;\r\n\t\t}\r\n\t\tif (actualBelowLeft < ctx.scrollLeft) {\r\n\t\t\tactualBelowLeft = ctx.scrollLeft;\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tfitsAbove: fitsAbove,\r\n\t\t\taboveTop: aboveTop,\r\n\t\t\taboveLeft: actualAboveLeft,\r\n\r\n\t\t\tfitsBelow: fitsBelow,\r\n\t\t\tbelowTop: belowTop,\r\n\t\t\tbelowLeft: actualBelowLeft,\r\n\t\t};\r\n\t}\r\n\r\n\tprivate _layoutHorizontalSegmentInPage(windowSize: dom.Dimension, domNodePosition: dom.IDomNodePagePosition, left: number, width: number): [number, number] {\r\n\t\t// Initially, the limits are defined as the dom node limits\r\n\t\tconst MIN_LIMIT = Math.max(0, domNodePosition.left - width);\r\n\t\tconst MAX_LIMIT = Math.min(domNodePosition.left + domNodePosition.width + width, windowSize.width);\r\n\r\n\t\tlet absoluteLeft = domNodePosition.left + left - dom.StandardWindow.scrollX;\r\n\r\n\t\tif (absoluteLeft + width > MAX_LIMIT) {\r\n\t\t\tconst delta = absoluteLeft - (MAX_LIMIT - width);\r\n\t\t\tabsoluteLeft -= delta;\r\n\t\t\tleft -= delta;\r\n\t\t}\r\n\r\n\t\tif (absoluteLeft < MIN_LIMIT) {\r\n\t\t\tconst delta = absoluteLeft - MIN_LIMIT;\r\n\t\t\tabsoluteLeft -= delta;\r\n\t\t\tleft -= delta;\r\n\t\t}\r\n\r\n\t\treturn [left, absoluteLeft];\r\n\t}\r\n\r\n\tprivate _layoutBoxInPage(topLeft: Coordinate, bottomLeft: Coordinate, width: number, height: number, ctx: RenderingContext): IBoxLayoutResult | null {\r\n\t\tconst aboveTop = topLeft.top - height;\r\n\t\tconst belowTop = bottomLeft.top + this._lineHeight;\r\n\r\n\t\tconst domNodePosition = dom.getDomNodePagePosition(this._viewDomNode.domNode);\r\n\t\tconst absoluteAboveTop = domNodePosition.top + aboveTop - dom.StandardWindow.scrollY;\r\n\t\tconst absoluteBelowTop = domNodePosition.top + belowTop - dom.StandardWindow.scrollY;\r\n\r\n\t\tconst windowSize = dom.getClientArea(document.body);\r\n\t\tconst [aboveLeft, absoluteAboveLeft] = this._layoutHorizontalSegmentInPage(windowSize, domNodePosition, topLeft.left - ctx.scrollLeft + this._contentLeft, width);\r\n\t\tconst [belowLeft, absoluteBelowLeft] = this._layoutHorizontalSegmentInPage(windowSize, domNodePosition, bottomLeft.left - ctx.scrollLeft + this._contentLeft, width);\r\n\r\n\t\t// Leave some clearance to the top/bottom\r\n\t\tconst TOP_PADDING = 22;\r\n\t\tconst BOTTOM_PADDING = 22;\r\n\r\n\t\tconst fitsAbove = (absoluteAboveTop >= TOP_PADDING);\r\n\t\tconst fitsBelow = (absoluteBelowTop + height <= windowSize.height - BOTTOM_PADDING);\r\n\r\n\t\tif (this._fixedOverflowWidgets) {\r\n\t\t\treturn {\r\n\t\t\t\tfitsAbove,\r\n\t\t\t\taboveTop: Math.max(absoluteAboveTop, TOP_PADDING),\r\n\t\t\t\taboveLeft: absoluteAboveLeft,\r\n\t\t\t\tfitsBelow,\r\n\t\t\t\tbelowTop: absoluteBelowTop,\r\n\t\t\t\tbelowLeft: absoluteBelowLeft\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tfitsAbove,\r\n\t\t\taboveTop: aboveTop,\r\n\t\t\taboveLeft,\r\n\t\t\tfitsBelow,\r\n\t\t\tbelowTop,\r\n\t\t\tbelowLeft\r\n\t\t};\r\n\t}\r\n\r\n\tprivate _prepareRenderWidgetAtExactPositionOverflowing(topLeft: Coordinate): Coordinate {\r\n\t\treturn new Coordinate(topLeft.top, topLeft.left + this._contentLeft);\r\n\t}\r\n\r\n\t/**\r\n\t * Compute `this._topLeft`\r\n\t */\r\n\tprivate _getTopAndBottomLeft(ctx: RenderingContext): [Coordinate, Coordinate] | [null, null] {\r\n\t\tif (!this._viewRange) {\r\n\t\t\treturn [null, null];\r\n\t\t}\r\n\r\n\t\tconst visibleRangesForRange = ctx.linesVisibleRangesForRange(this._viewRange, false);\r\n\t\tif (!visibleRangesForRange || visibleRangesForRange.length === 0) {\r\n\t\t\treturn [null, null];\r\n\t\t}\r\n\r\n\t\tlet firstLine = visibleRangesForRange[0];\r\n\t\tlet lastLine = visibleRangesForRange[0];\r\n\t\tfor (const visibleRangesForLine of visibleRangesForRange) {\r\n\t\t\tif (visibleRangesForLine.lineNumber < firstLine.lineNumber) {\r\n\t\t\t\tfirstLine = visibleRangesForLine;\r\n\t\t\t}\r\n\t\t\tif (visibleRangesForLine.lineNumber > lastLine.lineNumber) {\r\n\t\t\t\tlastLine = visibleRangesForLine;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet firstLineMinLeft = Constants.MAX_SAFE_SMALL_INTEGER;//firstLine.Constants.MAX_SAFE_SMALL_INTEGER;\r\n\t\tfor (const visibleRange of firstLine.ranges) {\r\n\t\t\tif (visibleRange.left < firstLineMinLeft) {\r\n\t\t\t\tfirstLineMinLeft = visibleRange.left;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet lastLineMinLeft = Constants.MAX_SAFE_SMALL_INTEGER;//lastLine.Constants.MAX_SAFE_SMALL_INTEGER;\r\n\t\tfor (const visibleRange of lastLine.ranges) {\r\n\t\t\tif (visibleRange.left < lastLineMinLeft) {\r\n\t\t\t\tlastLineMinLeft = visibleRange.left;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst topForPosition = ctx.getVerticalOffsetForLineNumber(firstLine.lineNumber) - ctx.scrollTop;\r\n\t\tconst topLeft = new Coordinate(topForPosition, firstLineMinLeft);\r\n\r\n\t\tconst topForBottomLine = ctx.getVerticalOffsetForLineNumber(lastLine.lineNumber) - ctx.scrollTop;\r\n\t\tconst bottomLeft = new Coordinate(topForBottomLine, lastLineMinLeft);\r\n\r\n\t\treturn [topLeft, bottomLeft];\r\n\t}\r\n\r\n\tprivate _prepareRenderWidget(ctx: RenderingContext): IRenderData | null {\r\n\t\tconst [topLeft, bottomLeft] = this._getTopAndBottomLeft(ctx);\r\n\t\tif (!topLeft || !bottomLeft) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (this._cachedDomNodeClientWidth === -1 || this._cachedDomNodeClientHeight === -1) {\r\n\r\n\t\t\tlet preferredDimensions: IDimension | null = null;\r\n\t\t\tif (typeof this._actual.beforeRender === 'function') {\r\n\t\t\t\tpreferredDimensions = safeInvoke(this._actual.beforeRender, this._actual);\r\n\t\t\t}\r\n\t\t\tif (preferredDimensions) {\r\n\t\t\t\tthis._cachedDomNodeClientWidth = preferredDimensions.width;\r\n\t\t\t\tthis._cachedDomNodeClientHeight = preferredDimensions.height;\r\n\t\t\t} else {\r\n\t\t\t\tconst domNode = this.domNode.domNode;\r\n\t\t\t\tthis._cachedDomNodeClientWidth = domNode.clientWidth;\r\n\t\t\t\tthis._cachedDomNodeClientHeight = domNode.clientHeight;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet placement: IBoxLayoutResult | null;\r\n\t\tif (this.allowEditorOverflow) {\r\n\t\t\tplacement = this._layoutBoxInPage(topLeft, bottomLeft, this._cachedDomNodeClientWidth, this._cachedDomNodeClientHeight, ctx);\r\n\t\t} else {\r\n\t\t\tplacement = this._layoutBoxInViewport(topLeft, bottomLeft, this._cachedDomNodeClientWidth, this._cachedDomNodeClientHeight, ctx);\r\n\t\t}\r\n\r\n\t\t// Do two passes, first for perfect fit, second picks first option\r\n\t\tif (this._preference) {\r\n\t\t\tfor (let pass = 1; pass <= 2; pass++) {\r\n\t\t\t\tfor (const pref of this._preference) {\r\n\t\t\t\t\t// placement\r\n\t\t\t\t\tif (pref === ContentWidgetPositionPreference.ABOVE) {\r\n\t\t\t\t\t\tif (!placement) {\r\n\t\t\t\t\t\t\t// Widget outside of viewport\r\n\t\t\t\t\t\t\treturn null;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (pass === 2 || placement.fitsAbove) {\r\n\t\t\t\t\t\t\treturn { coordinate: new Coordinate(placement.aboveTop, placement.aboveLeft), position: ContentWidgetPositionPreference.ABOVE };\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} else if (pref === ContentWidgetPositionPreference.BELOW) {\r\n\t\t\t\t\t\tif (!placement) {\r\n\t\t\t\t\t\t\t// Widget outside of viewport\r\n\t\t\t\t\t\t\treturn null;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (pass === 2 || placement.fitsBelow) {\r\n\t\t\t\t\t\t\treturn { coordinate: new Coordinate(placement.belowTop, placement.belowLeft), position: ContentWidgetPositionPreference.BELOW };\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tif (this.allowEditorOverflow) {\r\n\t\t\t\t\t\t\treturn { coordinate: this._prepareRenderWidgetAtExactPositionOverflowing(topLeft), position: ContentWidgetPositionPreference.EXACT };\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\treturn { coordinate: topLeft, position: ContentWidgetPositionPreference.EXACT };\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\t/**\r\n\t * On this first pass, we ensure that the content widget (if it is in the viewport) has the max width set correctly.\r\n\t */\r\n\tpublic onBeforeRender(viewportData: ViewportData): void {\r\n\t\tif (!this._viewRange || !this._preference) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this._viewRange.endLineNumber < viewportData.startLineNumber || this._viewRange.startLineNumber > viewportData.endLineNumber) {\r\n\t\t\t// Outside of viewport\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.domNode.setMaxWidth(this._maxWidth);\r\n\t}\r\n\r\n\tpublic prepareRender(ctx: RenderingContext): void {\r\n\t\tthis._renderData = this._prepareRenderWidget(ctx);\r\n\t}\r\n\r\n\tpublic render(ctx: RestrictedRenderingContext): void {\r\n\t\tif (!this._renderData) {\r\n\t\t\t// This widget should be invisible\r\n\t\t\tif (this._isVisible) {\r\n\t\t\t\tthis.domNode.removeAttribute('monaco-visible-content-widget');\r\n\t\t\t\tthis._isVisible = false;\r\n\t\t\t\tthis.domNode.setVisibility('hidden');\r\n\t\t\t}\r\n\r\n\t\t\tif (typeof this._actual.afterRender === 'function') {\r\n\t\t\t\tsafeInvoke(this._actual.afterRender, this._actual, null);\r\n\t\t\t}\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// This widget should be visible\r\n\t\tif (this.allowEditorOverflow) {\r\n\t\t\tthis.domNode.setTop(this._renderData.coordinate.top);\r\n\t\t\tthis.domNode.setLeft(this._renderData.coordinate.left);\r\n\t\t} else {\r\n\t\t\tthis.domNode.setTop(this._renderData.coordinate.top + ctx.scrollTop - ctx.bigNumbersDelta);\r\n\t\t\tthis.domNode.setLeft(this._renderData.coordinate.left);\r\n\t\t}\r\n\r\n\t\tif (!this._isVisible) {\r\n\t\t\tthis.domNode.setVisibility('inherit');\r\n\t\t\tthis.domNode.setAttribute('monaco-visible-content-widget', 'true');\r\n\t\t\tthis._isVisible = true;\r\n\t\t}\r\n\r\n\t\tif (typeof this._actual.afterRender === 'function') {\r\n\t\t\tsafeInvoke(this._actual.afterRender, this._actual, this._renderData.position);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction safeInvoke any>(fn: T, thisArg: ThisParameterType, ...args: Parameters): ReturnType | null {\r\n\ttry {\r\n\t\treturn fn.call(thisArg, ...args);\r\n\t} catch {\r\n\t\t// ignore\r\n\t\treturn null;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./decorations';\r\nimport { DynamicViewOverlay } from 'vs/editor/browser/view/dynamicViewOverlay';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { HorizontalRange, RenderingContext } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { ViewModelDecoration } from 'vs/editor/common/viewModel/viewModel';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\nexport class DecorationsOverlay extends DynamicViewOverlay {\r\n\r\n\tprivate readonly _context: ViewContext;\r\n\tprivate _lineHeight: number;\r\n\tprivate _typicalHalfwidthCharacterWidth: number;\r\n\tprivate _renderResult: string[] | null;\r\n\r\n\tconstructor(context: ViewContext) {\r\n\t\tsuper();\r\n\t\tthis._context = context;\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tthis._typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth;\r\n\t\tthis._renderResult = null;\r\n\r\n\t\tthis._context.addEventHandler(this);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._context.removeEventHandler(this);\r\n\t\tthis._renderResult = null;\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\t// --- begin event handlers\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tthis._typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth;\r\n\t\treturn true;\r\n\t}\r\n\tpublic onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\treturn e.scrollTopChanged || e.scrollWidthChanged;\r\n\t}\r\n\tpublic onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\t// --- end event handlers\r\n\r\n\tpublic prepareRender(ctx: RenderingContext): void {\r\n\t\tconst _decorations = ctx.getDecorationsInViewport();\r\n\r\n\t\t// Keep only decorations with `className`\r\n\t\tlet decorations: ViewModelDecoration[] = [], decorationsLen = 0;\r\n\t\tfor (let i = 0, len = _decorations.length; i < len; i++) {\r\n\t\t\tconst d = _decorations[i];\r\n\t\t\tif (d.options.className) {\r\n\t\t\t\tdecorations[decorationsLen++] = d;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Sort decorations for consistent render output\r\n\t\tdecorations = decorations.sort((a, b) => {\r\n\t\t\tif (a.options.zIndex! < b.options.zIndex!) {\r\n\t\t\t\treturn -1;\r\n\t\t\t}\r\n\t\t\tif (a.options.zIndex! > b.options.zIndex!) {\r\n\t\t\t\treturn 1;\r\n\t\t\t}\r\n\t\t\tconst aClassName = a.options.className!;\r\n\t\t\tconst bClassName = b.options.className!;\r\n\r\n\t\t\tif (aClassName < bClassName) {\r\n\t\t\t\treturn -1;\r\n\t\t\t}\r\n\t\t\tif (aClassName > bClassName) {\r\n\t\t\t\treturn 1;\r\n\t\t\t}\r\n\r\n\t\t\treturn Range.compareRangesUsingStarts(a.range, b.range);\r\n\t\t});\r\n\r\n\t\tconst visibleStartLineNumber = ctx.visibleRange.startLineNumber;\r\n\t\tconst visibleEndLineNumber = ctx.visibleRange.endLineNumber;\r\n\t\tconst output: string[] = [];\r\n\t\tfor (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) {\r\n\t\t\tconst lineIndex = lineNumber - visibleStartLineNumber;\r\n\t\t\toutput[lineIndex] = '';\r\n\t\t}\r\n\r\n\t\t// Render first whole line decorations and then regular decorations\r\n\t\tthis._renderWholeLineDecorations(ctx, decorations, output);\r\n\t\tthis._renderNormalDecorations(ctx, decorations, output);\r\n\t\tthis._renderResult = output;\r\n\t}\r\n\r\n\tprivate _renderWholeLineDecorations(ctx: RenderingContext, decorations: ViewModelDecoration[], output: string[]): void {\r\n\t\tconst lineHeight = String(this._lineHeight);\r\n\t\tconst visibleStartLineNumber = ctx.visibleRange.startLineNumber;\r\n\t\tconst visibleEndLineNumber = ctx.visibleRange.endLineNumber;\r\n\r\n\t\tfor (let i = 0, lenI = decorations.length; i < lenI; i++) {\r\n\t\t\tconst d = decorations[i];\r\n\r\n\t\t\tif (!d.options.isWholeLine) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tconst decorationOutput = (\r\n\t\t\t\t'
    '\r\n\t\t\t);\r\n\r\n\t\t\tconst startLineNumber = Math.max(d.range.startLineNumber, visibleStartLineNumber);\r\n\t\t\tconst endLineNumber = Math.min(d.range.endLineNumber, visibleEndLineNumber);\r\n\t\t\tfor (let j = startLineNumber; j <= endLineNumber; j++) {\r\n\t\t\t\tconst lineIndex = j - visibleStartLineNumber;\r\n\t\t\t\toutput[lineIndex] += decorationOutput;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _renderNormalDecorations(ctx: RenderingContext, decorations: ViewModelDecoration[], output: string[]): void {\r\n\t\tconst lineHeight = String(this._lineHeight);\r\n\t\tconst visibleStartLineNumber = ctx.visibleRange.startLineNumber;\r\n\r\n\t\tlet prevClassName: string | null = null;\r\n\t\tlet prevShowIfCollapsed: boolean = false;\r\n\t\tlet prevRange: Range | null = null;\r\n\r\n\t\tfor (let i = 0, lenI = decorations.length; i < lenI; i++) {\r\n\t\t\tconst d = decorations[i];\r\n\r\n\t\t\tif (d.options.isWholeLine) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tconst className = d.options.className!;\r\n\t\t\tconst showIfCollapsed = Boolean(d.options.showIfCollapsed);\r\n\r\n\t\t\tlet range = d.range;\r\n\t\t\tif (showIfCollapsed && range.endColumn === 1 && range.endLineNumber !== range.startLineNumber) {\r\n\t\t\t\trange = new Range(range.startLineNumber, range.startColumn, range.endLineNumber - 1, this._context.model.getLineMaxColumn(range.endLineNumber - 1));\r\n\t\t\t}\r\n\r\n\t\t\tif (prevClassName === className && prevShowIfCollapsed === showIfCollapsed && Range.areIntersectingOrTouching(prevRange!, range)) {\r\n\t\t\t\t// merge into previous decoration\r\n\t\t\t\tprevRange = Range.plusRange(prevRange!, range);\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\t// flush previous decoration\r\n\t\t\tif (prevClassName !== null) {\r\n\t\t\t\tthis._renderNormalDecoration(ctx, prevRange!, prevClassName, prevShowIfCollapsed, lineHeight, visibleStartLineNumber, output);\r\n\t\t\t}\r\n\r\n\t\t\tprevClassName = className;\r\n\t\t\tprevShowIfCollapsed = showIfCollapsed;\r\n\t\t\tprevRange = range;\r\n\t\t}\r\n\r\n\t\tif (prevClassName !== null) {\r\n\t\t\tthis._renderNormalDecoration(ctx, prevRange!, prevClassName, prevShowIfCollapsed, lineHeight, visibleStartLineNumber, output);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _renderNormalDecoration(ctx: RenderingContext, range: Range, className: string, showIfCollapsed: boolean, lineHeight: string, visibleStartLineNumber: number, output: string[]): void {\r\n\t\tconst linesVisibleRanges = ctx.linesVisibleRangesForRange(range, /*TODO@Alex*/className === 'findMatch');\r\n\t\tif (!linesVisibleRanges) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tfor (let j = 0, lenJ = linesVisibleRanges.length; j < lenJ; j++) {\r\n\t\t\tconst lineVisibleRanges = linesVisibleRanges[j];\r\n\t\t\tif (lineVisibleRanges.outsideRenderedLine) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tconst lineIndex = lineVisibleRanges.lineNumber - visibleStartLineNumber;\r\n\r\n\t\t\tif (showIfCollapsed && lineVisibleRanges.ranges.length === 1) {\r\n\t\t\t\tconst singleVisibleRange = lineVisibleRanges.ranges[0];\r\n\t\t\t\tif (singleVisibleRange.width === 0) {\r\n\t\t\t\t\t// collapsed range case => make the decoration visible by faking its width\r\n\t\t\t\t\tlineVisibleRanges.ranges[0] = new HorizontalRange(singleVisibleRange.left, this._typicalHalfwidthCharacterWidth);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tfor (let k = 0, lenK = lineVisibleRanges.ranges.length; k < lenK; k++) {\r\n\t\t\t\tconst visibleRange = lineVisibleRanges.ranges[k];\r\n\t\t\t\tconst decorationOutput = (\r\n\t\t\t\t\t'
    '\r\n\t\t\t\t);\r\n\t\t\t\toutput[lineIndex] += decorationOutput;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic render(startLineNumber: number, lineNumber: number): string {\r\n\t\tif (!this._renderResult) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\tconst lineIndex = lineNumber - startLineNumber;\r\n\t\tif (lineIndex < 0 || lineIndex >= this._renderResult.length) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\treturn this._renderResult[lineIndex];\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./glyphMargin';\r\nimport { DynamicViewOverlay } from 'vs/editor/browser/view/dynamicViewOverlay';\r\nimport { RenderingContext } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\n\r\nexport class DecorationToRender {\r\n\t_decorationToRenderBrand: void;\r\n\r\n\tpublic startLineNumber: number;\r\n\tpublic endLineNumber: number;\r\n\tpublic className: string;\r\n\r\n\tconstructor(startLineNumber: number, endLineNumber: number, className: string) {\r\n\t\tthis.startLineNumber = +startLineNumber;\r\n\t\tthis.endLineNumber = +endLineNumber;\r\n\t\tthis.className = String(className);\r\n\t}\r\n}\r\n\r\nexport abstract class DedupOverlay extends DynamicViewOverlay {\r\n\r\n\tprotected _render(visibleStartLineNumber: number, visibleEndLineNumber: number, decorations: DecorationToRender[]): string[][] {\r\n\r\n\t\tconst output: string[][] = [];\r\n\t\tfor (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) {\r\n\t\t\tconst lineIndex = lineNumber - visibleStartLineNumber;\r\n\t\t\toutput[lineIndex] = [];\r\n\t\t}\r\n\r\n\t\tif (decorations.length === 0) {\r\n\t\t\treturn output;\r\n\t\t}\r\n\r\n\t\tdecorations.sort((a, b) => {\r\n\t\t\tif (a.className === b.className) {\r\n\t\t\t\tif (a.startLineNumber === b.startLineNumber) {\r\n\t\t\t\t\treturn a.endLineNumber - b.endLineNumber;\r\n\t\t\t\t}\r\n\t\t\t\treturn a.startLineNumber - b.startLineNumber;\r\n\t\t\t}\r\n\t\t\treturn (a.className < b.className ? -1 : 1);\r\n\t\t});\r\n\r\n\t\tlet prevClassName: string | null = null;\r\n\t\tlet prevEndLineIndex = 0;\r\n\t\tfor (let i = 0, len = decorations.length; i < len; i++) {\r\n\t\t\tconst d = decorations[i];\r\n\t\t\tconst className = d.className;\r\n\t\t\tlet startLineIndex = Math.max(d.startLineNumber, visibleStartLineNumber) - visibleStartLineNumber;\r\n\t\t\tconst endLineIndex = Math.min(d.endLineNumber, visibleEndLineNumber) - visibleStartLineNumber;\r\n\r\n\t\t\tif (prevClassName === className) {\r\n\t\t\t\tstartLineIndex = Math.max(prevEndLineIndex + 1, startLineIndex);\r\n\t\t\t\tprevEndLineIndex = Math.max(prevEndLineIndex, endLineIndex);\r\n\t\t\t} else {\r\n\t\t\t\tprevClassName = className;\r\n\t\t\t\tprevEndLineIndex = endLineIndex;\r\n\t\t\t}\r\n\r\n\t\t\tfor (let i = startLineIndex; i <= prevEndLineIndex; i++) {\r\n\t\t\t\toutput[i].push(prevClassName);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn output;\r\n\t}\r\n}\r\n\r\nexport class GlyphMarginOverlay extends DedupOverlay {\r\n\r\n\tprivate readonly _context: ViewContext;\r\n\tprivate _lineHeight: number;\r\n\tprivate _glyphMargin: boolean;\r\n\tprivate _glyphMarginLeft: number;\r\n\tprivate _glyphMarginWidth: number;\r\n\tprivate _renderResult: string[] | null;\r\n\r\n\tconstructor(context: ViewContext) {\r\n\t\tsuper();\r\n\t\tthis._context = context;\r\n\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\r\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tthis._glyphMargin = options.get(EditorOption.glyphMargin);\r\n\t\tthis._glyphMarginLeft = layoutInfo.glyphMarginLeft;\r\n\t\tthis._glyphMarginWidth = layoutInfo.glyphMarginWidth;\r\n\t\tthis._renderResult = null;\r\n\t\tthis._context.addEventHandler(this);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._context.removeEventHandler(this);\r\n\t\tthis._renderResult = null;\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\t// --- begin event handlers\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\r\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tthis._glyphMargin = options.get(EditorOption.glyphMargin);\r\n\t\tthis._glyphMarginLeft = layoutInfo.glyphMarginLeft;\r\n\t\tthis._glyphMarginWidth = layoutInfo.glyphMarginWidth;\r\n\t\treturn true;\r\n\t}\r\n\tpublic onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\treturn e.scrollTopChanged;\r\n\t}\r\n\tpublic onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// --- end event handlers\r\n\r\n\tprotected _getDecorations(ctx: RenderingContext): DecorationToRender[] {\r\n\t\tconst decorations = ctx.getDecorationsInViewport();\r\n\t\tlet r: DecorationToRender[] = [], rLen = 0;\r\n\t\tfor (let i = 0, len = decorations.length; i < len; i++) {\r\n\t\t\tconst d = decorations[i];\r\n\t\t\tconst glyphMarginClassName = d.options.glyphMarginClassName;\r\n\t\t\tif (glyphMarginClassName) {\r\n\t\t\t\tr[rLen++] = new DecorationToRender(d.range.startLineNumber, d.range.endLineNumber, glyphMarginClassName);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn r;\r\n\t}\r\n\r\n\tpublic prepareRender(ctx: RenderingContext): void {\r\n\t\tif (!this._glyphMargin) {\r\n\t\t\tthis._renderResult = null;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst visibleStartLineNumber = ctx.visibleRange.startLineNumber;\r\n\t\tconst visibleEndLineNumber = ctx.visibleRange.endLineNumber;\r\n\t\tconst toRender = this._render(visibleStartLineNumber, visibleEndLineNumber, this._getDecorations(ctx));\r\n\r\n\t\tconst lineHeight = this._lineHeight.toString();\r\n\t\tconst left = this._glyphMarginLeft.toString();\r\n\t\tconst width = this._glyphMarginWidth.toString();\r\n\t\tconst common = '\" style=\"left:' + left + 'px;width:' + width + 'px' + ';height:' + lineHeight + 'px;\">';\r\n\r\n\t\tconst output: string[] = [];\r\n\t\tfor (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) {\r\n\t\t\tconst lineIndex = lineNumber - visibleStartLineNumber;\r\n\t\t\tconst classNames = toRender[lineIndex];\r\n\r\n\t\t\tif (classNames.length === 0) {\r\n\t\t\t\toutput[lineIndex] = '';\r\n\t\t\t} else {\r\n\t\t\t\toutput[lineIndex] = (\r\n\t\t\t\t\t'
    = this._renderResult.length) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\treturn this._renderResult[lineIndex];\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./linesDecorations';\r\nimport { DecorationToRender, DedupOverlay } from 'vs/editor/browser/viewParts/glyphMargin/glyphMargin';\r\nimport { RenderingContext } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\n\r\nexport class LinesDecorationsOverlay extends DedupOverlay {\r\n\r\n\tprivate readonly _context: ViewContext;\r\n\r\n\tprivate _decorationsLeft: number;\r\n\tprivate _decorationsWidth: number;\r\n\tprivate _renderResult: string[] | null;\r\n\r\n\tconstructor(context: ViewContext) {\r\n\t\tsuper();\r\n\t\tthis._context = context;\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\t\tthis._decorationsLeft = layoutInfo.decorationsLeft;\r\n\t\tthis._decorationsWidth = layoutInfo.decorationsWidth;\r\n\t\tthis._renderResult = null;\r\n\t\tthis._context.addEventHandler(this);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._context.removeEventHandler(this);\r\n\t\tthis._renderResult = null;\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\t// --- begin event handlers\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\t\tthis._decorationsLeft = layoutInfo.decorationsLeft;\r\n\t\tthis._decorationsWidth = layoutInfo.decorationsWidth;\r\n\t\treturn true;\r\n\t}\r\n\tpublic onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\treturn e.scrollTopChanged;\r\n\t}\r\n\tpublic onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// --- end event handlers\r\n\r\n\tprotected _getDecorations(ctx: RenderingContext): DecorationToRender[] {\r\n\t\tconst decorations = ctx.getDecorationsInViewport();\r\n\t\tlet r: DecorationToRender[] = [], rLen = 0;\r\n\t\tfor (let i = 0, len = decorations.length; i < len; i++) {\r\n\t\t\tconst d = decorations[i];\r\n\t\t\tconst linesDecorationsClassName = d.options.linesDecorationsClassName;\r\n\t\t\tif (linesDecorationsClassName) {\r\n\t\t\t\tr[rLen++] = new DecorationToRender(d.range.startLineNumber, d.range.endLineNumber, linesDecorationsClassName);\r\n\t\t\t}\r\n\t\t\tconst firstLineDecorationClassName = d.options.firstLineDecorationClassName;\r\n\t\t\tif (firstLineDecorationClassName) {\r\n\t\t\t\tr[rLen++] = new DecorationToRender(d.range.startLineNumber, d.range.startLineNumber, firstLineDecorationClassName);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn r;\r\n\t}\r\n\r\n\tpublic prepareRender(ctx: RenderingContext): void {\r\n\t\tconst visibleStartLineNumber = ctx.visibleRange.startLineNumber;\r\n\t\tconst visibleEndLineNumber = ctx.visibleRange.endLineNumber;\r\n\t\tconst toRender = this._render(visibleStartLineNumber, visibleEndLineNumber, this._getDecorations(ctx));\r\n\r\n\t\tconst left = this._decorationsLeft.toString();\r\n\t\tconst width = this._decorationsWidth.toString();\r\n\t\tconst common = '\" style=\"left:' + left + 'px;width:' + width + 'px;\">
    ';\r\n\r\n\t\tconst output: string[] = [];\r\n\t\tfor (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) {\r\n\t\t\tconst lineIndex = lineNumber - visibleStartLineNumber;\r\n\t\t\tconst classNames = toRender[lineIndex];\r\n\t\t\tlet lineOutput = '';\r\n\t\t\tfor (let i = 0, len = classNames.length; i < len; i++) {\r\n\t\t\t\tlineOutput += '
    ;\r\n\tprivate _canUseLayerHinting: boolean;\r\n\tprivate _contentLeft: number;\r\n\tprivate _glyphMarginLeft: number;\r\n\tprivate _glyphMarginWidth: number;\r\n\tprivate _glyphMarginBackgroundDomNode: FastDomNode;\r\n\r\n\tconstructor(context: ViewContext) {\r\n\t\tsuper(context);\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\r\n\t\tthis._canUseLayerHinting = !options.get(EditorOption.disableLayerHinting);\r\n\t\tthis._contentLeft = layoutInfo.contentLeft;\r\n\t\tthis._glyphMarginLeft = layoutInfo.glyphMarginLeft;\r\n\t\tthis._glyphMarginWidth = layoutInfo.glyphMarginWidth;\r\n\r\n\t\tthis._domNode = createFastDomNode(document.createElement('div'));\r\n\t\tthis._domNode.setClassName(Margin.OUTER_CLASS_NAME);\r\n\t\tthis._domNode.setPosition('absolute');\r\n\t\tthis._domNode.setAttribute('role', 'presentation');\r\n\t\tthis._domNode.setAttribute('aria-hidden', 'true');\r\n\r\n\t\tthis._glyphMarginBackgroundDomNode = createFastDomNode(document.createElement('div'));\r\n\t\tthis._glyphMarginBackgroundDomNode.setClassName(Margin.CLASS_NAME);\r\n\r\n\t\tthis._domNode.appendChild(this._glyphMarginBackgroundDomNode);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tpublic getDomNode(): FastDomNode {\r\n\t\treturn this._domNode;\r\n\t}\r\n\r\n\t// --- begin event handlers\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\r\n\t\tthis._canUseLayerHinting = !options.get(EditorOption.disableLayerHinting);\r\n\t\tthis._contentLeft = layoutInfo.contentLeft;\r\n\t\tthis._glyphMarginLeft = layoutInfo.glyphMarginLeft;\r\n\t\tthis._glyphMarginWidth = layoutInfo.glyphMarginWidth;\r\n\r\n\t\treturn true;\r\n\t}\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\treturn super.onScrollChanged(e) || e.scrollTopChanged;\r\n\t}\r\n\r\n\t// --- end event handlers\r\n\r\n\tpublic prepareRender(ctx: RenderingContext): void {\r\n\t\t// Nothing to read\r\n\t}\r\n\r\n\tpublic render(ctx: RestrictedRenderingContext): void {\r\n\t\tthis._domNode.setLayerHinting(this._canUseLayerHinting);\r\n\t\tthis._domNode.setContain('strict');\r\n\t\tconst adjustedScrollTop = ctx.scrollTop - ctx.bigNumbersDelta;\r\n\t\tthis._domNode.setTop(-adjustedScrollTop);\r\n\r\n\t\tconst height = Math.min(ctx.scrollHeight, 1000000);\r\n\t\tthis._domNode.setHeight(height);\r\n\t\tthis._domNode.setWidth(this._contentLeft);\r\n\r\n\t\tthis._glyphMarginBackgroundDomNode.setLeft(this._glyphMarginLeft);\r\n\t\tthis._glyphMarginBackgroundDomNode.setWidth(this._glyphMarginWidth);\r\n\t\tthis._glyphMarginBackgroundDomNode.setHeight(height);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./marginDecorations';\r\nimport { DecorationToRender, DedupOverlay } from 'vs/editor/browser/viewParts/glyphMargin/glyphMargin';\r\nimport { RenderingContext } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\n\r\nexport class MarginViewLineDecorationsOverlay extends DedupOverlay {\r\n\tprivate readonly _context: ViewContext;\r\n\tprivate _renderResult: string[] | null;\r\n\r\n\tconstructor(context: ViewContext) {\r\n\t\tsuper();\r\n\t\tthis._context = context;\r\n\t\tthis._renderResult = null;\r\n\t\tthis._context.addEventHandler(this);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._context.removeEventHandler(this);\r\n\t\tthis._renderResult = null;\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\t// --- begin event handlers\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\treturn e.scrollTopChanged;\r\n\t}\r\n\tpublic onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// --- end event handlers\r\n\r\n\tprotected _getDecorations(ctx: RenderingContext): DecorationToRender[] {\r\n\t\tconst decorations = ctx.getDecorationsInViewport();\r\n\t\tlet r: DecorationToRender[] = [], rLen = 0;\r\n\t\tfor (let i = 0, len = decorations.length; i < len; i++) {\r\n\t\t\tconst d = decorations[i];\r\n\t\t\tconst marginClassName = d.options.marginClassName;\r\n\t\t\tif (marginClassName) {\r\n\t\t\t\tr[rLen++] = new DecorationToRender(d.range.startLineNumber, d.range.endLineNumber, marginClassName);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn r;\r\n\t}\r\n\r\n\tpublic prepareRender(ctx: RenderingContext): void {\r\n\t\tconst visibleStartLineNumber = ctx.visibleRange.startLineNumber;\r\n\t\tconst visibleEndLineNumber = ctx.visibleRange.endLineNumber;\r\n\t\tconst toRender = this._render(visibleStartLineNumber, visibleEndLineNumber, this._getDecorations(ctx));\r\n\r\n\t\tconst output: string[] = [];\r\n\t\tfor (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) {\r\n\t\t\tconst lineIndex = lineNumber - visibleStartLineNumber;\r\n\t\t\tconst classNames = toRender[lineIndex];\r\n\t\t\tlet lineOutput = '';\r\n\t\t\tfor (let i = 0, len = classNames.length; i < len; i++) {\r\n\t\t\t\tlineOutput += '
    ';\r\n\t\t\t}\r\n\t\t\toutput[lineIndex] = lineOutput;\r\n\t\t}\r\n\r\n\t\tthis._renderResult = output;\r\n\t}\r\n\r\n\tpublic render(startLineNumber: number, lineNumber: number): string {\r\n\t\tif (!this._renderResult) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\treturn this._renderResult[lineNumber - startLineNumber];\r\n\t}\r\n}","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./overlayWidgets';\r\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { IOverlayWidget, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';\r\nimport { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/view/viewPart';\r\nimport { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\n\r\ninterface IWidgetData {\r\n\twidget: IOverlayWidget;\r\n\tpreference: OverlayWidgetPositionPreference | null;\r\n\tdomNode: FastDomNode;\r\n}\r\n\r\ninterface IWidgetMap {\r\n\t[key: string]: IWidgetData;\r\n}\r\n\r\nexport class ViewOverlayWidgets extends ViewPart {\r\n\r\n\tprivate _widgets: IWidgetMap;\r\n\tprivate readonly _domNode: FastDomNode;\r\n\r\n\tprivate _verticalScrollbarWidth: number;\r\n\tprivate _minimapWidth: number;\r\n\tprivate _horizontalScrollbarHeight: number;\r\n\tprivate _editorHeight: number;\r\n\tprivate _editorWidth: number;\r\n\r\n\tconstructor(context: ViewContext) {\r\n\t\tsuper(context);\r\n\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\r\n\t\tthis._widgets = {};\r\n\t\tthis._verticalScrollbarWidth = layoutInfo.verticalScrollbarWidth;\r\n\t\tthis._minimapWidth = layoutInfo.minimap.minimapWidth;\r\n\t\tthis._horizontalScrollbarHeight = layoutInfo.horizontalScrollbarHeight;\r\n\t\tthis._editorHeight = layoutInfo.height;\r\n\t\tthis._editorWidth = layoutInfo.width;\r\n\r\n\t\tthis._domNode = createFastDomNode(document.createElement('div'));\r\n\t\tPartFingerprints.write(this._domNode, PartFingerprint.OverlayWidgets);\r\n\t\tthis._domNode.setClassName('overlayWidgets');\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tsuper.dispose();\r\n\t\tthis._widgets = {};\r\n\t}\r\n\r\n\tpublic getDomNode(): FastDomNode {\r\n\t\treturn this._domNode;\r\n\t}\r\n\r\n\t// ---- begin view event handlers\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\r\n\t\tthis._verticalScrollbarWidth = layoutInfo.verticalScrollbarWidth;\r\n\t\tthis._minimapWidth = layoutInfo.minimap.minimapWidth;\r\n\t\tthis._horizontalScrollbarHeight = layoutInfo.horizontalScrollbarHeight;\r\n\t\tthis._editorHeight = layoutInfo.height;\r\n\t\tthis._editorWidth = layoutInfo.width;\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// ---- end view event handlers\r\n\r\n\tpublic addWidget(widget: IOverlayWidget): void {\r\n\t\tconst domNode = createFastDomNode(widget.getDomNode());\r\n\r\n\t\tthis._widgets[widget.getId()] = {\r\n\t\t\twidget: widget,\r\n\t\t\tpreference: null,\r\n\t\t\tdomNode: domNode\r\n\t\t};\r\n\r\n\t\t// This is sync because a widget wants to be in the dom\r\n\t\tdomNode.setPosition('absolute');\r\n\t\tdomNode.setAttribute('widgetId', widget.getId());\r\n\t\tthis._domNode.appendChild(domNode);\r\n\r\n\t\tthis.setShouldRender();\r\n\t}\r\n\r\n\tpublic setWidgetPosition(widget: IOverlayWidget, preference: OverlayWidgetPositionPreference | null): boolean {\r\n\t\tconst widgetData = this._widgets[widget.getId()];\r\n\t\tif (widgetData.preference === preference) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\twidgetData.preference = preference;\r\n\t\tthis.setShouldRender();\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic removeWidget(widget: IOverlayWidget): void {\r\n\t\tconst widgetId = widget.getId();\r\n\t\tif (this._widgets.hasOwnProperty(widgetId)) {\r\n\t\t\tconst widgetData = this._widgets[widgetId];\r\n\t\t\tconst domNode = widgetData.domNode.domNode;\r\n\t\t\tdelete this._widgets[widgetId];\r\n\r\n\t\t\tdomNode.parentNode!.removeChild(domNode);\r\n\t\t\tthis.setShouldRender();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _renderWidget(widgetData: IWidgetData): void {\r\n\t\tconst domNode = widgetData.domNode;\r\n\r\n\t\tif (widgetData.preference === null) {\r\n\t\t\tdomNode.unsetTop();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (widgetData.preference === OverlayWidgetPositionPreference.TOP_RIGHT_CORNER) {\r\n\t\t\tdomNode.setTop(0);\r\n\t\t\tdomNode.setRight((2 * this._verticalScrollbarWidth) + this._minimapWidth);\r\n\t\t} else if (widgetData.preference === OverlayWidgetPositionPreference.BOTTOM_RIGHT_CORNER) {\r\n\t\t\tconst widgetHeight = domNode.domNode.clientHeight;\r\n\t\t\tdomNode.setTop((this._editorHeight - widgetHeight - 2 * this._horizontalScrollbarHeight));\r\n\t\t\tdomNode.setRight((2 * this._verticalScrollbarWidth) + this._minimapWidth);\r\n\t\t} else if (widgetData.preference === OverlayWidgetPositionPreference.TOP_CENTER) {\r\n\t\t\tdomNode.setTop(0);\r\n\t\t\tdomNode.domNode.style.right = '50%';\r\n\t\t}\r\n\t}\r\n\r\n\tpublic prepareRender(ctx: RenderingContext): void {\r\n\t\t// Nothing to read\r\n\t}\r\n\r\n\tpublic render(ctx: RestrictedRenderingContext): void {\r\n\t\tthis._domNode.setWidth(this._editorWidth);\r\n\r\n\t\tconst keys = Object.keys(this._widgets);\r\n\t\tfor (let i = 0, len = keys.length; i < len; i++) {\r\n\t\t\tconst widgetId = keys[i];\r\n\t\t\tthis._renderWidget(this._widgets[widgetId]);\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { IOverviewRuler } from 'vs/editor/browser/editorBrowser';\r\nimport { OverviewRulerPosition, EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { ColorZone, OverviewRulerZone, OverviewZoneManager } from 'vs/editor/common/view/overviewZoneManager';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler';\r\n\r\nexport class OverviewRuler extends ViewEventHandler implements IOverviewRuler {\r\n\r\n\tprivate readonly _context: ViewContext;\r\n\tprivate readonly _domNode: FastDomNode;\r\n\tprivate readonly _zoneManager: OverviewZoneManager;\r\n\r\n\tconstructor(context: ViewContext, cssClassName: string) {\r\n\t\tsuper();\r\n\t\tthis._context = context;\r\n\t\tconst options = this._context.configuration.options;\r\n\r\n\t\tthis._domNode = createFastDomNode(document.createElement('canvas'));\r\n\t\tthis._domNode.setClassName(cssClassName);\r\n\t\tthis._domNode.setPosition('absolute');\r\n\t\tthis._domNode.setLayerHinting(true);\r\n\t\tthis._domNode.setContain('strict');\r\n\r\n\t\tthis._zoneManager = new OverviewZoneManager((lineNumber: number) => this._context.viewLayout.getVerticalOffsetForLineNumber(lineNumber));\r\n\t\tthis._zoneManager.setDOMWidth(0);\r\n\t\tthis._zoneManager.setDOMHeight(0);\r\n\t\tthis._zoneManager.setOuterHeight(this._context.viewLayout.getScrollHeight());\r\n\t\tthis._zoneManager.setLineHeight(options.get(EditorOption.lineHeight));\r\n\r\n\t\tthis._zoneManager.setPixelRatio(options.get(EditorOption.pixelRatio));\r\n\r\n\t\tthis._context.addEventHandler(this);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._context.removeEventHandler(this);\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\t// ---- begin view event handlers\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tconst options = this._context.configuration.options;\r\n\r\n\t\tif (e.hasChanged(EditorOption.lineHeight)) {\r\n\t\t\tthis._zoneManager.setLineHeight(options.get(EditorOption.lineHeight));\r\n\t\t\tthis._render();\r\n\t\t}\r\n\r\n\t\tif (e.hasChanged(EditorOption.pixelRatio)) {\r\n\t\t\tthis._zoneManager.setPixelRatio(options.get(EditorOption.pixelRatio));\r\n\t\t\tthis._domNode.setWidth(this._zoneManager.getDOMWidth());\r\n\t\t\tthis._domNode.setHeight(this._zoneManager.getDOMHeight());\r\n\t\t\tthis._domNode.domNode.width = this._zoneManager.getCanvasWidth();\r\n\t\t\tthis._domNode.domNode.height = this._zoneManager.getCanvasHeight();\r\n\t\t\tthis._render();\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\tpublic onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\r\n\t\tthis._render();\r\n\t\treturn true;\r\n\t}\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\tif (e.scrollHeightChanged) {\r\n\t\t\tthis._zoneManager.setOuterHeight(e.scrollHeight);\r\n\t\t\tthis._render();\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\tpublic onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\r\n\t\tthis._render();\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// ---- end view event handlers\r\n\r\n\tpublic getDomNode(): HTMLElement {\r\n\t\treturn this._domNode.domNode;\r\n\t}\r\n\r\n\tpublic setLayout(position: OverviewRulerPosition): void {\r\n\t\tthis._domNode.setTop(position.top);\r\n\t\tthis._domNode.setRight(position.right);\r\n\r\n\t\tlet hasChanged = false;\r\n\t\thasChanged = this._zoneManager.setDOMWidth(position.width) || hasChanged;\r\n\t\thasChanged = this._zoneManager.setDOMHeight(position.height) || hasChanged;\r\n\r\n\t\tif (hasChanged) {\r\n\t\t\tthis._domNode.setWidth(this._zoneManager.getDOMWidth());\r\n\t\t\tthis._domNode.setHeight(this._zoneManager.getDOMHeight());\r\n\t\t\tthis._domNode.domNode.width = this._zoneManager.getCanvasWidth();\r\n\t\t\tthis._domNode.domNode.height = this._zoneManager.getCanvasHeight();\r\n\r\n\t\t\tthis._render();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic setZones(zones: OverviewRulerZone[]): void {\r\n\t\tthis._zoneManager.setZones(zones);\r\n\t\tthis._render();\r\n\t}\r\n\r\n\tprivate _render(): boolean {\r\n\t\tif (this._zoneManager.getOuterHeight() === 0) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tconst width = this._zoneManager.getCanvasWidth();\r\n\t\tconst height = this._zoneManager.getCanvasHeight();\r\n\r\n\t\tconst colorZones = this._zoneManager.resolveColorZones();\r\n\t\tconst id2Color = this._zoneManager.getId2Color();\r\n\r\n\t\tconst ctx = this._domNode.domNode.getContext('2d')!;\r\n\t\tctx.clearRect(0, 0, width, height);\r\n\t\tif (colorZones.length > 0) {\r\n\t\t\tthis._renderOneLane(ctx, colorZones, id2Color, width);\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tprivate _renderOneLane(ctx: CanvasRenderingContext2D, colorZones: ColorZone[], id2Color: string[], width: number): void {\r\n\r\n\t\tlet currentColorId = 0;\r\n\t\tlet currentFrom = 0;\r\n\t\tlet currentTo = 0;\r\n\r\n\t\tfor (const zone of colorZones) {\r\n\r\n\t\t\tconst zoneColorId = zone.colorId;\r\n\t\t\tconst zoneFrom = zone.from;\r\n\t\t\tconst zoneTo = zone.to;\r\n\r\n\t\t\tif (zoneColorId !== currentColorId) {\r\n\t\t\t\tctx.fillRect(0, currentFrom, width, currentTo - currentFrom);\r\n\r\n\t\t\t\tcurrentColorId = zoneColorId;\r\n\t\t\t\tctx.fillStyle = id2Color[currentColorId];\r\n\t\t\t\tcurrentFrom = zoneFrom;\r\n\t\t\t\tcurrentTo = zoneTo;\r\n\t\t\t} else {\r\n\t\t\t\tif (currentTo >= zoneFrom) {\r\n\t\t\t\t\tcurrentTo = Math.max(currentTo, zoneTo);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tctx.fillRect(0, currentFrom, width, currentTo - currentFrom);\r\n\t\t\t\t\tcurrentFrom = zoneFrom;\r\n\t\t\t\t\tcurrentTo = zoneTo;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tctx.fillRect(0, currentFrom, width, currentTo - currentFrom);\r\n\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport { IViewZone, IViewZoneChangeAccessor } from 'vs/editor/browser/editorBrowser';\r\nimport { ViewPart } from 'vs/editor/browser/view/viewPart';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { IViewWhitespaceViewportData } from 'vs/editor/common/viewModel/viewModel';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { IWhitespaceChangeAccessor, IEditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout';\r\n\r\nexport interface IMyViewZone {\r\n\twhitespaceId: string;\r\n\tdelegate: IViewZone;\r\n\tisVisible: boolean;\r\n\tdomNode: FastDomNode;\r\n\tmarginDomNode: FastDomNode | null;\r\n}\r\n\r\ninterface IComputedViewZoneProps {\r\n\tafterViewLineNumber: number;\r\n\theightInPx: number;\r\n\tminWidthInPx: number;\r\n}\r\n\r\nconst invalidFunc = () => { throw new Error(`Invalid change accessor`); };\r\n\r\nexport class ViewZones extends ViewPart {\r\n\r\n\tprivate _zones: { [id: string]: IMyViewZone; };\r\n\tprivate _lineHeight: number;\r\n\tprivate _contentWidth: number;\r\n\tprivate _contentLeft: number;\r\n\r\n\tpublic domNode: FastDomNode;\r\n\r\n\tpublic marginDomNode: FastDomNode;\r\n\r\n\tconstructor(context: ViewContext) {\r\n\t\tsuper(context);\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\r\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tthis._contentWidth = layoutInfo.contentWidth;\r\n\t\tthis._contentLeft = layoutInfo.contentLeft;\r\n\r\n\t\tthis.domNode = createFastDomNode(document.createElement('div'));\r\n\t\tthis.domNode.setClassName('view-zones');\r\n\t\tthis.domNode.setPosition('absolute');\r\n\t\tthis.domNode.setAttribute('role', 'presentation');\r\n\t\tthis.domNode.setAttribute('aria-hidden', 'true');\r\n\r\n\t\tthis.marginDomNode = createFastDomNode(document.createElement('div'));\r\n\t\tthis.marginDomNode.setClassName('margin-view-zones');\r\n\t\tthis.marginDomNode.setPosition('absolute');\r\n\t\tthis.marginDomNode.setAttribute('role', 'presentation');\r\n\t\tthis.marginDomNode.setAttribute('aria-hidden', 'true');\r\n\r\n\t\tthis._zones = {};\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tsuper.dispose();\r\n\t\tthis._zones = {};\r\n\t}\r\n\r\n\t// ---- begin view event handlers\r\n\r\n\tprivate _recomputeWhitespacesProps(): boolean {\r\n\t\tconst whitespaces = this._context.viewLayout.getWhitespaces();\r\n\t\tconst oldWhitespaces = new Map();\r\n\t\tfor (const whitespace of whitespaces) {\r\n\t\t\toldWhitespaces.set(whitespace.id, whitespace);\r\n\t\t}\r\n\t\tlet hadAChange = false;\r\n\t\tthis._context.model.changeWhitespace((whitespaceAccessor: IWhitespaceChangeAccessor) => {\r\n\t\t\tconst keys = Object.keys(this._zones);\r\n\t\t\tfor (let i = 0, len = keys.length; i < len; i++) {\r\n\t\t\t\tconst id = keys[i];\r\n\t\t\t\tconst zone = this._zones[id];\r\n\t\t\t\tconst props = this._computeWhitespaceProps(zone.delegate);\r\n\t\t\t\tconst oldWhitespace = oldWhitespaces.get(id);\r\n\t\t\t\tif (oldWhitespace && (oldWhitespace.afterLineNumber !== props.afterViewLineNumber || oldWhitespace.height !== props.heightInPx)) {\r\n\t\t\t\t\twhitespaceAccessor.changeOneWhitespace(id, props.afterViewLineNumber, props.heightInPx);\r\n\t\t\t\t\tthis._safeCallOnComputedHeight(zone.delegate, props.heightInPx);\r\n\t\t\t\t\thadAChange = true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\t\treturn hadAChange;\r\n\t}\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\r\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tthis._contentWidth = layoutInfo.contentWidth;\r\n\t\tthis._contentLeft = layoutInfo.contentLeft;\r\n\r\n\t\tif (e.hasChanged(EditorOption.lineHeight)) {\r\n\t\t\tthis._recomputeWhitespacesProps();\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic onLineMappingChanged(e: viewEvents.ViewLineMappingChangedEvent): boolean {\r\n\t\treturn this._recomputeWhitespacesProps();\r\n\t}\r\n\r\n\tpublic onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\treturn e.scrollTopChanged || e.scrollWidthChanged;\r\n\t}\r\n\r\n\tpublic onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// ---- end view event handlers\r\n\r\n\tprivate _getZoneOrdinal(zone: IViewZone): number {\r\n\r\n\t\tif (typeof zone.afterColumn !== 'undefined') {\r\n\t\t\treturn zone.afterColumn;\r\n\t\t}\r\n\r\n\t\treturn 10000;\r\n\t}\r\n\r\n\tprivate _computeWhitespaceProps(zone: IViewZone): IComputedViewZoneProps {\r\n\t\tif (zone.afterLineNumber === 0) {\r\n\t\t\treturn {\r\n\t\t\t\tafterViewLineNumber: 0,\r\n\t\t\t\theightInPx: this._heightInPixels(zone),\r\n\t\t\t\tminWidthInPx: this._minWidthInPixels(zone)\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tlet zoneAfterModelPosition: Position;\r\n\t\tif (typeof zone.afterColumn !== 'undefined') {\r\n\t\t\tzoneAfterModelPosition = this._context.model.validateModelPosition({\r\n\t\t\t\tlineNumber: zone.afterLineNumber,\r\n\t\t\t\tcolumn: zone.afterColumn\r\n\t\t\t});\r\n\t\t} else {\r\n\t\t\tconst validAfterLineNumber = this._context.model.validateModelPosition({\r\n\t\t\t\tlineNumber: zone.afterLineNumber,\r\n\t\t\t\tcolumn: 1\r\n\t\t\t}).lineNumber;\r\n\r\n\t\t\tzoneAfterModelPosition = new Position(\r\n\t\t\t\tvalidAfterLineNumber,\r\n\t\t\t\tthis._context.model.getModelLineMaxColumn(validAfterLineNumber)\r\n\t\t\t);\r\n\t\t}\r\n\r\n\t\tlet zoneBeforeModelPosition: Position;\r\n\t\tif (zoneAfterModelPosition.column === this._context.model.getModelLineMaxColumn(zoneAfterModelPosition.lineNumber)) {\r\n\t\t\tzoneBeforeModelPosition = this._context.model.validateModelPosition({\r\n\t\t\t\tlineNumber: zoneAfterModelPosition.lineNumber + 1,\r\n\t\t\t\tcolumn: 1\r\n\t\t\t});\r\n\t\t} else {\r\n\t\t\tzoneBeforeModelPosition = this._context.model.validateModelPosition({\r\n\t\t\t\tlineNumber: zoneAfterModelPosition.lineNumber,\r\n\t\t\t\tcolumn: zoneAfterModelPosition.column + 1\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tconst viewPosition = this._context.model.coordinatesConverter.convertModelPositionToViewPosition(zoneAfterModelPosition);\r\n\t\tconst isVisible = this._context.model.coordinatesConverter.modelPositionIsVisible(zoneBeforeModelPosition);\r\n\t\treturn {\r\n\t\t\tafterViewLineNumber: viewPosition.lineNumber,\r\n\t\t\theightInPx: (isVisible ? this._heightInPixels(zone) : 0),\r\n\t\t\tminWidthInPx: this._minWidthInPixels(zone)\r\n\t\t};\r\n\t}\r\n\r\n\tpublic changeViewZones(callback: (changeAccessor: IViewZoneChangeAccessor) => any): boolean {\r\n\t\tlet zonesHaveChanged = false;\r\n\r\n\t\tthis._context.model.changeWhitespace((whitespaceAccessor: IWhitespaceChangeAccessor) => {\r\n\r\n\t\t\tconst changeAccessor: IViewZoneChangeAccessor = {\r\n\t\t\t\taddZone: (zone: IViewZone): string => {\r\n\t\t\t\t\tzonesHaveChanged = true;\r\n\t\t\t\t\treturn this._addZone(whitespaceAccessor, zone);\r\n\t\t\t\t},\r\n\t\t\t\tremoveZone: (id: string): void => {\r\n\t\t\t\t\tif (!id) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tzonesHaveChanged = this._removeZone(whitespaceAccessor, id) || zonesHaveChanged;\r\n\t\t\t\t},\r\n\t\t\t\tlayoutZone: (id: string): void => {\r\n\t\t\t\t\tif (!id) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tzonesHaveChanged = this._layoutZone(whitespaceAccessor, id) || zonesHaveChanged;\r\n\t\t\t\t}\r\n\t\t\t};\r\n\r\n\t\t\tsafeInvoke1Arg(callback, changeAccessor);\r\n\r\n\t\t\t// Invalidate changeAccessor\r\n\t\t\tchangeAccessor.addZone = invalidFunc;\r\n\t\t\tchangeAccessor.removeZone = invalidFunc;\r\n\t\t\tchangeAccessor.layoutZone = invalidFunc;\r\n\t\t});\r\n\r\n\t\treturn zonesHaveChanged;\r\n\t}\r\n\r\n\tprivate _addZone(whitespaceAccessor: IWhitespaceChangeAccessor, zone: IViewZone): string {\r\n\t\tconst props = this._computeWhitespaceProps(zone);\r\n\t\tconst whitespaceId = whitespaceAccessor.insertWhitespace(props.afterViewLineNumber, this._getZoneOrdinal(zone), props.heightInPx, props.minWidthInPx);\r\n\r\n\t\tconst myZone: IMyViewZone = {\r\n\t\t\twhitespaceId: whitespaceId,\r\n\t\t\tdelegate: zone,\r\n\t\t\tisVisible: false,\r\n\t\t\tdomNode: createFastDomNode(zone.domNode),\r\n\t\t\tmarginDomNode: zone.marginDomNode ? createFastDomNode(zone.marginDomNode) : null\r\n\t\t};\r\n\r\n\t\tthis._safeCallOnComputedHeight(myZone.delegate, props.heightInPx);\r\n\r\n\t\tmyZone.domNode.setPosition('absolute');\r\n\t\tmyZone.domNode.domNode.style.width = '100%';\r\n\t\tmyZone.domNode.setDisplay('none');\r\n\t\tmyZone.domNode.setAttribute('monaco-view-zone', myZone.whitespaceId);\r\n\t\tthis.domNode.appendChild(myZone.domNode);\r\n\r\n\t\tif (myZone.marginDomNode) {\r\n\t\t\tmyZone.marginDomNode.setPosition('absolute');\r\n\t\t\tmyZone.marginDomNode.domNode.style.width = '100%';\r\n\t\t\tmyZone.marginDomNode.setDisplay('none');\r\n\t\t\tmyZone.marginDomNode.setAttribute('monaco-view-zone', myZone.whitespaceId);\r\n\t\t\tthis.marginDomNode.appendChild(myZone.marginDomNode);\r\n\t\t}\r\n\r\n\t\tthis._zones[myZone.whitespaceId] = myZone;\r\n\r\n\r\n\t\tthis.setShouldRender();\r\n\r\n\t\treturn myZone.whitespaceId;\r\n\t}\r\n\r\n\tprivate _removeZone(whitespaceAccessor: IWhitespaceChangeAccessor, id: string): boolean {\r\n\t\tif (this._zones.hasOwnProperty(id)) {\r\n\t\t\tconst zone = this._zones[id];\r\n\t\t\tdelete this._zones[id];\r\n\t\t\twhitespaceAccessor.removeWhitespace(zone.whitespaceId);\r\n\r\n\t\t\tzone.domNode.removeAttribute('monaco-visible-view-zone');\r\n\t\t\tzone.domNode.removeAttribute('monaco-view-zone');\r\n\t\t\tzone.domNode.domNode.parentNode!.removeChild(zone.domNode.domNode);\r\n\r\n\t\t\tif (zone.marginDomNode) {\r\n\t\t\t\tzone.marginDomNode.removeAttribute('monaco-visible-view-zone');\r\n\t\t\t\tzone.marginDomNode.removeAttribute('monaco-view-zone');\r\n\t\t\t\tzone.marginDomNode.domNode.parentNode!.removeChild(zone.marginDomNode.domNode);\r\n\t\t\t}\r\n\r\n\t\t\tthis.setShouldRender();\r\n\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tprivate _layoutZone(whitespaceAccessor: IWhitespaceChangeAccessor, id: string): boolean {\r\n\t\tif (this._zones.hasOwnProperty(id)) {\r\n\t\t\tconst zone = this._zones[id];\r\n\t\t\tconst props = this._computeWhitespaceProps(zone.delegate);\r\n\t\t\t// const newOrdinal = this._getZoneOrdinal(zone.delegate);\r\n\t\t\twhitespaceAccessor.changeOneWhitespace(zone.whitespaceId, props.afterViewLineNumber, props.heightInPx);\r\n\t\t\t// TODO@Alex: change `newOrdinal` too\r\n\r\n\t\t\tthis._safeCallOnComputedHeight(zone.delegate, props.heightInPx);\r\n\t\t\tthis.setShouldRender();\r\n\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic shouldSuppressMouseDownOnViewZone(id: string): boolean {\r\n\t\tif (this._zones.hasOwnProperty(id)) {\r\n\t\t\tconst zone = this._zones[id];\r\n\t\t\treturn Boolean(zone.delegate.suppressMouseDown);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tprivate _heightInPixels(zone: IViewZone): number {\r\n\t\tif (typeof zone.heightInPx === 'number') {\r\n\t\t\treturn zone.heightInPx;\r\n\t\t}\r\n\t\tif (typeof zone.heightInLines === 'number') {\r\n\t\t\treturn this._lineHeight * zone.heightInLines;\r\n\t\t}\r\n\t\treturn this._lineHeight;\r\n\t}\r\n\r\n\tprivate _minWidthInPixels(zone: IViewZone): number {\r\n\t\tif (typeof zone.minWidthInPx === 'number') {\r\n\t\t\treturn zone.minWidthInPx;\r\n\t\t}\r\n\t\treturn 0;\r\n\t}\r\n\r\n\tprivate _safeCallOnComputedHeight(zone: IViewZone, height: number): void {\r\n\t\tif (typeof zone.onComputedHeight === 'function') {\r\n\t\t\ttry {\r\n\t\t\t\tzone.onComputedHeight(height);\r\n\t\t\t} catch (e) {\r\n\t\t\t\tonUnexpectedError(e);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _safeCallOnDomNodeTop(zone: IViewZone, top: number): void {\r\n\t\tif (typeof zone.onDomNodeTop === 'function') {\r\n\t\t\ttry {\r\n\t\t\t\tzone.onDomNodeTop(top);\r\n\t\t\t} catch (e) {\r\n\t\t\t\tonUnexpectedError(e);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic prepareRender(ctx: RenderingContext): void {\r\n\t\t// Nothing to read\r\n\t}\r\n\r\n\tpublic render(ctx: RestrictedRenderingContext): void {\r\n\t\tconst visibleWhitespaces = ctx.viewportData.whitespaceViewportData;\r\n\t\tconst visibleZones: { [id: string]: IViewWhitespaceViewportData; } = {};\r\n\r\n\t\tlet hasVisibleZone = false;\r\n\t\tfor (let i = 0, len = visibleWhitespaces.length; i < len; i++) {\r\n\t\t\tvisibleZones[visibleWhitespaces[i].id] = visibleWhitespaces[i];\r\n\t\t\thasVisibleZone = true;\r\n\t\t}\r\n\r\n\t\tconst keys = Object.keys(this._zones);\r\n\t\tfor (let i = 0, len = keys.length; i < len; i++) {\r\n\t\t\tconst id = keys[i];\r\n\t\t\tconst zone = this._zones[id];\r\n\r\n\t\t\tlet newTop = 0;\r\n\t\t\tlet newHeight = 0;\r\n\t\t\tlet newDisplay = 'none';\r\n\t\t\tif (visibleZones.hasOwnProperty(id)) {\r\n\t\t\t\tnewTop = visibleZones[id].verticalOffset - ctx.bigNumbersDelta;\r\n\t\t\t\tnewHeight = visibleZones[id].height;\r\n\t\t\t\tnewDisplay = 'block';\r\n\t\t\t\t// zone is visible\r\n\t\t\t\tif (!zone.isVisible) {\r\n\t\t\t\t\tzone.domNode.setAttribute('monaco-visible-view-zone', 'true');\r\n\t\t\t\t\tzone.isVisible = true;\r\n\t\t\t\t}\r\n\t\t\t\tthis._safeCallOnDomNodeTop(zone.delegate, ctx.getScrolledTopFromAbsoluteTop(visibleZones[id].verticalOffset));\r\n\t\t\t} else {\r\n\t\t\t\tif (zone.isVisible) {\r\n\t\t\t\t\tzone.domNode.removeAttribute('monaco-visible-view-zone');\r\n\t\t\t\t\tzone.isVisible = false;\r\n\t\t\t\t}\r\n\t\t\t\tthis._safeCallOnDomNodeTop(zone.delegate, ctx.getScrolledTopFromAbsoluteTop(-1000000));\r\n\t\t\t}\r\n\t\t\tzone.domNode.setTop(newTop);\r\n\t\t\tzone.domNode.setHeight(newHeight);\r\n\t\t\tzone.domNode.setDisplay(newDisplay);\r\n\r\n\t\t\tif (zone.marginDomNode) {\r\n\t\t\t\tzone.marginDomNode.setTop(newTop);\r\n\t\t\t\tzone.marginDomNode.setHeight(newHeight);\r\n\t\t\t\tzone.marginDomNode.setDisplay(newDisplay);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (hasVisibleZone) {\r\n\t\t\tthis.domNode.setWidth(Math.max(ctx.scrollWidth, this._contentWidth));\r\n\t\t\tthis.marginDomNode.setWidth(this._contentLeft);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction safeInvoke1Arg(func: Function, arg1: any): any {\r\n\ttry {\r\n\t\treturn func(arg1);\r\n\t} catch (e) {\r\n\t\tonUnexpectedError(e);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IScrollPosition, Scrollable } from 'vs/base/common/scrollable';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { IViewLineTokens } from 'vs/editor/common/core/lineTokens';\r\nimport { IPosition, Position } from 'vs/editor/common/core/position';\r\nimport { IRange, Range } from 'vs/editor/common/core/range';\r\nimport { INewScrollPosition, ScrollType } from 'vs/editor/common/editorCommon';\r\nimport { EndOfLinePreference, IActiveIndentGuideInfo, IModelDecorationOptions, TextModelResolvedOptions, ITextModel } from 'vs/editor/common/model';\r\nimport { VerticalRevealType } from 'vs/editor/common/view/viewEvents';\r\nimport { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';\r\nimport { IEditorWhitespace, IWhitespaceChangeAccessor } from 'vs/editor/common/viewLayout/linesLayout';\r\nimport { EditorTheme } from 'vs/editor/common/view/viewContext';\r\nimport { ICursorSimpleModel, PartialCursorState, CursorState, IColumnSelectData, EditOperationType, CursorConfiguration } from 'vs/editor/common/controller/cursorCommon';\r\nimport { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents';\r\nimport { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler';\r\n\r\nexport interface IViewWhitespaceViewportData {\r\n\treadonly id: string;\r\n\treadonly afterLineNumber: number;\r\n\treadonly verticalOffset: number;\r\n\treadonly height: number;\r\n}\r\n\r\nexport class Viewport {\r\n\treadonly _viewportBrand: void;\r\n\r\n\treadonly top: number;\r\n\treadonly left: number;\r\n\treadonly width: number;\r\n\treadonly height: number;\r\n\r\n\tconstructor(top: number, left: number, width: number, height: number) {\r\n\t\tthis.top = top | 0;\r\n\t\tthis.left = left | 0;\r\n\t\tthis.width = width | 0;\r\n\t\tthis.height = height | 0;\r\n\t}\r\n}\r\n\r\nexport interface IViewLayout {\r\n\r\n\tgetScrollable(): Scrollable;\r\n\r\n\tgetScrollWidth(): number;\r\n\tgetScrollHeight(): number;\r\n\r\n\tgetCurrentScrollLeft(): number;\r\n\tgetCurrentScrollTop(): number;\r\n\tgetCurrentViewport(): Viewport;\r\n\r\n\tgetFutureViewport(): Viewport;\r\n\r\n\tvalidateScrollPosition(scrollPosition: INewScrollPosition): IScrollPosition;\r\n\r\n\tgetLinesViewportData(): IPartialViewLinesViewportData;\r\n\tgetWhitespaces(): IEditorWhitespace[];\r\n\r\n\tisAfterLines(verticalOffset: number): boolean;\r\n\tisInTopPadding(verticalOffset: number): boolean;\r\n\tisInBottomPadding(verticalOffset: number): boolean;\r\n\tgetLineNumberAtVerticalOffset(verticalOffset: number): number;\r\n\tgetVerticalOffsetForLineNumber(lineNumber: number): number;\r\n\tgetWhitespaceAtVerticalOffset(verticalOffset: number): IViewWhitespaceViewportData | null;\r\n\r\n\t/**\r\n\t * Get the layout information for whitespaces currently in the viewport\r\n\t */\r\n\tgetWhitespaceViewportData(): IViewWhitespaceViewportData[];\r\n}\r\n\r\nexport interface ICoordinatesConverter {\r\n\t// View -> Model conversion and related methods\r\n\tconvertViewPositionToModelPosition(viewPosition: Position): Position;\r\n\tconvertViewRangeToModelRange(viewRange: Range): Range;\r\n\tvalidateViewPosition(viewPosition: Position, expectedModelPosition: Position): Position;\r\n\tvalidateViewRange(viewRange: Range, expectedModelRange: Range): Range;\r\n\r\n\t// Model -> View conversion and related methods\r\n\tconvertModelPositionToViewPosition(modelPosition: Position): Position;\r\n\tconvertModelRangeToViewRange(modelRange: Range): Range;\r\n\tmodelPositionIsVisible(modelPosition: Position): boolean;\r\n\tgetModelLineViewLineCount(modelLineNumber: number): number;\r\n}\r\n\r\nexport class OutputPosition {\r\n\toutputLineIndex: number;\r\n\toutputOffset: number;\r\n\r\n\tconstructor(outputLineIndex: number, outputOffset: number) {\r\n\t\tthis.outputLineIndex = outputLineIndex;\r\n\t\tthis.outputOffset = outputOffset;\r\n\t}\r\n}\r\n\r\nexport class LineBreakData {\r\n\tconstructor(\r\n\t\tpublic breakOffsets: number[],\r\n\t\tpublic breakOffsetsVisibleColumn: number[],\r\n\t\tpublic wrappedTextIndentLength: number\r\n\t) { }\r\n\r\n\tpublic static getInputOffsetOfOutputPosition(breakOffsets: number[], outputLineIndex: number, outputOffset: number): number {\r\n\t\tif (outputLineIndex === 0) {\r\n\t\t\treturn outputOffset;\r\n\t\t} else {\r\n\t\t\treturn breakOffsets[outputLineIndex - 1] + outputOffset;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic static getOutputPositionOfInputOffset(breakOffsets: number[], inputOffset: number): OutputPosition {\r\n\t\tlet low = 0;\r\n\t\tlet high = breakOffsets.length - 1;\r\n\t\tlet mid = 0;\r\n\t\tlet midStart = 0;\r\n\r\n\t\twhile (low <= high) {\r\n\t\t\tmid = low + ((high - low) / 2) | 0;\r\n\r\n\t\t\tconst midStop = breakOffsets[mid];\r\n\t\t\tmidStart = mid > 0 ? breakOffsets[mid - 1] : 0;\r\n\r\n\t\t\tif (inputOffset < midStart) {\r\n\t\t\t\thigh = mid - 1;\r\n\t\t\t} else if (inputOffset >= midStop) {\r\n\t\t\t\tlow = mid + 1;\r\n\t\t\t} else {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn new OutputPosition(mid, inputOffset - midStart);\r\n\t}\r\n}\r\n\r\nexport interface ILineBreaksComputer {\r\n\t/**\r\n\t * Pass in `previousLineBreakData` if the only difference is in breaking columns!!!\r\n\t */\r\n\taddRequest(lineText: string, previousLineBreakData: LineBreakData | null): void;\r\n\tfinalize(): (LineBreakData | null)[];\r\n}\r\n\r\nexport interface IViewModel extends ICursorSimpleModel {\r\n\r\n\treadonly model: ITextModel;\r\n\r\n\treadonly coordinatesConverter: ICoordinatesConverter;\r\n\r\n\treadonly viewLayout: IViewLayout;\r\n\r\n\treadonly cursorConfig: CursorConfiguration;\r\n\r\n\taddViewEventHandler(eventHandler: ViewEventHandler): void;\r\n\tremoveViewEventHandler(eventHandler: ViewEventHandler): void;\r\n\r\n\t/**\r\n\t * Gives a hint that a lot of requests are about to come in for these line numbers.\r\n\t */\r\n\tsetViewport(startLineNumber: number, endLineNumber: number, centeredLineNumber: number): void;\r\n\ttokenizeViewport(): void;\r\n\tsetHasFocus(hasFocus: boolean): void;\r\n\tonCompositionStart(): void;\r\n\tonCompositionEnd(): void;\r\n\tonDidColorThemeChange(): void;\r\n\r\n\tgetDecorationsInViewport(visibleRange: Range): ViewModelDecoration[];\r\n\tgetViewLineRenderingData(visibleRange: Range, lineNumber: number): ViewLineRenderingData;\r\n\tgetViewLineData(lineNumber: number): ViewLineData;\r\n\tgetMinimapLinesRenderingData(startLineNumber: number, endLineNumber: number, needed: boolean[]): MinimapLinesRenderingData;\r\n\tgetCompletelyVisibleViewRange(): Range;\r\n\tgetCompletelyVisibleViewRangeAtScrollTop(scrollTop: number): Range;\r\n\r\n\tgetTextModelOptions(): TextModelResolvedOptions;\r\n\tgetLineCount(): number;\r\n\tgetLineContent(lineNumber: number): string;\r\n\tgetLineLength(lineNumber: number): number;\r\n\tgetActiveIndentGuide(lineNumber: number, minLineNumber: number, maxLineNumber: number): IActiveIndentGuideInfo;\r\n\tgetLinesIndentGuides(startLineNumber: number, endLineNumber: number): number[];\r\n\tgetLineMinColumn(lineNumber: number): number;\r\n\tgetLineMaxColumn(lineNumber: number): number;\r\n\tgetLineFirstNonWhitespaceColumn(lineNumber: number): number;\r\n\tgetLineLastNonWhitespaceColumn(lineNumber: number): number;\r\n\tgetAllOverviewRulerDecorations(theme: EditorTheme): IOverviewRulerDecorations;\r\n\tinvalidateOverviewRulerColorCache(): void;\r\n\tinvalidateMinimapColorCache(): void;\r\n\tgetValueInRange(range: Range, eol: EndOfLinePreference): string;\r\n\r\n\tgetModelLineMaxColumn(modelLineNumber: number): number;\r\n\tvalidateModelPosition(modelPosition: IPosition): Position;\r\n\tvalidateModelRange(range: IRange): Range;\r\n\r\n\tdeduceModelPositionRelativeToViewPosition(viewAnchorPosition: Position, deltaOffset: number, lineFeedCnt: number): Position;\r\n\tgetEOL(): string;\r\n\tgetPlainTextToCopy(modelRanges: Range[], emptySelectionClipboard: boolean, forceCRLF: boolean): string | string[];\r\n\tgetRichTextToCopy(modelRanges: Range[], emptySelectionClipboard: boolean): { html: string, mode: string } | null;\r\n\r\n\t//#region model\r\n\r\n\tpushStackElement(): void;\r\n\r\n\t//#endregion\r\n\r\n\tcreateLineBreaksComputer(): ILineBreaksComputer;\r\n\r\n\t//#region cursor\r\n\tgetPrimaryCursorState(): CursorState;\r\n\tgetLastAddedCursorIndex(): number;\r\n\tgetCursorStates(): CursorState[];\r\n\tsetCursorStates(source: string | null | undefined, reason: CursorChangeReason, states: PartialCursorState[] | null): void;\r\n\tgetCursorColumnSelectData(): IColumnSelectData;\r\n\tsetCursorColumnSelectData(columnSelectData: IColumnSelectData): void;\r\n\tgetPrevEditOperationType(): EditOperationType;\r\n\tsetPrevEditOperationType(type: EditOperationType): void;\r\n\trevealPrimaryCursor(source: string | null | undefined, revealHorizontal: boolean): void;\r\n\trevealTopMostCursor(source: string | null | undefined): void;\r\n\trevealBottomMostCursor(source: string | null | undefined): void;\r\n\trevealRange(source: string | null | undefined, revealHorizontal: boolean, viewRange: Range, verticalType: VerticalRevealType, scrollType: ScrollType): void;\r\n\t//#endregion\r\n\r\n\t//#region viewLayout\r\n\tgetVerticalOffsetForLineNumber(viewLineNumber: number): number;\r\n\tgetScrollTop(): number;\r\n\tsetScrollTop(newScrollTop: number, scrollType: ScrollType): void;\r\n\tsetScrollPosition(position: INewScrollPosition, type: ScrollType): void;\r\n\tdeltaScrollNow(deltaScrollLeft: number, deltaScrollTop: number): void;\r\n\tchangeWhitespace(callback: (accessor: IWhitespaceChangeAccessor) => void): void;\r\n\tsetMaxLineWidth(maxLineWidth: number): void;\r\n\t//#endregion\r\n}\r\n\r\nexport class MinimapLinesRenderingData {\r\n\tpublic readonly tabSize: number;\r\n\tpublic readonly data: Array;\r\n\r\n\tconstructor(\r\n\t\ttabSize: number,\r\n\t\tdata: Array\r\n\t) {\r\n\t\tthis.tabSize = tabSize;\r\n\t\tthis.data = data;\r\n\t}\r\n}\r\n\r\nexport class ViewLineData {\r\n\t_viewLineDataBrand: void;\r\n\r\n\t/**\r\n\t * The content at this view line.\r\n\t */\r\n\tpublic readonly content: string;\r\n\t/**\r\n\t * Does this line continue with a wrapped line?\r\n\t */\r\n\tpublic readonly continuesWithWrappedLine: boolean;\r\n\t/**\r\n\t * The minimum allowed column at this view line.\r\n\t */\r\n\tpublic readonly minColumn: number;\r\n\t/**\r\n\t * The maximum allowed column at this view line.\r\n\t */\r\n\tpublic readonly maxColumn: number;\r\n\t/**\r\n\t * The visible column at the start of the line (after the fauxIndent).\r\n\t */\r\n\tpublic readonly startVisibleColumn: number;\r\n\t/**\r\n\t * The tokens at this view line.\r\n\t */\r\n\tpublic readonly tokens: IViewLineTokens;\r\n\r\n\tconstructor(\r\n\t\tcontent: string,\r\n\t\tcontinuesWithWrappedLine: boolean,\r\n\t\tminColumn: number,\r\n\t\tmaxColumn: number,\r\n\t\tstartVisibleColumn: number,\r\n\t\ttokens: IViewLineTokens\r\n\t) {\r\n\t\tthis.content = content;\r\n\t\tthis.continuesWithWrappedLine = continuesWithWrappedLine;\r\n\t\tthis.minColumn = minColumn;\r\n\t\tthis.maxColumn = maxColumn;\r\n\t\tthis.startVisibleColumn = startVisibleColumn;\r\n\t\tthis.tokens = tokens;\r\n\t}\r\n}\r\n\r\nexport class ViewLineRenderingData {\r\n\t/**\r\n\t * The minimum allowed column at this view line.\r\n\t */\r\n\tpublic readonly minColumn: number;\r\n\t/**\r\n\t * The maximum allowed column at this view line.\r\n\t */\r\n\tpublic readonly maxColumn: number;\r\n\t/**\r\n\t * The content at this view line.\r\n\t */\r\n\tpublic readonly content: string;\r\n\t/**\r\n\t * Does this line continue with a wrapped line?\r\n\t */\r\n\tpublic readonly continuesWithWrappedLine: boolean;\r\n\t/**\r\n\t * Describes if `content` contains RTL characters.\r\n\t */\r\n\tpublic readonly containsRTL: boolean;\r\n\t/**\r\n\t * Describes if `content` contains non basic ASCII chars.\r\n\t */\r\n\tpublic readonly isBasicASCII: boolean;\r\n\t/**\r\n\t * The tokens at this view line.\r\n\t */\r\n\tpublic readonly tokens: IViewLineTokens;\r\n\t/**\r\n\t * Inline decorations at this view line.\r\n\t */\r\n\tpublic readonly inlineDecorations: InlineDecoration[];\r\n\t/**\r\n\t * The tab size for this view model.\r\n\t */\r\n\tpublic readonly tabSize: number;\r\n\t/**\r\n\t * The visible column at the start of the line (after the fauxIndent)\r\n\t */\r\n\tpublic readonly startVisibleColumn: number;\r\n\r\n\tconstructor(\r\n\t\tminColumn: number,\r\n\t\tmaxColumn: number,\r\n\t\tcontent: string,\r\n\t\tcontinuesWithWrappedLine: boolean,\r\n\t\tmightContainRTL: boolean,\r\n\t\tmightContainNonBasicASCII: boolean,\r\n\t\ttokens: IViewLineTokens,\r\n\t\tinlineDecorations: InlineDecoration[],\r\n\t\ttabSize: number,\r\n\t\tstartVisibleColumn: number\r\n\t) {\r\n\t\tthis.minColumn = minColumn;\r\n\t\tthis.maxColumn = maxColumn;\r\n\t\tthis.content = content;\r\n\t\tthis.continuesWithWrappedLine = continuesWithWrappedLine;\r\n\r\n\t\tthis.isBasicASCII = ViewLineRenderingData.isBasicASCII(content, mightContainNonBasicASCII);\r\n\t\tthis.containsRTL = ViewLineRenderingData.containsRTL(content, this.isBasicASCII, mightContainRTL);\r\n\r\n\t\tthis.tokens = tokens;\r\n\t\tthis.inlineDecorations = inlineDecorations;\r\n\t\tthis.tabSize = tabSize;\r\n\t\tthis.startVisibleColumn = startVisibleColumn;\r\n\t}\r\n\r\n\tpublic static isBasicASCII(lineContent: string, mightContainNonBasicASCII: boolean): boolean {\r\n\t\tif (mightContainNonBasicASCII) {\r\n\t\t\treturn strings.isBasicASCII(lineContent);\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic static containsRTL(lineContent: string, isBasicASCII: boolean, mightContainRTL: boolean): boolean {\r\n\t\tif (!isBasicASCII && mightContainRTL) {\r\n\t\t\treturn strings.containsRTL(lineContent);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\nexport const enum InlineDecorationType {\r\n\tRegular = 0,\r\n\tBefore = 1,\r\n\tAfter = 2,\r\n\tRegularAffectingLetterSpacing = 3\r\n}\r\n\r\nexport class InlineDecoration {\r\n\tconstructor(\r\n\t\tpublic readonly range: Range,\r\n\t\tpublic readonly inlineClassName: string,\r\n\t\tpublic readonly type: InlineDecorationType\r\n\t) {\r\n\t}\r\n}\r\n\r\nexport class ViewModelDecoration {\r\n\t_viewModelDecorationBrand: void;\r\n\r\n\tpublic readonly range: Range;\r\n\tpublic readonly options: IModelDecorationOptions;\r\n\r\n\tconstructor(range: Range, options: IModelDecorationOptions) {\r\n\t\tthis.range = range;\r\n\t\tthis.options = options;\r\n\t}\r\n}\r\n\r\n/**\r\n * Decorations are encoded in a number array using the following scheme:\r\n * - 3*i = lane\r\n * - 3*i+1 = startLineNumber\r\n * - 3*i+2 = endLineNumber\r\n */\r\nexport interface IOverviewRulerDecorations {\r\n\t[color: string]: number[];\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { WrappingIndent, IComputedEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { CharacterClassifier } from 'vs/editor/common/core/characterClassifier';\r\nimport { ILineBreaksComputerFactory } from 'vs/editor/common/viewModel/splitLinesCollection';\r\nimport { FontInfo } from 'vs/editor/common/config/fontInfo';\r\nimport { ILineBreaksComputer, LineBreakData } from 'vs/editor/common/viewModel/viewModel';\r\n\r\nconst enum CharacterClass {\r\n\tNONE = 0,\r\n\tBREAK_BEFORE = 1,\r\n\tBREAK_AFTER = 2,\r\n\tBREAK_IDEOGRAPHIC = 3 // for Han and Kana.\r\n}\r\n\r\nclass WrappingCharacterClassifier extends CharacterClassifier {\r\n\r\n\tconstructor(BREAK_BEFORE: string, BREAK_AFTER: string) {\r\n\t\tsuper(CharacterClass.NONE);\r\n\r\n\t\tfor (let i = 0; i < BREAK_BEFORE.length; i++) {\r\n\t\t\tthis.set(BREAK_BEFORE.charCodeAt(i), CharacterClass.BREAK_BEFORE);\r\n\t\t}\r\n\r\n\t\tfor (let i = 0; i < BREAK_AFTER.length; i++) {\r\n\t\t\tthis.set(BREAK_AFTER.charCodeAt(i), CharacterClass.BREAK_AFTER);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic get(charCode: number): CharacterClass {\r\n\t\tif (charCode >= 0 && charCode < 256) {\r\n\t\t\treturn this._asciiMap[charCode];\r\n\t\t} else {\r\n\t\t\t// Initialize CharacterClass.BREAK_IDEOGRAPHIC for these Unicode ranges:\r\n\t\t\t// 1. CJK Unified Ideographs (0x4E00 -- 0x9FFF)\r\n\t\t\t// 2. CJK Unified Ideographs Extension A (0x3400 -- 0x4DBF)\r\n\t\t\t// 3. Hiragana and Katakana (0x3040 -- 0x30FF)\r\n\t\t\tif (\r\n\t\t\t\t(charCode >= 0x3040 && charCode <= 0x30FF)\r\n\t\t\t\t|| (charCode >= 0x3400 && charCode <= 0x4DBF)\r\n\t\t\t\t|| (charCode >= 0x4E00 && charCode <= 0x9FFF)\r\n\t\t\t) {\r\n\t\t\t\treturn CharacterClass.BREAK_IDEOGRAPHIC;\r\n\t\t\t}\r\n\r\n\t\t\treturn (this._map.get(charCode) || this._defaultValue);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nlet arrPool1: number[] = [];\r\nlet arrPool2: number[] = [];\r\n\r\nexport class MonospaceLineBreaksComputerFactory implements ILineBreaksComputerFactory {\r\n\r\n\tpublic static create(options: IComputedEditorOptions): MonospaceLineBreaksComputerFactory {\r\n\t\treturn new MonospaceLineBreaksComputerFactory(\r\n\t\t\toptions.get(EditorOption.wordWrapBreakBeforeCharacters),\r\n\t\t\toptions.get(EditorOption.wordWrapBreakAfterCharacters)\r\n\t\t);\r\n\t}\r\n\r\n\tprivate readonly classifier: WrappingCharacterClassifier;\r\n\r\n\tconstructor(breakBeforeChars: string, breakAfterChars: string) {\r\n\t\tthis.classifier = new WrappingCharacterClassifier(breakBeforeChars, breakAfterChars);\r\n\t}\r\n\r\n\tpublic createLineBreaksComputer(fontInfo: FontInfo, tabSize: number, wrappingColumn: number, wrappingIndent: WrappingIndent): ILineBreaksComputer {\r\n\t\ttabSize = tabSize | 0; //@perf\r\n\t\twrappingColumn = +wrappingColumn; //@perf\r\n\r\n\t\tlet requests: string[] = [];\r\n\t\tlet previousBreakingData: (LineBreakData | null)[] = [];\r\n\t\treturn {\r\n\t\t\taddRequest: (lineText: string, previousLineBreakData: LineBreakData | null) => {\r\n\t\t\t\trequests.push(lineText);\r\n\t\t\t\tpreviousBreakingData.push(previousLineBreakData);\r\n\t\t\t},\r\n\t\t\tfinalize: () => {\r\n\t\t\t\tconst columnsForFullWidthChar = fontInfo.typicalFullwidthCharacterWidth / fontInfo.typicalHalfwidthCharacterWidth; //@perf\r\n\t\t\t\tlet result: (LineBreakData | null)[] = [];\r\n\t\t\t\tfor (let i = 0, len = requests.length; i < len; i++) {\r\n\t\t\t\t\tconst previousLineBreakData = previousBreakingData[i];\r\n\t\t\t\t\tif (previousLineBreakData) {\r\n\t\t\t\t\t\tresult[i] = createLineBreaksFromPreviousLineBreaks(this.classifier, previousLineBreakData, requests[i], tabSize, wrappingColumn, columnsForFullWidthChar, wrappingIndent);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tresult[i] = createLineBreaks(this.classifier, requests[i], tabSize, wrappingColumn, columnsForFullWidthChar, wrappingIndent);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tarrPool1.length = 0;\r\n\t\t\t\tarrPool2.length = 0;\r\n\t\t\t\treturn result;\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n}\r\n\r\nfunction createLineBreaksFromPreviousLineBreaks(classifier: WrappingCharacterClassifier, previousBreakingData: LineBreakData, lineText: string, tabSize: number, firstLineBreakColumn: number, columnsForFullWidthChar: number, wrappingIndent: WrappingIndent): LineBreakData | null {\r\n\tif (firstLineBreakColumn === -1) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\tconst len = lineText.length;\r\n\tif (len <= 1) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\tconst prevBreakingOffsets = previousBreakingData.breakOffsets;\r\n\tconst prevBreakingOffsetsVisibleColumn = previousBreakingData.breakOffsetsVisibleColumn;\r\n\r\n\tconst wrappedTextIndentLength = computeWrappedTextIndentLength(lineText, tabSize, firstLineBreakColumn, columnsForFullWidthChar, wrappingIndent);\r\n\tconst wrappedLineBreakColumn = firstLineBreakColumn - wrappedTextIndentLength;\r\n\r\n\tlet breakingOffsets: number[] = arrPool1;\r\n\tlet breakingOffsetsVisibleColumn: number[] = arrPool2;\r\n\tlet breakingOffsetsCount: number = 0;\r\n\tlet lastBreakingOffset = 0;\r\n\tlet lastBreakingOffsetVisibleColumn = 0;\r\n\r\n\tlet breakingColumn = firstLineBreakColumn;\r\n\tconst prevLen = prevBreakingOffsets.length;\r\n\tlet prevIndex = 0;\r\n\r\n\tif (prevIndex >= 0) {\r\n\t\tlet bestDistance = Math.abs(prevBreakingOffsetsVisibleColumn[prevIndex] - breakingColumn);\r\n\t\twhile (prevIndex + 1 < prevLen) {\r\n\t\t\tconst distance = Math.abs(prevBreakingOffsetsVisibleColumn[prevIndex + 1] - breakingColumn);\r\n\t\t\tif (distance >= bestDistance) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tbestDistance = distance;\r\n\t\t\tprevIndex++;\r\n\t\t}\r\n\t}\r\n\r\n\twhile (prevIndex < prevLen) {\r\n\t\t// Allow for prevIndex to be -1 (for the case where we hit a tab when walking backwards from the first break)\r\n\t\tlet prevBreakOffset = prevIndex < 0 ? 0 : prevBreakingOffsets[prevIndex];\r\n\t\tlet prevBreakOffsetVisibleColumn = prevIndex < 0 ? 0 : prevBreakingOffsetsVisibleColumn[prevIndex];\r\n\t\tif (lastBreakingOffset > prevBreakOffset) {\r\n\t\t\tprevBreakOffset = lastBreakingOffset;\r\n\t\t\tprevBreakOffsetVisibleColumn = lastBreakingOffsetVisibleColumn;\r\n\t\t}\r\n\r\n\t\tlet breakOffset = 0;\r\n\t\tlet breakOffsetVisibleColumn = 0;\r\n\r\n\t\tlet forcedBreakOffset = 0;\r\n\t\tlet forcedBreakOffsetVisibleColumn = 0;\r\n\r\n\t\t// initially, we search as much as possible to the right (if it fits)\r\n\t\tif (prevBreakOffsetVisibleColumn <= breakingColumn) {\r\n\t\t\tlet visibleColumn = prevBreakOffsetVisibleColumn;\r\n\t\t\tlet prevCharCode = prevBreakOffset === 0 ? CharCode.Null : lineText.charCodeAt(prevBreakOffset - 1);\r\n\t\t\tlet prevCharCodeClass = prevBreakOffset === 0 ? CharacterClass.NONE : classifier.get(prevCharCode);\r\n\t\t\tlet entireLineFits = true;\r\n\t\t\tfor (let i = prevBreakOffset; i < len; i++) {\r\n\t\t\t\tconst charStartOffset = i;\r\n\t\t\t\tconst charCode = lineText.charCodeAt(i);\r\n\t\t\t\tlet charCodeClass: number;\r\n\t\t\t\tlet charWidth: number;\r\n\r\n\t\t\t\tif (strings.isHighSurrogate(charCode)) {\r\n\t\t\t\t\t// A surrogate pair must always be considered as a single unit, so it is never to be broken\r\n\t\t\t\t\ti++;\r\n\t\t\t\t\tcharCodeClass = CharacterClass.NONE;\r\n\t\t\t\t\tcharWidth = 2;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tcharCodeClass = classifier.get(charCode);\r\n\t\t\t\t\tcharWidth = computeCharWidth(charCode, visibleColumn, tabSize, columnsForFullWidthChar);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (charStartOffset > lastBreakingOffset && canBreak(prevCharCode, prevCharCodeClass, charCode, charCodeClass)) {\r\n\t\t\t\t\tbreakOffset = charStartOffset;\r\n\t\t\t\t\tbreakOffsetVisibleColumn = visibleColumn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvisibleColumn += charWidth;\r\n\r\n\t\t\t\t// check if adding character at `i` will go over the breaking column\r\n\t\t\t\tif (visibleColumn > breakingColumn) {\r\n\t\t\t\t\t// We need to break at least before character at `i`:\r\n\t\t\t\t\tif (charStartOffset > lastBreakingOffset) {\r\n\t\t\t\t\t\tforcedBreakOffset = charStartOffset;\r\n\t\t\t\t\t\tforcedBreakOffsetVisibleColumn = visibleColumn - charWidth;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t// we need to advance at least by one character\r\n\t\t\t\t\t\tforcedBreakOffset = i + 1;\r\n\t\t\t\t\t\tforcedBreakOffsetVisibleColumn = visibleColumn;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (visibleColumn - breakOffsetVisibleColumn > wrappedLineBreakColumn) {\r\n\t\t\t\t\t\t// Cannot break at `breakOffset` => reset it if it was set\r\n\t\t\t\t\t\tbreakOffset = 0;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tentireLineFits = false;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tprevCharCode = charCode;\r\n\t\t\t\tprevCharCodeClass = charCodeClass;\r\n\t\t\t}\r\n\r\n\t\t\tif (entireLineFits) {\r\n\t\t\t\t// there is no more need to break => stop the outer loop!\r\n\t\t\t\tif (breakingOffsetsCount > 0) {\r\n\t\t\t\t\t// Add last segment, no need to assign to `lastBreakingOffset` and `lastBreakingOffsetVisibleColumn`\r\n\t\t\t\t\tbreakingOffsets[breakingOffsetsCount] = prevBreakingOffsets[prevBreakingOffsets.length - 1];\r\n\t\t\t\t\tbreakingOffsetsVisibleColumn[breakingOffsetsCount] = prevBreakingOffsetsVisibleColumn[prevBreakingOffsets.length - 1];\r\n\t\t\t\t\tbreakingOffsetsCount++;\r\n\t\t\t\t}\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (breakOffset === 0) {\r\n\t\t\t// must search left\r\n\t\t\tlet visibleColumn = prevBreakOffsetVisibleColumn;\r\n\t\t\tlet charCode = lineText.charCodeAt(prevBreakOffset);\r\n\t\t\tlet charCodeClass = classifier.get(charCode);\r\n\t\t\tlet hitATabCharacter = false;\r\n\t\t\tfor (let i = prevBreakOffset - 1; i >= lastBreakingOffset; i--) {\r\n\t\t\t\tconst charStartOffset = i + 1;\r\n\t\t\t\tconst prevCharCode = lineText.charCodeAt(i);\r\n\r\n\t\t\t\tif (prevCharCode === CharCode.Tab) {\r\n\t\t\t\t\t// cannot determine the width of a tab when going backwards, so we must go forwards\r\n\t\t\t\t\thitATabCharacter = true;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tlet prevCharCodeClass: number;\r\n\t\t\t\tlet prevCharWidth: number;\r\n\r\n\t\t\t\tif (strings.isLowSurrogate(prevCharCode)) {\r\n\t\t\t\t\t// A surrogate pair must always be considered as a single unit, so it is never to be broken\r\n\t\t\t\t\ti--;\r\n\t\t\t\t\tprevCharCodeClass = CharacterClass.NONE;\r\n\t\t\t\t\tprevCharWidth = 2;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tprevCharCodeClass = classifier.get(prevCharCode);\r\n\t\t\t\t\tprevCharWidth = (strings.isFullWidthCharacter(prevCharCode) ? columnsForFullWidthChar : 1);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (visibleColumn <= breakingColumn) {\r\n\t\t\t\t\tif (forcedBreakOffset === 0) {\r\n\t\t\t\t\t\tforcedBreakOffset = charStartOffset;\r\n\t\t\t\t\t\tforcedBreakOffsetVisibleColumn = visibleColumn;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (visibleColumn <= breakingColumn - wrappedLineBreakColumn) {\r\n\t\t\t\t\t\t// went too far!\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (canBreak(prevCharCode, prevCharCodeClass, charCode, charCodeClass)) {\r\n\t\t\t\t\t\tbreakOffset = charStartOffset;\r\n\t\t\t\t\t\tbreakOffsetVisibleColumn = visibleColumn;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvisibleColumn -= prevCharWidth;\r\n\t\t\t\tcharCode = prevCharCode;\r\n\t\t\t\tcharCodeClass = prevCharCodeClass;\r\n\t\t\t}\r\n\r\n\t\t\tif (breakOffset !== 0) {\r\n\t\t\t\tconst remainingWidthOfNextLine = wrappedLineBreakColumn - (forcedBreakOffsetVisibleColumn - breakOffsetVisibleColumn);\r\n\t\t\t\tif (remainingWidthOfNextLine <= tabSize) {\r\n\t\t\t\t\tconst charCodeAtForcedBreakOffset = lineText.charCodeAt(forcedBreakOffset);\r\n\t\t\t\t\tlet charWidth: number;\r\n\t\t\t\t\tif (strings.isHighSurrogate(charCodeAtForcedBreakOffset)) {\r\n\t\t\t\t\t\t// A surrogate pair must always be considered as a single unit, so it is never to be broken\r\n\t\t\t\t\t\tcharWidth = 2;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tcharWidth = computeCharWidth(charCodeAtForcedBreakOffset, forcedBreakOffsetVisibleColumn, tabSize, columnsForFullWidthChar);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (remainingWidthOfNextLine - charWidth < 0) {\r\n\t\t\t\t\t\t// it is not worth it to break at breakOffset, it just introduces an extra needless line!\r\n\t\t\t\t\t\tbreakOffset = 0;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (hitATabCharacter) {\r\n\t\t\t\t// cannot determine the width of a tab when going backwards, so we must go forwards from the previous break\r\n\t\t\t\tprevIndex--;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (breakOffset === 0) {\r\n\t\t\t// Could not find a good breaking point\r\n\t\t\tbreakOffset = forcedBreakOffset;\r\n\t\t\tbreakOffsetVisibleColumn = forcedBreakOffsetVisibleColumn;\r\n\t\t}\r\n\r\n\t\tif (breakOffset <= lastBreakingOffset) {\r\n\t\t\t// Make sure that we are advancing (at least one character)\r\n\t\t\tconst charCode = lineText.charCodeAt(lastBreakingOffset);\r\n\t\t\tif (strings.isHighSurrogate(charCode)) {\r\n\t\t\t\t// A surrogate pair must always be considered as a single unit, so it is never to be broken\r\n\t\t\t\tbreakOffset = lastBreakingOffset + 2;\r\n\t\t\t\tbreakOffsetVisibleColumn = lastBreakingOffsetVisibleColumn + 2;\r\n\t\t\t} else {\r\n\t\t\t\tbreakOffset = lastBreakingOffset + 1;\r\n\t\t\t\tbreakOffsetVisibleColumn = lastBreakingOffsetVisibleColumn + computeCharWidth(charCode, lastBreakingOffsetVisibleColumn, tabSize, columnsForFullWidthChar);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlastBreakingOffset = breakOffset;\r\n\t\tbreakingOffsets[breakingOffsetsCount] = breakOffset;\r\n\t\tlastBreakingOffsetVisibleColumn = breakOffsetVisibleColumn;\r\n\t\tbreakingOffsetsVisibleColumn[breakingOffsetsCount] = breakOffsetVisibleColumn;\r\n\t\tbreakingOffsetsCount++;\r\n\t\tbreakingColumn = breakOffsetVisibleColumn + wrappedLineBreakColumn;\r\n\r\n\t\twhile (prevIndex < 0 || (prevIndex < prevLen && prevBreakingOffsetsVisibleColumn[prevIndex] < breakOffsetVisibleColumn)) {\r\n\t\t\tprevIndex++;\r\n\t\t}\r\n\r\n\t\tlet bestDistance = Math.abs(prevBreakingOffsetsVisibleColumn[prevIndex] - breakingColumn);\r\n\t\twhile (prevIndex + 1 < prevLen) {\r\n\t\t\tconst distance = Math.abs(prevBreakingOffsetsVisibleColumn[prevIndex + 1] - breakingColumn);\r\n\t\t\tif (distance >= bestDistance) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tbestDistance = distance;\r\n\t\t\tprevIndex++;\r\n\t\t}\r\n\t}\r\n\r\n\tif (breakingOffsetsCount === 0) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\t// Doing here some object reuse which ends up helping a huge deal with GC pauses!\r\n\tbreakingOffsets.length = breakingOffsetsCount;\r\n\tbreakingOffsetsVisibleColumn.length = breakingOffsetsCount;\r\n\tarrPool1 = previousBreakingData.breakOffsets;\r\n\tarrPool2 = previousBreakingData.breakOffsetsVisibleColumn;\r\n\tpreviousBreakingData.breakOffsets = breakingOffsets;\r\n\tpreviousBreakingData.breakOffsetsVisibleColumn = breakingOffsetsVisibleColumn;\r\n\tpreviousBreakingData.wrappedTextIndentLength = wrappedTextIndentLength;\r\n\treturn previousBreakingData;\r\n}\r\n\r\nfunction createLineBreaks(classifier: WrappingCharacterClassifier, lineText: string, tabSize: number, firstLineBreakColumn: number, columnsForFullWidthChar: number, wrappingIndent: WrappingIndent): LineBreakData | null {\r\n\tif (firstLineBreakColumn === -1) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\tconst len = lineText.length;\r\n\tif (len <= 1) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\tconst wrappedTextIndentLength = computeWrappedTextIndentLength(lineText, tabSize, firstLineBreakColumn, columnsForFullWidthChar, wrappingIndent);\r\n\tconst wrappedLineBreakColumn = firstLineBreakColumn - wrappedTextIndentLength;\r\n\r\n\tlet breakingOffsets: number[] = [];\r\n\tlet breakingOffsetsVisibleColumn: number[] = [];\r\n\tlet breakingOffsetsCount: number = 0;\r\n\tlet breakOffset = 0;\r\n\tlet breakOffsetVisibleColumn = 0;\r\n\r\n\tlet breakingColumn = firstLineBreakColumn;\r\n\tlet prevCharCode = lineText.charCodeAt(0);\r\n\tlet prevCharCodeClass = classifier.get(prevCharCode);\r\n\tlet visibleColumn = computeCharWidth(prevCharCode, 0, tabSize, columnsForFullWidthChar);\r\n\r\n\tlet startOffset = 1;\r\n\tif (strings.isHighSurrogate(prevCharCode)) {\r\n\t\t// A surrogate pair must always be considered as a single unit, so it is never to be broken\r\n\t\tvisibleColumn += 1;\r\n\t\tprevCharCode = lineText.charCodeAt(1);\r\n\t\tprevCharCodeClass = classifier.get(prevCharCode);\r\n\t\tstartOffset++;\r\n\t}\r\n\r\n\tfor (let i = startOffset; i < len; i++) {\r\n\t\tconst charStartOffset = i;\r\n\t\tconst charCode = lineText.charCodeAt(i);\r\n\t\tlet charCodeClass: number;\r\n\t\tlet charWidth: number;\r\n\r\n\t\tif (strings.isHighSurrogate(charCode)) {\r\n\t\t\t// A surrogate pair must always be considered as a single unit, so it is never to be broken\r\n\t\t\ti++;\r\n\t\t\tcharCodeClass = CharacterClass.NONE;\r\n\t\t\tcharWidth = 2;\r\n\t\t} else {\r\n\t\t\tcharCodeClass = classifier.get(charCode);\r\n\t\t\tcharWidth = computeCharWidth(charCode, visibleColumn, tabSize, columnsForFullWidthChar);\r\n\t\t}\r\n\r\n\t\tif (canBreak(prevCharCode, prevCharCodeClass, charCode, charCodeClass)) {\r\n\t\t\tbreakOffset = charStartOffset;\r\n\t\t\tbreakOffsetVisibleColumn = visibleColumn;\r\n\t\t}\r\n\r\n\t\tvisibleColumn += charWidth;\r\n\r\n\t\t// check if adding character at `i` will go over the breaking column\r\n\t\tif (visibleColumn > breakingColumn) {\r\n\t\t\t// We need to break at least before character at `i`:\r\n\r\n\t\t\tif (breakOffset === 0 || visibleColumn - breakOffsetVisibleColumn > wrappedLineBreakColumn) {\r\n\t\t\t\t// Cannot break at `breakOffset`, must break at `i`\r\n\t\t\t\tbreakOffset = charStartOffset;\r\n\t\t\t\tbreakOffsetVisibleColumn = visibleColumn - charWidth;\r\n\t\t\t}\r\n\r\n\t\t\tbreakingOffsets[breakingOffsetsCount] = breakOffset;\r\n\t\t\tbreakingOffsetsVisibleColumn[breakingOffsetsCount] = breakOffsetVisibleColumn;\r\n\t\t\tbreakingOffsetsCount++;\r\n\t\t\tbreakingColumn = breakOffsetVisibleColumn + wrappedLineBreakColumn;\r\n\t\t\tbreakOffset = 0;\r\n\t\t}\r\n\r\n\t\tprevCharCode = charCode;\r\n\t\tprevCharCodeClass = charCodeClass;\r\n\t}\r\n\r\n\tif (breakingOffsetsCount === 0) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\t// Add last segment\r\n\tbreakingOffsets[breakingOffsetsCount] = len;\r\n\tbreakingOffsetsVisibleColumn[breakingOffsetsCount] = visibleColumn;\r\n\r\n\treturn new LineBreakData(breakingOffsets, breakingOffsetsVisibleColumn, wrappedTextIndentLength);\r\n}\r\n\r\nfunction computeCharWidth(charCode: number, visibleColumn: number, tabSize: number, columnsForFullWidthChar: number): number {\r\n\tif (charCode === CharCode.Tab) {\r\n\t\treturn (tabSize - (visibleColumn % tabSize));\r\n\t}\r\n\tif (strings.isFullWidthCharacter(charCode)) {\r\n\t\treturn columnsForFullWidthChar;\r\n\t}\r\n\tif (charCode < 32) {\r\n\t\t// when using `editor.renderControlCharacters`, the substitutions are often wide\r\n\t\treturn columnsForFullWidthChar;\r\n\t}\r\n\treturn 1;\r\n}\r\n\r\nfunction tabCharacterWidth(visibleColumn: number, tabSize: number): number {\r\n\treturn (tabSize - (visibleColumn % tabSize));\r\n}\r\n\r\n/**\r\n * Kinsoku Shori : Don't break after a leading character, like an open bracket\r\n * Kinsoku Shori : Don't break before a trailing character, like a period\r\n */\r\nfunction canBreak(prevCharCode: number, prevCharCodeClass: CharacterClass, charCode: number, charCodeClass: CharacterClass): boolean {\r\n\treturn (\r\n\t\tcharCode !== CharCode.Space\r\n\t\t&& (\r\n\t\t\t(prevCharCodeClass === CharacterClass.BREAK_AFTER)\r\n\t\t\t|| (prevCharCodeClass === CharacterClass.BREAK_IDEOGRAPHIC && charCodeClass !== CharacterClass.BREAK_AFTER)\r\n\t\t\t|| (charCodeClass === CharacterClass.BREAK_BEFORE)\r\n\t\t\t|| (charCodeClass === CharacterClass.BREAK_IDEOGRAPHIC && prevCharCodeClass !== CharacterClass.BREAK_BEFORE)\r\n\t\t)\r\n\t);\r\n}\r\n\r\nfunction computeWrappedTextIndentLength(lineText: string, tabSize: number, firstLineBreakColumn: number, columnsForFullWidthChar: number, wrappingIndent: WrappingIndent): number {\r\n\tlet wrappedTextIndentLength = 0;\r\n\tif (wrappingIndent !== WrappingIndent.None) {\r\n\t\tconst firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(lineText);\r\n\t\tif (firstNonWhitespaceIndex !== -1) {\r\n\t\t\t// Track existing indent\r\n\r\n\t\t\tfor (let i = 0; i < firstNonWhitespaceIndex; i++) {\r\n\t\t\t\tconst charWidth = (lineText.charCodeAt(i) === CharCode.Tab ? tabCharacterWidth(wrappedTextIndentLength, tabSize) : 1);\r\n\t\t\t\twrappedTextIndentLength += charWidth;\r\n\t\t\t}\r\n\r\n\t\t\t// Increase indent of continuation lines, if desired\r\n\t\t\tconst numberOfAdditionalTabs = (wrappingIndent === WrappingIndent.DeepIndent ? 2 : wrappingIndent === WrappingIndent.Indent ? 1 : 0);\r\n\t\t\tfor (let i = 0; i < numberOfAdditionalTabs; i++) {\r\n\t\t\t\tconst charWidth = tabCharacterWidth(wrappedTextIndentLength, tabSize);\r\n\t\t\t\twrappedTextIndentLength += charWidth;\r\n\t\t\t}\r\n\r\n\t\t\t// Force sticking to beginning of line if no character would fit except for the indentation\r\n\t\t\tif (wrappedTextIndentLength + columnsForFullWidthChar > firstLineBreakColumn) {\r\n\t\t\t\twrappedTextIndentLength = 0;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn wrappedTextIndentLength;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler';\r\nimport { ViewEvent } from 'vs/editor/common/view/viewEvents';\r\nimport { IContentSizeChangedEvent } from 'vs/editor/common/editorCommon';\r\nimport { Emitter } from 'vs/base/common/event';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents';\r\n\r\nexport class ViewModelEventDispatcher extends Disposable {\r\n\r\n\tprivate readonly _onEvent = this._register(new Emitter());\r\n\tpublic readonly onEvent = this._onEvent.event;\r\n\r\n\tprivate readonly _eventHandlers: ViewEventHandler[];\r\n\tprivate _viewEventQueue: ViewEvent[] | null;\r\n\tprivate _isConsumingViewEventQueue: boolean;\r\n\tprivate _collector: ViewModelEventsCollector | null;\r\n\tprivate _collectorCnt: number;\r\n\tprivate _outgoingEvents: OutgoingViewModelEvent[];\r\n\r\n\tconstructor() {\r\n\t\tsuper();\r\n\t\tthis._eventHandlers = [];\r\n\t\tthis._viewEventQueue = null;\r\n\t\tthis._isConsumingViewEventQueue = false;\r\n\t\tthis._collector = null;\r\n\t\tthis._collectorCnt = 0;\r\n\t\tthis._outgoingEvents = [];\r\n\t}\r\n\r\n\tpublic emitOutgoingEvent(e: OutgoingViewModelEvent): void {\r\n\t\tthis._addOutgoingEvent(e);\r\n\t\tthis._emitOugoingEvents();\r\n\t}\r\n\r\n\tprivate _addOutgoingEvent(e: OutgoingViewModelEvent): void {\r\n\t\tfor (let i = 0, len = this._outgoingEvents.length; i < len; i++) {\r\n\t\t\tif (this._outgoingEvents[i].kind === e.kind) {\r\n\t\t\t\tthis._outgoingEvents[i] = this._outgoingEvents[i].merge(e);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\t\t// not merged\r\n\t\tthis._outgoingEvents.push(e);\r\n\t}\r\n\r\n\tprivate _emitOugoingEvents(): void {\r\n\t\twhile (this._outgoingEvents.length > 0) {\r\n\t\t\tif (this._collector || this._isConsumingViewEventQueue) {\r\n\t\t\t\t// right now collecting or emitting view events, so let's postpone emitting\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tconst event = this._outgoingEvents.shift()!;\r\n\t\t\tif (event.isNoOp()) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tthis._onEvent.fire(event);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic addViewEventHandler(eventHandler: ViewEventHandler): void {\r\n\t\tfor (let i = 0, len = this._eventHandlers.length; i < len; i++) {\r\n\t\t\tif (this._eventHandlers[i] === eventHandler) {\r\n\t\t\t\tconsole.warn('Detected duplicate listener in ViewEventDispatcher', eventHandler);\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis._eventHandlers.push(eventHandler);\r\n\t}\r\n\r\n\tpublic removeViewEventHandler(eventHandler: ViewEventHandler): void {\r\n\t\tfor (let i = 0; i < this._eventHandlers.length; i++) {\r\n\t\t\tif (this._eventHandlers[i] === eventHandler) {\r\n\t\t\t\tthis._eventHandlers.splice(i, 1);\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic beginEmitViewEvents(): ViewModelEventsCollector {\r\n\t\tthis._collectorCnt++;\r\n\t\tif (this._collectorCnt === 1) {\r\n\t\t\tthis._collector = new ViewModelEventsCollector();\r\n\t\t}\r\n\t\treturn this._collector!;\r\n\t}\r\n\r\n\tpublic endEmitViewEvents(): void {\r\n\t\tthis._collectorCnt--;\r\n\t\tif (this._collectorCnt === 0) {\r\n\t\t\tconst outgoingEvents = this._collector!.outgoingEvents;\r\n\t\t\tconst viewEvents = this._collector!.viewEvents;\r\n\t\t\tthis._collector = null;\r\n\r\n\t\t\tfor (const outgoingEvent of outgoingEvents) {\r\n\t\t\t\tthis._addOutgoingEvent(outgoingEvent);\r\n\t\t\t}\r\n\r\n\t\t\tif (viewEvents.length > 0) {\r\n\t\t\t\tthis._emitMany(viewEvents);\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis._emitOugoingEvents();\r\n\t}\r\n\r\n\tpublic emitSingleViewEvent(event: ViewEvent): void {\r\n\t\ttry {\r\n\t\t\tconst eventsCollector = this.beginEmitViewEvents();\r\n\t\t\teventsCollector.emitViewEvent(event);\r\n\t\t} finally {\r\n\t\t\tthis.endEmitViewEvents();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _emitMany(events: ViewEvent[]): void {\r\n\t\tif (this._viewEventQueue) {\r\n\t\t\tthis._viewEventQueue = this._viewEventQueue.concat(events);\r\n\t\t} else {\r\n\t\t\tthis._viewEventQueue = events;\r\n\t\t}\r\n\r\n\t\tif (!this._isConsumingViewEventQueue) {\r\n\t\t\tthis._consumeViewEventQueue();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _consumeViewEventQueue(): void {\r\n\t\ttry {\r\n\t\t\tthis._isConsumingViewEventQueue = true;\r\n\t\t\tthis._doConsumeQueue();\r\n\t\t} finally {\r\n\t\t\tthis._isConsumingViewEventQueue = false;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _doConsumeQueue(): void {\r\n\t\twhile (this._viewEventQueue) {\r\n\t\t\t// Empty event queue, as events might come in while sending these off\r\n\t\t\tconst events = this._viewEventQueue;\r\n\t\t\tthis._viewEventQueue = null;\r\n\r\n\t\t\t// Use a clone of the event handlers list, as they might remove themselves\r\n\t\t\tconst eventHandlers = this._eventHandlers.slice(0);\r\n\t\t\tfor (const eventHandler of eventHandlers) {\r\n\t\t\t\teventHandler.handleEvents(events);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class ViewModelEventsCollector {\r\n\r\n\tpublic readonly viewEvents: ViewEvent[];\r\n\tpublic readonly outgoingEvents: OutgoingViewModelEvent[];\r\n\r\n\tconstructor() {\r\n\t\tthis.viewEvents = [];\r\n\t\tthis.outgoingEvents = [];\r\n\t}\r\n\r\n\tpublic emitViewEvent(event: ViewEvent) {\r\n\t\tthis.viewEvents.push(event);\r\n\t}\r\n\r\n\tpublic emitOutgoingEvent(e: OutgoingViewModelEvent): void {\r\n\t\tthis.outgoingEvents.push(e);\r\n\t}\r\n}\r\n\r\nexport const enum OutgoingViewModelEventKind {\r\n\tContentSizeChanged,\r\n\tFocusChanged,\r\n\tScrollChanged,\r\n\tViewZonesChanged,\r\n\tReadOnlyEditAttempt,\r\n\tCursorStateChanged,\r\n}\r\n\r\nexport class ContentSizeChangedEvent implements IContentSizeChangedEvent {\r\n\r\n\tpublic readonly kind = OutgoingViewModelEventKind.ContentSizeChanged;\r\n\r\n\tprivate readonly _oldContentWidth: number;\r\n\tprivate readonly _oldContentHeight: number;\r\n\r\n\treadonly contentWidth: number;\r\n\treadonly contentHeight: number;\r\n\treadonly contentWidthChanged: boolean;\r\n\treadonly contentHeightChanged: boolean;\r\n\r\n\tconstructor(oldContentWidth: number, oldContentHeight: number, contentWidth: number, contentHeight: number) {\r\n\t\tthis._oldContentWidth = oldContentWidth;\r\n\t\tthis._oldContentHeight = oldContentHeight;\r\n\t\tthis.contentWidth = contentWidth;\r\n\t\tthis.contentHeight = contentHeight;\r\n\t\tthis.contentWidthChanged = (this._oldContentWidth !== this.contentWidth);\r\n\t\tthis.contentHeightChanged = (this._oldContentHeight !== this.contentHeight);\r\n\t}\r\n\r\n\tpublic isNoOp(): boolean {\r\n\t\treturn (!this.contentWidthChanged && !this.contentHeightChanged);\r\n\t}\r\n\r\n\r\n\tpublic merge(other: OutgoingViewModelEvent): ContentSizeChangedEvent {\r\n\t\tif (other.kind !== OutgoingViewModelEventKind.ContentSizeChanged) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\treturn new ContentSizeChangedEvent(this._oldContentWidth, this._oldContentHeight, other.contentWidth, other.contentHeight);\r\n\t}\r\n}\r\n\r\nexport class FocusChangedEvent {\r\n\r\n\tpublic readonly kind = OutgoingViewModelEventKind.FocusChanged;\r\n\r\n\treadonly oldHasFocus: boolean;\r\n\treadonly hasFocus: boolean;\r\n\r\n\tconstructor(oldHasFocus: boolean, hasFocus: boolean) {\r\n\t\tthis.oldHasFocus = oldHasFocus;\r\n\t\tthis.hasFocus = hasFocus;\r\n\t}\r\n\r\n\tpublic isNoOp(): boolean {\r\n\t\treturn (this.oldHasFocus === this.hasFocus);\r\n\t}\r\n\r\n\tpublic merge(other: OutgoingViewModelEvent): FocusChangedEvent {\r\n\t\tif (other.kind !== OutgoingViewModelEventKind.FocusChanged) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\treturn new FocusChangedEvent(this.oldHasFocus, other.hasFocus);\r\n\t}\r\n}\r\n\r\nexport class ScrollChangedEvent {\r\n\r\n\tpublic readonly kind = OutgoingViewModelEventKind.ScrollChanged;\r\n\r\n\tprivate readonly _oldScrollWidth: number;\r\n\tprivate readonly _oldScrollLeft: number;\r\n\tprivate readonly _oldScrollHeight: number;\r\n\tprivate readonly _oldScrollTop: number;\r\n\r\n\tpublic readonly scrollWidth: number;\r\n\tpublic readonly scrollLeft: number;\r\n\tpublic readonly scrollHeight: number;\r\n\tpublic readonly scrollTop: number;\r\n\r\n\tpublic readonly scrollWidthChanged: boolean;\r\n\tpublic readonly scrollLeftChanged: boolean;\r\n\tpublic readonly scrollHeightChanged: boolean;\r\n\tpublic readonly scrollTopChanged: boolean;\r\n\r\n\tconstructor(\r\n\t\toldScrollWidth: number, oldScrollLeft: number, oldScrollHeight: number, oldScrollTop: number,\r\n\t\tscrollWidth: number, scrollLeft: number, scrollHeight: number, scrollTop: number,\r\n\t) {\r\n\t\tthis._oldScrollWidth = oldScrollWidth;\r\n\t\tthis._oldScrollLeft = oldScrollLeft;\r\n\t\tthis._oldScrollHeight = oldScrollHeight;\r\n\t\tthis._oldScrollTop = oldScrollTop;\r\n\r\n\t\tthis.scrollWidth = scrollWidth;\r\n\t\tthis.scrollLeft = scrollLeft;\r\n\t\tthis.scrollHeight = scrollHeight;\r\n\t\tthis.scrollTop = scrollTop;\r\n\r\n\t\tthis.scrollWidthChanged = (this._oldScrollWidth !== this.scrollWidth);\r\n\t\tthis.scrollLeftChanged = (this._oldScrollLeft !== this.scrollLeft);\r\n\t\tthis.scrollHeightChanged = (this._oldScrollHeight !== this.scrollHeight);\r\n\t\tthis.scrollTopChanged = (this._oldScrollTop !== this.scrollTop);\r\n\t}\r\n\r\n\tpublic isNoOp(): boolean {\r\n\t\treturn (!this.scrollWidthChanged && !this.scrollLeftChanged && !this.scrollHeightChanged && !this.scrollTopChanged);\r\n\t}\r\n\r\n\tpublic merge(other: OutgoingViewModelEvent): ScrollChangedEvent {\r\n\t\tif (other.kind !== OutgoingViewModelEventKind.ScrollChanged) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\treturn new ScrollChangedEvent(\r\n\t\t\tthis._oldScrollWidth, this._oldScrollLeft, this._oldScrollHeight, this._oldScrollTop,\r\n\t\t\tother.scrollWidth, other.scrollLeft, other.scrollHeight, other.scrollTop\r\n\t\t);\r\n\t}\r\n}\r\n\r\nexport class ViewZonesChangedEvent {\r\n\r\n\tpublic readonly kind = OutgoingViewModelEventKind.ViewZonesChanged;\r\n\r\n\tconstructor() {\r\n\t}\r\n\r\n\tpublic isNoOp(): boolean {\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic merge(other: OutgoingViewModelEvent): ViewZonesChangedEvent {\r\n\t\treturn this;\r\n\t}\r\n}\r\n\r\nexport class CursorStateChangedEvent {\r\n\r\n\tpublic readonly kind = OutgoingViewModelEventKind.CursorStateChanged;\r\n\r\n\tpublic readonly oldSelections: Selection[] | null;\r\n\tpublic readonly selections: Selection[];\r\n\tpublic readonly oldModelVersionId: number;\r\n\tpublic readonly modelVersionId: number;\r\n\tpublic readonly source: string;\r\n\tpublic readonly reason: CursorChangeReason;\r\n\tpublic readonly reachedMaxCursorCount: boolean;\r\n\r\n\tconstructor(oldSelections: Selection[] | null, selections: Selection[], oldModelVersionId: number, modelVersionId: number, source: string, reason: CursorChangeReason, reachedMaxCursorCount: boolean) {\r\n\t\tthis.oldSelections = oldSelections;\r\n\t\tthis.selections = selections;\r\n\t\tthis.oldModelVersionId = oldModelVersionId;\r\n\t\tthis.modelVersionId = modelVersionId;\r\n\t\tthis.source = source;\r\n\t\tthis.reason = reason;\r\n\t\tthis.reachedMaxCursorCount = reachedMaxCursorCount;\r\n\t}\r\n\r\n\tprivate static _selectionsAreEqual(a: Selection[] | null, b: Selection[] | null): boolean {\r\n\t\tif (!a && !b) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (!a || !b) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tconst aLen = a.length;\r\n\t\tconst bLen = b.length;\r\n\t\tif (aLen !== bLen) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tfor (let i = 0; i < aLen; i++) {\r\n\t\t\tif (!a[i].equalsSelection(b[i])) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic isNoOp(): boolean {\r\n\t\treturn (\r\n\t\t\tCursorStateChangedEvent._selectionsAreEqual(this.oldSelections, this.selections)\r\n\t\t\t&& this.oldModelVersionId === this.modelVersionId\r\n\t\t);\r\n\t}\r\n\r\n\tpublic merge(other: OutgoingViewModelEvent): CursorStateChangedEvent {\r\n\t\tif (other.kind !== OutgoingViewModelEventKind.CursorStateChanged) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\treturn new CursorStateChangedEvent(\r\n\t\t\tthis.oldSelections, other.selections, this.oldModelVersionId, other.modelVersionId, other.source, other.reason, this.reachedMaxCursorCount || other.reachedMaxCursorCount\r\n\t\t);\r\n\t}\r\n}\r\n\r\nexport class ReadOnlyEditAttemptEvent {\r\n\r\n\tpublic readonly kind = OutgoingViewModelEventKind.ReadOnlyEditAttempt;\r\n\r\n\tconstructor() {\r\n\t}\r\n\r\n\tpublic isNoOp(): boolean {\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic merge(other: OutgoingViewModelEvent): ReadOnlyEditAttemptEvent {\r\n\t\treturn this;\r\n\t}\r\n}\r\n\r\nexport type OutgoingViewModelEvent = (\r\n\tContentSizeChangedEvent\r\n\t| FocusChangedEvent\r\n\t| ScrollChangedEvent\r\n\t| ViewZonesChangedEvent\r\n\t| ReadOnlyEditAttemptEvent\r\n\t| CursorStateChangedEvent\r\n);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Event, Emitter } from 'vs/base/common/event';\r\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\r\nimport { IScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility, INewScrollPosition } from 'vs/base/common/scrollable';\r\nimport { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { IConfiguration, ScrollType } from 'vs/editor/common/editorCommon';\r\nimport { LinesLayout, IEditorWhitespace, IWhitespaceChangeAccessor } from 'vs/editor/common/viewLayout/linesLayout';\r\nimport { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';\r\nimport { IViewLayout, IViewWhitespaceViewportData, Viewport } from 'vs/editor/common/viewModel/viewModel';\r\nimport { ContentSizeChangedEvent } from 'vs/editor/common/viewModel/viewModelEventDispatcher';\r\n\r\nconst SMOOTH_SCROLLING_TIME = 125;\r\n\r\nclass EditorScrollDimensions {\r\n\r\n\tpublic readonly width: number;\r\n\tpublic readonly contentWidth: number;\r\n\tpublic readonly scrollWidth: number;\r\n\r\n\tpublic readonly height: number;\r\n\tpublic readonly contentHeight: number;\r\n\tpublic readonly scrollHeight: number;\r\n\r\n\tconstructor(\r\n\t\twidth: number,\r\n\t\tcontentWidth: number,\r\n\t\theight: number,\r\n\t\tcontentHeight: number,\r\n\t) {\r\n\t\twidth = width | 0;\r\n\t\tcontentWidth = contentWidth | 0;\r\n\t\theight = height | 0;\r\n\t\tcontentHeight = contentHeight | 0;\r\n\r\n\t\tif (width < 0) {\r\n\t\t\twidth = 0;\r\n\t\t}\r\n\t\tif (contentWidth < 0) {\r\n\t\t\tcontentWidth = 0;\r\n\t\t}\r\n\r\n\t\tif (height < 0) {\r\n\t\t\theight = 0;\r\n\t\t}\r\n\t\tif (contentHeight < 0) {\r\n\t\t\tcontentHeight = 0;\r\n\t\t}\r\n\r\n\t\tthis.width = width;\r\n\t\tthis.contentWidth = contentWidth;\r\n\t\tthis.scrollWidth = Math.max(width, contentWidth);\r\n\r\n\t\tthis.height = height;\r\n\t\tthis.contentHeight = contentHeight;\r\n\t\tthis.scrollHeight = Math.max(height, contentHeight);\r\n\t}\r\n\r\n\tpublic equals(other: EditorScrollDimensions): boolean {\r\n\t\treturn (\r\n\t\t\tthis.width === other.width\r\n\t\t\t&& this.contentWidth === other.contentWidth\r\n\t\t\t&& this.height === other.height\r\n\t\t\t&& this.contentHeight === other.contentHeight\r\n\t\t);\r\n\t}\r\n}\r\n\r\nclass EditorScrollable extends Disposable {\r\n\r\n\tprivate readonly _scrollable: Scrollable;\r\n\tprivate _dimensions: EditorScrollDimensions;\r\n\r\n\tpublic readonly onDidScroll: Event;\r\n\r\n\tprivate readonly _onDidContentSizeChange = this._register(new Emitter());\r\n\tpublic readonly onDidContentSizeChange: Event = this._onDidContentSizeChange.event;\r\n\r\n\tconstructor(smoothScrollDuration: number, scheduleAtNextAnimationFrame: (callback: () => void) => IDisposable) {\r\n\t\tsuper();\r\n\t\tthis._dimensions = new EditorScrollDimensions(0, 0, 0, 0);\r\n\t\tthis._scrollable = this._register(new Scrollable(smoothScrollDuration, scheduleAtNextAnimationFrame));\r\n\t\tthis.onDidScroll = this._scrollable.onScroll;\r\n\t}\r\n\r\n\tpublic getScrollable(): Scrollable {\r\n\t\treturn this._scrollable;\r\n\t}\r\n\r\n\tpublic setSmoothScrollDuration(smoothScrollDuration: number): void {\r\n\t\tthis._scrollable.setSmoothScrollDuration(smoothScrollDuration);\r\n\t}\r\n\r\n\tpublic validateScrollPosition(scrollPosition: INewScrollPosition): IScrollPosition {\r\n\t\treturn this._scrollable.validateScrollPosition(scrollPosition);\r\n\t}\r\n\r\n\tpublic getScrollDimensions(): EditorScrollDimensions {\r\n\t\treturn this._dimensions;\r\n\t}\r\n\r\n\tpublic setScrollDimensions(dimensions: EditorScrollDimensions): void {\r\n\t\tif (this._dimensions.equals(dimensions)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst oldDimensions = this._dimensions;\r\n\t\tthis._dimensions = dimensions;\r\n\r\n\t\tthis._scrollable.setScrollDimensions({\r\n\t\t\twidth: dimensions.width,\r\n\t\t\tscrollWidth: dimensions.scrollWidth,\r\n\t\t\theight: dimensions.height,\r\n\t\t\tscrollHeight: dimensions.scrollHeight\r\n\t\t}, true);\r\n\r\n\t\tconst contentWidthChanged = (oldDimensions.contentWidth !== dimensions.contentWidth);\r\n\t\tconst contentHeightChanged = (oldDimensions.contentHeight !== dimensions.contentHeight);\r\n\t\tif (contentWidthChanged || contentHeightChanged) {\r\n\t\t\tthis._onDidContentSizeChange.fire(new ContentSizeChangedEvent(\r\n\t\t\t\toldDimensions.contentWidth, oldDimensions.contentHeight,\r\n\t\t\t\tdimensions.contentWidth, dimensions.contentHeight\r\n\t\t\t));\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getFutureScrollPosition(): IScrollPosition {\r\n\t\treturn this._scrollable.getFutureScrollPosition();\r\n\t}\r\n\r\n\tpublic getCurrentScrollPosition(): IScrollPosition {\r\n\t\treturn this._scrollable.getCurrentScrollPosition();\r\n\t}\r\n\r\n\tpublic setScrollPositionNow(update: INewScrollPosition): void {\r\n\t\tthis._scrollable.setScrollPositionNow(update);\r\n\t}\r\n\r\n\tpublic setScrollPositionSmooth(update: INewScrollPosition): void {\r\n\t\tthis._scrollable.setScrollPositionSmooth(update);\r\n\t}\r\n}\r\n\r\nexport class ViewLayout extends Disposable implements IViewLayout {\r\n\r\n\tprivate readonly _configuration: IConfiguration;\r\n\tprivate readonly _linesLayout: LinesLayout;\r\n\r\n\tprivate readonly _scrollable: EditorScrollable;\r\n\tpublic readonly onDidScroll: Event;\r\n\tpublic readonly onDidContentSizeChange: Event;\r\n\r\n\tconstructor(configuration: IConfiguration, lineCount: number, scheduleAtNextAnimationFrame: (callback: () => void) => IDisposable) {\r\n\t\tsuper();\r\n\r\n\t\tthis._configuration = configuration;\r\n\t\tconst options = this._configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\t\tconst padding = options.get(EditorOption.padding);\r\n\r\n\t\tthis._linesLayout = new LinesLayout(lineCount, options.get(EditorOption.lineHeight), padding.top, padding.bottom);\r\n\r\n\t\tthis._scrollable = this._register(new EditorScrollable(0, scheduleAtNextAnimationFrame));\r\n\t\tthis._configureSmoothScrollDuration();\r\n\r\n\t\tthis._scrollable.setScrollDimensions(new EditorScrollDimensions(\r\n\t\t\tlayoutInfo.contentWidth,\r\n\t\t\t0,\r\n\t\t\tlayoutInfo.height,\r\n\t\t\t0\r\n\t\t));\r\n\t\tthis.onDidScroll = this._scrollable.onDidScroll;\r\n\t\tthis.onDidContentSizeChange = this._scrollable.onDidContentSizeChange;\r\n\r\n\t\tthis._updateHeight();\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tpublic getScrollable(): Scrollable {\r\n\t\treturn this._scrollable.getScrollable();\r\n\t}\r\n\r\n\tpublic onHeightMaybeChanged(): void {\r\n\t\tthis._updateHeight();\r\n\t}\r\n\r\n\tprivate _configureSmoothScrollDuration(): void {\r\n\t\tthis._scrollable.setSmoothScrollDuration(this._configuration.options.get(EditorOption.smoothScrolling) ? SMOOTH_SCROLLING_TIME : 0);\r\n\t}\r\n\r\n\t// ---- begin view event handlers\r\n\r\n\tpublic onConfigurationChanged(e: ConfigurationChangedEvent): void {\r\n\t\tconst options = this._configuration.options;\r\n\t\tif (e.hasChanged(EditorOption.lineHeight)) {\r\n\t\t\tthis._linesLayout.setLineHeight(options.get(EditorOption.lineHeight));\r\n\t\t}\r\n\t\tif (e.hasChanged(EditorOption.padding)) {\r\n\t\t\tconst padding = options.get(EditorOption.padding);\r\n\t\t\tthis._linesLayout.setPadding(padding.top, padding.bottom);\r\n\t\t}\r\n\t\tif (e.hasChanged(EditorOption.layoutInfo)) {\r\n\t\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\t\t\tconst width = layoutInfo.contentWidth;\r\n\t\t\tconst height = layoutInfo.height;\r\n\t\t\tconst scrollDimensions = this._scrollable.getScrollDimensions();\r\n\t\t\tconst contentWidth = scrollDimensions.contentWidth;\r\n\t\t\tthis._scrollable.setScrollDimensions(new EditorScrollDimensions(\r\n\t\t\t\twidth,\r\n\t\t\t\tscrollDimensions.contentWidth,\r\n\t\t\t\theight,\r\n\t\t\t\tthis._getContentHeight(width, height, contentWidth)\r\n\t\t\t));\r\n\t\t} else {\r\n\t\t\tthis._updateHeight();\r\n\t\t}\r\n\t\tif (e.hasChanged(EditorOption.smoothScrolling)) {\r\n\t\t\tthis._configureSmoothScrollDuration();\r\n\t\t}\r\n\t}\r\n\tpublic onFlushed(lineCount: number): void {\r\n\t\tthis._linesLayout.onFlushed(lineCount);\r\n\t}\r\n\tpublic onLinesDeleted(fromLineNumber: number, toLineNumber: number): void {\r\n\t\tthis._linesLayout.onLinesDeleted(fromLineNumber, toLineNumber);\r\n\t}\r\n\tpublic onLinesInserted(fromLineNumber: number, toLineNumber: number): void {\r\n\t\tthis._linesLayout.onLinesInserted(fromLineNumber, toLineNumber);\r\n\t}\r\n\r\n\t// ---- end view event handlers\r\n\r\n\tprivate _getHorizontalScrollbarHeight(width: number, scrollWidth: number): number {\r\n\t\tconst options = this._configuration.options;\r\n\t\tconst scrollbar = options.get(EditorOption.scrollbar);\r\n\t\tif (scrollbar.horizontal === ScrollbarVisibility.Hidden) {\r\n\t\t\t// horizontal scrollbar not visible\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t\tif (width >= scrollWidth) {\r\n\t\t\t// horizontal scrollbar not visible\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t\treturn scrollbar.horizontalScrollbarSize;\r\n\t}\r\n\r\n\tprivate _getContentHeight(width: number, height: number, contentWidth: number): number {\r\n\t\tconst options = this._configuration.options;\r\n\r\n\t\tlet result = this._linesLayout.getLinesTotalHeight();\r\n\t\tif (options.get(EditorOption.scrollBeyondLastLine)) {\r\n\t\t\tresult += Math.max(0, height - options.get(EditorOption.lineHeight) - options.get(EditorOption.padding).bottom);\r\n\t\t} else {\r\n\t\t\tresult += this._getHorizontalScrollbarHeight(width, contentWidth);\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate _updateHeight(): void {\r\n\t\tconst scrollDimensions = this._scrollable.getScrollDimensions();\r\n\t\tconst width = scrollDimensions.width;\r\n\t\tconst height = scrollDimensions.height;\r\n\t\tconst contentWidth = scrollDimensions.contentWidth;\r\n\t\tthis._scrollable.setScrollDimensions(new EditorScrollDimensions(\r\n\t\t\twidth,\r\n\t\t\tscrollDimensions.contentWidth,\r\n\t\t\theight,\r\n\t\t\tthis._getContentHeight(width, height, contentWidth)\r\n\t\t));\r\n\t}\r\n\r\n\t// ---- Layouting logic\r\n\r\n\tpublic getCurrentViewport(): Viewport {\r\n\t\tconst scrollDimensions = this._scrollable.getScrollDimensions();\r\n\t\tconst currentScrollPosition = this._scrollable.getCurrentScrollPosition();\r\n\t\treturn new Viewport(\r\n\t\t\tcurrentScrollPosition.scrollTop,\r\n\t\t\tcurrentScrollPosition.scrollLeft,\r\n\t\t\tscrollDimensions.width,\r\n\t\t\tscrollDimensions.height\r\n\t\t);\r\n\t}\r\n\r\n\tpublic getFutureViewport(): Viewport {\r\n\t\tconst scrollDimensions = this._scrollable.getScrollDimensions();\r\n\t\tconst currentScrollPosition = this._scrollable.getFutureScrollPosition();\r\n\t\treturn new Viewport(\r\n\t\t\tcurrentScrollPosition.scrollTop,\r\n\t\t\tcurrentScrollPosition.scrollLeft,\r\n\t\t\tscrollDimensions.width,\r\n\t\t\tscrollDimensions.height\r\n\t\t);\r\n\t}\r\n\r\n\tprivate _computeContentWidth(maxLineWidth: number): number {\r\n\t\tconst options = this._configuration.options;\r\n\t\tconst wrappingInfo = options.get(EditorOption.wrappingInfo);\r\n\t\tconst fontInfo = options.get(EditorOption.fontInfo);\r\n\t\tif (wrappingInfo.isViewportWrapping) {\r\n\t\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\t\t\tconst minimap = options.get(EditorOption.minimap);\r\n\t\t\tif (maxLineWidth > layoutInfo.contentWidth + fontInfo.typicalHalfwidthCharacterWidth) {\r\n\t\t\t\t// This is a case where viewport wrapping is on, but the line extends above the viewport\r\n\t\t\t\tif (minimap.enabled && minimap.side === 'right') {\r\n\t\t\t\t\t// We need to accomodate the scrollbar width\r\n\t\t\t\t\treturn maxLineWidth + layoutInfo.verticalScrollbarWidth;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn maxLineWidth;\r\n\t\t} else {\r\n\t\t\tconst extraHorizontalSpace = options.get(EditorOption.scrollBeyondLastColumn) * fontInfo.typicalHalfwidthCharacterWidth;\r\n\t\t\tconst whitespaceMinWidth = this._linesLayout.getWhitespaceMinWidth();\r\n\t\t\treturn Math.max(maxLineWidth + extraHorizontalSpace, whitespaceMinWidth);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic setMaxLineWidth(maxLineWidth: number): void {\r\n\t\tconst scrollDimensions = this._scrollable.getScrollDimensions();\r\n\t\t// const newScrollWidth = ;\r\n\t\tthis._scrollable.setScrollDimensions(new EditorScrollDimensions(\r\n\t\t\tscrollDimensions.width,\r\n\t\t\tthis._computeContentWidth(maxLineWidth),\r\n\t\t\tscrollDimensions.height,\r\n\t\t\tscrollDimensions.contentHeight\r\n\t\t));\r\n\r\n\t\t// The height might depend on the fact that there is a horizontal scrollbar or not\r\n\t\tthis._updateHeight();\r\n\t}\r\n\r\n\t// ---- view state\r\n\r\n\tpublic saveState(): { scrollTop: number; scrollTopWithoutViewZones: number; scrollLeft: number; } {\r\n\t\tconst currentScrollPosition = this._scrollable.getFutureScrollPosition();\r\n\t\tlet scrollTop = currentScrollPosition.scrollTop;\r\n\t\tlet firstLineNumberInViewport = this._linesLayout.getLineNumberAtOrAfterVerticalOffset(scrollTop);\r\n\t\tlet whitespaceAboveFirstLine = this._linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(firstLineNumberInViewport);\r\n\t\treturn {\r\n\t\t\tscrollTop: scrollTop,\r\n\t\t\tscrollTopWithoutViewZones: scrollTop - whitespaceAboveFirstLine,\r\n\t\t\tscrollLeft: currentScrollPosition.scrollLeft\r\n\t\t};\r\n\t}\r\n\r\n\t// ---- IVerticalLayoutProvider\r\n\tpublic changeWhitespace(callback: (accessor: IWhitespaceChangeAccessor) => void): boolean {\r\n\t\tconst hadAChange = this._linesLayout.changeWhitespace(callback);\r\n\t\tif (hadAChange) {\r\n\t\t\tthis.onHeightMaybeChanged();\r\n\t\t}\r\n\t\treturn hadAChange;\r\n\t}\r\n\tpublic getVerticalOffsetForLineNumber(lineNumber: number): number {\r\n\t\treturn this._linesLayout.getVerticalOffsetForLineNumber(lineNumber);\r\n\t}\r\n\tpublic isAfterLines(verticalOffset: number): boolean {\r\n\t\treturn this._linesLayout.isAfterLines(verticalOffset);\r\n\t}\r\n\tpublic isInTopPadding(verticalOffset: number): boolean {\r\n\t\treturn this._linesLayout.isInTopPadding(verticalOffset);\r\n\t}\r\n\tisInBottomPadding(verticalOffset: number): boolean {\r\n\t\treturn this._linesLayout.isInBottomPadding(verticalOffset);\r\n\t}\r\n\r\n\tpublic getLineNumberAtVerticalOffset(verticalOffset: number): number {\r\n\t\treturn this._linesLayout.getLineNumberAtOrAfterVerticalOffset(verticalOffset);\r\n\t}\r\n\r\n\tpublic getWhitespaceAtVerticalOffset(verticalOffset: number): IViewWhitespaceViewportData | null {\r\n\t\treturn this._linesLayout.getWhitespaceAtVerticalOffset(verticalOffset);\r\n\t}\r\n\tpublic getLinesViewportData(): IPartialViewLinesViewportData {\r\n\t\tconst visibleBox = this.getCurrentViewport();\r\n\t\treturn this._linesLayout.getLinesViewportData(visibleBox.top, visibleBox.top + visibleBox.height);\r\n\t}\r\n\tpublic getLinesViewportDataAtScrollTop(scrollTop: number): IPartialViewLinesViewportData {\r\n\t\t// do some minimal validations on scrollTop\r\n\t\tconst scrollDimensions = this._scrollable.getScrollDimensions();\r\n\t\tif (scrollTop + scrollDimensions.height > scrollDimensions.scrollHeight) {\r\n\t\t\tscrollTop = scrollDimensions.scrollHeight - scrollDimensions.height;\r\n\t\t}\r\n\t\tif (scrollTop < 0) {\r\n\t\t\tscrollTop = 0;\r\n\t\t}\r\n\t\treturn this._linesLayout.getLinesViewportData(scrollTop, scrollTop + scrollDimensions.height);\r\n\t}\r\n\tpublic getWhitespaceViewportData(): IViewWhitespaceViewportData[] {\r\n\t\tconst visibleBox = this.getCurrentViewport();\r\n\t\treturn this._linesLayout.getWhitespaceViewportData(visibleBox.top, visibleBox.top + visibleBox.height);\r\n\t}\r\n\tpublic getWhitespaces(): IEditorWhitespace[] {\r\n\t\treturn this._linesLayout.getWhitespaces();\r\n\t}\r\n\r\n\t// ---- IScrollingProvider\r\n\r\n\tpublic getContentWidth(): number {\r\n\t\tconst scrollDimensions = this._scrollable.getScrollDimensions();\r\n\t\treturn scrollDimensions.contentWidth;\r\n\t}\r\n\tpublic getScrollWidth(): number {\r\n\t\tconst scrollDimensions = this._scrollable.getScrollDimensions();\r\n\t\treturn scrollDimensions.scrollWidth;\r\n\t}\r\n\tpublic getContentHeight(): number {\r\n\t\tconst scrollDimensions = this._scrollable.getScrollDimensions();\r\n\t\treturn scrollDimensions.contentHeight;\r\n\t}\r\n\tpublic getScrollHeight(): number {\r\n\t\tconst scrollDimensions = this._scrollable.getScrollDimensions();\r\n\t\treturn scrollDimensions.scrollHeight;\r\n\t}\r\n\r\n\tpublic getCurrentScrollLeft(): number {\r\n\t\tconst currentScrollPosition = this._scrollable.getCurrentScrollPosition();\r\n\t\treturn currentScrollPosition.scrollLeft;\r\n\t}\r\n\tpublic getCurrentScrollTop(): number {\r\n\t\tconst currentScrollPosition = this._scrollable.getCurrentScrollPosition();\r\n\t\treturn currentScrollPosition.scrollTop;\r\n\t}\r\n\r\n\tpublic validateScrollPosition(scrollPosition: INewScrollPosition): IScrollPosition {\r\n\t\treturn this._scrollable.validateScrollPosition(scrollPosition);\r\n\t}\r\n\r\n\tpublic setScrollPosition(position: INewScrollPosition, type: ScrollType): void {\r\n\t\tif (type === ScrollType.Immediate) {\r\n\t\t\tthis._scrollable.setScrollPositionNow(position);\r\n\t\t} else {\r\n\t\t\tthis._scrollable.setScrollPositionSmooth(position);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic deltaScrollNow(deltaScrollLeft: number, deltaScrollTop: number): void {\r\n\t\tconst currentScrollPosition = this._scrollable.getCurrentScrollPosition();\r\n\t\tthis._scrollable.setScrollPositionNow({\r\n\t\t\tscrollLeft: currentScrollPosition.scrollLeft + deltaScrollLeft,\r\n\t\t\tscrollTop: currentScrollPosition.scrollTop + deltaScrollTop\r\n\t\t});\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { ICommand, ICursorStateComputerData, IEditOperationBuilder } from 'vs/editor/common/editorCommon';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\n\r\nexport class MoveCaretCommand implements ICommand {\r\n\r\n\tprivate readonly _selection: Selection;\r\n\tprivate readonly _isMovingLeft: boolean;\r\n\r\n\tconstructor(selection: Selection, isMovingLeft: boolean) {\r\n\t\tthis._selection = selection;\r\n\t\tthis._isMovingLeft = isMovingLeft;\r\n\t}\r\n\r\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\r\n\t\tif (this._selection.startLineNumber !== this._selection.endLineNumber || this._selection.isEmpty()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst lineNumber = this._selection.startLineNumber;\r\n\t\tconst startColumn = this._selection.startColumn;\r\n\t\tconst endColumn = this._selection.endColumn;\r\n\t\tif (this._isMovingLeft && startColumn === 1) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (!this._isMovingLeft && endColumn === model.getLineMaxColumn(lineNumber)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this._isMovingLeft) {\r\n\t\t\tconst rangeBefore = new Range(lineNumber, startColumn - 1, lineNumber, startColumn);\r\n\t\t\tconst charBefore = model.getValueInRange(rangeBefore);\r\n\t\t\tbuilder.addEditOperation(rangeBefore, null);\r\n\t\t\tbuilder.addEditOperation(new Range(lineNumber, endColumn, lineNumber, endColumn), charBefore);\r\n\t\t} else {\r\n\t\t\tconst rangeAfter = new Range(lineNumber, endColumn, lineNumber, endColumn + 1);\r\n\t\t\tconst charAfter = model.getValueInRange(rangeAfter);\r\n\t\t\tbuilder.addEditOperation(rangeAfter, null);\r\n\t\t\tbuilder.addEditOperation(new Range(lineNumber, startColumn, lineNumber, startColumn), charAfter);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\r\n\t\tif (this._isMovingLeft) {\r\n\t\t\treturn new Selection(this._selection.startLineNumber, this._selection.startColumn - 1, this._selection.endLineNumber, this._selection.endColumn - 1);\r\n\t\t} else {\r\n\t\t\treturn new Selection(this._selection.startLineNumber, this._selection.startColumn + 1, this._selection.endLineNumber, this._selection.endColumn + 1);\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CodeAction, CodeActionTriggerType } from 'vs/editor/common/modes';\r\nimport { Position } from 'vs/editor/common/core/position';\r\n\r\nexport class CodeActionKind {\r\n\tprivate static readonly sep = '.';\r\n\r\n\tpublic static readonly None = new CodeActionKind('@@none@@'); // Special code action that contains nothing\r\n\tpublic static readonly Empty = new CodeActionKind('');\r\n\tpublic static readonly QuickFix = new CodeActionKind('quickfix');\r\n\tpublic static readonly Refactor = new CodeActionKind('refactor');\r\n\tpublic static readonly Source = new CodeActionKind('source');\r\n\tpublic static readonly SourceOrganizeImports = CodeActionKind.Source.append('organizeImports');\r\n\tpublic static readonly SourceFixAll = CodeActionKind.Source.append('fixAll');\r\n\r\n\tconstructor(\r\n\t\tpublic readonly value: string\r\n\t) { }\r\n\r\n\tpublic equals(other: CodeActionKind): boolean {\r\n\t\treturn this.value === other.value;\r\n\t}\r\n\r\n\tpublic contains(other: CodeActionKind): boolean {\r\n\t\treturn this.equals(other) || this.value === '' || other.value.startsWith(this.value + CodeActionKind.sep);\r\n\t}\r\n\r\n\tpublic intersects(other: CodeActionKind): boolean {\r\n\t\treturn this.contains(other) || other.contains(this);\r\n\t}\r\n\r\n\tpublic append(part: string): CodeActionKind {\r\n\t\treturn new CodeActionKind(this.value + CodeActionKind.sep + part);\r\n\t}\r\n}\r\n\r\nexport const enum CodeActionAutoApply {\r\n\tIfSingle = 'ifSingle',\r\n\tFirst = 'first',\r\n\tNever = 'never',\r\n}\r\n\r\nexport interface CodeActionFilter {\r\n\treadonly include?: CodeActionKind;\r\n\treadonly excludes?: readonly CodeActionKind[];\r\n\treadonly includeSourceActions?: boolean;\r\n\treadonly onlyIncludePreferredActions?: boolean;\r\n}\r\n\r\nexport function mayIncludeActionsOfKind(filter: CodeActionFilter, providedKind: CodeActionKind): boolean {\r\n\t// A provided kind may be a subset or superset of our filtered kind.\r\n\tif (filter.include && !filter.include.intersects(providedKind)) {\r\n\t\treturn false;\r\n\t}\r\n\r\n\tif (filter.excludes) {\r\n\t\tif (filter.excludes.some(exclude => excludesAction(providedKind, exclude, filter.include))) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n\r\n\t// Don't return source actions unless they are explicitly requested\r\n\tif (!filter.includeSourceActions && CodeActionKind.Source.contains(providedKind)) {\r\n\t\treturn false;\r\n\t}\r\n\r\n\treturn true;\r\n}\r\n\r\nexport function filtersAction(filter: CodeActionFilter, action: CodeAction): boolean {\r\n\tconst actionKind = action.kind ? new CodeActionKind(action.kind) : undefined;\r\n\r\n\t// Filter out actions by kind\r\n\tif (filter.include) {\r\n\t\tif (!actionKind || !filter.include.contains(actionKind)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n\r\n\tif (filter.excludes) {\r\n\t\tif (actionKind && filter.excludes.some(exclude => excludesAction(actionKind, exclude, filter.include))) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n\r\n\t// Don't return source actions unless they are explicitly requested\r\n\tif (!filter.includeSourceActions) {\r\n\t\tif (actionKind && CodeActionKind.Source.contains(actionKind)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n\r\n\tif (filter.onlyIncludePreferredActions) {\r\n\t\tif (!action.isPreferred) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n\r\n\treturn true;\r\n}\r\n\r\nfunction excludesAction(providedKind: CodeActionKind, exclude: CodeActionKind, include: CodeActionKind | undefined): boolean {\r\n\tif (!exclude.contains(providedKind)) {\r\n\t\treturn false;\r\n\t}\r\n\tif (include && exclude.contains(include)) {\r\n\t\t// The include is more specific, don't filter out\r\n\t\treturn false;\r\n\t}\r\n\treturn true;\r\n}\r\n\r\nexport interface CodeActionTrigger {\r\n\treadonly type: CodeActionTriggerType;\r\n\treadonly filter?: CodeActionFilter;\r\n\treadonly autoApply?: CodeActionAutoApply;\r\n\treadonly context?: {\r\n\t\treadonly notAvailableMessage: string;\r\n\t\treadonly position: Position;\r\n\t};\r\n}\r\n\r\nexport class CodeActionCommandArgs {\r\n\tpublic static fromUser(arg: any, defaults: { kind: CodeActionKind, apply: CodeActionAutoApply }): CodeActionCommandArgs {\r\n\t\tif (!arg || typeof arg !== 'object') {\r\n\t\t\treturn new CodeActionCommandArgs(defaults.kind, defaults.apply, false);\r\n\t\t}\r\n\t\treturn new CodeActionCommandArgs(\r\n\t\t\tCodeActionCommandArgs.getKindFromUser(arg, defaults.kind),\r\n\t\t\tCodeActionCommandArgs.getApplyFromUser(arg, defaults.apply),\r\n\t\t\tCodeActionCommandArgs.getPreferredUser(arg));\r\n\t}\r\n\r\n\tprivate static getApplyFromUser(arg: any, defaultAutoApply: CodeActionAutoApply) {\r\n\t\tswitch (typeof arg.apply === 'string' ? arg.apply.toLowerCase() : '') {\r\n\t\t\tcase 'first': return CodeActionAutoApply.First;\r\n\t\t\tcase 'never': return CodeActionAutoApply.Never;\r\n\t\t\tcase 'ifsingle': return CodeActionAutoApply.IfSingle;\r\n\t\t\tdefault: return defaultAutoApply;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static getKindFromUser(arg: any, defaultKind: CodeActionKind) {\r\n\t\treturn typeof arg.kind === 'string'\r\n\t\t\t? new CodeActionKind(arg.kind)\r\n\t\t\t: defaultKind;\r\n\t}\r\n\r\n\tprivate static getPreferredUser(arg: any): boolean {\r\n\t\treturn typeof arg.preferred === 'boolean'\r\n\t\t\t? arg.preferred\r\n\t\t\t: false;\r\n\t}\r\n\r\n\tprivate constructor(\r\n\t\tpublic readonly kind: CodeActionKind,\r\n\t\tpublic readonly apply: CodeActionAutoApply,\r\n\t\tpublic readonly preferred: boolean,\r\n\t) { }\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Color } from 'vs/base/common/color';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { IColorPresentation } from 'vs/editor/common/modes';\r\n\r\nexport class ColorPickerModel {\r\n\r\n\treadonly originalColor: Color;\r\n\tprivate _color: Color;\r\n\r\n\tget color(): Color {\r\n\t\treturn this._color;\r\n\t}\r\n\r\n\tset color(color: Color) {\r\n\t\tif (this._color.equals(color)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._color = color;\r\n\t\tthis._onDidChangeColor.fire(color);\r\n\t}\r\n\r\n\tget presentation(): IColorPresentation { return this.colorPresentations[this.presentationIndex]; }\r\n\r\n\tprivate _colorPresentations: IColorPresentation[];\r\n\r\n\tget colorPresentations(): IColorPresentation[] {\r\n\t\treturn this._colorPresentations;\r\n\t}\r\n\r\n\tset colorPresentations(colorPresentations: IColorPresentation[]) {\r\n\t\tthis._colorPresentations = colorPresentations;\r\n\t\tif (this.presentationIndex > colorPresentations.length - 1) {\r\n\t\t\tthis.presentationIndex = 0;\r\n\t\t}\r\n\t\tthis._onDidChangePresentation.fire(this.presentation);\r\n\t}\r\n\r\n\tprivate readonly _onColorFlushed = new Emitter();\r\n\treadonly onColorFlushed: Event = this._onColorFlushed.event;\r\n\r\n\tprivate readonly _onDidChangeColor = new Emitter();\r\n\treadonly onDidChangeColor: Event = this._onDidChangeColor.event;\r\n\r\n\tprivate readonly _onDidChangePresentation = new Emitter();\r\n\treadonly onDidChangePresentation: Event = this._onDidChangePresentation.event;\r\n\r\n\tconstructor(color: Color, availableColorPresentations: IColorPresentation[], private presentationIndex: number) {\r\n\t\tthis.originalColor = color;\r\n\t\tthis._color = color;\r\n\t\tthis._colorPresentations = availableColorPresentations;\r\n\t}\r\n\r\n\tselectNextColorPresentation(): void {\r\n\t\tthis.presentationIndex = (this.presentationIndex + 1) % this.colorPresentations.length;\r\n\t\tthis.flushColor();\r\n\t\tthis._onDidChangePresentation.fire(this.presentation);\r\n\t}\r\n\r\n\tguessColorPresentation(color: Color, originalText: string): void {\r\n\t\tfor (let i = 0; i < this.colorPresentations.length; i++) {\r\n\t\t\tif (originalText.toLowerCase() === this.colorPresentations[i].label) {\r\n\t\t\t\tthis.presentationIndex = i;\r\n\t\t\t\tthis._onDidChangePresentation.fire(this.presentation);\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tflushColor(): void {\r\n\t\tthis._onColorFlushed.fire(this._color);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport { EditOperation } from 'vs/editor/common/core/editOperation';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { ICommand, IEditOperationBuilder, ICursorStateComputerData } from 'vs/editor/common/editorCommon';\r\nimport { ITextModel, IIdentifiedSingleEditOperation } from 'vs/editor/common/model';\r\nimport { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';\r\n\r\nexport class BlockCommentCommand implements ICommand {\r\n\r\n\tprivate readonly _selection: Selection;\r\n\tprivate readonly _insertSpace: boolean;\r\n\tprivate _usedEndToken: string | null;\r\n\r\n\tconstructor(selection: Selection, insertSpace: boolean) {\r\n\t\tthis._selection = selection;\r\n\t\tthis._insertSpace = insertSpace;\r\n\t\tthis._usedEndToken = null;\r\n\t}\r\n\r\n\tpublic static _haystackHasNeedleAtOffset(haystack: string, needle: string, offset: number): boolean {\r\n\t\tif (offset < 0) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tconst needleLength = needle.length;\r\n\t\tconst haystackLength = haystack.length;\r\n\t\tif (offset + needleLength > haystackLength) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tfor (let i = 0; i < needleLength; i++) {\r\n\t\t\tconst codeA = haystack.charCodeAt(offset + i);\r\n\t\t\tconst codeB = needle.charCodeAt(i);\r\n\r\n\t\t\tif (codeA === codeB) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (codeA >= CharCode.A && codeA <= CharCode.Z && codeA + 32 === codeB) {\r\n\t\t\t\t// codeA is upper-case variant of codeB\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (codeB >= CharCode.A && codeB <= CharCode.Z && codeB + 32 === codeA) {\r\n\t\t\t\t// codeB is upper-case variant of codeA\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\tprivate _createOperationsForBlockComment(selection: Range, startToken: string, endToken: string, insertSpace: boolean, model: ITextModel, builder: IEditOperationBuilder): void {\r\n\t\tconst startLineNumber = selection.startLineNumber;\r\n\t\tconst startColumn = selection.startColumn;\r\n\t\tconst endLineNumber = selection.endLineNumber;\r\n\t\tconst endColumn = selection.endColumn;\r\n\r\n\t\tconst startLineText = model.getLineContent(startLineNumber);\r\n\t\tconst endLineText = model.getLineContent(endLineNumber);\r\n\r\n\t\tlet startTokenIndex = startLineText.lastIndexOf(startToken, startColumn - 1 + startToken.length);\r\n\t\tlet endTokenIndex = endLineText.indexOf(endToken, endColumn - 1 - endToken.length);\r\n\r\n\t\tif (startTokenIndex !== -1 && endTokenIndex !== -1) {\r\n\r\n\t\t\tif (startLineNumber === endLineNumber) {\r\n\t\t\t\tconst lineBetweenTokens = startLineText.substring(startTokenIndex + startToken.length, endTokenIndex);\r\n\r\n\t\t\t\tif (lineBetweenTokens.indexOf(endToken) >= 0) {\r\n\t\t\t\t\t// force to add a block comment\r\n\t\t\t\t\tstartTokenIndex = -1;\r\n\t\t\t\t\tendTokenIndex = -1;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tconst startLineAfterStartToken = startLineText.substring(startTokenIndex + startToken.length);\r\n\t\t\t\tconst endLineBeforeEndToken = endLineText.substring(0, endTokenIndex);\r\n\r\n\t\t\t\tif (startLineAfterStartToken.indexOf(endToken) >= 0 || endLineBeforeEndToken.indexOf(endToken) >= 0) {\r\n\t\t\t\t\t// force to add a block comment\r\n\t\t\t\t\tstartTokenIndex = -1;\r\n\t\t\t\t\tendTokenIndex = -1;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet ops: IIdentifiedSingleEditOperation[];\r\n\r\n\t\tif (startTokenIndex !== -1 && endTokenIndex !== -1) {\r\n\t\t\t// Consider spaces as part of the comment tokens\r\n\t\t\tif (insertSpace && startTokenIndex + startToken.length < startLineText.length && startLineText.charCodeAt(startTokenIndex + startToken.length) === CharCode.Space) {\r\n\t\t\t\t// Pretend the start token contains a trailing space\r\n\t\t\t\tstartToken = startToken + ' ';\r\n\t\t\t}\r\n\r\n\t\t\tif (insertSpace && endTokenIndex > 0 && endLineText.charCodeAt(endTokenIndex - 1) === CharCode.Space) {\r\n\t\t\t\t// Pretend the end token contains a leading space\r\n\t\t\t\tendToken = ' ' + endToken;\r\n\t\t\t\tendTokenIndex -= 1;\r\n\t\t\t}\r\n\t\t\tops = BlockCommentCommand._createRemoveBlockCommentOperations(\r\n\t\t\t\tnew Range(startLineNumber, startTokenIndex + startToken.length + 1, endLineNumber, endTokenIndex + 1), startToken, endToken\r\n\t\t\t);\r\n\t\t} else {\r\n\t\t\tops = BlockCommentCommand._createAddBlockCommentOperations(selection, startToken, endToken, this._insertSpace);\r\n\t\t\tthis._usedEndToken = ops.length === 1 ? endToken : null;\r\n\t\t}\r\n\r\n\t\tfor (const op of ops) {\r\n\t\t\tbuilder.addTrackedEditOperation(op.range, op.text);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic static _createRemoveBlockCommentOperations(r: Range, startToken: string, endToken: string): IIdentifiedSingleEditOperation[] {\r\n\t\tlet res: IIdentifiedSingleEditOperation[] = [];\r\n\r\n\t\tif (!Range.isEmpty(r)) {\r\n\t\t\t// Remove block comment start\r\n\t\t\tres.push(EditOperation.delete(new Range(\r\n\t\t\t\tr.startLineNumber, r.startColumn - startToken.length,\r\n\t\t\t\tr.startLineNumber, r.startColumn\r\n\t\t\t)));\r\n\r\n\t\t\t// Remove block comment end\r\n\t\t\tres.push(EditOperation.delete(new Range(\r\n\t\t\t\tr.endLineNumber, r.endColumn,\r\n\t\t\t\tr.endLineNumber, r.endColumn + endToken.length\r\n\t\t\t)));\r\n\t\t} else {\r\n\t\t\t// Remove both continuously\r\n\t\t\tres.push(EditOperation.delete(new Range(\r\n\t\t\t\tr.startLineNumber, r.startColumn - startToken.length,\r\n\t\t\t\tr.endLineNumber, r.endColumn + endToken.length\r\n\t\t\t)));\r\n\t\t}\r\n\r\n\t\treturn res;\r\n\t}\r\n\r\n\tpublic static _createAddBlockCommentOperations(r: Range, startToken: string, endToken: string, insertSpace: boolean): IIdentifiedSingleEditOperation[] {\r\n\t\tlet res: IIdentifiedSingleEditOperation[] = [];\r\n\r\n\t\tif (!Range.isEmpty(r)) {\r\n\t\t\t// Insert block comment start\r\n\t\t\tres.push(EditOperation.insert(new Position(r.startLineNumber, r.startColumn), startToken + (insertSpace ? ' ' : '')));\r\n\r\n\t\t\t// Insert block comment end\r\n\t\t\tres.push(EditOperation.insert(new Position(r.endLineNumber, r.endColumn), (insertSpace ? ' ' : '') + endToken));\r\n\t\t} else {\r\n\t\t\t// Insert both continuously\r\n\t\t\tres.push(EditOperation.replace(new Range(\r\n\t\t\t\tr.startLineNumber, r.startColumn,\r\n\t\t\t\tr.endLineNumber, r.endColumn\r\n\t\t\t), startToken + ' ' + endToken));\r\n\t\t}\r\n\r\n\t\treturn res;\r\n\t}\r\n\r\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\r\n\t\tconst startLineNumber = this._selection.startLineNumber;\r\n\t\tconst startColumn = this._selection.startColumn;\r\n\r\n\t\tmodel.tokenizeIfCheap(startLineNumber);\r\n\t\tconst languageId = model.getLanguageIdAtPosition(startLineNumber, startColumn);\r\n\t\tconst config = LanguageConfigurationRegistry.getComments(languageId);\r\n\t\tif (!config || !config.blockCommentStartToken || !config.blockCommentEndToken) {\r\n\t\t\t// Mode does not support block comments\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._createOperationsForBlockComment(this._selection, config.blockCommentStartToken, config.blockCommentEndToken, this._insertSpace, model, builder);\r\n\t}\r\n\r\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\r\n\t\tconst inverseEditOperations = helper.getInverseEditOperations();\r\n\t\tif (inverseEditOperations.length === 2) {\r\n\t\t\tconst startTokenEditOperation = inverseEditOperations[0];\r\n\t\t\tconst endTokenEditOperation = inverseEditOperations[1];\r\n\r\n\t\t\treturn new Selection(\r\n\t\t\t\tstartTokenEditOperation.range.endLineNumber,\r\n\t\t\t\tstartTokenEditOperation.range.endColumn,\r\n\t\t\t\tendTokenEditOperation.range.startLineNumber,\r\n\t\t\t\tendTokenEditOperation.range.startColumn\r\n\t\t\t);\r\n\t\t} else {\r\n\t\t\tconst srcRange = inverseEditOperations[0].range;\r\n\t\t\tconst deltaColumn = this._usedEndToken ? -this._usedEndToken.length - 1 : 0; // minus 1 space before endToken\r\n\t\t\treturn new Selection(\r\n\t\t\t\tsrcRange.endLineNumber,\r\n\t\t\t\tsrcRange.endColumn + deltaColumn,\r\n\t\t\t\tsrcRange.endLineNumber,\r\n\t\t\t\tsrcRange.endColumn + deltaColumn\r\n\t\t\t);\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { EditOperation } from 'vs/editor/common/core/editOperation';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { ICommand, IEditOperationBuilder, ICursorStateComputerData } from 'vs/editor/common/editorCommon';\r\nimport { IIdentifiedSingleEditOperation, ITextModel } from 'vs/editor/common/model';\r\nimport { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';\r\nimport { BlockCommentCommand } from 'vs/editor/contrib/comment/blockCommentCommand';\r\nimport { Constants } from 'vs/base/common/uint';\r\n\r\nexport interface IInsertionPoint {\r\n\tignore: boolean;\r\n\tcommentStrOffset: number;\r\n}\r\n\r\nexport interface ILinePreflightData {\r\n\tignore: boolean;\r\n\tcommentStr: string;\r\n\tcommentStrOffset: number;\r\n\tcommentStrLength: number;\r\n}\r\n\r\nexport interface IPreflightDataSupported {\r\n\tsupported: true;\r\n\tshouldRemoveComments: boolean;\r\n\tlines: ILinePreflightData[];\r\n}\r\nexport interface IPreflightDataUnsupported {\r\n\tsupported: false;\r\n}\r\nexport type IPreflightData = IPreflightDataSupported | IPreflightDataUnsupported;\r\n\r\nexport interface ISimpleModel {\r\n\tgetLineContent(lineNumber: number): string;\r\n}\r\n\r\nexport const enum Type {\r\n\tToggle = 0,\r\n\tForceAdd = 1,\r\n\tForceRemove = 2\r\n}\r\n\r\nexport class LineCommentCommand implements ICommand {\r\n\r\n\tprivate readonly _selection: Selection;\r\n\tprivate readonly _tabSize: number;\r\n\tprivate readonly _type: Type;\r\n\tprivate readonly _insertSpace: boolean;\r\n\tprivate readonly _ignoreEmptyLines: boolean;\r\n\tprivate _selectionId: string | null;\r\n\tprivate _deltaColumn: number;\r\n\tprivate _moveEndPositionDown: boolean;\r\n\tprivate _ignoreFirstLine: boolean;\r\n\r\n\tconstructor(\r\n\t\tselection: Selection,\r\n\t\ttabSize: number,\r\n\t\ttype: Type,\r\n\t\tinsertSpace: boolean,\r\n\t\tignoreEmptyLines: boolean,\r\n\t\tignoreFirstLine?: boolean\r\n\t) {\r\n\t\tthis._selection = selection;\r\n\t\tthis._tabSize = tabSize;\r\n\t\tthis._type = type;\r\n\t\tthis._insertSpace = insertSpace;\r\n\t\tthis._selectionId = null;\r\n\t\tthis._deltaColumn = 0;\r\n\t\tthis._moveEndPositionDown = false;\r\n\t\tthis._ignoreEmptyLines = ignoreEmptyLines;\r\n\t\tthis._ignoreFirstLine = ignoreFirstLine || false;\r\n\t}\r\n\r\n\t/**\r\n\t * Do an initial pass over the lines and gather info about the line comment string.\r\n\t * Returns null if any of the lines doesn't support a line comment string.\r\n\t */\r\n\tpublic static _gatherPreflightCommentStrings(model: ITextModel, startLineNumber: number, endLineNumber: number): ILinePreflightData[] | null {\r\n\r\n\t\tmodel.tokenizeIfCheap(startLineNumber);\r\n\t\tconst languageId = model.getLanguageIdAtPosition(startLineNumber, 1);\r\n\r\n\t\tconst config = LanguageConfigurationRegistry.getComments(languageId);\r\n\t\tconst commentStr = (config ? config.lineCommentToken : null);\r\n\t\tif (!commentStr) {\r\n\t\t\t// Mode does not support line comments\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet lines: ILinePreflightData[] = [];\r\n\t\tfor (let i = 0, lineCount = endLineNumber - startLineNumber + 1; i < lineCount; i++) {\r\n\t\t\tlines[i] = {\r\n\t\t\t\tignore: false,\r\n\t\t\t\tcommentStr: commentStr,\r\n\t\t\t\tcommentStrOffset: 0,\r\n\t\t\t\tcommentStrLength: commentStr.length\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\treturn lines;\r\n\t}\r\n\r\n\t/**\r\n\t * Analyze lines and decide which lines are relevant and what the toggle should do.\r\n\t * Also, build up several offsets and lengths useful in the generation of editor operations.\r\n\t */\r\n\tpublic static _analyzeLines(type: Type, insertSpace: boolean, model: ISimpleModel, lines: ILinePreflightData[], startLineNumber: number, ignoreEmptyLines: boolean, ignoreFirstLine: boolean): IPreflightData {\r\n\t\tlet onlyWhitespaceLines = true;\r\n\r\n\t\tlet shouldRemoveComments: boolean;\r\n\t\tif (type === Type.Toggle) {\r\n\t\t\tshouldRemoveComments = true;\r\n\t\t} else if (type === Type.ForceAdd) {\r\n\t\t\tshouldRemoveComments = false;\r\n\t\t} else {\r\n\t\t\tshouldRemoveComments = true;\r\n\t\t}\r\n\r\n\t\tfor (let i = 0, lineCount = lines.length; i < lineCount; i++) {\r\n\t\t\tconst lineData = lines[i];\r\n\t\t\tconst lineNumber = startLineNumber + i;\r\n\r\n\t\t\tif (lineNumber === startLineNumber && ignoreFirstLine) {\r\n\t\t\t\t// first line ignored\r\n\t\t\t\tlineData.ignore = true;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tconst lineContent = model.getLineContent(lineNumber);\r\n\t\t\tconst lineContentStartOffset = strings.firstNonWhitespaceIndex(lineContent);\r\n\r\n\t\t\tif (lineContentStartOffset === -1) {\r\n\t\t\t\t// Empty or whitespace only line\r\n\t\t\t\tlineData.ignore = ignoreEmptyLines;\r\n\t\t\t\tlineData.commentStrOffset = lineContent.length;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tonlyWhitespaceLines = false;\r\n\t\t\tlineData.ignore = false;\r\n\t\t\tlineData.commentStrOffset = lineContentStartOffset;\r\n\r\n\t\t\tif (shouldRemoveComments && !BlockCommentCommand._haystackHasNeedleAtOffset(lineContent, lineData.commentStr, lineContentStartOffset)) {\r\n\t\t\t\tif (type === Type.Toggle) {\r\n\t\t\t\t\t// Every line so far has been a line comment, but this one is not\r\n\t\t\t\t\tshouldRemoveComments = false;\r\n\t\t\t\t} else if (type === Type.ForceAdd) {\r\n\t\t\t\t\t// Will not happen\r\n\t\t\t\t} else {\r\n\t\t\t\t\tlineData.ignore = true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (shouldRemoveComments && insertSpace) {\r\n\t\t\t\t// Remove a following space if present\r\n\t\t\t\tconst commentStrEndOffset = lineContentStartOffset + lineData.commentStrLength;\r\n\t\t\t\tif (commentStrEndOffset < lineContent.length && lineContent.charCodeAt(commentStrEndOffset) === CharCode.Space) {\r\n\t\t\t\t\tlineData.commentStrLength += 1;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (type === Type.Toggle && onlyWhitespaceLines) {\r\n\t\t\t// For only whitespace lines, we insert comments\r\n\t\t\tshouldRemoveComments = false;\r\n\r\n\t\t\t// Also, no longer ignore them\r\n\t\t\tfor (let i = 0, lineCount = lines.length; i < lineCount; i++) {\r\n\t\t\t\tlines[i].ignore = false;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tsupported: true,\r\n\t\t\tshouldRemoveComments: shouldRemoveComments,\r\n\t\t\tlines: lines\r\n\t\t};\r\n\t}\r\n\r\n\t/**\r\n\t * Analyze all lines and decide exactly what to do => not supported | insert line comments | remove line comments\r\n\t */\r\n\tpublic static _gatherPreflightData(type: Type, insertSpace: boolean, model: ITextModel, startLineNumber: number, endLineNumber: number, ignoreEmptyLines: boolean, ignoreFirstLine: boolean): IPreflightData {\r\n\t\tconst lines = LineCommentCommand._gatherPreflightCommentStrings(model, startLineNumber, endLineNumber);\r\n\t\tif (lines === null) {\r\n\t\t\treturn {\r\n\t\t\t\tsupported: false\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\treturn LineCommentCommand._analyzeLines(type, insertSpace, model, lines, startLineNumber, ignoreEmptyLines, ignoreFirstLine);\r\n\t}\r\n\r\n\t/**\r\n\t * Given a successful analysis, execute either insert line comments, either remove line comments\r\n\t */\r\n\tprivate _executeLineComments(model: ISimpleModel, builder: IEditOperationBuilder, data: IPreflightDataSupported, s: Selection): void {\r\n\r\n\t\tlet ops: IIdentifiedSingleEditOperation[];\r\n\r\n\t\tif (data.shouldRemoveComments) {\r\n\t\t\tops = LineCommentCommand._createRemoveLineCommentsOperations(data.lines, s.startLineNumber);\r\n\t\t} else {\r\n\t\t\tLineCommentCommand._normalizeInsertionPoint(model, data.lines, s.startLineNumber, this._tabSize);\r\n\t\t\tops = this._createAddLineCommentsOperations(data.lines, s.startLineNumber);\r\n\t\t}\r\n\r\n\t\tconst cursorPosition = new Position(s.positionLineNumber, s.positionColumn);\r\n\r\n\t\tfor (let i = 0, len = ops.length; i < len; i++) {\r\n\t\t\tbuilder.addEditOperation(ops[i].range, ops[i].text);\r\n\t\t\tif (Range.isEmpty(ops[i].range) && Range.getStartPosition(ops[i].range).equals(cursorPosition)) {\r\n\t\t\t\tconst lineContent = model.getLineContent(cursorPosition.lineNumber);\r\n\t\t\t\tif (lineContent.length + 1 === cursorPosition.column) {\r\n\t\t\t\t\tthis._deltaColumn = (ops[i].text || '').length;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._selectionId = builder.trackSelection(s);\r\n\t}\r\n\r\n\tprivate _attemptRemoveBlockComment(model: ITextModel, s: Selection, startToken: string, endToken: string): IIdentifiedSingleEditOperation[] | null {\r\n\t\tlet startLineNumber = s.startLineNumber;\r\n\t\tlet endLineNumber = s.endLineNumber;\r\n\r\n\t\tlet startTokenAllowedBeforeColumn = endToken.length + Math.max(\r\n\t\t\tmodel.getLineFirstNonWhitespaceColumn(s.startLineNumber),\r\n\t\t\ts.startColumn\r\n\t\t);\r\n\r\n\t\tlet startTokenIndex = model.getLineContent(startLineNumber).lastIndexOf(startToken, startTokenAllowedBeforeColumn - 1);\r\n\t\tlet endTokenIndex = model.getLineContent(endLineNumber).indexOf(endToken, s.endColumn - 1 - startToken.length);\r\n\r\n\t\tif (startTokenIndex !== -1 && endTokenIndex === -1) {\r\n\t\t\tendTokenIndex = model.getLineContent(startLineNumber).indexOf(endToken, startTokenIndex + startToken.length);\r\n\t\t\tendLineNumber = startLineNumber;\r\n\t\t}\r\n\r\n\t\tif (startTokenIndex === -1 && endTokenIndex !== -1) {\r\n\t\t\tstartTokenIndex = model.getLineContent(endLineNumber).lastIndexOf(startToken, endTokenIndex);\r\n\t\t\tstartLineNumber = endLineNumber;\r\n\t\t}\r\n\r\n\t\tif (s.isEmpty() && (startTokenIndex === -1 || endTokenIndex === -1)) {\r\n\t\t\tstartTokenIndex = model.getLineContent(startLineNumber).indexOf(startToken);\r\n\t\t\tif (startTokenIndex !== -1) {\r\n\t\t\t\tendTokenIndex = model.getLineContent(startLineNumber).indexOf(endToken, startTokenIndex + startToken.length);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// We have to adjust to possible inner white space.\r\n\t\t// For Space after startToken, add Space to startToken - range math will work out.\r\n\t\tif (startTokenIndex !== -1 && model.getLineContent(startLineNumber).charCodeAt(startTokenIndex + startToken.length) === CharCode.Space) {\r\n\t\t\tstartToken += ' ';\r\n\t\t}\r\n\r\n\t\t// For Space before endToken, add Space before endToken and shift index one left.\r\n\t\tif (endTokenIndex !== -1 && model.getLineContent(endLineNumber).charCodeAt(endTokenIndex - 1) === CharCode.Space) {\r\n\t\t\tendToken = ' ' + endToken;\r\n\t\t\tendTokenIndex -= 1;\r\n\t\t}\r\n\r\n\t\tif (startTokenIndex !== -1 && endTokenIndex !== -1) {\r\n\t\t\treturn BlockCommentCommand._createRemoveBlockCommentOperations(\r\n\t\t\t\tnew Range(startLineNumber, startTokenIndex + startToken.length + 1, endLineNumber, endTokenIndex + 1), startToken, endToken\r\n\t\t\t);\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\t/**\r\n\t * Given an unsuccessful analysis, delegate to the block comment command\r\n\t */\r\n\tprivate _executeBlockComment(model: ITextModel, builder: IEditOperationBuilder, s: Selection): void {\r\n\t\tmodel.tokenizeIfCheap(s.startLineNumber);\r\n\t\tlet languageId = model.getLanguageIdAtPosition(s.startLineNumber, 1);\r\n\t\tlet config = LanguageConfigurationRegistry.getComments(languageId);\r\n\t\tif (!config || !config.blockCommentStartToken || !config.blockCommentEndToken) {\r\n\t\t\t// Mode does not support block comments\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst startToken = config.blockCommentStartToken;\r\n\t\tconst endToken = config.blockCommentEndToken;\r\n\r\n\t\tlet ops = this._attemptRemoveBlockComment(model, s, startToken, endToken);\r\n\t\tif (!ops) {\r\n\t\t\tif (s.isEmpty()) {\r\n\t\t\t\tconst lineContent = model.getLineContent(s.startLineNumber);\r\n\t\t\t\tlet firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(lineContent);\r\n\t\t\t\tif (firstNonWhitespaceIndex === -1) {\r\n\t\t\t\t\t// Line is empty or contains only whitespace\r\n\t\t\t\t\tfirstNonWhitespaceIndex = lineContent.length;\r\n\t\t\t\t}\r\n\t\t\t\tops = BlockCommentCommand._createAddBlockCommentOperations(\r\n\t\t\t\t\tnew Range(s.startLineNumber, firstNonWhitespaceIndex + 1, s.startLineNumber, lineContent.length + 1),\r\n\t\t\t\t\tstartToken,\r\n\t\t\t\t\tendToken,\r\n\t\t\t\t\tthis._insertSpace\r\n\t\t\t\t);\r\n\t\t\t} else {\r\n\t\t\t\tops = BlockCommentCommand._createAddBlockCommentOperations(\r\n\t\t\t\t\tnew Range(s.startLineNumber, model.getLineFirstNonWhitespaceColumn(s.startLineNumber), s.endLineNumber, model.getLineMaxColumn(s.endLineNumber)),\r\n\t\t\t\t\tstartToken,\r\n\t\t\t\t\tendToken,\r\n\t\t\t\t\tthis._insertSpace\r\n\t\t\t\t);\r\n\t\t\t}\r\n\r\n\t\t\tif (ops.length === 1) {\r\n\t\t\t\t// Leave cursor after token and Space\r\n\t\t\t\tthis._deltaColumn = startToken.length + 1;\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis._selectionId = builder.trackSelection(s);\r\n\t\tfor (const op of ops) {\r\n\t\t\tbuilder.addEditOperation(op.range, op.text);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\r\n\r\n\t\tlet s = this._selection;\r\n\t\tthis._moveEndPositionDown = false;\r\n\r\n\t\tif (s.startLineNumber === s.endLineNumber && this._ignoreFirstLine) {\r\n\t\t\tbuilder.addEditOperation(new Range(s.startLineNumber, model.getLineMaxColumn(s.startLineNumber), s.startLineNumber + 1, 1), s.startLineNumber === model.getLineCount() ? '' : '\\n');\r\n\t\t\tthis._selectionId = builder.trackSelection(s);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (s.startLineNumber < s.endLineNumber && s.endColumn === 1) {\r\n\t\t\tthis._moveEndPositionDown = true;\r\n\t\t\ts = s.setEndPosition(s.endLineNumber - 1, model.getLineMaxColumn(s.endLineNumber - 1));\r\n\t\t}\r\n\r\n\t\tconst data = LineCommentCommand._gatherPreflightData(\r\n\t\t\tthis._type,\r\n\t\t\tthis._insertSpace,\r\n\t\t\tmodel,\r\n\t\t\ts.startLineNumber,\r\n\t\t\ts.endLineNumber,\r\n\t\t\tthis._ignoreEmptyLines,\r\n\t\t\tthis._ignoreFirstLine\r\n\t\t);\r\n\r\n\t\tif (data.supported) {\r\n\t\t\treturn this._executeLineComments(model, builder, data, s);\r\n\t\t}\r\n\r\n\t\treturn this._executeBlockComment(model, builder, s);\r\n\t}\r\n\r\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\r\n\t\tlet result = helper.getTrackedSelection(this._selectionId!);\r\n\r\n\t\tif (this._moveEndPositionDown) {\r\n\t\t\tresult = result.setEndPosition(result.endLineNumber + 1, 1);\r\n\t\t}\r\n\r\n\t\treturn new Selection(\r\n\t\t\tresult.selectionStartLineNumber,\r\n\t\t\tresult.selectionStartColumn + this._deltaColumn,\r\n\t\t\tresult.positionLineNumber,\r\n\t\t\tresult.positionColumn + this._deltaColumn\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * Generate edit operations in the remove line comment case\r\n\t */\r\n\tpublic static _createRemoveLineCommentsOperations(lines: ILinePreflightData[], startLineNumber: number): IIdentifiedSingleEditOperation[] {\r\n\t\tlet res: IIdentifiedSingleEditOperation[] = [];\r\n\r\n\t\tfor (let i = 0, len = lines.length; i < len; i++) {\r\n\t\t\tconst lineData = lines[i];\r\n\r\n\t\t\tif (lineData.ignore) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tres.push(EditOperation.delete(new Range(\r\n\t\t\t\tstartLineNumber + i, lineData.commentStrOffset + 1,\r\n\t\t\t\tstartLineNumber + i, lineData.commentStrOffset + lineData.commentStrLength + 1\r\n\t\t\t)));\r\n\t\t}\r\n\r\n\t\treturn res;\r\n\t}\r\n\r\n\t/**\r\n\t * Generate edit operations in the add line comment case\r\n\t */\r\n\tprivate _createAddLineCommentsOperations(lines: ILinePreflightData[], startLineNumber: number): IIdentifiedSingleEditOperation[] {\r\n\t\tlet res: IIdentifiedSingleEditOperation[] = [];\r\n\t\tconst afterCommentStr = this._insertSpace ? ' ' : '';\r\n\r\n\r\n\t\tfor (let i = 0, len = lines.length; i < len; i++) {\r\n\t\t\tconst lineData = lines[i];\r\n\r\n\t\t\tif (lineData.ignore) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tres.push(EditOperation.insert(new Position(startLineNumber + i, lineData.commentStrOffset + 1), lineData.commentStr + afterCommentStr));\r\n\t\t}\r\n\r\n\t\treturn res;\r\n\t}\r\n\r\n\tprivate static nextVisibleColumn(currentVisibleColumn: number, tabSize: number, isTab: boolean, columnSize: number): number {\r\n\t\tif (isTab) {\r\n\t\t\treturn currentVisibleColumn + (tabSize - (currentVisibleColumn % tabSize));\r\n\t\t}\r\n\t\treturn currentVisibleColumn + columnSize;\r\n\t}\r\n\r\n\t/**\r\n\t * Adjust insertion points to have them vertically aligned in the add line comment case\r\n\t */\r\n\tpublic static _normalizeInsertionPoint(model: ISimpleModel, lines: IInsertionPoint[], startLineNumber: number, tabSize: number): void {\r\n\t\tlet minVisibleColumn = Constants.MAX_SAFE_SMALL_INTEGER;\r\n\t\tlet j: number;\r\n\t\tlet lenJ: number;\r\n\r\n\t\tfor (let i = 0, len = lines.length; i < len; i++) {\r\n\t\t\tif (lines[i].ignore) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tconst lineContent = model.getLineContent(startLineNumber + i);\r\n\r\n\t\t\tlet currentVisibleColumn = 0;\r\n\t\t\tfor (let j = 0, lenJ = lines[i].commentStrOffset; currentVisibleColumn < minVisibleColumn && j < lenJ; j++) {\r\n\t\t\t\tcurrentVisibleColumn = LineCommentCommand.nextVisibleColumn(currentVisibleColumn, tabSize, lineContent.charCodeAt(j) === CharCode.Tab, 1);\r\n\t\t\t}\r\n\r\n\t\t\tif (currentVisibleColumn < minVisibleColumn) {\r\n\t\t\t\tminVisibleColumn = currentVisibleColumn;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tminVisibleColumn = Math.floor(minVisibleColumn / tabSize) * tabSize;\r\n\r\n\t\tfor (let i = 0, len = lines.length; i < len; i++) {\r\n\t\t\tif (lines[i].ignore) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tconst lineContent = model.getLineContent(startLineNumber + i);\r\n\r\n\t\t\tlet currentVisibleColumn = 0;\r\n\t\t\tfor (j = 0, lenJ = lines[i].commentStrOffset; currentVisibleColumn < minVisibleColumn && j < lenJ; j++) {\r\n\t\t\t\tcurrentVisibleColumn = LineCommentCommand.nextVisibleColumn(currentVisibleColumn, tabSize, lineContent.charCodeAt(j) === CharCode.Tab, 1);\r\n\t\t\t}\r\n\r\n\t\t\tif (currentVisibleColumn > minVisibleColumn) {\r\n\t\t\t\tlines[i].commentStrOffset = j - 1;\r\n\t\t\t} else {\r\n\t\t\t\tlines[i].commentStrOffset = j;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { ICommand, IEditOperationBuilder, ICursorStateComputerData } from 'vs/editor/common/editorCommon';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\n\r\n\r\nexport class DragAndDropCommand implements ICommand {\r\n\r\n\tprivate readonly selection: Selection;\r\n\tprivate readonly targetPosition: Position;\r\n\tprivate targetSelection: Selection | null;\r\n\tprivate readonly copy: boolean;\r\n\r\n\tconstructor(selection: Selection, targetPosition: Position, copy: boolean) {\r\n\t\tthis.selection = selection;\r\n\t\tthis.targetPosition = targetPosition;\r\n\t\tthis.copy = copy;\r\n\t\tthis.targetSelection = null;\r\n\t}\r\n\r\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\r\n\t\tlet text = model.getValueInRange(this.selection);\r\n\t\tif (!this.copy) {\r\n\t\t\tbuilder.addEditOperation(this.selection, null);\r\n\t\t}\r\n\t\tbuilder.addEditOperation(new Range(this.targetPosition.lineNumber, this.targetPosition.column, this.targetPosition.lineNumber, this.targetPosition.column), text);\r\n\r\n\t\tif (this.selection.containsPosition(this.targetPosition) && !(\r\n\t\t\tthis.copy && (\r\n\t\t\t\tthis.selection.getEndPosition().equals(this.targetPosition) || this.selection.getStartPosition().equals(this.targetPosition)\r\n\t\t\t) // we allow users to paste content beside the selection\r\n\t\t)) {\r\n\t\t\tthis.targetSelection = this.selection;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this.copy) {\r\n\t\t\tthis.targetSelection = new Selection(\r\n\t\t\t\tthis.targetPosition.lineNumber,\r\n\t\t\t\tthis.targetPosition.column,\r\n\t\t\t\tthis.selection.endLineNumber - this.selection.startLineNumber + this.targetPosition.lineNumber,\r\n\t\t\t\tthis.selection.startLineNumber === this.selection.endLineNumber ?\r\n\t\t\t\t\tthis.targetPosition.column + this.selection.endColumn - this.selection.startColumn :\r\n\t\t\t\t\tthis.selection.endColumn\r\n\t\t\t);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this.targetPosition.lineNumber > this.selection.endLineNumber) {\r\n\t\t\t// Drag the selection downwards\r\n\t\t\tthis.targetSelection = new Selection(\r\n\t\t\t\tthis.targetPosition.lineNumber - this.selection.endLineNumber + this.selection.startLineNumber,\r\n\t\t\t\tthis.targetPosition.column,\r\n\t\t\t\tthis.targetPosition.lineNumber,\r\n\t\t\t\tthis.selection.startLineNumber === this.selection.endLineNumber ?\r\n\t\t\t\t\tthis.targetPosition.column + this.selection.endColumn - this.selection.startColumn :\r\n\t\t\t\t\tthis.selection.endColumn\r\n\t\t\t);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this.targetPosition.lineNumber < this.selection.endLineNumber) {\r\n\t\t\t// Drag the selection upwards\r\n\t\t\tthis.targetSelection = new Selection(\r\n\t\t\t\tthis.targetPosition.lineNumber,\r\n\t\t\t\tthis.targetPosition.column,\r\n\t\t\t\tthis.targetPosition.lineNumber + this.selection.endLineNumber - this.selection.startLineNumber,\r\n\t\t\t\tthis.selection.startLineNumber === this.selection.endLineNumber ?\r\n\t\t\t\t\tthis.targetPosition.column + this.selection.endColumn - this.selection.startColumn :\r\n\t\t\t\t\tthis.selection.endColumn\r\n\t\t\t);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// The target position is at the same line as the selection's end position.\r\n\t\tif (this.selection.endColumn <= this.targetPosition.column) {\r\n\t\t\t// The target position is after the selection's end position\r\n\t\t\tthis.targetSelection = new Selection(\r\n\t\t\t\tthis.targetPosition.lineNumber - this.selection.endLineNumber + this.selection.startLineNumber,\r\n\t\t\t\tthis.selection.startLineNumber === this.selection.endLineNumber ?\r\n\t\t\t\t\tthis.targetPosition.column - this.selection.endColumn + this.selection.startColumn :\r\n\t\t\t\t\tthis.targetPosition.column - this.selection.endColumn + this.selection.startColumn,\r\n\t\t\t\tthis.targetPosition.lineNumber,\r\n\t\t\t\tthis.selection.startLineNumber === this.selection.endLineNumber ?\r\n\t\t\t\t\tthis.targetPosition.column :\r\n\t\t\t\t\tthis.selection.endColumn\r\n\t\t\t);\r\n\t\t} else {\r\n\t\t\t// The target position is before the selection's end position. Since the selection doesn't contain the target position, the selection is one-line and target position is before this selection.\r\n\t\t\tthis.targetSelection = new Selection(\r\n\t\t\t\tthis.targetPosition.lineNumber - this.selection.endLineNumber + this.selection.startLineNumber,\r\n\t\t\t\tthis.targetPosition.column,\r\n\t\t\t\tthis.targetPosition.lineNumber,\r\n\t\t\t\tthis.targetPosition.column + this.selection.endColumn - this.selection.startColumn\r\n\t\t\t);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\r\n\t\treturn this.targetSelection!;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { ICommand, IEditOperationBuilder, ICursorStateComputerData } from 'vs/editor/common/editorCommon';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\n\r\ninterface IEditOperation {\r\n\trange: Range;\r\n\ttext: string;\r\n}\r\n\r\nexport class ReplaceAllCommand implements ICommand {\r\n\r\n\tprivate readonly _editorSelection: Selection;\r\n\tprivate _trackedEditorSelectionId: string | null;\r\n\tprivate readonly _ranges: Range[];\r\n\tprivate readonly _replaceStrings: string[];\r\n\r\n\tconstructor(editorSelection: Selection, ranges: Range[], replaceStrings: string[]) {\r\n\t\tthis._editorSelection = editorSelection;\r\n\t\tthis._ranges = ranges;\r\n\t\tthis._replaceStrings = replaceStrings;\r\n\t\tthis._trackedEditorSelectionId = null;\r\n\t}\r\n\r\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\r\n\t\tif (this._ranges.length > 0) {\r\n\t\t\t// Collect all edit operations\r\n\t\t\tlet ops: IEditOperation[] = [];\r\n\t\t\tfor (let i = 0; i < this._ranges.length; i++) {\r\n\t\t\t\tops.push({\r\n\t\t\t\t\trange: this._ranges[i],\r\n\t\t\t\t\ttext: this._replaceStrings[i]\r\n\t\t\t\t});\r\n\t\t\t}\r\n\r\n\t\t\t// Sort them in ascending order by range starts\r\n\t\t\tops.sort((o1, o2) => {\r\n\t\t\t\treturn Range.compareRangesUsingStarts(o1.range, o2.range);\r\n\t\t\t});\r\n\r\n\t\t\t// Merge operations that touch each other\r\n\t\t\tlet resultOps: IEditOperation[] = [];\r\n\t\t\tlet previousOp = ops[0];\r\n\t\t\tfor (let i = 1; i < ops.length; i++) {\r\n\t\t\t\tif (previousOp.range.endLineNumber === ops[i].range.startLineNumber && previousOp.range.endColumn === ops[i].range.startColumn) {\r\n\t\t\t\t\t// These operations are one after another and can be merged\r\n\t\t\t\t\tpreviousOp.range = previousOp.range.plusRange(ops[i].range);\r\n\t\t\t\t\tpreviousOp.text = previousOp.text + ops[i].text;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tresultOps.push(previousOp);\r\n\t\t\t\t\tpreviousOp = ops[i];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tresultOps.push(previousOp);\r\n\r\n\t\t\tfor (const op of resultOps) {\r\n\t\t\t\tbuilder.addEditOperation(op.range, op.text);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._trackedEditorSelectionId = builder.trackSelection(this._editorSelection);\r\n\t}\r\n\r\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\r\n\t\treturn helper.getTrackedSelection(this._trackedEditorSelectionId!);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport { buildReplaceStringWithCasePreserved } from 'vs/base/common/search';\r\n\r\nconst enum ReplacePatternKind {\r\n\tStaticValue = 0,\r\n\tDynamicPieces = 1\r\n}\r\n\r\n/**\r\n * Assigned when the replace pattern is entirely static.\r\n */\r\nclass StaticValueReplacePattern {\r\n\tpublic readonly kind = ReplacePatternKind.StaticValue;\r\n\tconstructor(public readonly staticValue: string) { }\r\n}\r\n\r\n/**\r\n * Assigned when the replace pattern has replacement patterns.\r\n */\r\nclass DynamicPiecesReplacePattern {\r\n\tpublic readonly kind = ReplacePatternKind.DynamicPieces;\r\n\tconstructor(public readonly pieces: ReplacePiece[]) { }\r\n}\r\n\r\nexport class ReplacePattern {\r\n\r\n\tpublic static fromStaticValue(value: string): ReplacePattern {\r\n\t\treturn new ReplacePattern([ReplacePiece.staticValue(value)]);\r\n\t}\r\n\r\n\tprivate readonly _state: StaticValueReplacePattern | DynamicPiecesReplacePattern;\r\n\r\n\tpublic get hasReplacementPatterns(): boolean {\r\n\t\treturn (this._state.kind === ReplacePatternKind.DynamicPieces);\r\n\t}\r\n\r\n\tconstructor(pieces: ReplacePiece[] | null) {\r\n\t\tif (!pieces || pieces.length === 0) {\r\n\t\t\tthis._state = new StaticValueReplacePattern('');\r\n\t\t} else if (pieces.length === 1 && pieces[0].staticValue !== null) {\r\n\t\t\tthis._state = new StaticValueReplacePattern(pieces[0].staticValue);\r\n\t\t} else {\r\n\t\t\tthis._state = new DynamicPiecesReplacePattern(pieces);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic buildReplaceString(matches: string[] | null, preserveCase?: boolean): string {\r\n\t\tif (this._state.kind === ReplacePatternKind.StaticValue) {\r\n\t\t\tif (preserveCase) {\r\n\t\t\t\treturn buildReplaceStringWithCasePreserved(matches, this._state.staticValue);\r\n\t\t\t} else {\r\n\t\t\t\treturn this._state.staticValue;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet result = '';\r\n\t\tfor (let i = 0, len = this._state.pieces.length; i < len; i++) {\r\n\t\t\tlet piece = this._state.pieces[i];\r\n\t\t\tif (piece.staticValue !== null) {\r\n\t\t\t\t// static value ReplacePiece\r\n\t\t\t\tresult += piece.staticValue;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\t// match index ReplacePiece\r\n\t\t\tlet match: string = ReplacePattern._substitute(piece.matchIndex, matches);\r\n\t\t\tif (piece.caseOps !== null && piece.caseOps.length > 0) {\r\n\t\t\t\tlet repl: string[] = [];\r\n\t\t\t\tlet lenOps: number = piece.caseOps.length;\r\n\t\t\t\tlet opIdx: number = 0;\r\n\t\t\t\tfor (let idx: number = 0, len: number = match.length; idx < len; idx++) {\r\n\t\t\t\t\tif (opIdx >= lenOps) {\r\n\t\t\t\t\t\trepl.push(match.slice(idx));\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tswitch (piece.caseOps[opIdx]) {\r\n\t\t\t\t\t\tcase 'U':\r\n\t\t\t\t\t\t\trepl.push(match[idx].toUpperCase());\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\tcase 'u':\r\n\t\t\t\t\t\t\trepl.push(match[idx].toUpperCase());\r\n\t\t\t\t\t\t\topIdx++;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\tcase 'L':\r\n\t\t\t\t\t\t\trepl.push(match[idx].toLowerCase());\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\tcase 'l':\r\n\t\t\t\t\t\t\trepl.push(match[idx].toLowerCase());\r\n\t\t\t\t\t\t\topIdx++;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\tdefault:\r\n\t\t\t\t\t\t\trepl.push(match[idx]);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tmatch = repl.join('');\r\n\t\t\t}\r\n\t\t\tresult += match;\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _substitute(matchIndex: number, matches: string[] | null): string {\r\n\t\tif (matches === null) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\tif (matchIndex === 0) {\r\n\t\t\treturn matches[0];\r\n\t\t}\r\n\r\n\t\tlet remainder = '';\r\n\t\twhile (matchIndex > 0) {\r\n\t\t\tif (matchIndex < matches.length) {\r\n\t\t\t\t// A match can be undefined\r\n\t\t\t\tlet match = (matches[matchIndex] || '');\r\n\t\t\t\treturn match + remainder;\r\n\t\t\t}\r\n\t\t\tremainder = String(matchIndex % 10) + remainder;\r\n\t\t\tmatchIndex = Math.floor(matchIndex / 10);\r\n\t\t}\r\n\t\treturn '$' + remainder;\r\n\t}\r\n}\r\n\r\n/**\r\n * A replace piece can either be a static string or an index to a specific match.\r\n */\r\nexport class ReplacePiece {\r\n\r\n\tpublic static staticValue(value: string): ReplacePiece {\r\n\t\treturn new ReplacePiece(value, -1, null);\r\n\t}\r\n\r\n\tpublic static caseOps(index: number, caseOps: string[]): ReplacePiece {\r\n\t\treturn new ReplacePiece(null, index, caseOps);\r\n\t}\r\n\r\n\tpublic readonly staticValue: string | null;\r\n\tpublic readonly matchIndex: number;\r\n\tpublic readonly caseOps: string[] | null;\r\n\r\n\tprivate constructor(staticValue: string | null, matchIndex: number, caseOps: string[] | null) {\r\n\t\tthis.staticValue = staticValue;\r\n\t\tthis.matchIndex = matchIndex;\r\n\t\tif (!caseOps || caseOps.length === 0) {\r\n\t\t\tthis.caseOps = null;\r\n\t\t} else {\r\n\t\t\tthis.caseOps = caseOps.slice(0);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass ReplacePieceBuilder {\r\n\r\n\tprivate readonly _source: string;\r\n\tprivate _lastCharIndex: number;\r\n\tprivate readonly _result: ReplacePiece[];\r\n\tprivate _resultLen: number;\r\n\tprivate _currentStaticPiece: string;\r\n\r\n\tconstructor(source: string) {\r\n\t\tthis._source = source;\r\n\t\tthis._lastCharIndex = 0;\r\n\t\tthis._result = [];\r\n\t\tthis._resultLen = 0;\r\n\t\tthis._currentStaticPiece = '';\r\n\t}\r\n\r\n\tpublic emitUnchanged(toCharIndex: number): void {\r\n\t\tthis._emitStatic(this._source.substring(this._lastCharIndex, toCharIndex));\r\n\t\tthis._lastCharIndex = toCharIndex;\r\n\t}\r\n\r\n\tpublic emitStatic(value: string, toCharIndex: number): void {\r\n\t\tthis._emitStatic(value);\r\n\t\tthis._lastCharIndex = toCharIndex;\r\n\t}\r\n\r\n\tprivate _emitStatic(value: string): void {\r\n\t\tif (value.length === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._currentStaticPiece += value;\r\n\t}\r\n\r\n\tpublic emitMatchIndex(index: number, toCharIndex: number, caseOps: string[]): void {\r\n\t\tif (this._currentStaticPiece.length !== 0) {\r\n\t\t\tthis._result[this._resultLen++] = ReplacePiece.staticValue(this._currentStaticPiece);\r\n\t\t\tthis._currentStaticPiece = '';\r\n\t\t}\r\n\t\tthis._result[this._resultLen++] = ReplacePiece.caseOps(index, caseOps);\r\n\t\tthis._lastCharIndex = toCharIndex;\r\n\t}\r\n\r\n\r\n\tpublic finalize(): ReplacePattern {\r\n\t\tthis.emitUnchanged(this._source.length);\r\n\t\tif (this._currentStaticPiece.length !== 0) {\r\n\t\t\tthis._result[this._resultLen++] = ReplacePiece.staticValue(this._currentStaticPiece);\r\n\t\t\tthis._currentStaticPiece = '';\r\n\t\t}\r\n\t\treturn new ReplacePattern(this._result);\r\n\t}\r\n}\r\n\r\n/**\r\n * \\n\t\t\t=> inserts a LF\r\n * \\t\t\t\t=> inserts a TAB\r\n * \\\\\t\t\t=> inserts a \"\\\".\r\n * \\u\t\t\t=> upper-cases one character in a match.\r\n * \\U\t\t\t=> upper-cases ALL remaining characters in a match.\r\n * \\l\t\t\t=> lower-cases one character in a match.\r\n * \\L\t\t\t=> lower-cases ALL remaining characters in a match.\r\n * $$\t\t\t=> inserts a \"$\".\r\n * $& and $0\t=> inserts the matched substring.\r\n * $n\t\t\t=> Where n is a non-negative integer lesser than 100, inserts the nth parenthesized submatch string\r\n * everything else stays untouched\r\n *\r\n * Also see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_string_as_a_parameter\r\n */\r\nexport function parseReplaceString(replaceString: string): ReplacePattern {\r\n\tif (!replaceString || replaceString.length === 0) {\r\n\t\treturn new ReplacePattern(null);\r\n\t}\r\n\r\n\tlet caseOps: string[] = [];\r\n\tlet result = new ReplacePieceBuilder(replaceString);\r\n\r\n\tfor (let i = 0, len = replaceString.length; i < len; i++) {\r\n\t\tlet chCode = replaceString.charCodeAt(i);\r\n\r\n\t\tif (chCode === CharCode.Backslash) {\r\n\r\n\t\t\t// move to next char\r\n\t\t\ti++;\r\n\r\n\t\t\tif (i >= len) {\r\n\t\t\t\t// string ends with a \\\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tlet nextChCode = replaceString.charCodeAt(i);\r\n\t\t\t// let replaceWithCharacter: string | null = null;\r\n\r\n\t\t\tswitch (nextChCode) {\r\n\t\t\t\tcase CharCode.Backslash:\r\n\t\t\t\t\t// \\\\ => inserts a \"\\\"\r\n\t\t\t\t\tresult.emitUnchanged(i - 1);\r\n\t\t\t\t\tresult.emitStatic('\\\\', i + 1);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase CharCode.n:\r\n\t\t\t\t\t// \\n => inserts a LF\r\n\t\t\t\t\tresult.emitUnchanged(i - 1);\r\n\t\t\t\t\tresult.emitStatic('\\n', i + 1);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase CharCode.t:\r\n\t\t\t\t\t// \\t => inserts a TAB\r\n\t\t\t\t\tresult.emitUnchanged(i - 1);\r\n\t\t\t\t\tresult.emitStatic('\\t', i + 1);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t// Case modification of string replacements, patterned after Boost, but only applied\r\n\t\t\t\t// to the replacement text, not subsequent content.\r\n\t\t\t\tcase CharCode.u:\r\n\t\t\t\t// \\u => upper-cases one character.\r\n\t\t\t\tcase CharCode.U:\r\n\t\t\t\t// \\U => upper-cases ALL following characters.\r\n\t\t\t\tcase CharCode.l:\r\n\t\t\t\t// \\l => lower-cases one character.\r\n\t\t\t\tcase CharCode.L:\r\n\t\t\t\t\t// \\L => lower-cases ALL following characters.\r\n\t\t\t\t\tresult.emitUnchanged(i - 1);\r\n\t\t\t\t\tresult.emitStatic('', i + 1);\r\n\t\t\t\t\tcaseOps.push(String.fromCharCode(nextChCode));\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tif (chCode === CharCode.DollarSign) {\r\n\r\n\t\t\t// move to next char\r\n\t\t\ti++;\r\n\r\n\t\t\tif (i >= len) {\r\n\t\t\t\t// string ends with a $\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tlet nextChCode = replaceString.charCodeAt(i);\r\n\r\n\t\t\tif (nextChCode === CharCode.DollarSign) {\r\n\t\t\t\t// $$ => inserts a \"$\"\r\n\t\t\t\tresult.emitUnchanged(i - 1);\r\n\t\t\t\tresult.emitStatic('$', i + 1);\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (nextChCode === CharCode.Digit0 || nextChCode === CharCode.Ampersand) {\r\n\t\t\t\t// $& and $0 => inserts the matched substring.\r\n\t\t\t\tresult.emitUnchanged(i - 1);\r\n\t\t\t\tresult.emitMatchIndex(0, i + 1, caseOps);\r\n\t\t\t\tcaseOps.length = 0;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (CharCode.Digit1 <= nextChCode && nextChCode <= CharCode.Digit9) {\r\n\t\t\t\t// $n\r\n\r\n\t\t\t\tlet matchIndex = nextChCode - CharCode.Digit0;\r\n\r\n\t\t\t\t// peek next char to probe for $nn\r\n\t\t\t\tif (i + 1 < len) {\r\n\t\t\t\t\tlet nextNextChCode = replaceString.charCodeAt(i + 1);\r\n\t\t\t\t\tif (CharCode.Digit0 <= nextNextChCode && nextNextChCode <= CharCode.Digit9) {\r\n\t\t\t\t\t\t// $nn\r\n\r\n\t\t\t\t\t\t// move to next char\r\n\t\t\t\t\t\ti++;\r\n\t\t\t\t\t\tmatchIndex = matchIndex * 10 + (nextNextChCode - CharCode.Digit0);\r\n\r\n\t\t\t\t\t\tresult.emitUnchanged(i - 2);\r\n\t\t\t\t\t\tresult.emitMatchIndex(matchIndex, i + 1, caseOps);\r\n\t\t\t\t\t\tcaseOps.length = 0;\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tresult.emitUnchanged(i - 1);\r\n\t\t\t\tresult.emitMatchIndex(matchIndex, i + 1, caseOps);\r\n\t\t\t\tcaseOps.length = 0;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\treturn result.finalize();\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nexport interface ILineRange {\r\n\tstartLineNumber: number;\r\n\tendLineNumber: number;\r\n}\r\n\r\nexport const MAX_FOLDING_REGIONS = 0xFFFF;\r\nexport const MAX_LINE_NUMBER = 0xFFFFFF;\r\n\r\nconst MASK_INDENT = 0xFF000000;\r\n\r\nexport class FoldingRegions {\r\n\tprivate readonly _startIndexes: Uint32Array;\r\n\tprivate readonly _endIndexes: Uint32Array;\r\n\tprivate readonly _collapseStates: Uint32Array;\r\n\tprivate _parentsComputed: boolean;\r\n\tprivate readonly _types: Array | undefined;\r\n\r\n\tconstructor(startIndexes: Uint32Array, endIndexes: Uint32Array, types?: Array) {\r\n\t\tif (startIndexes.length !== endIndexes.length || startIndexes.length > MAX_FOLDING_REGIONS) {\r\n\t\t\tthrow new Error('invalid startIndexes or endIndexes size');\r\n\t\t}\r\n\t\tthis._startIndexes = startIndexes;\r\n\t\tthis._endIndexes = endIndexes;\r\n\t\tthis._collapseStates = new Uint32Array(Math.ceil(startIndexes.length / 32));\r\n\t\tthis._types = types;\r\n\t\tthis._parentsComputed = false;\r\n\t}\r\n\r\n\tprivate ensureParentIndices() {\r\n\t\tif (!this._parentsComputed) {\r\n\t\t\tthis._parentsComputed = true;\r\n\t\t\tlet parentIndexes: number[] = [];\r\n\t\t\tlet isInsideLast = (startLineNumber: number, endLineNumber: number) => {\r\n\t\t\t\tlet index = parentIndexes[parentIndexes.length - 1];\r\n\t\t\t\treturn this.getStartLineNumber(index) <= startLineNumber && this.getEndLineNumber(index) >= endLineNumber;\r\n\t\t\t};\r\n\t\t\tfor (let i = 0, len = this._startIndexes.length; i < len; i++) {\r\n\t\t\t\tlet startLineNumber = this._startIndexes[i];\r\n\t\t\t\tlet endLineNumber = this._endIndexes[i];\r\n\t\t\t\tif (startLineNumber > MAX_LINE_NUMBER || endLineNumber > MAX_LINE_NUMBER) {\r\n\t\t\t\t\tthrow new Error('startLineNumber or endLineNumber must not exceed ' + MAX_LINE_NUMBER);\r\n\t\t\t\t}\r\n\t\t\t\twhile (parentIndexes.length > 0 && !isInsideLast(startLineNumber, endLineNumber)) {\r\n\t\t\t\t\tparentIndexes.pop();\r\n\t\t\t\t}\r\n\t\t\t\tlet parentIndex = parentIndexes.length > 0 ? parentIndexes[parentIndexes.length - 1] : -1;\r\n\t\t\t\tparentIndexes.push(i);\r\n\t\t\t\tthis._startIndexes[i] = startLineNumber + ((parentIndex & 0xFF) << 24);\r\n\t\t\t\tthis._endIndexes[i] = endLineNumber + ((parentIndex & 0xFF00) << 16);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic get length(): number {\r\n\t\treturn this._startIndexes.length;\r\n\t}\r\n\r\n\tpublic getStartLineNumber(index: number): number {\r\n\t\treturn this._startIndexes[index] & MAX_LINE_NUMBER;\r\n\t}\r\n\r\n\tpublic getEndLineNumber(index: number): number {\r\n\t\treturn this._endIndexes[index] & MAX_LINE_NUMBER;\r\n\t}\r\n\r\n\tpublic getType(index: number): string | undefined {\r\n\t\treturn this._types ? this._types[index] : undefined;\r\n\t}\r\n\r\n\tpublic hasTypes() {\r\n\t\treturn !!this._types;\r\n\t}\r\n\r\n\tpublic isCollapsed(index: number): boolean {\r\n\t\tlet arrayIndex = (index / 32) | 0;\r\n\t\tlet bit = index % 32;\r\n\t\treturn (this._collapseStates[arrayIndex] & (1 << bit)) !== 0;\r\n\t}\r\n\r\n\tpublic setCollapsed(index: number, newState: boolean) {\r\n\t\tlet arrayIndex = (index / 32) | 0;\r\n\t\tlet bit = index % 32;\r\n\t\tlet value = this._collapseStates[arrayIndex];\r\n\t\tif (newState) {\r\n\t\t\tthis._collapseStates[arrayIndex] = value | (1 << bit);\r\n\t\t} else {\r\n\t\t\tthis._collapseStates[arrayIndex] = value & ~(1 << bit);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic toRegion(index: number): FoldingRegion {\r\n\t\treturn new FoldingRegion(this, index);\r\n\t}\r\n\r\n\tpublic getParentIndex(index: number) {\r\n\t\tthis.ensureParentIndices();\r\n\t\tlet parent = ((this._startIndexes[index] & MASK_INDENT) >>> 24) + ((this._endIndexes[index] & MASK_INDENT) >>> 16);\r\n\t\tif (parent === MAX_FOLDING_REGIONS) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\treturn parent;\r\n\t}\r\n\r\n\tpublic contains(index: number, line: number) {\r\n\t\treturn this.getStartLineNumber(index) <= line && this.getEndLineNumber(index) >= line;\r\n\t}\r\n\r\n\tprivate findIndex(line: number) {\r\n\t\tlet low = 0, high = this._startIndexes.length;\r\n\t\tif (high === 0) {\r\n\t\t\treturn -1; // no children\r\n\t\t}\r\n\t\twhile (low < high) {\r\n\t\t\tlet mid = Math.floor((low + high) / 2);\r\n\t\t\tif (line < this.getStartLineNumber(mid)) {\r\n\t\t\t\thigh = mid;\r\n\t\t\t} else {\r\n\t\t\t\tlow = mid + 1;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn low - 1;\r\n\t}\r\n\r\n\tpublic findRange(line: number): number {\r\n\t\tlet index = this.findIndex(line);\r\n\t\tif (index >= 0) {\r\n\t\t\tlet endLineNumber = this.getEndLineNumber(index);\r\n\t\t\tif (endLineNumber >= line) {\r\n\t\t\t\treturn index;\r\n\t\t\t}\r\n\t\t\tindex = this.getParentIndex(index);\r\n\t\t\twhile (index !== -1) {\r\n\t\t\t\tif (this.contains(index, line)) {\r\n\t\t\t\t\treturn index;\r\n\t\t\t\t}\r\n\t\t\t\tindex = this.getParentIndex(index);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn -1;\r\n\t}\r\n\r\n\tpublic toString() {\r\n\t\tlet res: string[] = [];\r\n\t\tfor (let i = 0; i < this.length; i++) {\r\n\t\t\tres[i] = `[${this.isCollapsed(i) ? '+' : '-'}] ${this.getStartLineNumber(i)}/${this.getEndLineNumber(i)}`;\r\n\t\t}\r\n\t\treturn res.join(', ');\r\n\t}\r\n}\r\n\r\nexport class FoldingRegion {\r\n\r\n\tconstructor(private readonly ranges: FoldingRegions, private index: number) {\r\n\t}\r\n\r\n\tpublic get startLineNumber() {\r\n\t\treturn this.ranges.getStartLineNumber(this.index);\r\n\t}\r\n\r\n\tpublic get endLineNumber() {\r\n\t\treturn this.ranges.getEndLineNumber(this.index);\r\n\t}\r\n\r\n\tpublic get regionIndex() {\r\n\t\treturn this.index;\r\n\t}\r\n\r\n\tpublic get parentIndex() {\r\n\t\treturn this.ranges.getParentIndex(this.index);\r\n\t}\r\n\r\n\tpublic get isCollapsed() {\r\n\t\treturn this.ranges.isCollapsed(this.index);\r\n\t}\r\n\r\n\tcontainedBy(range: ILineRange): boolean {\r\n\t\treturn range.startLineNumber <= this.startLineNumber && range.endLineNumber >= this.endLineNumber;\r\n\t}\r\n\tcontainsLine(lineNumber: number) {\r\n\t\treturn this.startLineNumber <= lineNumber && lineNumber <= this.endLineNumber;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { ITextModel, IModelDecorationOptions, IModelDeltaDecoration, IModelDecorationsChangeAccessor } from 'vs/editor/common/model';\r\nimport { Event, Emitter } from 'vs/base/common/event';\r\nimport { FoldingRegions, ILineRange, FoldingRegion } from './foldingRanges';\r\n\r\nexport interface IDecorationProvider {\r\n\tgetDecorationOption(isCollapsed: boolean, isHidden: boolean): IModelDecorationOptions;\r\n\tdeltaDecorations(oldDecorations: string[], newDecorations: IModelDeltaDecoration[]): string[];\r\n\tchangeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => T): T | null;\r\n}\r\n\r\nexport interface FoldingModelChangeEvent {\r\n\tmodel: FoldingModel;\r\n\tcollapseStateChanged?: FoldingRegion[];\r\n}\r\n\r\nexport type CollapseMemento = ILineRange[];\r\n\r\nexport class FoldingModel {\r\n\tprivate readonly _textModel: ITextModel;\r\n\tprivate readonly _decorationProvider: IDecorationProvider;\r\n\r\n\tprivate _regions: FoldingRegions;\r\n\tprivate _editorDecorationIds: string[];\r\n\tprivate _isInitialized: boolean;\r\n\r\n\tprivate readonly _updateEventEmitter = new Emitter();\r\n\tpublic readonly onDidChange: Event = this._updateEventEmitter.event;\r\n\r\n\tpublic get regions(): FoldingRegions { return this._regions; }\r\n\tpublic get textModel() { return this._textModel; }\r\n\tpublic get isInitialized() { return this._isInitialized; }\r\n\r\n\tconstructor(textModel: ITextModel, decorationProvider: IDecorationProvider) {\r\n\t\tthis._textModel = textModel;\r\n\t\tthis._decorationProvider = decorationProvider;\r\n\t\tthis._regions = new FoldingRegions(new Uint32Array(0), new Uint32Array(0));\r\n\t\tthis._editorDecorationIds = [];\r\n\t\tthis._isInitialized = false;\r\n\t}\r\n\r\n\tpublic toggleCollapseState(toggledRegions: FoldingRegion[]) {\r\n\t\tif (!toggledRegions.length) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\ttoggledRegions = toggledRegions.sort((r1, r2) => r1.regionIndex - r2.regionIndex);\r\n\r\n\t\tconst processed: { [key: string]: boolean | undefined } = {};\r\n\t\tthis._decorationProvider.changeDecorations(accessor => {\r\n\t\t\tlet k = 0; // index from [0 ... this.regions.length]\r\n\t\t\tlet dirtyRegionEndLine = -1; // end of the range where decorations need to be updated\r\n\t\t\tlet lastHiddenLine = -1; // the end of the last hidden lines\r\n\t\t\tconst updateDecorationsUntil = (index: number) => {\r\n\t\t\t\twhile (k < index) {\r\n\t\t\t\t\tconst endLineNumber = this._regions.getEndLineNumber(k);\r\n\t\t\t\t\tconst isCollapsed = this._regions.isCollapsed(k);\r\n\t\t\t\t\tif (endLineNumber <= dirtyRegionEndLine) {\r\n\t\t\t\t\t\taccessor.changeDecorationOptions(this._editorDecorationIds[k], this._decorationProvider.getDecorationOption(isCollapsed, endLineNumber <= lastHiddenLine));\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (isCollapsed && endLineNumber > lastHiddenLine) {\r\n\t\t\t\t\t\tlastHiddenLine = endLineNumber;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tk++;\r\n\t\t\t\t}\r\n\t\t\t};\r\n\t\t\tfor (let region of toggledRegions) {\r\n\t\t\t\tlet index = region.regionIndex;\r\n\t\t\t\tlet editorDecorationId = this._editorDecorationIds[index];\r\n\t\t\t\tif (editorDecorationId && !processed[editorDecorationId]) {\r\n\t\t\t\t\tprocessed[editorDecorationId] = true;\r\n\r\n\t\t\t\t\tupdateDecorationsUntil(index); // update all decorations up to current index using the old dirtyRegionEndLine\r\n\r\n\t\t\t\t\tlet newCollapseState = !this._regions.isCollapsed(index);\r\n\t\t\t\t\tthis._regions.setCollapsed(index, newCollapseState);\r\n\r\n\t\t\t\t\tdirtyRegionEndLine = Math.max(dirtyRegionEndLine, this._regions.getEndLineNumber(index));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tupdateDecorationsUntil(this._regions.length);\r\n\t\t});\r\n\t\tthis._updateEventEmitter.fire({ model: this, collapseStateChanged: toggledRegions });\r\n\t}\r\n\r\n\tpublic update(newRegions: FoldingRegions, blockedLineNumers: number[] = []): void {\r\n\t\tlet newEditorDecorations: IModelDeltaDecoration[] = [];\r\n\r\n\t\tlet isBlocked = (startLineNumber: number, endLineNumber: number) => {\r\n\t\t\tfor (let blockedLineNumber of blockedLineNumers) {\r\n\t\t\t\tif (startLineNumber < blockedLineNumber && blockedLineNumber <= endLineNumber) { // first line is visible\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn false;\r\n\t\t};\r\n\r\n\t\tlet lastHiddenLine = -1;\r\n\r\n\t\tlet initRange = (index: number, isCollapsed: boolean) => {\r\n\t\t\tconst startLineNumber = newRegions.getStartLineNumber(index);\r\n\t\t\tconst endLineNumber = newRegions.getEndLineNumber(index);\r\n\t\t\tif (isCollapsed && isBlocked(startLineNumber, endLineNumber)) {\r\n\t\t\t\tisCollapsed = false;\r\n\t\t\t}\r\n\t\t\tnewRegions.setCollapsed(index, isCollapsed);\r\n\r\n\t\t\tconst maxColumn = this._textModel.getLineMaxColumn(startLineNumber);\r\n\t\t\tconst decorationRange = {\r\n\t\t\t\tstartLineNumber: startLineNumber,\r\n\t\t\t\tstartColumn: Math.max(maxColumn - 1, 1), // make it length == 1 to detect deletions\r\n\t\t\t\tendLineNumber: startLineNumber,\r\n\t\t\t\tendColumn: maxColumn\r\n\t\t\t};\r\n\t\t\tnewEditorDecorations.push({ range: decorationRange, options: this._decorationProvider.getDecorationOption(isCollapsed, endLineNumber <= lastHiddenLine) });\r\n\t\t\tif (isCollapsed && endLineNumber > lastHiddenLine) {\r\n\t\t\t\tlastHiddenLine = endLineNumber;\r\n\t\t\t}\r\n\t\t};\r\n\t\tlet i = 0;\r\n\t\tlet nextCollapsed = () => {\r\n\t\t\twhile (i < this._regions.length) {\r\n\t\t\t\tlet isCollapsed = this._regions.isCollapsed(i);\r\n\t\t\t\ti++;\r\n\t\t\t\tif (isCollapsed) {\r\n\t\t\t\t\treturn i - 1;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn -1;\r\n\t\t};\r\n\r\n\t\tlet k = 0;\r\n\t\tlet collapsedIndex = nextCollapsed();\r\n\t\twhile (collapsedIndex !== -1 && k < newRegions.length) {\r\n\t\t\t// get the latest range\r\n\t\t\tlet decRange = this._textModel.getDecorationRange(this._editorDecorationIds[collapsedIndex]);\r\n\t\t\tif (decRange) {\r\n\t\t\t\tlet collapsedStartLineNumber = decRange.startLineNumber;\r\n\t\t\t\tif (decRange.startColumn === Math.max(decRange.endColumn - 1, 1) && this._textModel.getLineMaxColumn(collapsedStartLineNumber) === decRange.endColumn) { // test that the decoration is still covering the full line else it got deleted\r\n\t\t\t\t\twhile (k < newRegions.length) {\r\n\t\t\t\t\t\tlet startLineNumber = newRegions.getStartLineNumber(k);\r\n\t\t\t\t\t\tif (collapsedStartLineNumber >= startLineNumber) {\r\n\t\t\t\t\t\t\tinitRange(k, collapsedStartLineNumber === startLineNumber);\r\n\t\t\t\t\t\t\tk++;\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tcollapsedIndex = nextCollapsed();\r\n\t\t}\r\n\t\twhile (k < newRegions.length) {\r\n\t\t\tinitRange(k, false);\r\n\t\t\tk++;\r\n\t\t}\r\n\r\n\t\tthis._editorDecorationIds = this._decorationProvider.deltaDecorations(this._editorDecorationIds, newEditorDecorations);\r\n\t\tthis._regions = newRegions;\r\n\t\tthis._isInitialized = true;\r\n\t\tthis._updateEventEmitter.fire({ model: this });\r\n\t}\r\n\r\n\t/**\r\n\t * Collapse state memento, for persistence only\r\n\t */\r\n\tpublic getMemento(): CollapseMemento | undefined {\r\n\t\tlet collapsedRanges: ILineRange[] = [];\r\n\t\tfor (let i = 0; i < this._regions.length; i++) {\r\n\t\t\tif (this._regions.isCollapsed(i)) {\r\n\t\t\t\tlet range = this._textModel.getDecorationRange(this._editorDecorationIds[i]);\r\n\t\t\t\tif (range) {\r\n\t\t\t\t\tlet startLineNumber = range.startLineNumber;\r\n\t\t\t\t\tlet endLineNumber = range.endLineNumber + this._regions.getEndLineNumber(i) - this._regions.getStartLineNumber(i);\r\n\t\t\t\t\tcollapsedRanges.push({ startLineNumber, endLineNumber });\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (collapsedRanges.length > 0) {\r\n\t\t\treturn collapsedRanges;\r\n\t\t}\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\t/**\r\n\t * Apply persisted state, for persistence only\r\n\t */\r\n\tpublic applyMemento(state: CollapseMemento) {\r\n\t\tif (!Array.isArray(state)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tlet toToogle: FoldingRegion[] = [];\r\n\t\tfor (let range of state) {\r\n\t\t\tlet region = this.getRegionAtLine(range.startLineNumber);\r\n\t\t\tif (region && !region.isCollapsed) {\r\n\t\t\t\ttoToogle.push(region);\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis.toggleCollapseState(toToogle);\r\n\t}\r\n\r\n\tpublic dispose() {\r\n\t\tthis._decorationProvider.deltaDecorations(this._editorDecorationIds, []);\r\n\t}\r\n\r\n\tgetAllRegionsAtLine(lineNumber: number, filter?: (r: FoldingRegion, level: number) => boolean): FoldingRegion[] {\r\n\t\tlet result: FoldingRegion[] = [];\r\n\t\tif (this._regions) {\r\n\t\t\tlet index = this._regions.findRange(lineNumber);\r\n\t\t\tlet level = 1;\r\n\t\t\twhile (index >= 0) {\r\n\t\t\t\tlet current = this._regions.toRegion(index);\r\n\t\t\t\tif (!filter || filter(current, level)) {\r\n\t\t\t\t\tresult.push(current);\r\n\t\t\t\t}\r\n\t\t\t\tlevel++;\r\n\t\t\t\tindex = current.parentIndex;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tgetRegionAtLine(lineNumber: number): FoldingRegion | null {\r\n\t\tif (this._regions) {\r\n\t\t\tlet index = this._regions.findRange(lineNumber);\r\n\t\t\tif (index >= 0) {\r\n\t\t\t\treturn this._regions.toRegion(index);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tgetRegionsInside(region: FoldingRegion | null, filter?: RegionFilter | RegionFilterWithLevel): FoldingRegion[] {\r\n\t\tlet result: FoldingRegion[] = [];\r\n\t\tlet index = region ? region.regionIndex + 1 : 0;\r\n\t\tlet endLineNumber = region ? region.endLineNumber : Number.MAX_VALUE;\r\n\r\n\t\tif (filter && filter.length === 2) {\r\n\t\t\tconst levelStack: FoldingRegion[] = [];\r\n\t\t\tfor (let i = index, len = this._regions.length; i < len; i++) {\r\n\t\t\t\tlet current = this._regions.toRegion(i);\r\n\t\t\t\tif (this._regions.getStartLineNumber(i) < endLineNumber) {\r\n\t\t\t\t\twhile (levelStack.length > 0 && !current.containedBy(levelStack[levelStack.length - 1])) {\r\n\t\t\t\t\t\tlevelStack.pop();\r\n\t\t\t\t\t}\r\n\t\t\t\t\tlevelStack.push(current);\r\n\t\t\t\t\tif (filter(current, levelStack.length)) {\r\n\t\t\t\t\t\tresult.push(current);\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tfor (let i = index, len = this._regions.length; i < len; i++) {\r\n\t\t\t\tlet current = this._regions.toRegion(i);\r\n\t\t\t\tif (this._regions.getStartLineNumber(i) < endLineNumber) {\r\n\t\t\t\t\tif (!filter || (filter as RegionFilter)(current)) {\r\n\t\t\t\t\t\tresult.push(current);\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n}\r\n\r\ntype RegionFilter = (r: FoldingRegion) => boolean;\r\ntype RegionFilterWithLevel = (r: FoldingRegion, level: number) => boolean;\r\n\r\n\r\n/**\r\n * Collapse or expand the regions at the given locations\r\n * @param levels The number of levels. Use 1 to only impact the regions at the location, use Number.MAX_VALUE for all levels.\r\n * @param lineNumbers the location of the regions to collapse or expand, or if not set, all regions in the model.\r\n */\r\nexport function toggleCollapseState(foldingModel: FoldingModel, levels: number, lineNumbers: number[]) {\r\n\tlet toToggle: FoldingRegion[] = [];\r\n\tfor (let lineNumber of lineNumbers) {\r\n\t\tlet region = foldingModel.getRegionAtLine(lineNumber);\r\n\t\tif (region) {\r\n\t\t\tconst doCollapse = !region.isCollapsed;\r\n\t\t\ttoToggle.push(region);\r\n\t\t\tif (levels > 1) {\r\n\t\t\t\tlet regionsInside = foldingModel.getRegionsInside(region, (r, level: number) => r.isCollapsed !== doCollapse && level < levels);\r\n\t\t\t\ttoToggle.push(...regionsInside);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\tfoldingModel.toggleCollapseState(toToggle);\r\n}\r\n\r\n\r\n/**\r\n * Collapse or expand the regions at the given locations including all children.\r\n * @param doCollapse Wheter to collase or expand\r\n * @param levels The number of levels. Use 1 to only impact the regions at the location, use Number.MAX_VALUE for all levels.\r\n * @param lineNumbers the location of the regions to collapse or expand, or if not set, all regions in the model.\r\n */\r\nexport function setCollapseStateLevelsDown(foldingModel: FoldingModel, doCollapse: boolean, levels = Number.MAX_VALUE, lineNumbers?: number[]): void {\r\n\tlet toToggle: FoldingRegion[] = [];\r\n\tif (lineNumbers && lineNumbers.length > 0) {\r\n\t\tfor (let lineNumber of lineNumbers) {\r\n\t\t\tlet region = foldingModel.getRegionAtLine(lineNumber);\r\n\t\t\tif (region) {\r\n\t\t\t\tif (region.isCollapsed !== doCollapse) {\r\n\t\t\t\t\ttoToggle.push(region);\r\n\t\t\t\t}\r\n\t\t\t\tif (levels > 1) {\r\n\t\t\t\t\tlet regionsInside = foldingModel.getRegionsInside(region, (r, level: number) => r.isCollapsed !== doCollapse && level < levels);\r\n\t\t\t\t\ttoToggle.push(...regionsInside);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t} else {\r\n\t\tlet regionsInside = foldingModel.getRegionsInside(null, (r, level: number) => r.isCollapsed !== doCollapse && level < levels);\r\n\t\ttoToggle.push(...regionsInside);\r\n\t}\r\n\tfoldingModel.toggleCollapseState(toToggle);\r\n}\r\n\r\n/**\r\n * Collapse or expand the regions at the given locations including all parents.\r\n * @param doCollapse Wheter to collase or expand\r\n * @param levels The number of levels. Use 1 to only impact the regions at the location, use Number.MAX_VALUE for all levels.\r\n * @param lineNumbers the location of the regions to collapse or expand.\r\n */\r\nexport function setCollapseStateLevelsUp(foldingModel: FoldingModel, doCollapse: boolean, levels: number, lineNumbers: number[]): void {\r\n\tlet toToggle: FoldingRegion[] = [];\r\n\tfor (let lineNumber of lineNumbers) {\r\n\t\tlet regions = foldingModel.getAllRegionsAtLine(lineNumber, (region, level) => region.isCollapsed !== doCollapse && level <= levels);\r\n\t\ttoToggle.push(...regions);\r\n\t}\r\n\tfoldingModel.toggleCollapseState(toToggle);\r\n}\r\n\r\n/**\r\n * Collapse or expand a region at the given locations. If the inner most region is already collapsed/expanded, uses the first parent instead.\r\n * @param doCollapse Wheter to collase or expand\r\n * @param lineNumbers the location of the regions to collapse or expand.\r\n */\r\nexport function setCollapseStateUp(foldingModel: FoldingModel, doCollapse: boolean, lineNumbers: number[]): void {\r\n\tlet toToggle: FoldingRegion[] = [];\r\n\tfor (let lineNumber of lineNumbers) {\r\n\t\tlet regions = foldingModel.getAllRegionsAtLine(lineNumber, (region,) => region.isCollapsed !== doCollapse);\r\n\t\tif (regions.length > 0) {\r\n\t\t\ttoToggle.push(regions[0]);\r\n\t\t}\r\n\t}\r\n\tfoldingModel.toggleCollapseState(toToggle);\r\n}\r\n\r\n/**\r\n * Folds or unfolds all regions that have a given level, except if they contain one of the blocked lines.\r\n * @param foldLevel level. Level == 1 is the top level\r\n * @param doCollapse Wheter to collase or expand\r\n*/\r\nexport function setCollapseStateAtLevel(foldingModel: FoldingModel, foldLevel: number, doCollapse: boolean, blockedLineNumbers: number[]): void {\r\n\tlet filter = (region: FoldingRegion, level: number) => level === foldLevel && region.isCollapsed !== doCollapse && !blockedLineNumbers.some(line => region.containsLine(line));\r\n\tlet toToggle = foldingModel.getRegionsInside(null, filter);\r\n\tfoldingModel.toggleCollapseState(toToggle);\r\n}\r\n\r\n/**\r\n * Folds all regions for which the lines start with a given regex\r\n * @param foldingModel the folding model\r\n */\r\nexport function setCollapseStateForMatchingLines(foldingModel: FoldingModel, regExp: RegExp, doCollapse: boolean): void {\r\n\tlet editorModel = foldingModel.textModel;\r\n\tlet regions = foldingModel.regions;\r\n\tlet toToggle: FoldingRegion[] = [];\r\n\tfor (let i = regions.length - 1; i >= 0; i--) {\r\n\t\tif (doCollapse !== regions.isCollapsed(i)) {\r\n\t\t\tlet startLineNumber = regions.getStartLineNumber(i);\r\n\t\t\tif (regExp.test(editorModel.getLineContent(startLineNumber))) {\r\n\t\t\t\ttoToggle.push(regions.toRegion(i));\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\tfoldingModel.toggleCollapseState(toToggle);\r\n}\r\n\r\n/**\r\n * Folds all regions of the given type\r\n * @param foldingModel the folding model\r\n */\r\nexport function setCollapseStateForType(foldingModel: FoldingModel, type: string, doCollapse: boolean): void {\r\n\tlet regions = foldingModel.regions;\r\n\tlet toToggle: FoldingRegion[] = [];\r\n\tfor (let i = regions.length - 1; i >= 0; i--) {\r\n\t\tif (doCollapse !== regions.isCollapsed(i) && type === regions.getType(i)) {\r\n\t\t\ttoToggle.push(regions.toRegion(i));\r\n\t\t}\r\n\t}\r\n\tfoldingModel.toggleCollapseState(toToggle);\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Event, Emitter } from 'vs/base/common/event';\r\nimport { Range, IRange } from 'vs/editor/common/core/range';\r\nimport { FoldingModel, CollapseMemento } from 'vs/editor/contrib/folding/foldingModel';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { findFirstInSorted } from 'vs/base/common/arrays';\r\n\r\nexport class HiddenRangeModel {\r\n\tprivate readonly _foldingModel: FoldingModel;\r\n\tprivate _hiddenRanges: IRange[];\r\n\tprivate _foldingModelListener: IDisposable | null;\r\n\tprivate readonly _updateEventEmitter = new Emitter();\r\n\r\n\tpublic get onDidChange(): Event { return this._updateEventEmitter.event; }\r\n\tpublic get hiddenRanges() { return this._hiddenRanges; }\r\n\r\n\tpublic constructor(model: FoldingModel) {\r\n\t\tthis._foldingModel = model;\r\n\t\tthis._foldingModelListener = model.onDidChange(_ => this.updateHiddenRanges());\r\n\t\tthis._hiddenRanges = [];\r\n\t\tif (model.regions.length) {\r\n\t\t\tthis.updateHiddenRanges();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate updateHiddenRanges(): void {\r\n\t\tlet updateHiddenAreas = false;\r\n\t\tlet newHiddenAreas: IRange[] = [];\r\n\t\tlet i = 0; // index into hidden\r\n\t\tlet k = 0;\r\n\r\n\t\tlet lastCollapsedStart = Number.MAX_VALUE;\r\n\t\tlet lastCollapsedEnd = -1;\r\n\r\n\t\tlet ranges = this._foldingModel.regions;\r\n\t\tfor (; i < ranges.length; i++) {\r\n\t\t\tif (!ranges.isCollapsed(i)) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tlet startLineNumber = ranges.getStartLineNumber(i) + 1; // the first line is not hidden\r\n\t\t\tlet endLineNumber = ranges.getEndLineNumber(i);\r\n\t\t\tif (lastCollapsedStart <= startLineNumber && endLineNumber <= lastCollapsedEnd) {\r\n\t\t\t\t// ignore ranges contained in collapsed regions\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (!updateHiddenAreas && k < this._hiddenRanges.length && this._hiddenRanges[k].startLineNumber === startLineNumber && this._hiddenRanges[k].endLineNumber === endLineNumber) {\r\n\t\t\t\t// reuse the old ranges\r\n\t\t\t\tnewHiddenAreas.push(this._hiddenRanges[k]);\r\n\t\t\t\tk++;\r\n\t\t\t} else {\r\n\t\t\t\tupdateHiddenAreas = true;\r\n\t\t\t\tnewHiddenAreas.push(new Range(startLineNumber, 1, endLineNumber, 1));\r\n\t\t\t}\r\n\t\t\tlastCollapsedStart = startLineNumber;\r\n\t\t\tlastCollapsedEnd = endLineNumber;\r\n\t\t}\r\n\t\tif (updateHiddenAreas || k < this._hiddenRanges.length) {\r\n\t\t\tthis.applyHiddenRanges(newHiddenAreas);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic applyMemento(state: CollapseMemento): boolean {\r\n\t\tif (!Array.isArray(state) || state.length === 0) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tlet hiddenRanges: IRange[] = [];\r\n\t\tfor (let r of state) {\r\n\t\t\tif (!r.startLineNumber || !r.endLineNumber) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t\thiddenRanges.push(new Range(r.startLineNumber + 1, 1, r.endLineNumber, 1));\r\n\t\t}\r\n\t\tthis.applyHiddenRanges(hiddenRanges);\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t * Collapse state memento, for persistence only, only used if folding model is not yet initialized\r\n\t */\r\n\tpublic getMemento(): CollapseMemento {\r\n\t\treturn this._hiddenRanges.map(r => ({ startLineNumber: r.startLineNumber - 1, endLineNumber: r.endLineNumber }));\r\n\t}\r\n\r\n\tprivate applyHiddenRanges(newHiddenAreas: IRange[]) {\r\n\t\tthis._hiddenRanges = newHiddenAreas;\r\n\t\tthis._updateEventEmitter.fire(newHiddenAreas);\r\n\t}\r\n\r\n\tpublic hasRanges() {\r\n\t\treturn this._hiddenRanges.length > 0;\r\n\t}\r\n\r\n\tpublic isHidden(line: number): boolean {\r\n\t\treturn findRange(this._hiddenRanges, line) !== null;\r\n\t}\r\n\r\n\tpublic adjustSelections(selections: Selection[]): boolean {\r\n\t\tlet hasChanges = false;\r\n\t\tlet editorModel = this._foldingModel.textModel;\r\n\t\tlet lastRange: IRange | null = null;\r\n\r\n\t\tlet adjustLine = (line: number) => {\r\n\t\t\tif (!lastRange || !isInside(line, lastRange)) {\r\n\t\t\t\tlastRange = findRange(this._hiddenRanges, line);\r\n\t\t\t}\r\n\t\t\tif (lastRange) {\r\n\t\t\t\treturn lastRange.startLineNumber - 1;\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t};\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tlet selection = selections[i];\r\n\t\t\tlet adjustedStartLine = adjustLine(selection.startLineNumber);\r\n\t\t\tif (adjustedStartLine) {\r\n\t\t\t\tselection = selection.setStartPosition(adjustedStartLine, editorModel.getLineMaxColumn(adjustedStartLine));\r\n\t\t\t\thasChanges = true;\r\n\t\t\t}\r\n\t\t\tlet adjustedEndLine = adjustLine(selection.endLineNumber);\r\n\t\t\tif (adjustedEndLine) {\r\n\t\t\t\tselection = selection.setEndPosition(adjustedEndLine, editorModel.getLineMaxColumn(adjustedEndLine));\r\n\t\t\t\thasChanges = true;\r\n\t\t\t}\r\n\t\t\tselections[i] = selection;\r\n\t\t}\r\n\t\treturn hasChanges;\r\n\t}\r\n\r\n\r\n\tpublic dispose() {\r\n\t\tif (this.hiddenRanges.length > 0) {\r\n\t\t\tthis._hiddenRanges = [];\r\n\t\t\tthis._updateEventEmitter.fire(this._hiddenRanges);\r\n\t\t}\r\n\t\tif (this._foldingModelListener) {\r\n\t\t\tthis._foldingModelListener.dispose();\r\n\t\t\tthis._foldingModelListener = null;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction isInside(line: number, range: IRange) {\r\n\treturn line >= range.startLineNumber && line <= range.endLineNumber;\r\n}\r\nfunction findRange(ranges: IRange[], line: number): IRange | null {\r\n\tlet i = findFirstInSorted(ranges, r => line < r.startLineNumber) - 1;\r\n\tif (i >= 0 && ranges[i].endLineNumber >= line) {\r\n\t\treturn ranges[i];\r\n\t}\r\n\treturn null;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { FoldingRangeProvider, FoldingRange, FoldingContext } from 'vs/editor/common/modes';\r\nimport { onUnexpectedExternalError } from 'vs/base/common/errors';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { RangeProvider } from './folding';\r\nimport { MAX_LINE_NUMBER, FoldingRegions } from './foldingRanges';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { DisposableStore } from 'vs/base/common/lifecycle';\r\n\r\nconst MAX_FOLDING_REGIONS = 5000;\r\n\r\nexport interface IFoldingRangeData extends FoldingRange {\r\n\trank: number;\r\n}\r\n\r\nconst foldingContext: FoldingContext = {\r\n};\r\n\r\nexport const ID_SYNTAX_PROVIDER = 'syntax';\r\n\r\nexport class SyntaxRangeProvider implements RangeProvider {\r\n\r\n\treadonly id = ID_SYNTAX_PROVIDER;\r\n\r\n\treadonly disposables: DisposableStore | undefined;\r\n\r\n\tconstructor(private readonly editorModel: ITextModel, private providers: FoldingRangeProvider[], handleFoldingRangesChange: () => void, private limit = MAX_FOLDING_REGIONS) {\r\n\t\tfor (const provider of providers) {\r\n\t\t\tif (typeof provider.onDidChange === 'function') {\r\n\t\t\t\tif (!this.disposables) {\r\n\t\t\t\t\tthis.disposables = new DisposableStore();\r\n\t\t\t\t}\r\n\t\t\t\tthis.disposables.add(provider.onDidChange(handleFoldingRangesChange));\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tcompute(cancellationToken: CancellationToken): Promise {\r\n\t\treturn collectSyntaxRanges(this.providers, this.editorModel, cancellationToken).then(ranges => {\r\n\t\t\tif (ranges) {\r\n\t\t\t\tlet res = sanitizeRanges(ranges, this.limit);\r\n\t\t\t\treturn res;\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t});\r\n\t}\r\n\r\n\tdispose() {\r\n\t\tthis.disposables?.dispose();\r\n\t}\r\n}\r\n\r\nfunction collectSyntaxRanges(providers: FoldingRangeProvider[], model: ITextModel, cancellationToken: CancellationToken): Promise {\r\n\tlet rangeData: IFoldingRangeData[] | null = null;\r\n\tlet promises = providers.map((provider, i) => {\r\n\t\treturn Promise.resolve(provider.provideFoldingRanges(model, foldingContext, cancellationToken)).then(ranges => {\r\n\t\t\tif (cancellationToken.isCancellationRequested) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (Array.isArray(ranges)) {\r\n\t\t\t\tif (!Array.isArray(rangeData)) {\r\n\t\t\t\t\trangeData = [];\r\n\t\t\t\t}\r\n\t\t\t\tlet nLines = model.getLineCount();\r\n\t\t\t\tfor (let r of ranges) {\r\n\t\t\t\t\tif (r.start > 0 && r.end > r.start && r.end <= nLines) {\r\n\t\t\t\t\t\trangeData.push({ start: r.start, end: r.end, rank: i, kind: r.kind });\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}, onUnexpectedExternalError);\r\n\t});\r\n\treturn Promise.all(promises).then(_ => {\r\n\t\treturn rangeData;\r\n\t});\r\n}\r\n\r\nexport class RangesCollector {\r\n\tprivate readonly _startIndexes: number[];\r\n\tprivate readonly _endIndexes: number[];\r\n\tprivate readonly _nestingLevels: number[];\r\n\tprivate readonly _nestingLevelCounts: number[];\r\n\tprivate readonly _types: Array;\r\n\tprivate _length: number;\r\n\tprivate readonly _foldingRangesLimit: number;\r\n\r\n\tconstructor(foldingRangesLimit: number) {\r\n\t\tthis._startIndexes = [];\r\n\t\tthis._endIndexes = [];\r\n\t\tthis._nestingLevels = [];\r\n\t\tthis._nestingLevelCounts = [];\r\n\t\tthis._types = [];\r\n\t\tthis._length = 0;\r\n\t\tthis._foldingRangesLimit = foldingRangesLimit;\r\n\t}\r\n\r\n\tpublic add(startLineNumber: number, endLineNumber: number, type: string | undefined, nestingLevel: number) {\r\n\t\tif (startLineNumber > MAX_LINE_NUMBER || endLineNumber > MAX_LINE_NUMBER) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tlet index = this._length;\r\n\t\tthis._startIndexes[index] = startLineNumber;\r\n\t\tthis._endIndexes[index] = endLineNumber;\r\n\t\tthis._nestingLevels[index] = nestingLevel;\r\n\t\tthis._types[index] = type;\r\n\t\tthis._length++;\r\n\t\tif (nestingLevel < 30) {\r\n\t\t\tthis._nestingLevelCounts[nestingLevel] = (this._nestingLevelCounts[nestingLevel] || 0) + 1;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic toIndentRanges() {\r\n\t\tif (this._length <= this._foldingRangesLimit) {\r\n\t\t\tlet startIndexes = new Uint32Array(this._length);\r\n\t\t\tlet endIndexes = new Uint32Array(this._length);\r\n\t\t\tfor (let i = 0; i < this._length; i++) {\r\n\t\t\t\tstartIndexes[i] = this._startIndexes[i];\r\n\t\t\t\tendIndexes[i] = this._endIndexes[i];\r\n\t\t\t}\r\n\t\t\treturn new FoldingRegions(startIndexes, endIndexes, this._types);\r\n\t\t} else {\r\n\t\t\tlet entries = 0;\r\n\t\t\tlet maxLevel = this._nestingLevelCounts.length;\r\n\t\t\tfor (let i = 0; i < this._nestingLevelCounts.length; i++) {\r\n\t\t\t\tlet n = this._nestingLevelCounts[i];\r\n\t\t\t\tif (n) {\r\n\t\t\t\t\tif (n + entries > this._foldingRangesLimit) {\r\n\t\t\t\t\t\tmaxLevel = i;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tentries += n;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tlet startIndexes = new Uint32Array(this._foldingRangesLimit);\r\n\t\t\tlet endIndexes = new Uint32Array(this._foldingRangesLimit);\r\n\t\t\tlet types: Array = [];\r\n\t\t\tfor (let i = 0, k = 0; i < this._length; i++) {\r\n\t\t\t\tlet level = this._nestingLevels[i];\r\n\t\t\t\tif (level < maxLevel || (level === maxLevel && entries++ < this._foldingRangesLimit)) {\r\n\t\t\t\t\tstartIndexes[k] = this._startIndexes[i];\r\n\t\t\t\t\tendIndexes[k] = this._endIndexes[i];\r\n\t\t\t\t\ttypes[k] = this._types[i];\r\n\t\t\t\t\tk++;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn new FoldingRegions(startIndexes, endIndexes, types);\r\n\t\t}\r\n\r\n\t}\r\n\r\n}\r\n\r\nexport function sanitizeRanges(rangeData: IFoldingRangeData[], limit: number): FoldingRegions {\r\n\r\n\tlet sorted = rangeData.sort((d1, d2) => {\r\n\t\tlet diff = d1.start - d2.start;\r\n\t\tif (diff === 0) {\r\n\t\t\tdiff = d1.rank - d2.rank;\r\n\t\t}\r\n\t\treturn diff;\r\n\t});\r\n\tlet collector = new RangesCollector(limit);\r\n\r\n\tlet top: IFoldingRangeData | undefined = undefined;\r\n\tlet previous: IFoldingRangeData[] = [];\r\n\tfor (let entry of sorted) {\r\n\t\tif (!top) {\r\n\t\t\ttop = entry;\r\n\t\t\tcollector.add(entry.start, entry.end, entry.kind && entry.kind.value, previous.length);\r\n\t\t} else {\r\n\t\t\tif (entry.start > top.start) {\r\n\t\t\t\tif (entry.end <= top.end) {\r\n\t\t\t\t\tprevious.push(top);\r\n\t\t\t\t\ttop = entry;\r\n\t\t\t\t\tcollector.add(entry.start, entry.end, entry.kind && entry.kind.value, previous.length);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tif (entry.start > top.end) {\r\n\t\t\t\t\t\tdo {\r\n\t\t\t\t\t\t\ttop = previous.pop();\r\n\t\t\t\t\t\t} while (top && entry.start > top.end);\r\n\t\t\t\t\t\tif (top) {\r\n\t\t\t\t\t\t\tprevious.push(top);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\ttop = entry;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tcollector.add(entry.start, entry.end, entry.kind && entry.kind.value, previous.length);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn collector.toIndentRanges();\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { ITextModel, IModelDeltaDecoration, TrackedRangeStickiness } from 'vs/editor/common/model';\r\nimport { FoldingRegions, ILineRange } from 'vs/editor/contrib/folding/foldingRanges';\r\nimport { RangeProvider } from './folding';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { IFoldingRangeData, sanitizeRanges } from 'vs/editor/contrib/folding/syntaxRangeProvider';\r\n\r\nexport const ID_INIT_PROVIDER = 'init';\r\n\r\nexport class InitializingRangeProvider implements RangeProvider {\r\n\treadonly id = ID_INIT_PROVIDER;\r\n\r\n\tprivate decorationIds: string[] | undefined;\r\n\tprivate timeout: any;\r\n\r\n\tconstructor(private readonly editorModel: ITextModel, initialRanges: ILineRange[], onTimeout: () => void, timeoutTime: number) {\r\n\t\tif (initialRanges.length) {\r\n\t\t\tlet toDecorationRange = (range: ILineRange): IModelDeltaDecoration => {\r\n\t\t\t\treturn {\r\n\t\t\t\t\trange: {\r\n\t\t\t\t\t\tstartLineNumber: range.startLineNumber,\r\n\t\t\t\t\t\tstartColumn: 0,\r\n\t\t\t\t\t\tendLineNumber: range.endLineNumber,\r\n\t\t\t\t\t\tendColumn: editorModel.getLineLength(range.endLineNumber)\r\n\t\t\t\t\t},\r\n\t\t\t\t\toptions: {\r\n\t\t\t\t\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges\r\n\t\t\t\t\t}\r\n\t\t\t\t};\r\n\t\t\t};\r\n\t\t\tthis.decorationIds = editorModel.deltaDecorations([], initialRanges.map(toDecorationRange));\r\n\t\t\tthis.timeout = setTimeout(onTimeout, timeoutTime);\r\n\t\t}\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tif (this.decorationIds) {\r\n\t\t\tthis.editorModel.deltaDecorations(this.decorationIds, []);\r\n\t\t\tthis.decorationIds = undefined;\r\n\t\t}\r\n\t\tif (typeof this.timeout === 'number') {\r\n\t\t\tclearTimeout(this.timeout);\r\n\t\t\tthis.timeout = undefined;\r\n\t\t}\r\n\t}\r\n\r\n\tcompute(cancelationToken: CancellationToken): Promise {\r\n\t\tlet foldingRangeData: IFoldingRangeData[] = [];\r\n\t\tif (this.decorationIds) {\r\n\t\t\tfor (let id of this.decorationIds) {\r\n\t\t\t\tlet range = this.editorModel.getDecorationRange(id);\r\n\t\t\t\tif (range) {\r\n\t\t\t\t\tfoldingRangeData.push({ start: range.startLineNumber, end: range.endLineNumber, rank: 1 });\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn Promise.resolve(sanitizeRanges(foldingRangeData, Number.MAX_VALUE));\r\n\t}\r\n}\r\n\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditOperation } from 'vs/editor/common/core/editOperation';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { EndOfLineSequence, ISingleEditOperation } from 'vs/editor/common/model';\r\nimport { TextEdit } from 'vs/editor/common/modes';\r\n\r\nexport class FormattingEdit {\r\n\r\n\tprivate static _handleEolEdits(editor: ICodeEditor, edits: TextEdit[]): ISingleEditOperation[] {\r\n\t\tlet newEol: EndOfLineSequence | undefined = undefined;\r\n\t\tlet singleEdits: ISingleEditOperation[] = [];\r\n\r\n\t\tfor (let edit of edits) {\r\n\t\t\tif (typeof edit.eol === 'number') {\r\n\t\t\t\tnewEol = edit.eol;\r\n\t\t\t}\r\n\t\t\tif (edit.range && typeof edit.text === 'string') {\r\n\t\t\t\tsingleEdits.push(edit);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (typeof newEol === 'number') {\r\n\t\t\tif (editor.hasModel()) {\r\n\t\t\t\teditor.getModel().pushEOL(newEol);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn singleEdits;\r\n\t}\r\n\r\n\tprivate static _isFullModelReplaceEdit(editor: ICodeEditor, edit: ISingleEditOperation): boolean {\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tconst model = editor.getModel();\r\n\t\tconst editRange = model.validateRange(edit.range);\r\n\t\tconst fullModelRange = model.getFullModelRange();\r\n\t\treturn fullModelRange.equalsRange(editRange);\r\n\t}\r\n\r\n\tstatic execute(editor: ICodeEditor, _edits: TextEdit[], addUndoStops: boolean) {\r\n\t\tif (addUndoStops) {\r\n\t\t\teditor.pushUndoStop();\r\n\t\t}\r\n\t\tconst edits = FormattingEdit._handleEolEdits(editor, _edits);\r\n\t\tif (edits.length === 1 && FormattingEdit._isFullModelReplaceEdit(editor, edits[0])) {\r\n\t\t\t// We use replace semantics and hope that markers stay put...\r\n\t\t\teditor.executeEdits('formatEditsCommand', edits.map(edit => EditOperation.replace(Range.lift(edit.range), edit.text)));\r\n\t\t} else {\r\n\t\t\teditor.executeEdits('formatEditsCommand', edits.map(edit => EditOperation.replaceMove(Range.lift(edit.range), edit.text)));\r\n\t\t}\r\n\t\tif (addUndoStops) {\r\n\t\t\teditor.pushUndoStop();\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { KeyCode } from 'vs/base/common/keyCodes';\r\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { ICodeEditor, IEditorMouseEvent, IMouseTarget } from 'vs/editor/browser/editorBrowser';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';\r\nimport { Event, Emitter } from 'vs/base/common/event';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\nfunction hasModifier(e: { ctrlKey: boolean; shiftKey: boolean; altKey: boolean; metaKey: boolean }, modifier: 'ctrlKey' | 'shiftKey' | 'altKey' | 'metaKey'): boolean {\r\n\treturn !!e[modifier];\r\n}\r\n\r\n/**\r\n * An event that encapsulates the various trigger modifiers logic needed for go to definition.\r\n */\r\nexport class ClickLinkMouseEvent {\r\n\r\n\tpublic readonly target: IMouseTarget;\r\n\tpublic readonly hasTriggerModifier: boolean;\r\n\tpublic readonly hasSideBySideModifier: boolean;\r\n\tpublic readonly isNoneOrSingleMouseDown: boolean;\r\n\r\n\tconstructor(source: IEditorMouseEvent, opts: ClickLinkOptions) {\r\n\t\tthis.target = source.target;\r\n\t\tthis.hasTriggerModifier = hasModifier(source.event, opts.triggerModifier);\r\n\t\tthis.hasSideBySideModifier = hasModifier(source.event, opts.triggerSideBySideModifier);\r\n\t\tthis.isNoneOrSingleMouseDown = (source.event.detail <= 1);\r\n\t}\r\n}\r\n\r\n/**\r\n * An event that encapsulates the various trigger modifiers logic needed for go to definition.\r\n */\r\nexport class ClickLinkKeyboardEvent {\r\n\r\n\tpublic readonly keyCodeIsTriggerKey: boolean;\r\n\tpublic readonly keyCodeIsSideBySideKey: boolean;\r\n\tpublic readonly hasTriggerModifier: boolean;\r\n\r\n\tconstructor(source: IKeyboardEvent, opts: ClickLinkOptions) {\r\n\t\tthis.keyCodeIsTriggerKey = (source.keyCode === opts.triggerKey);\r\n\t\tthis.keyCodeIsSideBySideKey = (source.keyCode === opts.triggerSideBySideKey);\r\n\t\tthis.hasTriggerModifier = hasModifier(source, opts.triggerModifier);\r\n\t}\r\n}\r\nexport type TriggerModifier = 'ctrlKey' | 'shiftKey' | 'altKey' | 'metaKey';\r\n\r\nexport class ClickLinkOptions {\r\n\r\n\tpublic readonly triggerKey: KeyCode;\r\n\tpublic readonly triggerModifier: TriggerModifier;\r\n\tpublic readonly triggerSideBySideKey: KeyCode;\r\n\tpublic readonly triggerSideBySideModifier: TriggerModifier;\r\n\r\n\tconstructor(\r\n\t\ttriggerKey: KeyCode,\r\n\t\ttriggerModifier: TriggerModifier,\r\n\t\ttriggerSideBySideKey: KeyCode,\r\n\t\ttriggerSideBySideModifier: TriggerModifier\r\n\t) {\r\n\t\tthis.triggerKey = triggerKey;\r\n\t\tthis.triggerModifier = triggerModifier;\r\n\t\tthis.triggerSideBySideKey = triggerSideBySideKey;\r\n\t\tthis.triggerSideBySideModifier = triggerSideBySideModifier;\r\n\t}\r\n\r\n\tpublic equals(other: ClickLinkOptions): boolean {\r\n\t\treturn (\r\n\t\t\tthis.triggerKey === other.triggerKey\r\n\t\t\t&& this.triggerModifier === other.triggerModifier\r\n\t\t\t&& this.triggerSideBySideKey === other.triggerSideBySideKey\r\n\t\t\t&& this.triggerSideBySideModifier === other.triggerSideBySideModifier\r\n\t\t);\r\n\t}\r\n}\r\n\r\nfunction createOptions(multiCursorModifier: 'altKey' | 'ctrlKey' | 'metaKey'): ClickLinkOptions {\r\n\tif (multiCursorModifier === 'altKey') {\r\n\t\tif (platform.isMacintosh) {\r\n\t\t\treturn new ClickLinkOptions(KeyCode.Meta, 'metaKey', KeyCode.Alt, 'altKey');\r\n\t\t}\r\n\t\treturn new ClickLinkOptions(KeyCode.Ctrl, 'ctrlKey', KeyCode.Alt, 'altKey');\r\n\t}\r\n\r\n\tif (platform.isMacintosh) {\r\n\t\treturn new ClickLinkOptions(KeyCode.Alt, 'altKey', KeyCode.Meta, 'metaKey');\r\n\t}\r\n\treturn new ClickLinkOptions(KeyCode.Alt, 'altKey', KeyCode.Ctrl, 'ctrlKey');\r\n}\r\n\r\nexport class ClickLinkGesture extends Disposable {\r\n\r\n\tprivate readonly _onMouseMoveOrRelevantKeyDown: Emitter<[ClickLinkMouseEvent, ClickLinkKeyboardEvent | null]> = this._register(new Emitter<[ClickLinkMouseEvent, ClickLinkKeyboardEvent | null]>());\r\n\tpublic readonly onMouseMoveOrRelevantKeyDown: Event<[ClickLinkMouseEvent, ClickLinkKeyboardEvent | null]> = this._onMouseMoveOrRelevantKeyDown.event;\r\n\r\n\tprivate readonly _onExecute: Emitter = this._register(new Emitter());\r\n\tpublic readonly onExecute: Event = this._onExecute.event;\r\n\r\n\tprivate readonly _onCancel: Emitter = this._register(new Emitter());\r\n\tpublic readonly onCancel: Event = this._onCancel.event;\r\n\r\n\tprivate readonly _editor: ICodeEditor;\r\n\tprivate _opts: ClickLinkOptions;\r\n\r\n\tprivate _lastMouseMoveEvent: ClickLinkMouseEvent | null;\r\n\tprivate _hasTriggerKeyOnMouseDown: boolean;\r\n\tprivate _lineNumberOnMouseDown: number;\r\n\r\n\tconstructor(editor: ICodeEditor) {\r\n\t\tsuper();\r\n\r\n\t\tthis._editor = editor;\r\n\t\tthis._opts = createOptions(this._editor.getOption(EditorOption.multiCursorModifier));\r\n\r\n\t\tthis._lastMouseMoveEvent = null;\r\n\t\tthis._hasTriggerKeyOnMouseDown = false;\r\n\t\tthis._lineNumberOnMouseDown = 0;\r\n\r\n\t\tthis._register(this._editor.onDidChangeConfiguration((e) => {\r\n\t\t\tif (e.hasChanged(EditorOption.multiCursorModifier)) {\r\n\t\t\t\tconst newOpts = createOptions(this._editor.getOption(EditorOption.multiCursorModifier));\r\n\t\t\t\tif (this._opts.equals(newOpts)) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\tthis._opts = newOpts;\r\n\t\t\t\tthis._lastMouseMoveEvent = null;\r\n\t\t\t\tthis._hasTriggerKeyOnMouseDown = false;\r\n\t\t\t\tthis._lineNumberOnMouseDown = 0;\r\n\t\t\t\tthis._onCancel.fire();\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._register(this._editor.onMouseMove((e: IEditorMouseEvent) => this._onEditorMouseMove(new ClickLinkMouseEvent(e, this._opts))));\r\n\t\tthis._register(this._editor.onMouseDown((e: IEditorMouseEvent) => this._onEditorMouseDown(new ClickLinkMouseEvent(e, this._opts))));\r\n\t\tthis._register(this._editor.onMouseUp((e: IEditorMouseEvent) => this._onEditorMouseUp(new ClickLinkMouseEvent(e, this._opts))));\r\n\t\tthis._register(this._editor.onKeyDown((e: IKeyboardEvent) => this._onEditorKeyDown(new ClickLinkKeyboardEvent(e, this._opts))));\r\n\t\tthis._register(this._editor.onKeyUp((e: IKeyboardEvent) => this._onEditorKeyUp(new ClickLinkKeyboardEvent(e, this._opts))));\r\n\t\tthis._register(this._editor.onMouseDrag(() => this._resetHandler()));\r\n\r\n\t\tthis._register(this._editor.onDidChangeCursorSelection((e) => this._onDidChangeCursorSelection(e)));\r\n\t\tthis._register(this._editor.onDidChangeModel((e) => this._resetHandler()));\r\n\t\tthis._register(this._editor.onDidChangeModelContent(() => this._resetHandler()));\r\n\t\tthis._register(this._editor.onDidScrollChange((e) => {\r\n\t\t\tif (e.scrollTopChanged || e.scrollLeftChanged) {\r\n\t\t\t\tthis._resetHandler();\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\tprivate _onDidChangeCursorSelection(e: ICursorSelectionChangedEvent): void {\r\n\t\tif (e.selection && e.selection.startColumn !== e.selection.endColumn) {\r\n\t\t\tthis._resetHandler(); // immediately stop this feature if the user starts to select (https://github.com/microsoft/vscode/issues/7827)\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _onEditorMouseMove(mouseEvent: ClickLinkMouseEvent): void {\r\n\t\tthis._lastMouseMoveEvent = mouseEvent;\r\n\r\n\t\tthis._onMouseMoveOrRelevantKeyDown.fire([mouseEvent, null]);\r\n\t}\r\n\r\n\tprivate _onEditorMouseDown(mouseEvent: ClickLinkMouseEvent): void {\r\n\t\t// We need to record if we had the trigger key on mouse down because someone might select something in the editor\r\n\t\t// holding the mouse down and then while mouse is down start to press Ctrl/Cmd to start a copy operation and then\r\n\t\t// release the mouse button without wanting to do the navigation.\r\n\t\t// With this flag we prevent goto definition if the mouse was down before the trigger key was pressed.\r\n\t\tthis._hasTriggerKeyOnMouseDown = mouseEvent.hasTriggerModifier;\r\n\t\tthis._lineNumberOnMouseDown = mouseEvent.target.position ? mouseEvent.target.position.lineNumber : 0;\r\n\t}\r\n\r\n\tprivate _onEditorMouseUp(mouseEvent: ClickLinkMouseEvent): void {\r\n\t\tconst currentLineNumber = mouseEvent.target.position ? mouseEvent.target.position.lineNumber : 0;\r\n\t\tif (this._hasTriggerKeyOnMouseDown && this._lineNumberOnMouseDown && this._lineNumberOnMouseDown === currentLineNumber) {\r\n\t\t\tthis._onExecute.fire(mouseEvent);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _onEditorKeyDown(e: ClickLinkKeyboardEvent): void {\r\n\t\tif (\r\n\t\t\tthis._lastMouseMoveEvent\r\n\t\t\t&& (\r\n\t\t\t\te.keyCodeIsTriggerKey // User just pressed Ctrl/Cmd (normal goto definition)\r\n\t\t\t\t|| (e.keyCodeIsSideBySideKey && e.hasTriggerModifier) // User pressed Ctrl/Cmd+Alt (goto definition to the side)\r\n\t\t\t)\r\n\t\t) {\r\n\t\t\tthis._onMouseMoveOrRelevantKeyDown.fire([this._lastMouseMoveEvent, e]);\r\n\t\t} else if (e.hasTriggerModifier) {\r\n\t\t\tthis._onCancel.fire(); // remove decorations if user holds another key with ctrl/cmd to prevent accident goto declaration\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _onEditorKeyUp(e: ClickLinkKeyboardEvent): void {\r\n\t\tif (e.keyCodeIsTriggerKey) {\r\n\t\t\tthis._onCancel.fire();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _resetHandler(): void {\r\n\t\tthis._lastMouseMoveEvent = null;\r\n\t\tthis._hasTriggerKeyOnMouseDown = false;\r\n\t\tthis._onCancel.fire();\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CancelablePromise, RunOnceScheduler, createCancelablePromise } from 'vs/base/common/async';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\n\r\nexport interface IHoverComputer {\r\n\r\n\t/**\r\n\t * This is called after half the hover time\r\n\t */\r\n\tcomputeAsync?: (token: CancellationToken) => Promise;\r\n\r\n\t/**\r\n\t * This is called after all the hover time\r\n\t */\r\n\tcomputeSync?: () => Result;\r\n\r\n\t/**\r\n\t * This is called whenever one of the compute* methods returns a truey value\r\n\t */\r\n\tonResult: (result: Result, isFromSynchronousComputation: boolean) => void;\r\n\r\n\t/**\r\n\t * This is what will be sent as progress/complete to the computation promise\r\n\t */\r\n\tgetResult: () => Result;\r\n\r\n\tgetResultWithLoadingMessage: () => Result;\r\n\r\n}\r\n\r\nconst enum ComputeHoverOperationState {\r\n\tIDLE = 0,\r\n\tFIRST_WAIT = 1,\r\n\tSECOND_WAIT = 2,\r\n\tWAITING_FOR_ASYNC_COMPUTATION = 3\r\n}\r\n\r\nexport const enum HoverStartMode {\r\n\tDelayed = 0,\r\n\tImmediate = 1\r\n}\r\n\r\nexport class HoverOperation {\r\n\r\n\tprivate readonly _computer: IHoverComputer;\r\n\tprivate _state: ComputeHoverOperationState;\r\n\tprivate _hoverTime: number;\r\n\r\n\tprivate readonly _firstWaitScheduler: RunOnceScheduler;\r\n\tprivate readonly _secondWaitScheduler: RunOnceScheduler;\r\n\tprivate readonly _loadingMessageScheduler: RunOnceScheduler;\r\n\tprivate _asyncComputationPromise: CancelablePromise | null;\r\n\tprivate _asyncComputationPromiseDone: boolean;\r\n\r\n\tprivate readonly _completeCallback: (r: Result) => void;\r\n\tprivate readonly _errorCallback: ((err: any) => void) | null | undefined;\r\n\tprivate readonly _progressCallback: (progress: any) => void;\r\n\r\n\tconstructor(computer: IHoverComputer, success: (r: Result) => void, error: ((err: any) => void) | null | undefined, progress: (progress: any) => void, hoverTime: number) {\r\n\t\tthis._computer = computer;\r\n\t\tthis._state = ComputeHoverOperationState.IDLE;\r\n\t\tthis._hoverTime = hoverTime;\r\n\r\n\t\tthis._firstWaitScheduler = new RunOnceScheduler(() => this._triggerAsyncComputation(), 0);\r\n\t\tthis._secondWaitScheduler = new RunOnceScheduler(() => this._triggerSyncComputation(), 0);\r\n\t\tthis._loadingMessageScheduler = new RunOnceScheduler(() => this._showLoadingMessage(), 0);\r\n\r\n\t\tthis._asyncComputationPromise = null;\r\n\t\tthis._asyncComputationPromiseDone = false;\r\n\r\n\t\tthis._completeCallback = success;\r\n\t\tthis._errorCallback = error;\r\n\t\tthis._progressCallback = progress;\r\n\t}\r\n\r\n\tpublic setHoverTime(hoverTime: number): void {\r\n\t\tthis._hoverTime = hoverTime;\r\n\t}\r\n\r\n\tprivate _firstWaitTime(): number {\r\n\t\treturn this._hoverTime / 2;\r\n\t}\r\n\r\n\tprivate _secondWaitTime(): number {\r\n\t\treturn this._hoverTime / 2;\r\n\t}\r\n\r\n\tprivate _loadingMessageTime(): number {\r\n\t\treturn 3 * this._hoverTime;\r\n\t}\r\n\r\n\tprivate _triggerAsyncComputation(): void {\r\n\t\tthis._state = ComputeHoverOperationState.SECOND_WAIT;\r\n\t\tthis._secondWaitScheduler.schedule(this._secondWaitTime());\r\n\r\n\t\tif (this._computer.computeAsync) {\r\n\t\t\tthis._asyncComputationPromiseDone = false;\r\n\t\t\tthis._asyncComputationPromise = createCancelablePromise(token => this._computer.computeAsync!(token));\r\n\t\t\tthis._asyncComputationPromise.then((asyncResult: Result) => {\r\n\t\t\t\tthis._asyncComputationPromiseDone = true;\r\n\t\t\t\tthis._withAsyncResult(asyncResult);\r\n\t\t\t}, (e) => this._onError(e));\r\n\r\n\t\t} else {\r\n\t\t\tthis._asyncComputationPromiseDone = true;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _triggerSyncComputation(): void {\r\n\t\tif (this._computer.computeSync) {\r\n\t\t\tthis._computer.onResult(this._computer.computeSync(), true);\r\n\t\t}\r\n\r\n\t\tif (this._asyncComputationPromiseDone) {\r\n\t\t\tthis._state = ComputeHoverOperationState.IDLE;\r\n\t\t\tthis._onComplete(this._computer.getResult());\r\n\t\t} else {\r\n\t\t\tthis._state = ComputeHoverOperationState.WAITING_FOR_ASYNC_COMPUTATION;\r\n\t\t\tthis._onProgress(this._computer.getResult());\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _showLoadingMessage(): void {\r\n\t\tif (this._state === ComputeHoverOperationState.WAITING_FOR_ASYNC_COMPUTATION) {\r\n\t\t\tthis._onProgress(this._computer.getResultWithLoadingMessage());\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _withAsyncResult(asyncResult: Result): void {\r\n\t\tif (asyncResult) {\r\n\t\t\tthis._computer.onResult(asyncResult, false);\r\n\t\t}\r\n\r\n\t\tif (this._state === ComputeHoverOperationState.WAITING_FOR_ASYNC_COMPUTATION) {\r\n\t\t\tthis._state = ComputeHoverOperationState.IDLE;\r\n\t\t\tthis._onComplete(this._computer.getResult());\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _onComplete(value: Result): void {\r\n\t\tthis._completeCallback(value);\r\n\t}\r\n\r\n\tprivate _onError(error: any): void {\r\n\t\tif (this._errorCallback) {\r\n\t\t\tthis._errorCallback(error);\r\n\t\t} else {\r\n\t\t\tonUnexpectedError(error);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _onProgress(value: Result): void {\r\n\t\tthis._progressCallback(value);\r\n\t}\r\n\r\n\tpublic start(mode: HoverStartMode): void {\r\n\t\tif (mode === HoverStartMode.Delayed) {\r\n\t\t\tif (this._state === ComputeHoverOperationState.IDLE) {\r\n\t\t\t\tthis._state = ComputeHoverOperationState.FIRST_WAIT;\r\n\t\t\t\tthis._firstWaitScheduler.schedule(this._firstWaitTime());\r\n\t\t\t\tthis._loadingMessageScheduler.schedule(this._loadingMessageTime());\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tswitch (this._state) {\r\n\t\t\t\tcase ComputeHoverOperationState.IDLE:\r\n\t\t\t\t\tthis._triggerAsyncComputation();\r\n\t\t\t\t\tthis._secondWaitScheduler.cancel();\r\n\t\t\t\t\tthis._triggerSyncComputation();\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase ComputeHoverOperationState.SECOND_WAIT:\r\n\t\t\t\t\tthis._secondWaitScheduler.cancel();\r\n\t\t\t\t\tthis._triggerSyncComputation();\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic cancel(): void {\r\n\t\tthis._loadingMessageScheduler.cancel();\r\n\t\tif (this._state === ComputeHoverOperationState.FIRST_WAIT) {\r\n\t\t\tthis._firstWaitScheduler.cancel();\r\n\t\t}\r\n\t\tif (this._state === ComputeHoverOperationState.SECOND_WAIT) {\r\n\t\t\tthis._secondWaitScheduler.cancel();\r\n\t\t\tif (this._asyncComputationPromise) {\r\n\t\t\t\tthis._asyncComputationPromise.cancel();\r\n\t\t\t\tthis._asyncComputationPromise = null;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (this._state === ComputeHoverOperationState.WAITING_FOR_ASYNC_COMPUTATION) {\r\n\t\t\tif (this._asyncComputationPromise) {\r\n\t\t\t\tthis._asyncComputationPromise.cancel();\r\n\t\t\t\tthis._asyncComputationPromise = null;\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis._state = ComputeHoverOperationState.IDLE;\r\n\t}\r\n\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Widget } from 'vs/base/browser/ui/widget';\r\nimport { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition } from 'vs/editor/browser/editorBrowser';\r\nimport { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\nexport class GlyphHoverWidget extends Widget implements IOverlayWidget {\r\n\r\n\tprivate readonly _id: string;\r\n\tprotected _editor: ICodeEditor;\r\n\tprivate _isVisible: boolean;\r\n\tprivate readonly _domNode: HTMLElement;\r\n\tprotected _showAtLineNumber: number;\r\n\r\n\tconstructor(id: string, editor: ICodeEditor) {\r\n\t\tsuper();\r\n\t\tthis._id = id;\r\n\t\tthis._editor = editor;\r\n\t\tthis._isVisible = false;\r\n\r\n\t\tthis._domNode = document.createElement('div');\r\n\t\tthis._domNode.className = 'monaco-hover hidden';\r\n\t\tthis._domNode.setAttribute('aria-hidden', 'true');\r\n\t\tthis._domNode.setAttribute('role', 'tooltip');\r\n\r\n\t\tthis._showAtLineNumber = -1;\r\n\r\n\t\tthis._register(this._editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => {\r\n\t\t\tif (e.hasChanged(EditorOption.fontInfo)) {\r\n\t\t\t\tthis.updateFont();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._editor.addOverlayWidget(this);\r\n\t}\r\n\r\n\tprotected get isVisible(): boolean {\r\n\t\treturn this._isVisible;\r\n\t}\r\n\r\n\tprotected set isVisible(value: boolean) {\r\n\t\tthis._isVisible = value;\r\n\t\tthis._domNode.classList.toggle('hidden', !this._isVisible);\r\n\t}\r\n\r\n\tpublic getId(): string {\r\n\t\treturn this._id;\r\n\t}\r\n\r\n\tpublic getDomNode(): HTMLElement {\r\n\t\treturn this._domNode;\r\n\t}\r\n\r\n\tpublic showAt(lineNumber: number): void {\r\n\t\tthis._showAtLineNumber = lineNumber;\r\n\r\n\t\tif (!this.isVisible) {\r\n\t\t\tthis.isVisible = true;\r\n\t\t}\r\n\r\n\t\tconst editorLayout = this._editor.getLayoutInfo();\r\n\t\tconst topForLineNumber = this._editor.getTopForLineNumber(this._showAtLineNumber);\r\n\t\tconst editorScrollTop = this._editor.getScrollTop();\r\n\t\tconst lineHeight = this._editor.getOption(EditorOption.lineHeight);\r\n\t\tconst nodeHeight = this._domNode.clientHeight;\r\n\t\tconst top = topForLineNumber - editorScrollTop - ((nodeHeight - lineHeight) / 2);\r\n\r\n\t\tthis._domNode.style.left = `${editorLayout.glyphMarginLeft + editorLayout.glyphMarginWidth}px`;\r\n\t\tthis._domNode.style.top = `${Math.max(Math.round(top), 0)}px`;\r\n\t}\r\n\r\n\tpublic hide(): void {\r\n\t\tif (!this.isVisible) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis.isVisible = false;\r\n\t}\r\n\r\n\tpublic getPosition(): IOverlayWidgetPosition | null {\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._editor.removeOverlayWidget(this);\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tprivate updateFont(): void {\r\n\t\tconst codeTags: HTMLElement[] = Array.prototype.slice.call(this._domNode.getElementsByTagName('code'));\r\n\t\tconst codeClasses: HTMLElement[] = Array.prototype.slice.call(this._domNode.getElementsByClassName('code'));\r\n\r\n\t\t[...codeTags, ...codeClasses].forEach(node => this._editor.applyFontInfo(node));\r\n\t}\r\n\r\n\tprotected updateContents(node: Node): void {\r\n\t\tthis._domNode.textContent = '';\r\n\t\tthis._domNode.appendChild(node);\r\n\t\tthis.updateFont();\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { ICommand, IEditOperationBuilder, ICursorStateComputerData } from 'vs/editor/common/editorCommon';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\n\r\nexport class InPlaceReplaceCommand implements ICommand {\r\n\r\n\tprivate readonly _editRange: Range;\r\n\tprivate readonly _originalSelection: Selection;\r\n\tprivate readonly _text: string;\r\n\r\n\tconstructor(editRange: Range, originalSelection: Selection, text: string) {\r\n\t\tthis._editRange = editRange;\r\n\t\tthis._originalSelection = originalSelection;\r\n\t\tthis._text = text;\r\n\t}\r\n\r\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\r\n\t\tbuilder.addTrackedEditOperation(this._editRange, this._text);\r\n\t}\r\n\r\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\r\n\t\tconst inverseEditOperations = helper.getInverseEditOperations();\r\n\t\tconst srcRange = inverseEditOperations[0].range;\r\n\r\n\t\tif (!this._originalSelection.isEmpty()) {\r\n\t\t\t// Preserve selection and extends to typed text\r\n\t\t\treturn new Selection(\r\n\t\t\t\tsrcRange.endLineNumber,\r\n\t\t\t\tsrcRange.endColumn - this._text.length,\r\n\t\t\t\tsrcRange.endLineNumber,\r\n\t\t\t\tsrcRange.endColumn\r\n\t\t\t);\r\n\t\t}\r\n\r\n\t\treturn new Selection(\r\n\t\t\tsrcRange.endLineNumber,\r\n\t\t\tMath.min(this._originalSelection.positionColumn, srcRange.endColumn),\r\n\t\t\tsrcRange.endLineNumber,\r\n\t\t\tMath.min(this._originalSelection.positionColumn, srcRange.endColumn)\r\n\t\t);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nexport function getSpaceCnt(str: string, tabSize: number) {\r\n\tlet spacesCnt = 0;\r\n\r\n\tfor (let i = 0; i < str.length; i++) {\r\n\t\tif (str.charAt(i) === '\\t') {\r\n\t\t\tspacesCnt += tabSize;\r\n\t\t} else {\r\n\t\t\tspacesCnt++;\r\n\t\t}\r\n\t}\r\n\r\n\treturn spacesCnt;\r\n}\r\n\r\nexport function generateIndent(spacesCnt: number, tabSize: number, insertSpaces: boolean) {\r\n\tspacesCnt = spacesCnt < 0 ? 0 : spacesCnt;\r\n\r\n\tlet result = '';\r\n\tif (!insertSpaces) {\r\n\t\tlet tabsCnt = Math.floor(spacesCnt / tabSize);\r\n\t\tspacesCnt = spacesCnt % tabSize;\r\n\t\tfor (let i = 0; i < tabsCnt; i++) {\r\n\t\t\tresult += '\\t';\r\n\t\t}\r\n\t}\r\n\r\n\tfor (let i = 0; i < spacesCnt; i++) {\r\n\t\tresult += ' ';\r\n\t}\r\n\r\n\treturn result;\r\n}","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection, SelectionDirection } from 'vs/editor/common/core/selection';\r\nimport { ICommand, IEditOperationBuilder, ICursorStateComputerData } from 'vs/editor/common/editorCommon';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\n\r\nexport class CopyLinesCommand implements ICommand {\r\n\r\n\tprivate readonly _selection: Selection;\r\n\tprivate readonly _isCopyingDown: boolean;\r\n\tprivate readonly _noop: boolean;\r\n\r\n\tprivate _selectionDirection: SelectionDirection;\r\n\tprivate _selectionId: string | null;\r\n\tprivate _startLineNumberDelta: number;\r\n\tprivate _endLineNumberDelta: number;\r\n\r\n\tconstructor(selection: Selection, isCopyingDown: boolean, noop?: boolean) {\r\n\t\tthis._selection = selection;\r\n\t\tthis._isCopyingDown = isCopyingDown;\r\n\t\tthis._noop = noop || false;\r\n\t\tthis._selectionDirection = SelectionDirection.LTR;\r\n\t\tthis._selectionId = null;\r\n\t\tthis._startLineNumberDelta = 0;\r\n\t\tthis._endLineNumberDelta = 0;\r\n\t}\r\n\r\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\r\n\t\tlet s = this._selection;\r\n\r\n\t\tthis._startLineNumberDelta = 0;\r\n\t\tthis._endLineNumberDelta = 0;\r\n\t\tif (s.startLineNumber < s.endLineNumber && s.endColumn === 1) {\r\n\t\t\tthis._endLineNumberDelta = 1;\r\n\t\t\ts = s.setEndPosition(s.endLineNumber - 1, model.getLineMaxColumn(s.endLineNumber - 1));\r\n\t\t}\r\n\r\n\t\tlet sourceLines: string[] = [];\r\n\t\tfor (let i = s.startLineNumber; i <= s.endLineNumber; i++) {\r\n\t\t\tsourceLines.push(model.getLineContent(i));\r\n\t\t}\r\n\t\tconst sourceText = sourceLines.join('\\n');\r\n\r\n\t\tif (sourceText === '') {\r\n\t\t\t// Duplicating empty line\r\n\t\t\tif (this._isCopyingDown) {\r\n\t\t\t\tthis._startLineNumberDelta++;\r\n\t\t\t\tthis._endLineNumberDelta++;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (this._noop) {\r\n\t\t\tbuilder.addEditOperation(new Range(s.endLineNumber, model.getLineMaxColumn(s.endLineNumber), s.endLineNumber + 1, 1), s.endLineNumber === model.getLineCount() ? '' : '\\n');\r\n\t\t} else {\r\n\t\t\tif (!this._isCopyingDown) {\r\n\t\t\t\tbuilder.addEditOperation(new Range(s.endLineNumber, model.getLineMaxColumn(s.endLineNumber), s.endLineNumber, model.getLineMaxColumn(s.endLineNumber)), '\\n' + sourceText);\r\n\t\t\t} else {\r\n\t\t\t\tbuilder.addEditOperation(new Range(s.startLineNumber, 1, s.startLineNumber, 1), sourceText + '\\n');\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._selectionId = builder.trackSelection(s);\r\n\t\tthis._selectionDirection = this._selection.getDirection();\r\n\t}\r\n\r\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\r\n\t\tlet result = helper.getTrackedSelection(this._selectionId!);\r\n\r\n\t\tif (this._startLineNumberDelta !== 0 || this._endLineNumberDelta !== 0) {\r\n\t\t\tlet startLineNumber = result.startLineNumber;\r\n\t\t\tlet startColumn = result.startColumn;\r\n\t\t\tlet endLineNumber = result.endLineNumber;\r\n\t\t\tlet endColumn = result.endColumn;\r\n\r\n\t\t\tif (this._startLineNumberDelta !== 0) {\r\n\t\t\t\tstartLineNumber = startLineNumber + this._startLineNumberDelta;\r\n\t\t\t\tstartColumn = 1;\r\n\t\t\t}\r\n\r\n\t\t\tif (this._endLineNumberDelta !== 0) {\r\n\t\t\t\tendLineNumber = endLineNumber + this._endLineNumberDelta;\r\n\t\t\t\tendColumn = 1;\r\n\t\t\t}\r\n\r\n\t\t\tresult = Selection.createWithDirection(startLineNumber, startColumn, endLineNumber, endColumn, this._selectionDirection);\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { EditOperation } from 'vs/editor/common/core/editOperation';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { ICommand, IEditOperationBuilder, ICursorStateComputerData } from 'vs/editor/common/editorCommon';\r\nimport { IIdentifiedSingleEditOperation, ITextModel } from 'vs/editor/common/model';\r\n\r\nexport class SortLinesCommand implements ICommand {\r\n\r\n\tprivate static _COLLATOR: Intl.Collator | null = null;\r\n\tpublic static getCollator(): Intl.Collator {\r\n\t\tif (!SortLinesCommand._COLLATOR) {\r\n\t\t\tSortLinesCommand._COLLATOR = new Intl.Collator();\r\n\t\t}\r\n\t\treturn SortLinesCommand._COLLATOR;\r\n\t}\r\n\r\n\tprivate readonly selection: Selection;\r\n\tprivate readonly descending: boolean;\r\n\tprivate selectionId: string | null;\r\n\r\n\tconstructor(selection: Selection, descending: boolean) {\r\n\t\tthis.selection = selection;\r\n\t\tthis.descending = descending;\r\n\t\tthis.selectionId = null;\r\n\t}\r\n\r\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\r\n\t\tlet op = sortLines(model, this.selection, this.descending);\r\n\t\tif (op) {\r\n\t\t\tbuilder.addEditOperation(op.range, op.text);\r\n\t\t}\r\n\r\n\t\tthis.selectionId = builder.trackSelection(this.selection);\r\n\t}\r\n\r\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\r\n\t\treturn helper.getTrackedSelection(this.selectionId!);\r\n\t}\r\n\r\n\tpublic static canRun(model: ITextModel | null, selection: Selection, descending: boolean): boolean {\r\n\t\tif (model === null) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tlet data = getSortData(model, selection, descending);\r\n\r\n\t\tif (!data) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tfor (let i = 0, len = data.before.length; i < len; i++) {\r\n\t\t\tif (data.before[i] !== data.after[i]) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\nfunction getSortData(model: ITextModel, selection: Selection, descending: boolean) {\r\n\tlet startLineNumber = selection.startLineNumber;\r\n\tlet endLineNumber = selection.endLineNumber;\r\n\r\n\tif (selection.endColumn === 1) {\r\n\t\tendLineNumber--;\r\n\t}\r\n\r\n\t// Nothing to sort if user didn't select anything.\r\n\tif (startLineNumber >= endLineNumber) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\tlet linesToSort: string[] = [];\r\n\r\n\t// Get the contents of the selection to be sorted.\r\n\tfor (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {\r\n\t\tlinesToSort.push(model.getLineContent(lineNumber));\r\n\t}\r\n\r\n\tlet sorted = linesToSort.slice(0);\r\n\tsorted.sort(SortLinesCommand.getCollator().compare);\r\n\r\n\t// If descending, reverse the order.\r\n\tif (descending === true) {\r\n\t\tsorted = sorted.reverse();\r\n\t}\r\n\r\n\treturn {\r\n\t\tstartLineNumber: startLineNumber,\r\n\t\tendLineNumber: endLineNumber,\r\n\t\tbefore: linesToSort,\r\n\t\tafter: sorted\r\n\t};\r\n}\r\n\r\n/**\r\n * Generate commands for sorting lines on a model.\r\n */\r\nfunction sortLines(model: ITextModel, selection: Selection, descending: boolean): IIdentifiedSingleEditOperation | null {\r\n\tlet data = getSortData(model, selection, descending);\r\n\r\n\tif (!data) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\treturn EditOperation.replace(\r\n\t\tnew Range(data.startLineNumber, 1, data.endLineNumber, model.getLineMaxColumn(data.endLineNumber)),\r\n\t\tdata.after.join('\\n')\r\n\t);\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { SelectionRangeProvider, SelectionRange } from 'vs/editor/common/modes';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { LinkedList } from 'vs/base/common/linkedList';\r\n\r\nexport class BracketSelectionRangeProvider implements SelectionRangeProvider {\r\n\r\n\tasync provideSelectionRanges(model: ITextModel, positions: Position[]): Promise {\r\n\t\tconst result: SelectionRange[][] = [];\r\n\r\n\t\tfor (const position of positions) {\r\n\t\t\tconst bucket: SelectionRange[] = [];\r\n\t\t\tresult.push(bucket);\r\n\r\n\t\t\tconst ranges = new Map>();\r\n\t\t\tawait new Promise(resolve => BracketSelectionRangeProvider._bracketsRightYield(resolve, 0, model, position, ranges));\r\n\t\t\tawait new Promise(resolve => BracketSelectionRangeProvider._bracketsLeftYield(resolve, 0, model, position, ranges, bucket));\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic static _maxDuration = 30;\r\n\tprivate static readonly _maxRounds = 2;\r\n\r\n\tprivate static _bracketsRightYield(resolve: () => void, round: number, model: ITextModel, pos: Position, ranges: Map>): void {\r\n\t\tconst counts = new Map();\r\n\t\tconst t1 = Date.now();\r\n\t\twhile (true) {\r\n\t\t\tif (round >= BracketSelectionRangeProvider._maxRounds) {\r\n\t\t\t\tresolve();\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tif (!pos) {\r\n\t\t\t\tresolve();\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tlet bracket = model.findNextBracket(pos);\r\n\t\t\tif (!bracket) {\r\n\t\t\t\tresolve();\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tlet d = Date.now() - t1;\r\n\t\t\tif (d > BracketSelectionRangeProvider._maxDuration) {\r\n\t\t\t\tsetTimeout(() => BracketSelectionRangeProvider._bracketsRightYield(resolve, round + 1, model, pos, ranges));\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tconst key = bracket.close[0];\r\n\t\t\tif (bracket.isOpen) {\r\n\t\t\t\t// wait for closing\r\n\t\t\t\tlet val = counts.has(key) ? counts.get(key)! : 0;\r\n\t\t\t\tcounts.set(key, val + 1);\r\n\t\t\t} else {\r\n\t\t\t\t// process closing\r\n\t\t\t\tlet val = counts.has(key) ? counts.get(key)! : 0;\r\n\t\t\t\tval -= 1;\r\n\t\t\t\tcounts.set(key, Math.max(0, val));\r\n\t\t\t\tif (val < 0) {\r\n\t\t\t\t\tlet list = ranges.get(key);\r\n\t\t\t\t\tif (!list) {\r\n\t\t\t\t\t\tlist = new LinkedList();\r\n\t\t\t\t\t\tranges.set(key, list);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tlist.push(bracket.range);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tpos = bracket.range.getEndPosition();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static _bracketsLeftYield(resolve: () => void, round: number, model: ITextModel, pos: Position, ranges: Map>, bucket: SelectionRange[]): void {\r\n\t\tconst counts = new Map();\r\n\t\tconst t1 = Date.now();\r\n\t\twhile (true) {\r\n\t\t\tif (round >= BracketSelectionRangeProvider._maxRounds && ranges.size === 0) {\r\n\t\t\t\tresolve();\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tif (!pos) {\r\n\t\t\t\tresolve();\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tlet bracket = model.findPrevBracket(pos);\r\n\t\t\tif (!bracket) {\r\n\t\t\t\tresolve();\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tlet d = Date.now() - t1;\r\n\t\t\tif (d > BracketSelectionRangeProvider._maxDuration) {\r\n\t\t\t\tsetTimeout(() => BracketSelectionRangeProvider._bracketsLeftYield(resolve, round + 1, model, pos, ranges, bucket));\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tconst key = bracket.close[0];\r\n\t\t\tif (!bracket.isOpen) {\r\n\t\t\t\t// wait for opening\r\n\t\t\t\tlet val = counts.has(key) ? counts.get(key)! : 0;\r\n\t\t\t\tcounts.set(key, val + 1);\r\n\t\t\t} else {\r\n\t\t\t\t// opening\r\n\t\t\t\tlet val = counts.has(key) ? counts.get(key)! : 0;\r\n\t\t\t\tval -= 1;\r\n\t\t\t\tcounts.set(key, Math.max(0, val));\r\n\t\t\t\tif (val < 0) {\r\n\t\t\t\t\tlet list = ranges.get(key);\r\n\t\t\t\t\tif (list) {\r\n\t\t\t\t\t\tlet closing = list.shift();\r\n\t\t\t\t\t\tif (list.size === 0) {\r\n\t\t\t\t\t\t\tranges.delete(key);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tconst innerBracket = Range.fromPositions(bracket.range.getEndPosition(), closing!.getStartPosition());\r\n\t\t\t\t\t\tconst outerBracket = Range.fromPositions(bracket.range.getStartPosition(), closing!.getEndPosition());\r\n\t\t\t\t\t\tbucket.push({ range: innerBracket });\r\n\t\t\t\t\t\tbucket.push({ range: outerBracket });\r\n\t\t\t\t\t\tBracketSelectionRangeProvider._addBracketLeading(model, outerBracket, bucket);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tpos = bracket.range.getStartPosition();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static _addBracketLeading(model: ITextModel, bracket: Range, bucket: SelectionRange[]): void {\r\n\t\tif (bracket.startLineNumber === bracket.endLineNumber) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\t// xxxxxxxx {\r\n\t\t//\r\n\t\t// }\r\n\t\tconst startLine = bracket.startLineNumber;\r\n\t\tconst column = model.getLineFirstNonWhitespaceColumn(startLine);\r\n\t\tif (column !== 0 && column !== bracket.startColumn) {\r\n\t\t\tbucket.push({ range: Range.fromPositions(new Position(startLine, column), bracket.getEndPosition()) });\r\n\t\t\tbucket.push({ range: Range.fromPositions(new Position(startLine, 1), bracket.getEndPosition()) });\r\n\t\t}\r\n\r\n\t\t// xxxxxxxx\r\n\t\t// {\r\n\t\t//\r\n\t\t// }\r\n\t\tconst aboveLine = startLine - 1;\r\n\t\tif (aboveLine > 0) {\r\n\t\t\tconst column = model.getLineFirstNonWhitespaceColumn(aboveLine);\r\n\t\t\tif (column === bracket.startColumn && column !== model.getLineLastNonWhitespaceColumn(aboveLine)) {\r\n\t\t\t\tbucket.push({ range: Range.fromPositions(new Position(aboveLine, column), bracket.getEndPosition()) });\r\n\t\t\t\tbucket.push({ range: Range.fromPositions(new Position(aboveLine, 1), bracket.getEndPosition()) });\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { SelectionRangeProvider, SelectionRange } from 'vs/editor/common/modes';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport { isUpperAsciiLetter, isLowerAsciiLetter } from 'vs/base/common/strings';\r\n\r\nexport class WordSelectionRangeProvider implements SelectionRangeProvider {\r\n\r\n\tprovideSelectionRanges(model: ITextModel, positions: Position[]): SelectionRange[][] {\r\n\t\tconst result: SelectionRange[][] = [];\r\n\t\tfor (const position of positions) {\r\n\t\t\tconst bucket: SelectionRange[] = [];\r\n\t\t\tresult.push(bucket);\r\n\t\t\tthis._addInWordRanges(bucket, model, position);\r\n\t\t\tthis._addWordRanges(bucket, model, position);\r\n\t\t\tthis._addWhitespaceLine(bucket, model, position);\r\n\t\t\tbucket.push({ range: model.getFullModelRange() });\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate _addInWordRanges(bucket: SelectionRange[], model: ITextModel, pos: Position): void {\r\n\t\tconst obj = model.getWordAtPosition(pos);\r\n\t\tif (!obj) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet { word, startColumn } = obj;\r\n\t\tlet offset = pos.column - startColumn;\r\n\t\tlet start = offset;\r\n\t\tlet end = offset;\r\n\t\tlet lastCh: number = 0;\r\n\r\n\t\t// LEFT anchor (start)\r\n\t\tfor (; start >= 0; start--) {\r\n\t\t\tlet ch = word.charCodeAt(start);\r\n\t\t\tif ((start !== offset) && (ch === CharCode.Underline || ch === CharCode.Dash)) {\r\n\t\t\t\t// foo-bar OR foo_bar\r\n\t\t\t\tbreak;\r\n\t\t\t} else if (isLowerAsciiLetter(ch) && isUpperAsciiLetter(lastCh)) {\r\n\t\t\t\t// fooBar\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tlastCh = ch;\r\n\t\t}\r\n\t\tstart += 1;\r\n\r\n\t\t// RIGHT anchor (end)\r\n\t\tfor (; end < word.length; end++) {\r\n\t\t\tlet ch = word.charCodeAt(end);\r\n\t\t\tif (isUpperAsciiLetter(ch) && isLowerAsciiLetter(lastCh)) {\r\n\t\t\t\t// fooBar\r\n\t\t\t\tbreak;\r\n\t\t\t} else if (ch === CharCode.Underline || ch === CharCode.Dash) {\r\n\t\t\t\t// foo-bar OR foo_bar\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tlastCh = ch;\r\n\t\t}\r\n\r\n\t\tif (start < end) {\r\n\t\t\tbucket.push({ range: new Range(pos.lineNumber, startColumn + start, pos.lineNumber, startColumn + end) });\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _addWordRanges(bucket: SelectionRange[], model: ITextModel, pos: Position): void {\r\n\t\tconst word = model.getWordAtPosition(pos);\r\n\t\tif (word) {\r\n\t\t\tbucket.push({ range: new Range(pos.lineNumber, word.startColumn, pos.lineNumber, word.endColumn) });\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _addWhitespaceLine(bucket: SelectionRange[], model: ITextModel, pos: Position): void {\r\n\t\tif (model.getLineLength(pos.lineNumber) > 0\r\n\t\t\t&& model.getLineFirstNonWhitespaceColumn(pos.lineNumber) === 0\r\n\t\t\t&& model.getLineLastNonWhitespaceColumn(pos.lineNumber) === 0\r\n\t\t) {\r\n\t\t\tbucket.push({ range: new Range(pos.lineNumber, 1, pos.lineNumber, model.getLineMaxColumn(pos.lineNumber)) });\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CharCode } from 'vs/base/common/charCode';\r\n\r\nexport const enum TokenType {\r\n\tDollar,\r\n\tColon,\r\n\tComma,\r\n\tCurlyOpen,\r\n\tCurlyClose,\r\n\tBackslash,\r\n\tForwardslash,\r\n\tPipe,\r\n\tInt,\r\n\tVariableName,\r\n\tFormat,\r\n\tPlus,\r\n\tDash,\r\n\tQuestionMark,\r\n\tEOF\r\n}\r\n\r\nexport interface Token {\r\n\ttype: TokenType;\r\n\tpos: number;\r\n\tlen: number;\r\n}\r\n\r\n\r\nexport class Scanner {\r\n\r\n\tprivate static _table: { [ch: number]: TokenType } = {\r\n\t\t[CharCode.DollarSign]: TokenType.Dollar,\r\n\t\t[CharCode.Colon]: TokenType.Colon,\r\n\t\t[CharCode.Comma]: TokenType.Comma,\r\n\t\t[CharCode.OpenCurlyBrace]: TokenType.CurlyOpen,\r\n\t\t[CharCode.CloseCurlyBrace]: TokenType.CurlyClose,\r\n\t\t[CharCode.Backslash]: TokenType.Backslash,\r\n\t\t[CharCode.Slash]: TokenType.Forwardslash,\r\n\t\t[CharCode.Pipe]: TokenType.Pipe,\r\n\t\t[CharCode.Plus]: TokenType.Plus,\r\n\t\t[CharCode.Dash]: TokenType.Dash,\r\n\t\t[CharCode.QuestionMark]: TokenType.QuestionMark,\r\n\t};\r\n\r\n\tstatic isDigitCharacter(ch: number): boolean {\r\n\t\treturn ch >= CharCode.Digit0 && ch <= CharCode.Digit9;\r\n\t}\r\n\r\n\tstatic isVariableCharacter(ch: number): boolean {\r\n\t\treturn ch === CharCode.Underline\r\n\t\t\t|| (ch >= CharCode.a && ch <= CharCode.z)\r\n\t\t\t|| (ch >= CharCode.A && ch <= CharCode.Z);\r\n\t}\r\n\r\n\tvalue: string = '';\r\n\tpos: number = 0;\r\n\r\n\ttext(value: string) {\r\n\t\tthis.value = value;\r\n\t\tthis.pos = 0;\r\n\t}\r\n\r\n\ttokenText(token: Token): string {\r\n\t\treturn this.value.substr(token.pos, token.len);\r\n\t}\r\n\r\n\tnext(): Token {\r\n\r\n\t\tif (this.pos >= this.value.length) {\r\n\t\t\treturn { type: TokenType.EOF, pos: this.pos, len: 0 };\r\n\t\t}\r\n\r\n\t\tlet pos = this.pos;\r\n\t\tlet len = 0;\r\n\t\tlet ch = this.value.charCodeAt(pos);\r\n\t\tlet type: TokenType;\r\n\r\n\t\t// static types\r\n\t\ttype = Scanner._table[ch];\r\n\t\tif (typeof type === 'number') {\r\n\t\t\tthis.pos += 1;\r\n\t\t\treturn { type, pos, len: 1 };\r\n\t\t}\r\n\r\n\t\t// number\r\n\t\tif (Scanner.isDigitCharacter(ch)) {\r\n\t\t\ttype = TokenType.Int;\r\n\t\t\tdo {\r\n\t\t\t\tlen += 1;\r\n\t\t\t\tch = this.value.charCodeAt(pos + len);\r\n\t\t\t} while (Scanner.isDigitCharacter(ch));\r\n\r\n\t\t\tthis.pos += len;\r\n\t\t\treturn { type, pos, len };\r\n\t\t}\r\n\r\n\t\t// variable name\r\n\t\tif (Scanner.isVariableCharacter(ch)) {\r\n\t\t\ttype = TokenType.VariableName;\r\n\t\t\tdo {\r\n\t\t\t\tch = this.value.charCodeAt(pos + (++len));\r\n\t\t\t} while (Scanner.isVariableCharacter(ch) || Scanner.isDigitCharacter(ch));\r\n\r\n\t\t\tthis.pos += len;\r\n\t\t\treturn { type, pos, len };\r\n\t\t}\r\n\r\n\r\n\t\t// format\r\n\t\ttype = TokenType.Format;\r\n\t\tdo {\r\n\t\t\tlen += 1;\r\n\t\t\tch = this.value.charCodeAt(pos + len);\r\n\t\t} while (\r\n\t\t\t!isNaN(ch)\r\n\t\t\t&& typeof Scanner._table[ch] === 'undefined' // not static token\r\n\t\t\t&& !Scanner.isDigitCharacter(ch) // not number\r\n\t\t\t&& !Scanner.isVariableCharacter(ch) // not variable\r\n\t\t);\r\n\r\n\t\tthis.pos += len;\r\n\t\treturn { type, pos, len };\r\n\t}\r\n}\r\n\r\nexport abstract class Marker {\r\n\r\n\treadonly _markerBrand: any;\r\n\r\n\tpublic parent!: Marker;\r\n\tprotected _children: Marker[] = [];\r\n\r\n\tappendChild(child: Marker): this {\r\n\t\tif (child instanceof Text && this._children[this._children.length - 1] instanceof Text) {\r\n\t\t\t// this and previous child are text -> merge them\r\n\t\t\t(this._children[this._children.length - 1]).value += child.value;\r\n\t\t} else {\r\n\t\t\t// normal adoption of child\r\n\t\t\tchild.parent = this;\r\n\t\t\tthis._children.push(child);\r\n\t\t}\r\n\t\treturn this;\r\n\t}\r\n\r\n\treplace(child: Marker, others: Marker[]): void {\r\n\t\tconst { parent } = child;\r\n\t\tconst idx = parent.children.indexOf(child);\r\n\t\tconst newChildren = parent.children.slice(0);\r\n\t\tnewChildren.splice(idx, 1, ...others);\r\n\t\tparent._children = newChildren;\r\n\r\n\t\t(function _fixParent(children: Marker[], parent: Marker) {\r\n\t\t\tfor (const child of children) {\r\n\t\t\t\tchild.parent = parent;\r\n\t\t\t\t_fixParent(child.children, child);\r\n\t\t\t}\r\n\t\t})(others, parent);\r\n\t}\r\n\r\n\tget children(): Marker[] {\r\n\t\treturn this._children;\r\n\t}\r\n\r\n\tget snippet(): TextmateSnippet | undefined {\r\n\t\tlet candidate: Marker = this;\r\n\t\twhile (true) {\r\n\t\t\tif (!candidate) {\r\n\t\t\t\treturn undefined;\r\n\t\t\t}\r\n\t\t\tif (candidate instanceof TextmateSnippet) {\r\n\t\t\t\treturn candidate;\r\n\t\t\t}\r\n\t\t\tcandidate = candidate.parent;\r\n\t\t}\r\n\t}\r\n\r\n\ttoString(): string {\r\n\t\treturn this.children.reduce((prev, cur) => prev + cur.toString(), '');\r\n\t}\r\n\r\n\tlen(): number {\r\n\t\treturn 0;\r\n\t}\r\n\r\n\tabstract clone(): Marker;\r\n}\r\n\r\nexport class Text extends Marker {\r\n\r\n\tconstructor(public value: string) {\r\n\t\tsuper();\r\n\t}\r\n\ttoString() {\r\n\t\treturn this.value;\r\n\t}\r\n\tlen(): number {\r\n\t\treturn this.value.length;\r\n\t}\r\n\tclone(): Text {\r\n\t\treturn new Text(this.value);\r\n\t}\r\n}\r\n\r\nexport abstract class TransformableMarker extends Marker {\r\n\tpublic transform?: Transform;\r\n}\r\n\r\nexport class Placeholder extends TransformableMarker {\r\n\tstatic compareByIndex(a: Placeholder, b: Placeholder): number {\r\n\t\tif (a.index === b.index) {\r\n\t\t\treturn 0;\r\n\t\t} else if (a.isFinalTabstop) {\r\n\t\t\treturn 1;\r\n\t\t} else if (b.isFinalTabstop) {\r\n\t\t\treturn -1;\r\n\t\t} else if (a.index < b.index) {\r\n\t\t\treturn -1;\r\n\t\t} else if (a.index > b.index) {\r\n\t\t\treturn 1;\r\n\t\t} else {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t}\r\n\r\n\tconstructor(public index: number) {\r\n\t\tsuper();\r\n\t}\r\n\r\n\tget isFinalTabstop() {\r\n\t\treturn this.index === 0;\r\n\t}\r\n\r\n\tget choice(): Choice | undefined {\r\n\t\treturn this._children.length === 1 && this._children[0] instanceof Choice\r\n\t\t\t? this._children[0] as Choice\r\n\t\t\t: undefined;\r\n\t}\r\n\r\n\tclone(): Placeholder {\r\n\t\tlet ret = new Placeholder(this.index);\r\n\t\tif (this.transform) {\r\n\t\t\tret.transform = this.transform.clone();\r\n\t\t}\r\n\t\tret._children = this.children.map(child => child.clone());\r\n\t\treturn ret;\r\n\t}\r\n}\r\n\r\nexport class Choice extends Marker {\r\n\r\n\treadonly options: Text[] = [];\r\n\r\n\tappendChild(marker: Marker): this {\r\n\t\tif (marker instanceof Text) {\r\n\t\t\tmarker.parent = this;\r\n\t\t\tthis.options.push(marker);\r\n\t\t}\r\n\t\treturn this;\r\n\t}\r\n\r\n\ttoString() {\r\n\t\treturn this.options[0].value;\r\n\t}\r\n\r\n\tlen(): number {\r\n\t\treturn this.options[0].len();\r\n\t}\r\n\r\n\tclone(): Choice {\r\n\t\tlet ret = new Choice();\r\n\t\tthis.options.forEach(ret.appendChild, ret);\r\n\t\treturn ret;\r\n\t}\r\n}\r\n\r\nexport class Transform extends Marker {\r\n\r\n\tregexp: RegExp = new RegExp('');\r\n\r\n\tresolve(value: string): string {\r\n\t\tconst _this = this;\r\n\t\tlet didMatch = false;\r\n\t\tlet ret = value.replace(this.regexp, function () {\r\n\t\t\tdidMatch = true;\r\n\t\t\treturn _this._replace(Array.prototype.slice.call(arguments, 0, -2));\r\n\t\t});\r\n\t\t// when the regex didn't match and when the transform has\r\n\t\t// else branches, then run those\r\n\t\tif (!didMatch && this._children.some(child => child instanceof FormatString && Boolean(child.elseValue))) {\r\n\t\t\tret = this._replace([]);\r\n\t\t}\r\n\t\treturn ret;\r\n\t}\r\n\r\n\tprivate _replace(groups: string[]): string {\r\n\t\tlet ret = '';\r\n\t\tfor (const marker of this._children) {\r\n\t\t\tif (marker instanceof FormatString) {\r\n\t\t\t\tlet value = groups[marker.index] || '';\r\n\t\t\t\tvalue = marker.resolve(value);\r\n\t\t\t\tret += value;\r\n\t\t\t} else {\r\n\t\t\t\tret += marker.toString();\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn ret;\r\n\t}\r\n\r\n\ttoString(): string {\r\n\t\treturn '';\r\n\t}\r\n\r\n\tclone(): Transform {\r\n\t\tlet ret = new Transform();\r\n\t\tret.regexp = new RegExp(this.regexp.source, '' + (this.regexp.ignoreCase ? 'i' : '') + (this.regexp.global ? 'g' : ''));\r\n\t\tret._children = this.children.map(child => child.clone());\r\n\t\treturn ret;\r\n\t}\r\n\r\n}\r\n\r\nexport class FormatString extends Marker {\r\n\r\n\tconstructor(\r\n\t\treadonly index: number,\r\n\t\treadonly shorthandName?: string,\r\n\t\treadonly ifValue?: string,\r\n\t\treadonly elseValue?: string,\r\n\t) {\r\n\t\tsuper();\r\n\t}\r\n\r\n\tresolve(value?: string): string {\r\n\t\tif (this.shorthandName === 'upcase') {\r\n\t\t\treturn !value ? '' : value.toLocaleUpperCase();\r\n\t\t} else if (this.shorthandName === 'downcase') {\r\n\t\t\treturn !value ? '' : value.toLocaleLowerCase();\r\n\t\t} else if (this.shorthandName === 'capitalize') {\r\n\t\t\treturn !value ? '' : (value[0].toLocaleUpperCase() + value.substr(1));\r\n\t\t} else if (this.shorthandName === 'pascalcase') {\r\n\t\t\treturn !value ? '' : this._toPascalCase(value);\r\n\t\t} else if (Boolean(value) && typeof this.ifValue === 'string') {\r\n\t\t\treturn this.ifValue;\r\n\t\t} else if (!Boolean(value) && typeof this.elseValue === 'string') {\r\n\t\t\treturn this.elseValue;\r\n\t\t} else {\r\n\t\t\treturn value || '';\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _toPascalCase(value: string): string {\r\n\t\tconst match = value.match(/[a-z]+/gi);\r\n\t\tif (!match) {\r\n\t\t\treturn value;\r\n\t\t}\r\n\t\treturn match.map(function (word) {\r\n\t\t\treturn word.charAt(0).toUpperCase()\r\n\t\t\t\t+ word.substr(1).toLowerCase();\r\n\t\t})\r\n\t\t\t.join('');\r\n\t}\r\n\r\n\tclone(): FormatString {\r\n\t\tlet ret = new FormatString(this.index, this.shorthandName, this.ifValue, this.elseValue);\r\n\t\treturn ret;\r\n\t}\r\n}\r\n\r\nexport class Variable extends TransformableMarker {\r\n\r\n\tconstructor(public name: string) {\r\n\t\tsuper();\r\n\t}\r\n\r\n\tresolve(resolver: VariableResolver): boolean {\r\n\t\tlet value = resolver.resolve(this);\r\n\t\tif (this.transform) {\r\n\t\t\tvalue = this.transform.resolve(value || '');\r\n\t\t}\r\n\t\tif (value !== undefined) {\r\n\t\t\tthis._children = [new Text(value)];\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tclone(): Variable {\r\n\t\tconst ret = new Variable(this.name);\r\n\t\tif (this.transform) {\r\n\t\t\tret.transform = this.transform.clone();\r\n\t\t}\r\n\t\tret._children = this.children.map(child => child.clone());\r\n\t\treturn ret;\r\n\t}\r\n}\r\n\r\nexport interface VariableResolver {\r\n\tresolve(variable: Variable): string | undefined;\r\n}\r\n\r\nfunction walk(marker: Marker[], visitor: (marker: Marker) => boolean): void {\r\n\tconst stack = [...marker];\r\n\twhile (stack.length > 0) {\r\n\t\tconst marker = stack.shift()!;\r\n\t\tconst recurse = visitor(marker);\r\n\t\tif (!recurse) {\r\n\t\t\tbreak;\r\n\t\t}\r\n\t\tstack.unshift(...marker.children);\r\n\t}\r\n}\r\n\r\nexport class TextmateSnippet extends Marker {\r\n\r\n\tprivate _placeholders?: { all: Placeholder[], last?: Placeholder };\r\n\r\n\tget placeholderInfo() {\r\n\t\tif (!this._placeholders) {\r\n\t\t\t// fill in placeholders\r\n\t\t\tlet all: Placeholder[] = [];\r\n\t\t\tlet last: Placeholder | undefined;\r\n\t\t\tthis.walk(function (candidate) {\r\n\t\t\t\tif (candidate instanceof Placeholder) {\r\n\t\t\t\t\tall.push(candidate);\r\n\t\t\t\t\tlast = !last || last.index < candidate.index ? candidate : last;\r\n\t\t\t\t}\r\n\t\t\t\treturn true;\r\n\t\t\t});\r\n\t\t\tthis._placeholders = { all, last };\r\n\t\t}\r\n\t\treturn this._placeholders;\r\n\t}\r\n\r\n\tget placeholders(): Placeholder[] {\r\n\t\tconst { all } = this.placeholderInfo;\r\n\t\treturn all;\r\n\t}\r\n\r\n\toffset(marker: Marker): number {\r\n\t\tlet pos = 0;\r\n\t\tlet found = false;\r\n\t\tthis.walk(candidate => {\r\n\t\t\tif (candidate === marker) {\r\n\t\t\t\tfound = true;\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t\tpos += candidate.len();\r\n\t\t\treturn true;\r\n\t\t});\r\n\r\n\t\tif (!found) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\treturn pos;\r\n\t}\r\n\r\n\tfullLen(marker: Marker): number {\r\n\t\tlet ret = 0;\r\n\t\twalk([marker], marker => {\r\n\t\t\tret += marker.len();\r\n\t\t\treturn true;\r\n\t\t});\r\n\t\treturn ret;\r\n\t}\r\n\r\n\tenclosingPlaceholders(placeholder: Placeholder): Placeholder[] {\r\n\t\tlet ret: Placeholder[] = [];\r\n\t\tlet { parent } = placeholder;\r\n\t\twhile (parent) {\r\n\t\t\tif (parent instanceof Placeholder) {\r\n\t\t\t\tret.push(parent);\r\n\t\t\t}\r\n\t\t\tparent = parent.parent;\r\n\t\t}\r\n\t\treturn ret;\r\n\t}\r\n\r\n\tresolveVariables(resolver: VariableResolver): this {\r\n\t\tthis.walk(candidate => {\r\n\t\t\tif (candidate instanceof Variable) {\r\n\t\t\t\tif (candidate.resolve(resolver)) {\r\n\t\t\t\t\tthis._placeholders = undefined;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t});\r\n\t\treturn this;\r\n\t}\r\n\r\n\tappendChild(child: Marker) {\r\n\t\tthis._placeholders = undefined;\r\n\t\treturn super.appendChild(child);\r\n\t}\r\n\r\n\treplace(child: Marker, others: Marker[]): void {\r\n\t\tthis._placeholders = undefined;\r\n\t\treturn super.replace(child, others);\r\n\t}\r\n\r\n\tclone(): TextmateSnippet {\r\n\t\tlet ret = new TextmateSnippet();\r\n\t\tthis._children = this.children.map(child => child.clone());\r\n\t\treturn ret;\r\n\t}\r\n\r\n\twalk(visitor: (marker: Marker) => boolean): void {\r\n\t\twalk(this.children, visitor);\r\n\t}\r\n}\r\n\r\nexport class SnippetParser {\r\n\r\n\tstatic escape(value: string): string {\r\n\t\treturn value.replace(/\\$|}|\\\\/g, '\\\\$&');\r\n\t}\r\n\r\n\tstatic guessNeedsClipboard(template: string): boolean {\r\n\t\treturn /\\${?CLIPBOARD/.test(template);\r\n\t}\r\n\r\n\tprivate _scanner: Scanner = new Scanner();\r\n\tprivate _token: Token = { type: TokenType.EOF, pos: 0, len: 0 };\r\n\r\n\tparse(value: string, insertFinalTabstop?: boolean, enforceFinalTabstop?: boolean): TextmateSnippet {\r\n\r\n\t\tthis._scanner.text(value);\r\n\t\tthis._token = this._scanner.next();\r\n\r\n\t\tconst snippet = new TextmateSnippet();\r\n\t\twhile (this._parse(snippet)) {\r\n\t\t\t// nothing\r\n\t\t}\r\n\r\n\t\t// fill in values for placeholders. the first placeholder of an index\r\n\t\t// that has a value defines the value for all placeholders with that index\r\n\t\tconst placeholderDefaultValues = new Map();\r\n\t\tconst incompletePlaceholders: Placeholder[] = [];\r\n\t\tlet placeholderCount = 0;\r\n\t\tsnippet.walk(marker => {\r\n\t\t\tif (marker instanceof Placeholder) {\r\n\t\t\t\tplaceholderCount += 1;\r\n\t\t\t\tif (marker.isFinalTabstop) {\r\n\t\t\t\t\tplaceholderDefaultValues.set(0, undefined);\r\n\t\t\t\t} else if (!placeholderDefaultValues.has(marker.index) && marker.children.length > 0) {\r\n\t\t\t\t\tplaceholderDefaultValues.set(marker.index, marker.children);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tincompletePlaceholders.push(marker);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t});\r\n\t\tfor (const placeholder of incompletePlaceholders) {\r\n\t\t\tconst defaultValues = placeholderDefaultValues.get(placeholder.index);\r\n\t\t\tif (defaultValues) {\r\n\t\t\t\tconst clone = new Placeholder(placeholder.index);\r\n\t\t\t\tclone.transform = placeholder.transform;\r\n\t\t\t\tfor (const child of defaultValues) {\r\n\t\t\t\t\tclone.appendChild(child.clone());\r\n\t\t\t\t}\r\n\t\t\t\tsnippet.replace(placeholder, [clone]);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!enforceFinalTabstop) {\r\n\t\t\tenforceFinalTabstop = placeholderCount > 0 && insertFinalTabstop;\r\n\t\t}\r\n\r\n\t\tif (!placeholderDefaultValues.has(0) && enforceFinalTabstop) {\r\n\t\t\t// the snippet uses placeholders but has no\r\n\t\t\t// final tabstop defined -> insert at the end\r\n\t\t\tsnippet.appendChild(new Placeholder(0));\r\n\t\t}\r\n\r\n\t\treturn snippet;\r\n\t}\r\n\r\n\tprivate _accept(type?: TokenType): boolean;\r\n\tprivate _accept(type: TokenType | undefined, value: true): string;\r\n\tprivate _accept(type: TokenType, value?: boolean): boolean | string {\r\n\t\tif (type === undefined || this._token.type === type) {\r\n\t\t\tlet ret = !value ? true : this._scanner.tokenText(this._token);\r\n\t\t\tthis._token = this._scanner.next();\r\n\t\t\treturn ret;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tprivate _backTo(token: Token): false {\r\n\t\tthis._scanner.pos = token.pos + token.len;\r\n\t\tthis._token = token;\r\n\t\treturn false;\r\n\t}\r\n\r\n\tprivate _until(type: TokenType): false | string {\r\n\t\tconst start = this._token;\r\n\t\twhile (this._token.type !== type) {\r\n\t\t\tif (this._token.type === TokenType.EOF) {\r\n\t\t\t\treturn false;\r\n\t\t\t} else if (this._token.type === TokenType.Backslash) {\r\n\t\t\t\tconst nextToken = this._scanner.next();\r\n\t\t\t\tif (nextToken.type !== TokenType.Dollar\r\n\t\t\t\t\t&& nextToken.type !== TokenType.CurlyClose\r\n\t\t\t\t\t&& nextToken.type !== TokenType.Backslash) {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tthis._token = this._scanner.next();\r\n\t\t}\r\n\t\tconst value = this._scanner.value.substring(start.pos, this._token.pos).replace(/\\\\(\\$|}|\\\\)/g, '$1');\r\n\t\tthis._token = this._scanner.next();\r\n\t\treturn value;\r\n\t}\r\n\r\n\tprivate _parse(marker: Marker): boolean {\r\n\t\treturn this._parseEscaped(marker)\r\n\t\t\t|| this._parseTabstopOrVariableName(marker)\r\n\t\t\t|| this._parseComplexPlaceholder(marker)\r\n\t\t\t|| this._parseComplexVariable(marker)\r\n\t\t\t|| this._parseAnything(marker);\r\n\t}\r\n\r\n\t// \\$, \\\\, \\} -> just text\r\n\tprivate _parseEscaped(marker: Marker): boolean {\r\n\t\tlet value: string;\r\n\t\tif (value = this._accept(TokenType.Backslash, true)) {\r\n\t\t\t// saw a backslash, append escaped token or that backslash\r\n\t\t\tvalue = this._accept(TokenType.Dollar, true)\r\n\t\t\t\t|| this._accept(TokenType.CurlyClose, true)\r\n\t\t\t\t|| this._accept(TokenType.Backslash, true)\r\n\t\t\t\t|| value;\r\n\r\n\t\t\tmarker.appendChild(new Text(value));\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\t// $foo -> variable, $1 -> tabstop\r\n\tprivate _parseTabstopOrVariableName(parent: Marker): boolean {\r\n\t\tlet value: string;\r\n\t\tconst token = this._token;\r\n\t\tconst match = this._accept(TokenType.Dollar)\r\n\t\t\t&& (value = this._accept(TokenType.VariableName, true) || this._accept(TokenType.Int, true));\r\n\r\n\t\tif (!match) {\r\n\t\t\treturn this._backTo(token);\r\n\t\t}\r\n\r\n\t\tparent.appendChild(/^\\d+$/.test(value!)\r\n\t\t\t? new Placeholder(Number(value!))\r\n\t\t\t: new Variable(value!)\r\n\t\t);\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// ${1:}, ${1} -> placeholder\r\n\tprivate _parseComplexPlaceholder(parent: Marker): boolean {\r\n\t\tlet index: string;\r\n\t\tconst token = this._token;\r\n\t\tconst match = this._accept(TokenType.Dollar)\r\n\t\t\t&& this._accept(TokenType.CurlyOpen)\r\n\t\t\t&& (index = this._accept(TokenType.Int, true));\r\n\r\n\t\tif (!match) {\r\n\t\t\treturn this._backTo(token);\r\n\t\t}\r\n\r\n\t\tconst placeholder = new Placeholder(Number(index!));\r\n\r\n\t\tif (this._accept(TokenType.Colon)) {\r\n\t\t\t// ${1:}\r\n\t\t\twhile (true) {\r\n\r\n\t\t\t\t// ...} -> done\r\n\t\t\t\tif (this._accept(TokenType.CurlyClose)) {\r\n\t\t\t\t\tparent.appendChild(placeholder);\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (this._parse(placeholder)) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// fallback\r\n\t\t\t\tparent.appendChild(new Text('${' + index! + ':'));\r\n\t\t\t\tplaceholder.children.forEach(parent.appendChild, parent);\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t} else if (placeholder.index > 0 && this._accept(TokenType.Pipe)) {\r\n\t\t\t// ${1|one,two,three|}\r\n\t\t\tconst choice = new Choice();\r\n\r\n\t\t\twhile (true) {\r\n\t\t\t\tif (this._parseChoiceElement(choice)) {\r\n\r\n\t\t\t\t\tif (this._accept(TokenType.Comma)) {\r\n\t\t\t\t\t\t// opt, -> more\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (this._accept(TokenType.Pipe)) {\r\n\t\t\t\t\t\tplaceholder.appendChild(choice);\r\n\t\t\t\t\t\tif (this._accept(TokenType.CurlyClose)) {\r\n\t\t\t\t\t\t\t// ..|} -> done\r\n\t\t\t\t\t\t\tparent.appendChild(placeholder);\r\n\t\t\t\t\t\t\treturn true;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis._backTo(token);\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t} else if (this._accept(TokenType.Forwardslash)) {\r\n\t\t\t// ${1///}\r\n\t\t\tif (this._parseTransform(placeholder)) {\r\n\t\t\t\tparent.appendChild(placeholder);\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\r\n\t\t\tthis._backTo(token);\r\n\t\t\treturn false;\r\n\r\n\t\t} else if (this._accept(TokenType.CurlyClose)) {\r\n\t\t\t// ${1}\r\n\t\t\tparent.appendChild(placeholder);\r\n\t\t\treturn true;\r\n\r\n\t\t} else {\r\n\t\t\t// ${1 <- missing curly or colon\r\n\t\t\treturn this._backTo(token);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _parseChoiceElement(parent: Choice): boolean {\r\n\t\tconst token = this._token;\r\n\t\tconst values: string[] = [];\r\n\r\n\t\twhile (true) {\r\n\t\t\tif (this._token.type === TokenType.Comma || this._token.type === TokenType.Pipe) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tlet value: string;\r\n\t\t\tif (value = this._accept(TokenType.Backslash, true)) {\r\n\t\t\t\t// \\, \\|, or \\\\\r\n\t\t\t\tvalue = this._accept(TokenType.Comma, true)\r\n\t\t\t\t\t|| this._accept(TokenType.Pipe, true)\r\n\t\t\t\t\t|| this._accept(TokenType.Backslash, true)\r\n\t\t\t\t\t|| value;\r\n\t\t\t} else {\r\n\t\t\t\tvalue = this._accept(undefined, true);\r\n\t\t\t}\r\n\t\t\tif (!value) {\r\n\t\t\t\t// EOF\r\n\t\t\t\tthis._backTo(token);\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t\tvalues.push(value);\r\n\t\t}\r\n\r\n\t\tif (values.length === 0) {\r\n\t\t\tthis._backTo(token);\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tparent.appendChild(new Text(values.join('')));\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// ${foo:}, ${foo} -> variable\r\n\tprivate _parseComplexVariable(parent: Marker): boolean {\r\n\t\tlet name: string;\r\n\t\tconst token = this._token;\r\n\t\tconst match = this._accept(TokenType.Dollar)\r\n\t\t\t&& this._accept(TokenType.CurlyOpen)\r\n\t\t\t&& (name = this._accept(TokenType.VariableName, true));\r\n\r\n\t\tif (!match) {\r\n\t\t\treturn this._backTo(token);\r\n\t\t}\r\n\r\n\t\tconst variable = new Variable(name!);\r\n\r\n\t\tif (this._accept(TokenType.Colon)) {\r\n\t\t\t// ${foo:}\r\n\t\t\twhile (true) {\r\n\r\n\t\t\t\t// ...} -> done\r\n\t\t\t\tif (this._accept(TokenType.CurlyClose)) {\r\n\t\t\t\t\tparent.appendChild(variable);\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (this._parse(variable)) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// fallback\r\n\t\t\t\tparent.appendChild(new Text('${' + name! + ':'));\r\n\t\t\t\tvariable.children.forEach(parent.appendChild, parent);\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\r\n\t\t} else if (this._accept(TokenType.Forwardslash)) {\r\n\t\t\t// ${foo///}\r\n\t\t\tif (this._parseTransform(variable)) {\r\n\t\t\t\tparent.appendChild(variable);\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\r\n\t\t\tthis._backTo(token);\r\n\t\t\treturn false;\r\n\r\n\t\t} else if (this._accept(TokenType.CurlyClose)) {\r\n\t\t\t// ${foo}\r\n\t\t\tparent.appendChild(variable);\r\n\t\t\treturn true;\r\n\r\n\t\t} else {\r\n\t\t\t// ${foo <- missing curly or colon\r\n\t\t\treturn this._backTo(token);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _parseTransform(parent: TransformableMarker): boolean {\r\n\t\t// ...//}\r\n\r\n\t\tlet transform = new Transform();\r\n\t\tlet regexValue = '';\r\n\t\tlet regexOptions = '';\r\n\r\n\t\t// (1) /regex\r\n\t\twhile (true) {\r\n\t\t\tif (this._accept(TokenType.Forwardslash)) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tlet escaped: string;\r\n\t\t\tif (escaped = this._accept(TokenType.Backslash, true)) {\r\n\t\t\t\tescaped = this._accept(TokenType.Forwardslash, true) || escaped;\r\n\t\t\t\tregexValue += escaped;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (this._token.type !== TokenType.EOF) {\r\n\t\t\t\tregexValue += this._accept(undefined, true);\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\t// (2) /format\r\n\t\twhile (true) {\r\n\t\t\tif (this._accept(TokenType.Forwardslash)) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tlet escaped: string;\r\n\t\t\tif (escaped = this._accept(TokenType.Backslash, true)) {\r\n\t\t\t\tescaped = this._accept(TokenType.Backslash, true) || this._accept(TokenType.Forwardslash, true) || escaped;\r\n\t\t\t\ttransform.appendChild(new Text(escaped));\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (this._parseFormatString(transform) || this._parseAnything(transform)) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\t// (3) /option\r\n\t\twhile (true) {\r\n\t\t\tif (this._accept(TokenType.CurlyClose)) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tif (this._token.type !== TokenType.EOF) {\r\n\t\t\t\tregexOptions += this._accept(undefined, true);\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\ttransform.regexp = new RegExp(regexValue, regexOptions);\r\n\t\t} catch (e) {\r\n\t\t\t// invalid regexp\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tparent.transform = transform;\r\n\t\treturn true;\r\n\t}\r\n\r\n\tprivate _parseFormatString(parent: Transform): boolean {\r\n\r\n\t\tconst token = this._token;\r\n\t\tif (!this._accept(TokenType.Dollar)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tlet complex = false;\r\n\t\tif (this._accept(TokenType.CurlyOpen)) {\r\n\t\t\tcomplex = true;\r\n\t\t}\r\n\r\n\t\tlet index = this._accept(TokenType.Int, true);\r\n\r\n\t\tif (!index) {\r\n\t\t\tthis._backTo(token);\r\n\t\t\treturn false;\r\n\r\n\t\t} else if (!complex) {\r\n\t\t\t// $1\r\n\t\t\tparent.appendChild(new FormatString(Number(index)));\r\n\t\t\treturn true;\r\n\r\n\t\t} else if (this._accept(TokenType.CurlyClose)) {\r\n\t\t\t// ${1}\r\n\t\t\tparent.appendChild(new FormatString(Number(index)));\r\n\t\t\treturn true;\r\n\r\n\t\t} else if (!this._accept(TokenType.Colon)) {\r\n\t\t\tthis._backTo(token);\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tif (this._accept(TokenType.Forwardslash)) {\r\n\t\t\t// ${1:/upcase}\r\n\t\t\tlet shorthand = this._accept(TokenType.VariableName, true);\r\n\t\t\tif (!shorthand || !this._accept(TokenType.CurlyClose)) {\r\n\t\t\t\tthis._backTo(token);\r\n\t\t\t\treturn false;\r\n\t\t\t} else {\r\n\t\t\t\tparent.appendChild(new FormatString(Number(index), shorthand));\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\r\n\t\t} else if (this._accept(TokenType.Plus)) {\r\n\t\t\t// ${1:+}\r\n\t\t\tlet ifValue = this._until(TokenType.CurlyClose);\r\n\t\t\tif (ifValue) {\r\n\t\t\t\tparent.appendChild(new FormatString(Number(index), undefined, ifValue, undefined));\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\r\n\t\t} else if (this._accept(TokenType.Dash)) {\r\n\t\t\t// ${2:-}\r\n\t\t\tlet elseValue = this._until(TokenType.CurlyClose);\r\n\t\t\tif (elseValue) {\r\n\t\t\t\tparent.appendChild(new FormatString(Number(index), undefined, undefined, elseValue));\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\r\n\t\t} else if (this._accept(TokenType.QuestionMark)) {\r\n\t\t\t// ${2:?:}\r\n\t\t\tlet ifValue = this._until(TokenType.Colon);\r\n\t\t\tif (ifValue) {\r\n\t\t\t\tlet elseValue = this._until(TokenType.CurlyClose);\r\n\t\t\t\tif (elseValue) {\r\n\t\t\t\t\tparent.appendChild(new FormatString(Number(index), undefined, ifValue, elseValue));\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\t\t\t// ${1:}\r\n\t\t\tlet elseValue = this._until(TokenType.CurlyClose);\r\n\t\t\tif (elseValue) {\r\n\t\t\t\tparent.appendChild(new FormatString(Number(index), undefined, undefined, elseValue));\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._backTo(token);\r\n\t\treturn false;\r\n\t}\r\n\r\n\tprivate _parseAnything(marker: Marker): boolean {\r\n\t\tif (this._token.type !== TokenType.EOF) {\r\n\t\t\tmarker.appendChild(new Text(this._scanner.tokenText(this._token)));\r\n\t\t\tthis._accept(undefined);\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { fuzzyScore, fuzzyScoreGracefulAggressive, FuzzyScorer, FuzzyScore, anyScore } from 'vs/base/common/filters';\r\nimport { CompletionItemProvider, CompletionItemKind } from 'vs/editor/common/modes';\r\nimport { CompletionItem } from './suggest';\r\nimport { InternalSuggestOptions } from 'vs/editor/common/config/editorOptions';\r\nimport { WordDistance } from 'vs/editor/contrib/suggest/wordDistance';\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport { compareIgnoreCase } from 'vs/base/common/strings';\r\nimport { quickSelect } from 'vs/base/common/arrays';\r\n\r\ntype StrictCompletionItem = Required;\r\n\r\nexport interface ICompletionStats {\r\n\tpLabelLen: number;\r\n}\r\n\r\nexport class LineContext {\r\n\tconstructor(\r\n\t\treadonly leadingLineContent: string,\r\n\t\treadonly characterCountDelta: number,\r\n\t) { }\r\n}\r\n\r\nconst enum Refilter {\r\n\tNothing = 0,\r\n\tAll = 1,\r\n\tIncr = 2\r\n}\r\n\r\n/**\r\n * Sorted, filtered completion view model\r\n * */\r\nexport class CompletionModel {\r\n\r\n\tprivate readonly _items: CompletionItem[];\r\n\tprivate readonly _column: number;\r\n\tprivate readonly _wordDistance: WordDistance;\r\n\tprivate readonly _options: InternalSuggestOptions;\r\n\tprivate readonly _snippetCompareFn = CompletionModel._compareCompletionItems;\r\n\r\n\tprivate _lineContext: LineContext;\r\n\tprivate _refilterKind: Refilter;\r\n\tprivate _filteredItems?: StrictCompletionItem[];\r\n\tprivate _providerInfo?: Map;\r\n\tprivate _stats?: ICompletionStats;\r\n\r\n\tconstructor(\r\n\t\titems: CompletionItem[],\r\n\t\tcolumn: number,\r\n\t\tlineContext: LineContext,\r\n\t\twordDistance: WordDistance,\r\n\t\toptions: InternalSuggestOptions,\r\n\t\tsnippetSuggestions: 'top' | 'bottom' | 'inline' | 'none',\r\n\t\treadonly clipboardText: string | undefined\r\n\t) {\r\n\t\tthis._items = items;\r\n\t\tthis._column = column;\r\n\t\tthis._wordDistance = wordDistance;\r\n\t\tthis._options = options;\r\n\t\tthis._refilterKind = Refilter.All;\r\n\t\tthis._lineContext = lineContext;\r\n\r\n\t\tif (snippetSuggestions === 'top') {\r\n\t\t\tthis._snippetCompareFn = CompletionModel._compareCompletionItemsSnippetsUp;\r\n\t\t} else if (snippetSuggestions === 'bottom') {\r\n\t\t\tthis._snippetCompareFn = CompletionModel._compareCompletionItemsSnippetsDown;\r\n\t\t}\r\n\t}\r\n\r\n\tget lineContext(): LineContext {\r\n\t\treturn this._lineContext;\r\n\t}\r\n\r\n\tset lineContext(value: LineContext) {\r\n\t\tif (this._lineContext.leadingLineContent !== value.leadingLineContent\r\n\t\t\t|| this._lineContext.characterCountDelta !== value.characterCountDelta\r\n\t\t) {\r\n\t\t\tthis._refilterKind = this._lineContext.characterCountDelta < value.characterCountDelta && this._filteredItems ? Refilter.Incr : Refilter.All;\r\n\t\t\tthis._lineContext = value;\r\n\t\t}\r\n\t}\r\n\r\n\tget items(): CompletionItem[] {\r\n\t\tthis._ensureCachedState();\r\n\t\treturn this._filteredItems!;\r\n\t}\r\n\r\n\tget allProvider(): IterableIterator {\r\n\t\tthis._ensureCachedState();\r\n\t\treturn this._providerInfo!.keys();\r\n\t}\r\n\r\n\tget incomplete(): Set {\r\n\t\tthis._ensureCachedState();\r\n\t\tconst result = new Set();\r\n\t\tfor (let [provider, incomplete] of this._providerInfo!) {\r\n\t\t\tif (incomplete) {\r\n\t\t\t\tresult.add(provider);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tadopt(except: Set): CompletionItem[] {\r\n\t\tlet res: CompletionItem[] = [];\r\n\t\tfor (let i = 0; i < this._items.length;) {\r\n\t\t\tif (!except.has(this._items[i].provider)) {\r\n\t\t\t\tres.push(this._items[i]);\r\n\r\n\t\t\t\t// unordered removed\r\n\t\t\t\tthis._items[i] = this._items[this._items.length - 1];\r\n\t\t\t\tthis._items.pop();\r\n\t\t\t} else {\r\n\t\t\t\t// continue with next item\r\n\t\t\t\ti++;\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis._refilterKind = Refilter.All;\r\n\t\treturn res;\r\n\t}\r\n\r\n\tget stats(): ICompletionStats {\r\n\t\tthis._ensureCachedState();\r\n\t\treturn this._stats!;\r\n\t}\r\n\r\n\tprivate _ensureCachedState(): void {\r\n\t\tif (this._refilterKind !== Refilter.Nothing) {\r\n\t\t\tthis._createCachedState();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _createCachedState(): void {\r\n\r\n\t\tthis._providerInfo = new Map();\r\n\r\n\t\tconst labelLengths: number[] = [];\r\n\r\n\t\tconst { leadingLineContent, characterCountDelta } = this._lineContext;\r\n\t\tlet word = '';\r\n\t\tlet wordLow = '';\r\n\r\n\t\t// incrementally filter less\r\n\t\tconst source = this._refilterKind === Refilter.All ? this._items : this._filteredItems!;\r\n\t\tconst target: StrictCompletionItem[] = [];\r\n\r\n\t\t// picks a score function based on the number of\r\n\t\t// items that we have to score/filter and based on the\r\n\t\t// user-configuration\r\n\t\tconst scoreFn: FuzzyScorer = (!this._options.filterGraceful || source.length > 2000) ? fuzzyScore : fuzzyScoreGracefulAggressive;\r\n\r\n\t\tfor (let i = 0; i < source.length; i++) {\r\n\r\n\t\t\tconst item = source[i];\r\n\r\n\t\t\tif (item.isInvalid) {\r\n\t\t\t\tcontinue; // SKIP invalid items\r\n\t\t\t}\r\n\r\n\t\t\t// collect all support, know if their result is incomplete\r\n\t\t\tthis._providerInfo.set(item.provider, Boolean(item.container.incomplete));\r\n\r\n\t\t\t// 'word' is that remainder of the current line that we\r\n\t\t\t// filter and score against. In theory each suggestion uses a\r\n\t\t\t// different word, but in practice not - that's why we cache\r\n\t\t\tconst overwriteBefore = item.position.column - item.editStart.column;\r\n\t\t\tconst wordLen = overwriteBefore + characterCountDelta - (item.position.column - this._column);\r\n\t\t\tif (word.length !== wordLen) {\r\n\t\t\t\tword = wordLen === 0 ? '' : leadingLineContent.slice(-wordLen);\r\n\t\t\t\twordLow = word.toLowerCase();\r\n\t\t\t}\r\n\r\n\t\t\tconst textLabel = typeof item.completion.label === 'string' ? item.completion.label : item.completion.label.name;\r\n\r\n\t\t\t// remember the word against which this item was\r\n\t\t\t// scored\r\n\t\t\titem.word = word;\r\n\r\n\t\t\tif (wordLen === 0) {\r\n\t\t\t\t// when there is nothing to score against, don't\r\n\t\t\t\t// event try to do. Use a const rank and rely on\r\n\t\t\t\t// the fallback-sort using the initial sort order.\r\n\t\t\t\t// use a score of `-100` because that is out of the\r\n\t\t\t\t// bound of values `fuzzyScore` will return\r\n\t\t\t\titem.score = FuzzyScore.Default;\r\n\r\n\t\t\t} else {\r\n\t\t\t\t// skip word characters that are whitespace until\r\n\t\t\t\t// we have hit the replace range (overwriteBefore)\r\n\t\t\t\tlet wordPos = 0;\r\n\t\t\t\twhile (wordPos < overwriteBefore) {\r\n\t\t\t\t\tconst ch = word.charCodeAt(wordPos);\r\n\t\t\t\t\tif (ch === CharCode.Space || ch === CharCode.Tab) {\r\n\t\t\t\t\t\twordPos += 1;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (wordPos >= wordLen) {\r\n\t\t\t\t\t// the wordPos at which scoring starts is the whole word\r\n\t\t\t\t\t// and therefore the same rules as not having a word apply\r\n\t\t\t\t\titem.score = FuzzyScore.Default;\r\n\r\n\t\t\t\t} else if (typeof item.completion.filterText === 'string') {\r\n\t\t\t\t\t// when there is a `filterText` it must match the `word`.\r\n\t\t\t\t\t// if it matches we check with the label to compute highlights\r\n\t\t\t\t\t// and if that doesn't yield a result we have no highlights,\r\n\t\t\t\t\t// despite having the match\r\n\t\t\t\t\tlet match = scoreFn(word, wordLow, wordPos, item.completion.filterText, item.filterTextLow!, 0, false);\r\n\t\t\t\t\tif (!match) {\r\n\t\t\t\t\t\tcontinue; // NO match\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (compareIgnoreCase(item.completion.filterText, textLabel) === 0) {\r\n\t\t\t\t\t\t// filterText and label are actually the same -> use good highlights\r\n\t\t\t\t\t\titem.score = match;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t// re-run the scorer on the label in the hope of a result BUT use the rank\r\n\t\t\t\t\t\t// of the filterText-match\r\n\t\t\t\t\t\titem.score = anyScore(word, wordLow, wordPos, textLabel, item.labelLow, 0);\r\n\t\t\t\t\t\titem.score[0] = match[0]; // use score from filterText\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// by default match `word` against the `label`\r\n\t\t\t\t\tlet match = scoreFn(word, wordLow, wordPos, textLabel, item.labelLow, 0, false);\r\n\t\t\t\t\tif (!match) {\r\n\t\t\t\t\t\tcontinue; // NO match\r\n\t\t\t\t\t}\r\n\t\t\t\t\titem.score = match;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\titem.idx = i;\r\n\t\t\titem.distance = this._wordDistance.distance(item.position, item.completion);\r\n\t\t\ttarget.push(item as StrictCompletionItem);\r\n\r\n\t\t\t// update stats\r\n\t\t\tlabelLengths.push(textLabel.length);\r\n\t\t}\r\n\r\n\t\tthis._filteredItems = target.sort(this._snippetCompareFn);\r\n\t\tthis._refilterKind = Refilter.Nothing;\r\n\t\tthis._stats = {\r\n\t\t\tpLabelLen: labelLengths.length ?\r\n\t\t\t\tquickSelect(labelLengths.length - .85, labelLengths, (a, b) => a - b)\r\n\t\t\t\t: 0\r\n\t\t};\r\n\t}\r\n\r\n\tprivate static _compareCompletionItems(a: StrictCompletionItem, b: StrictCompletionItem): number {\r\n\t\tif (a.score[0] > b.score[0]) {\r\n\t\t\treturn -1;\r\n\t\t} else if (a.score[0] < b.score[0]) {\r\n\t\t\treturn 1;\r\n\t\t} else if (a.distance < b.distance) {\r\n\t\t\treturn -1;\r\n\t\t} else if (a.distance > b.distance) {\r\n\t\t\treturn 1;\r\n\t\t} else if (a.idx < b.idx) {\r\n\t\t\treturn -1;\r\n\t\t} else if (a.idx > b.idx) {\r\n\t\t\treturn 1;\r\n\t\t} else {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static _compareCompletionItemsSnippetsDown(a: StrictCompletionItem, b: StrictCompletionItem): number {\r\n\t\tif (a.completion.kind !== b.completion.kind) {\r\n\t\t\tif (a.completion.kind === CompletionItemKind.Snippet) {\r\n\t\t\t\treturn 1;\r\n\t\t\t} else if (b.completion.kind === CompletionItemKind.Snippet) {\r\n\t\t\t\treturn -1;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn CompletionModel._compareCompletionItems(a, b);\r\n\t}\r\n\r\n\tprivate static _compareCompletionItemsSnippetsUp(a: StrictCompletionItem, b: StrictCompletionItem): number {\r\n\t\tif (a.completion.kind !== b.completion.kind) {\r\n\t\t\tif (a.completion.kind === CompletionItemKind.Snippet) {\r\n\t\t\t\treturn -1;\r\n\t\t\t} else if (b.completion.kind === CompletionItemKind.Snippet) {\r\n\t\t\t\treturn 1;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn CompletionModel._compareCompletionItems(a, b);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Event, Emitter } from 'vs/base/common/event';\r\nimport { DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { Dimension } from 'vs/base/browser/dom';\r\nimport { Orientation, OrthogonalEdge, Sash, SashState } from 'vs/base/browser/ui/sash/sash';\r\n\r\n\r\nexport interface IResizeEvent {\r\n\tdimension: Dimension;\r\n\tdone: boolean;\r\n\tnorth?: boolean;\r\n\teast?: boolean;\r\n\tsouth?: boolean;\r\n\twest?: boolean;\r\n}\r\n\r\nexport class ResizableHTMLElement {\r\n\r\n\treadonly domNode: HTMLElement;\r\n\r\n\tprivate readonly _onDidWillResize = new Emitter();\r\n\treadonly onDidWillResize: Event = this._onDidWillResize.event;\r\n\r\n\tprivate readonly _onDidResize = new Emitter();\r\n\treadonly onDidResize: Event = this._onDidResize.event;\r\n\r\n\tprivate readonly _northSash: Sash;\r\n\tprivate readonly _eastSash: Sash;\r\n\tprivate readonly _southSash: Sash;\r\n\tprivate readonly _westSash: Sash;\r\n\tprivate readonly _sashListener = new DisposableStore();\r\n\r\n\tprivate _size = new Dimension(0, 0);\r\n\tprivate _minSize = new Dimension(0, 0);\r\n\tprivate _maxSize = new Dimension(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);\r\n\tprivate _preferredSize?: Dimension;\r\n\r\n\tconstructor() {\r\n\t\tthis.domNode = document.createElement('div');\r\n\t\tthis._eastSash = new Sash(this.domNode, { getVerticalSashLeft: () => this._size.width }, { orientation: Orientation.VERTICAL });\r\n\t\tthis._westSash = new Sash(this.domNode, { getVerticalSashLeft: () => 0 }, { orientation: Orientation.VERTICAL });\r\n\t\tthis._northSash = new Sash(this.domNode, { getHorizontalSashTop: () => 0 }, { orientation: Orientation.HORIZONTAL, orthogonalEdge: OrthogonalEdge.North });\r\n\t\tthis._southSash = new Sash(this.domNode, { getHorizontalSashTop: () => this._size.height }, { orientation: Orientation.HORIZONTAL, orthogonalEdge: OrthogonalEdge.South });\r\n\r\n\t\tthis._northSash.orthogonalStartSash = this._westSash;\r\n\t\tthis._northSash.orthogonalEndSash = this._eastSash;\r\n\t\tthis._southSash.orthogonalStartSash = this._westSash;\r\n\t\tthis._southSash.orthogonalEndSash = this._eastSash;\r\n\r\n\t\tlet currentSize: Dimension | undefined;\r\n\t\tlet deltaY = 0;\r\n\t\tlet deltaX = 0;\r\n\r\n\t\tthis._sashListener.add(Event.any(this._northSash.onDidStart, this._eastSash.onDidStart, this._southSash.onDidStart, this._westSash.onDidStart)(() => {\r\n\t\t\tif (currentSize === undefined) {\r\n\t\t\t\tthis._onDidWillResize.fire();\r\n\t\t\t\tcurrentSize = this._size;\r\n\t\t\t\tdeltaY = 0;\r\n\t\t\t\tdeltaX = 0;\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._sashListener.add(Event.any(this._northSash.onDidEnd, this._eastSash.onDidEnd, this._southSash.onDidEnd, this._westSash.onDidEnd)(() => {\r\n\t\t\tif (currentSize !== undefined) {\r\n\t\t\t\tcurrentSize = undefined;\r\n\t\t\t\tdeltaY = 0;\r\n\t\t\t\tdeltaX = 0;\r\n\t\t\t\tthis._onDidResize.fire({ dimension: this._size, done: true });\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._sashListener.add(this._eastSash.onDidChange(e => {\r\n\t\t\tif (currentSize) {\r\n\t\t\t\tdeltaX = e.currentX - e.startX;\r\n\t\t\t\tthis.layout(currentSize.height + deltaY, currentSize.width + deltaX);\r\n\t\t\t\tthis._onDidResize.fire({ dimension: this._size, done: false, east: true });\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._sashListener.add(this._westSash.onDidChange(e => {\r\n\t\t\tif (currentSize) {\r\n\t\t\t\tdeltaX = -(e.currentX - e.startX);\r\n\t\t\t\tthis.layout(currentSize.height + deltaY, currentSize.width + deltaX);\r\n\t\t\t\tthis._onDidResize.fire({ dimension: this._size, done: false, west: true });\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._sashListener.add(this._northSash.onDidChange(e => {\r\n\t\t\tif (currentSize) {\r\n\t\t\t\tdeltaY = -(e.currentY - e.startY);\r\n\t\t\t\tthis.layout(currentSize.height + deltaY, currentSize.width + deltaX);\r\n\t\t\t\tthis._onDidResize.fire({ dimension: this._size, done: false, north: true });\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._sashListener.add(this._southSash.onDidChange(e => {\r\n\t\t\tif (currentSize) {\r\n\t\t\t\tdeltaY = e.currentY - e.startY;\r\n\t\t\t\tthis.layout(currentSize.height + deltaY, currentSize.width + deltaX);\r\n\t\t\t\tthis._onDidResize.fire({ dimension: this._size, done: false, south: true });\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._sashListener.add(Event.any(this._eastSash.onDidReset, this._westSash.onDidReset)(e => {\r\n\t\t\tif (this._preferredSize) {\r\n\t\t\t\tthis.layout(this._size.height, this._preferredSize.width);\r\n\t\t\t\tthis._onDidResize.fire({ dimension: this._size, done: true });\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._sashListener.add(Event.any(this._northSash.onDidReset, this._southSash.onDidReset)(e => {\r\n\t\t\tif (this._preferredSize) {\r\n\t\t\t\tthis.layout(this._preferredSize.height, this._size.width);\r\n\t\t\t\tthis._onDidResize.fire({ dimension: this._size, done: true });\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._northSash.dispose();\r\n\t\tthis._southSash.dispose();\r\n\t\tthis._eastSash.dispose();\r\n\t\tthis._westSash.dispose();\r\n\t\tthis._sashListener.dispose();\r\n\t\tthis.domNode.remove();\r\n\t}\r\n\r\n\tenableSashes(north: boolean, east: boolean, south: boolean, west: boolean): void {\r\n\t\tthis._northSash.state = north ? SashState.Enabled : SashState.Disabled;\r\n\t\tthis._eastSash.state = east ? SashState.Enabled : SashState.Disabled;\r\n\t\tthis._southSash.state = south ? SashState.Enabled : SashState.Disabled;\r\n\t\tthis._westSash.state = west ? SashState.Enabled : SashState.Disabled;\r\n\t}\r\n\r\n\tlayout(height: number = this.size.height, width: number = this.size.width): void {\r\n\r\n\t\tconst { height: minHeight, width: minWidth } = this._minSize;\r\n\t\tconst { height: maxHeight, width: maxWidth } = this._maxSize;\r\n\r\n\t\theight = Math.max(minHeight, Math.min(maxHeight, height));\r\n\t\twidth = Math.max(minWidth, Math.min(maxWidth, width));\r\n\r\n\t\tconst newSize = new Dimension(width, height);\r\n\t\tif (!Dimension.equals(newSize, this._size)) {\r\n\t\t\tthis.domNode.style.height = height + 'px';\r\n\t\t\tthis.domNode.style.width = width + 'px';\r\n\t\t\tthis._size = newSize;\r\n\t\t\tthis._northSash.layout();\r\n\t\t\tthis._eastSash.layout();\r\n\t\t\tthis._southSash.layout();\r\n\t\t\tthis._westSash.layout();\r\n\t\t}\r\n\t}\r\n\r\n\tget size() {\r\n\t\treturn this._size;\r\n\t}\r\n\r\n\tset maxSize(value: Dimension) {\r\n\t\tthis._maxSize = value;\r\n\t}\r\n\r\n\tget maxSize() {\r\n\t\treturn this._maxSize;\r\n\t}\r\n\r\n\tset minSize(value: Dimension) {\r\n\t\tthis._minSize = value;\r\n\t}\r\n\r\n\tget minSize() {\r\n\t\treturn this._minSize;\r\n\t}\r\n\r\n\tset preferredSize(value: Dimension | undefined) {\r\n\t\tthis._preferredSize = value;\r\n\t}\r\n\r\n\tget preferredSize() {\r\n\t\treturn this._preferredSize;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { isNonEmptyArray } from 'vs/base/common/arrays';\r\nimport { DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { ISelectedSuggestion, SuggestWidget } from './suggestWidget';\r\nimport { CharacterSet } from 'vs/editor/common/core/characterClassifier';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\nexport class CommitCharacterController {\r\n\r\n\tprivate readonly _disposables = new DisposableStore();\r\n\r\n\tprivate _active?: {\r\n\t\treadonly acceptCharacters: CharacterSet;\r\n\t\treadonly item: ISelectedSuggestion;\r\n\t};\r\n\r\n\tconstructor(editor: ICodeEditor, widget: SuggestWidget, accept: (selected: ISelectedSuggestion) => any) {\r\n\r\n\t\tthis._disposables.add(widget.onDidShow(() => this._onItem(widget.getFocusedItem())));\r\n\t\tthis._disposables.add(widget.onDidFocus(this._onItem, this));\r\n\t\tthis._disposables.add(widget.onDidHide(this.reset, this));\r\n\r\n\t\tthis._disposables.add(editor.onWillType(text => {\r\n\t\t\tif (this._active && !widget.isFrozen()) {\r\n\t\t\t\tconst ch = text.charCodeAt(text.length - 1);\r\n\t\t\t\tif (this._active.acceptCharacters.has(ch) && editor.getOption(EditorOption.acceptSuggestionOnCommitCharacter)) {\r\n\t\t\t\t\taccept(this._active.item);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\tprivate _onItem(selected: ISelectedSuggestion | undefined): void {\r\n\t\tif (!selected || !isNonEmptyArray(selected.item.completion.commitCharacters)) {\r\n\t\t\t// no item or no commit characters\r\n\t\t\tthis.reset();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this._active && this._active.item.item === selected.item) {\r\n\t\t\t// still the same item\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// keep item and its commit characters\r\n\t\tconst acceptCharacters = new CharacterSet();\r\n\t\tfor (const ch of selected.item.completion.commitCharacters) {\r\n\t\t\tif (ch.length > 0) {\r\n\t\t\t\tacceptCharacters.add(ch.charCodeAt(0));\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis._active = { acceptCharacters, item: selected };\r\n\t}\r\n\r\n\treset(): void {\r\n\t\tthis._active = undefined;\r\n\t}\r\n\r\n\tdispose() {\r\n\t\tthis._disposables.dispose();\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { SuggestModel } from 'vs/editor/contrib/suggest/suggestModel';\r\n\r\nexport class OvertypingCapturer implements IDisposable {\r\n\r\n\tprivate static readonly _maxSelectionLength = 51200;\r\n\tprivate readonly _disposables = new DisposableStore();\r\n\r\n\tprivate _lastOvertyped: { value: string; multiline: boolean }[] = [];\r\n\tprivate _empty: boolean = true;\r\n\r\n\tconstructor(editor: ICodeEditor, suggestModel: SuggestModel) {\r\n\r\n\t\tthis._disposables.add(editor.onWillType(() => {\r\n\t\t\tif (!this._empty) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (!editor.hasModel()) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst selections = editor.getSelections();\r\n\t\t\tconst selectionsLength = selections.length;\r\n\r\n\t\t\t// Check if it will overtype any selections\r\n\t\t\tlet willOvertype = false;\r\n\t\t\tfor (let i = 0; i < selectionsLength; i++) {\r\n\t\t\t\tif (!selections[i].isEmpty()) {\r\n\t\t\t\t\twillOvertype = true;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (!willOvertype) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tthis._lastOvertyped = [];\r\n\t\t\tconst model = editor.getModel();\r\n\t\t\tfor (let i = 0; i < selectionsLength; i++) {\r\n\t\t\t\tconst selection = selections[i];\r\n\t\t\t\t// Check for overtyping capturer restrictions\r\n\t\t\t\tif (model.getValueLengthInRange(selection) > OvertypingCapturer._maxSelectionLength) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\tthis._lastOvertyped[i] = { value: model.getValueInRange(selection), multiline: selection.startLineNumber !== selection.endLineNumber };\r\n\t\t\t}\r\n\t\t\tthis._empty = false;\r\n\t\t}));\r\n\r\n\t\tthis._disposables.add(suggestModel.onDidCancel(e => {\r\n\t\t\tif (!this._empty && !e.retrigger) {\r\n\t\t\t\tthis._empty = true;\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\tgetLastOvertypedInfo(idx: number): { value: string; multiline: boolean } | undefined {\r\n\t\tif (!this._empty && idx >= 0 && idx < this._lastOvertyped.length) {\r\n\t\t\treturn this._lastOvertyped[idx];\r\n\t\t}\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tdispose() {\r\n\t\tthis._disposables.dispose();\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { binarySearch, isFalsyOrEmpty } from 'vs/base/common/arrays';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';\r\nimport { IPosition } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { CompletionItem, CompletionItemKind } from 'vs/editor/common/modes';\r\nimport { BracketSelectionRangeProvider } from 'vs/editor/contrib/smartSelect/bracketSelections';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\nexport abstract class WordDistance {\r\n\r\n\tstatic readonly None = new class extends WordDistance {\r\n\t\tdistance() { return 0; }\r\n\t};\r\n\r\n\tstatic async create(service: IEditorWorkerService, editor: ICodeEditor): Promise {\r\n\r\n\t\tif (!editor.getOption(EditorOption.suggest).localityBonus) {\r\n\t\t\treturn WordDistance.None;\r\n\t\t}\r\n\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn WordDistance.None;\r\n\t\t}\r\n\r\n\t\tconst model = editor.getModel();\r\n\t\tconst position = editor.getPosition();\r\n\r\n\t\tif (!service.canComputeWordRanges(model.uri)) {\r\n\t\t\treturn WordDistance.None;\r\n\t\t}\r\n\r\n\t\tconst [ranges] = await new BracketSelectionRangeProvider().provideSelectionRanges(model, [position]);\r\n\t\tif (ranges.length === 0) {\r\n\t\t\treturn WordDistance.None;\r\n\t\t}\r\n\r\n\t\tconst wordRanges = await service.computeWordRanges(model.uri, ranges[0].range);\r\n\t\tif (!wordRanges) {\r\n\t\t\treturn WordDistance.None;\r\n\t\t}\r\n\r\n\t\t// remove current word\r\n\t\tconst wordUntilPos = model.getWordUntilPosition(position);\r\n\t\tdelete wordRanges[wordUntilPos.word];\r\n\r\n\t\treturn new class extends WordDistance {\r\n\t\t\tdistance(anchor: IPosition, suggestion: CompletionItem) {\r\n\t\t\t\tif (!position.equals(editor.getPosition())) {\r\n\t\t\t\t\treturn 0;\r\n\t\t\t\t}\r\n\t\t\t\tif (suggestion.kind === CompletionItemKind.Keyword) {\r\n\t\t\t\t\treturn 2 << 20;\r\n\t\t\t\t}\r\n\t\t\t\tlet word = typeof suggestion.label === 'string' ? suggestion.label : suggestion.label.name;\r\n\t\t\t\tlet wordLines = wordRanges[word];\r\n\t\t\t\tif (isFalsyOrEmpty(wordLines)) {\r\n\t\t\t\t\treturn 2 << 20;\r\n\t\t\t\t}\r\n\t\t\t\tlet idx = binarySearch(wordLines, Range.fromPositions(anchor), Range.compareRangesUsingStarts);\r\n\t\t\t\tlet bestWordRange = idx >= 0 ? wordLines[idx] : wordLines[Math.max(0, ~idx - 1)];\r\n\t\t\t\tlet blockDistance = ranges.length;\r\n\t\t\t\tfor (const range of ranges) {\r\n\t\t\t\t\tif (!Range.containsRange(range.range, bestWordRange)) {\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tblockDistance -= 1;\r\n\t\t\t\t}\r\n\t\t\t\treturn blockDistance;\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\tabstract distance(anchor: IPosition, suggestion: CompletionItem): number;\r\n}\r\n\r\n\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\n/*\r\n * This module exports common types and functionality shared between\r\n * the Monarch compiler that compiles JSON to ILexer, and the Monarch\r\n * Tokenizer (that highlights at runtime)\r\n */\r\n\r\n/*\r\n * Type definitions to be used internally to Monarch.\r\n * Inside monarch we use fully typed definitions and compiled versions of the more abstract JSON descriptions.\r\n */\r\n\r\nexport const enum MonarchBracket {\r\n\tNone = 0,\r\n\tOpen = 1,\r\n\tClose = -1\r\n}\r\n\r\nexport interface ILexerMin {\r\n\tlanguageId: string;\r\n\tincludeLF: boolean;\r\n\tnoThrow: boolean;\r\n\tignoreCase: boolean;\r\n\tunicode: boolean;\r\n\tusesEmbedded: boolean;\r\n\tdefaultToken: string;\r\n\tstateNames: { [stateName: string]: any; };\r\n\t[attr: string]: any;\r\n}\r\n\r\nexport interface ILexer extends ILexerMin {\r\n\tmaxStack: number;\r\n\tstart: string | null;\r\n\tignoreCase: boolean;\r\n\tunicode: boolean;\r\n\ttokenPostfix: string;\r\n\r\n\ttokenizer: { [stateName: string]: IRule[]; };\r\n\tbrackets: IBracket[];\r\n}\r\n\r\nexport interface IBracket {\r\n\ttoken: string;\r\n\topen: string;\r\n\tclose: string;\r\n}\r\n\r\nexport type FuzzyAction = IAction | string;\r\n\r\nexport function isFuzzyActionArr(what: FuzzyAction | FuzzyAction[]): what is FuzzyAction[] {\r\n\treturn (Array.isArray(what));\r\n}\r\n\r\nexport function isFuzzyAction(what: FuzzyAction | FuzzyAction[]): what is FuzzyAction {\r\n\treturn !isFuzzyActionArr(what);\r\n}\r\n\r\nexport function isString(what: FuzzyAction): what is string {\r\n\treturn (typeof what === 'string');\r\n}\r\n\r\nexport function isIAction(what: FuzzyAction): what is IAction {\r\n\treturn !isString(what);\r\n}\r\n\r\nexport interface IRule {\r\n\tregex: RegExp;\r\n\taction: FuzzyAction;\r\n\tmatchOnlyAtLineStart: boolean;\r\n\tname: string;\r\n}\r\n\r\nexport interface IAction {\r\n\t// an action is either a group of actions\r\n\tgroup?: FuzzyAction[];\r\n\r\n\t// or a function that returns a fresh action\r\n\ttest?: (id: string, matches: string[], state: string, eos: boolean) => FuzzyAction;\r\n\r\n\t// or it is a declarative action with a token value and various other attributes\r\n\ttoken?: string;\r\n\ttokenSubst?: boolean;\r\n\tnext?: string;\r\n\tnextEmbedded?: string;\r\n\tbracket?: MonarchBracket;\r\n\tlog?: string;\r\n\tswitchTo?: string;\r\n\tgoBack?: number;\r\n\ttransform?: (states: string[]) => string[];\r\n}\r\n\r\nexport interface IBranch {\r\n\tname: string;\r\n\tvalue: FuzzyAction;\r\n\ttest?: (id: string, matches: string[], state: string, eos: boolean) => boolean;\r\n}\r\n\r\n// Small helper functions\r\n\r\n/**\r\n * Is a string null, undefined, or empty?\r\n */\r\nexport function empty(s: string): boolean {\r\n\treturn (s ? false : true);\r\n}\r\n\r\n/**\r\n * Puts a string to lower case if 'ignoreCase' is set.\r\n */\r\nexport function fixCase(lexer: ILexerMin, str: string): string {\r\n\treturn (lexer.ignoreCase && str ? str.toLowerCase() : str);\r\n}\r\n\r\n/**\r\n * Ensures there are no bad characters in a CSS token class.\r\n */\r\nexport function sanitize(s: string) {\r\n\treturn s.replace(/[&<>'\"_]/g, '-'); // used on all output token CSS classes\r\n}\r\n\r\n// Logging\r\n\r\n/**\r\n * Logs a message.\r\n */\r\nexport function log(lexer: ILexerMin, msg: string) {\r\n\tconsole.log(`${lexer.languageId}: ${msg}`);\r\n}\r\n\r\n// Throwing errors\r\n\r\nexport function createError(lexer: ILexerMin, msg: string): Error {\r\n\treturn new Error(`${lexer.languageId}: ${msg}`);\r\n}\r\n\r\n// Helper functions for rule finding and substitution\r\n\r\n/**\r\n * substituteMatches is used on lexer strings and can substitutes predefined patterns:\r\n * \t\t$$ => $\r\n * \t\t$# => id\r\n * \t\t$n => matched entry n\r\n * \t\t@attr => contents of lexer[attr]\r\n *\r\n * See documentation for more info\r\n */\r\nexport function substituteMatches(lexer: ILexerMin, str: string, id: string, matches: string[], state: string): string {\r\n\tconst re = /\\$((\\$)|(#)|(\\d\\d?)|[sS](\\d\\d?)|@(\\w+))/g;\r\n\tlet stateMatches: string[] | null = null;\r\n\treturn str.replace(re, function (full, sub?, dollar?, hash?, n?, s?, attr?, ofs?, total?) {\r\n\t\tif (!empty(dollar)) {\r\n\t\t\treturn '$'; // $$\r\n\t\t}\r\n\t\tif (!empty(hash)) {\r\n\t\t\treturn fixCase(lexer, id); // default $#\r\n\t\t}\r\n\t\tif (!empty(n) && n < matches.length) {\r\n\t\t\treturn fixCase(lexer, matches[n]); // $n\r\n\t\t}\r\n\t\tif (!empty(attr) && lexer && typeof (lexer[attr]) === 'string') {\r\n\t\t\treturn lexer[attr]; //@attribute\r\n\t\t}\r\n\t\tif (stateMatches === null) { // split state on demand\r\n\t\t\tstateMatches = state.split('.');\r\n\t\t\tstateMatches.unshift(state);\r\n\t\t}\r\n\t\tif (!empty(s) && s < stateMatches.length) {\r\n\t\t\treturn fixCase(lexer, stateMatches[s]); //$Sn\r\n\t\t}\r\n\t\treturn '';\r\n\t});\r\n}\r\n\r\n/**\r\n * Find the tokenizer rules for a specific state (i.e. next action)\r\n */\r\nexport function findRules(lexer: ILexer, inState: string): IRule[] | null {\r\n\tlet state: string | null = inState;\r\n\twhile (state && state.length > 0) {\r\n\t\tconst rules = lexer.tokenizer[state];\r\n\t\tif (rules) {\r\n\t\t\treturn rules;\r\n\t\t}\r\n\r\n\t\tconst idx = state.lastIndexOf('.');\r\n\t\tif (idx < 0) {\r\n\t\t\tstate = null; // no further parent\r\n\t\t} else {\r\n\t\t\tstate = state.substr(0, idx);\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n}\r\n\r\n/**\r\n * Is a certain state defined? In contrast to 'findRules' this works on a ILexerMin.\r\n * This is used during compilation where we may know the defined states\r\n * but not yet whether the corresponding rules are correct.\r\n */\r\nexport function stateExists(lexer: ILexerMin, inState: string): boolean {\r\n\tlet state: string | null = inState;\r\n\twhile (state && state.length > 0) {\r\n\t\tconst exist = lexer.stateNames[state];\r\n\t\tif (exist) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tconst idx = state.lastIndexOf('.');\r\n\t\tif (idx < 0) {\r\n\t\t\tstate = null; // no further parent\r\n\t\t} else {\r\n\t\t\tstate = state.substr(0, idx);\r\n\t\t}\r\n\t}\r\n\treturn false;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\n/*\r\n * This module only exports 'compile' which compiles a JSON language definition\r\n * into a typed and checked ILexer definition.\r\n */\r\n\r\nimport * as monarchCommon from 'vs/editor/standalone/common/monarch/monarchCommon';\r\nimport { IMonarchLanguage, IMonarchLanguageBracket } from 'vs/editor/standalone/common/monarch/monarchTypes';\r\n\r\n/*\r\n * Type helpers\r\n *\r\n * Note: this is just for sanity checks on the JSON description which is\r\n * helpful for the programmer. No checks are done anymore once the lexer is\r\n * already 'compiled and checked'.\r\n *\r\n */\r\n\r\nfunction isArrayOf(elemType: (x: any) => boolean, obj: any): boolean {\r\n\tif (!obj) {\r\n\t\treturn false;\r\n\t}\r\n\tif (!(Array.isArray(obj))) {\r\n\t\treturn false;\r\n\t}\r\n\tfor (const el of obj) {\r\n\t\tif (!(elemType(el))) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n\treturn true;\r\n}\r\n\r\nfunction bool(prop: any, defValue: boolean): boolean {\r\n\tif (typeof prop === 'boolean') {\r\n\t\treturn prop;\r\n\t}\r\n\treturn defValue;\r\n}\r\n\r\nfunction string(prop: any, defValue: string): string {\r\n\tif (typeof (prop) === 'string') {\r\n\t\treturn prop;\r\n\t}\r\n\treturn defValue;\r\n}\r\n\r\n\r\nfunction arrayToHash(array: string[]): { [name: string]: true } {\r\n\tconst result: any = {};\r\n\tfor (const e of array) {\r\n\t\tresult[e] = true;\r\n\t}\r\n\treturn result;\r\n}\r\n\r\n\r\nfunction createKeywordMatcher(arr: string[], caseInsensitive: boolean = false): (str: string) => boolean {\r\n\tif (caseInsensitive) {\r\n\t\tarr = arr.map(function (x) { return x.toLowerCase(); });\r\n\t}\r\n\tconst hash = arrayToHash(arr);\r\n\tif (caseInsensitive) {\r\n\t\treturn function (word) {\r\n\t\t\treturn hash[word.toLowerCase()] !== undefined && hash.hasOwnProperty(word.toLowerCase());\r\n\t\t};\r\n\t} else {\r\n\t\treturn function (word) {\r\n\t\t\treturn hash[word] !== undefined && hash.hasOwnProperty(word);\r\n\t\t};\r\n\t}\r\n}\r\n\r\n\r\n// Lexer helpers\r\n\r\n/**\r\n * Compiles a regular expression string, adding the 'i' flag if 'ignoreCase' is set, and the 'u' flag if 'unicode' is set.\r\n * Also replaces @\\w+ or sequences with the content of the specified attribute\r\n */\r\nfunction compileRegExp(lexer: monarchCommon.ILexerMin, str: string): RegExp {\r\n\tlet n = 0;\r\n\twhile (str.indexOf('@') >= 0 && n < 5) { // at most 5 expansions\r\n\t\tn++;\r\n\t\tstr = str.replace(/@(\\w+)/g, function (s, attr?) {\r\n\t\t\tlet sub = '';\r\n\t\t\tif (typeof (lexer[attr]) === 'string') {\r\n\t\t\t\tsub = lexer[attr];\r\n\t\t\t} else if (lexer[attr] && lexer[attr] instanceof RegExp) {\r\n\t\t\t\tsub = lexer[attr].source;\r\n\t\t\t} else {\r\n\t\t\t\tif (lexer[attr] === undefined) {\r\n\t\t\t\t\tthrow monarchCommon.createError(lexer, 'language definition does not contain attribute \\'' + attr + '\\', used at: ' + str);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthrow monarchCommon.createError(lexer, 'attribute reference \\'' + attr + '\\' must be a string, used at: ' + str);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn (monarchCommon.empty(sub) ? '' : '(?:' + sub + ')');\r\n\t\t});\r\n\t}\r\n\r\n\tlet flags = (lexer.ignoreCase ? 'i' : '') + (lexer.unicode ? 'u' : '');\r\n\treturn new RegExp(str, flags);\r\n}\r\n\r\n/**\r\n * Compiles guard functions for case matches.\r\n * This compiles 'cases' attributes into efficient match functions.\r\n *\r\n */\r\nfunction selectScrutinee(id: string, matches: string[], state: string, num: number): string | null {\r\n\tif (num < 0) {\r\n\t\treturn id;\r\n\t}\r\n\tif (num < matches.length) {\r\n\t\treturn matches[num];\r\n\t}\r\n\tif (num >= 100) {\r\n\t\tnum = num - 100;\r\n\t\tlet parts = state.split('.');\r\n\t\tparts.unshift(state);\r\n\t\tif (num < parts.length) {\r\n\t\t\treturn parts[num];\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n}\r\n\r\nfunction createGuard(lexer: monarchCommon.ILexerMin, ruleName: string, tkey: string, val: monarchCommon.FuzzyAction): monarchCommon.IBranch {\r\n\t// get the scrutinee and pattern\r\n\tlet scrut = -1; // -1: $!, 0-99: $n, 100+n: $Sn\r\n\tlet oppat = tkey;\r\n\tlet matches = tkey.match(/^\\$(([sS]?)(\\d\\d?)|#)(.*)$/);\r\n\tif (matches) {\r\n\t\tif (matches[3]) { // if digits\r\n\t\t\tscrut = parseInt(matches[3]);\r\n\t\t\tif (matches[2]) {\r\n\t\t\t\tscrut = scrut + 100; // if [sS] present\r\n\t\t\t}\r\n\t\t}\r\n\t\toppat = matches[4];\r\n\t}\r\n\t// get operator\r\n\tlet op = '~';\r\n\tlet pat = oppat;\r\n\tif (!oppat || oppat.length === 0) {\r\n\t\top = '!=';\r\n\t\tpat = '';\r\n\t}\r\n\telse if (/^\\w*$/.test(pat)) { // just a word\r\n\t\top = '==';\r\n\t}\r\n\telse {\r\n\t\tmatches = oppat.match(/^(@|!@|~|!~|==|!=)(.*)$/);\r\n\t\tif (matches) {\r\n\t\t\top = matches[1];\r\n\t\t\tpat = matches[2];\r\n\t\t}\r\n\t}\r\n\r\n\t// set the tester function\r\n\tlet tester: (s: string, id: string, matches: string[], state: string, eos: boolean) => boolean;\r\n\r\n\t// special case a regexp that matches just words\r\n\tif ((op === '~' || op === '!~') && /^(\\w|\\|)*$/.test(pat)) {\r\n\t\tlet inWords = createKeywordMatcher(pat.split('|'), lexer.ignoreCase);\r\n\t\ttester = function (s) { return (op === '~' ? inWords(s) : !inWords(s)); };\r\n\t}\r\n\telse if (op === '@' || op === '!@') {\r\n\t\tlet words = lexer[pat];\r\n\t\tif (!words) {\r\n\t\t\tthrow monarchCommon.createError(lexer, 'the @ match target \\'' + pat + '\\' is not defined, in rule: ' + ruleName);\r\n\t\t}\r\n\t\tif (!(isArrayOf(function (elem) { return (typeof (elem) === 'string'); }, words))) {\r\n\t\t\tthrow monarchCommon.createError(lexer, 'the @ match target \\'' + pat + '\\' must be an array of strings, in rule: ' + ruleName);\r\n\t\t}\r\n\t\tlet inWords = createKeywordMatcher(words, lexer.ignoreCase);\r\n\t\ttester = function (s) { return (op === '@' ? inWords(s) : !inWords(s)); };\r\n\t}\r\n\telse if (op === '~' || op === '!~') {\r\n\t\tif (pat.indexOf('$') < 0) {\r\n\t\t\t// precompile regular expression\r\n\t\t\tlet re = compileRegExp(lexer, '^' + pat + '$');\r\n\t\t\ttester = function (s) { return (op === '~' ? re.test(s) : !re.test(s)); };\r\n\t\t}\r\n\t\telse {\r\n\t\t\ttester = function (s, id, matches, state) {\r\n\t\t\t\tlet re = compileRegExp(lexer, '^' + monarchCommon.substituteMatches(lexer, pat, id, matches, state) + '$');\r\n\t\t\t\treturn re.test(s);\r\n\t\t\t};\r\n\t\t}\r\n\t}\r\n\telse { // if (op==='==' || op==='!=') {\r\n\t\tif (pat.indexOf('$') < 0) {\r\n\t\t\tlet patx = monarchCommon.fixCase(lexer, pat);\r\n\t\t\ttester = function (s) { return (op === '==' ? s === patx : s !== patx); };\r\n\t\t}\r\n\t\telse {\r\n\t\t\tlet patx = monarchCommon.fixCase(lexer, pat);\r\n\t\t\ttester = function (s, id, matches, state, eos) {\r\n\t\t\t\tlet patexp = monarchCommon.substituteMatches(lexer, patx, id, matches, state);\r\n\t\t\t\treturn (op === '==' ? s === patexp : s !== patexp);\r\n\t\t\t};\r\n\t\t}\r\n\t}\r\n\r\n\t// return the branch object\r\n\tif (scrut === -1) {\r\n\t\treturn {\r\n\t\t\tname: tkey, value: val, test: function (id, matches, state, eos) {\r\n\t\t\t\treturn tester(id, id, matches, state, eos);\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\telse {\r\n\t\treturn {\r\n\t\t\tname: tkey, value: val, test: function (id, matches, state, eos) {\r\n\t\t\t\tlet scrutinee = selectScrutinee(id, matches, state, scrut);\r\n\t\t\t\treturn tester(!scrutinee ? '' : scrutinee, id, matches, state, eos);\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n}\r\n\r\n/**\r\n * Compiles an action: i.e. optimize regular expressions and case matches\r\n * and do many sanity checks.\r\n *\r\n * This is called only during compilation but if the lexer definition\r\n * contains user functions as actions (which is usually not allowed), then this\r\n * may be called during lexing. It is important therefore to compile common cases efficiently\r\n */\r\nfunction compileAction(lexer: monarchCommon.ILexerMin, ruleName: string, action: any): monarchCommon.FuzzyAction {\r\n\tif (!action) {\r\n\t\treturn { token: '' };\r\n\t}\r\n\telse if (typeof (action) === 'string') {\r\n\t\treturn action; // { token: action };\r\n\t}\r\n\telse if (action.token || action.token === '') {\r\n\t\tif (typeof (action.token) !== 'string') {\r\n\t\t\tthrow monarchCommon.createError(lexer, 'a \\'token\\' attribute must be of type string, in rule: ' + ruleName);\r\n\t\t}\r\n\t\telse {\r\n\t\t\t// only copy specific typed fields (only happens once during compile Lexer)\r\n\t\t\tlet newAction: monarchCommon.IAction = { token: action.token };\r\n\t\t\tif (action.token.indexOf('$') >= 0) {\r\n\t\t\t\tnewAction.tokenSubst = true;\r\n\t\t\t}\r\n\t\t\tif (typeof (action.bracket) === 'string') {\r\n\t\t\t\tif (action.bracket === '@open') {\r\n\t\t\t\t\tnewAction.bracket = monarchCommon.MonarchBracket.Open;\r\n\t\t\t\t} else if (action.bracket === '@close') {\r\n\t\t\t\t\tnewAction.bracket = monarchCommon.MonarchBracket.Close;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthrow monarchCommon.createError(lexer, 'a \\'bracket\\' attribute must be either \\'@open\\' or \\'@close\\', in rule: ' + ruleName);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (action.next) {\r\n\t\t\t\tif (typeof (action.next) !== 'string') {\r\n\t\t\t\t\tthrow monarchCommon.createError(lexer, 'the next state must be a string value in rule: ' + ruleName);\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\tlet next: string = action.next;\r\n\t\t\t\t\tif (!/^(@pop|@push|@popall)$/.test(next)) {\r\n\t\t\t\t\t\tif (next[0] === '@') {\r\n\t\t\t\t\t\t\tnext = next.substr(1); // peel off starting @ sign\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (next.indexOf('$') < 0) { // no dollar substitution, we can check if the state exists\r\n\t\t\t\t\t\t\tif (!monarchCommon.stateExists(lexer, monarchCommon.substituteMatches(lexer, next, '', [], ''))) {\r\n\t\t\t\t\t\t\t\tthrow monarchCommon.createError(lexer, 'the next state \\'' + action.next + '\\' is not defined in rule: ' + ruleName);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tnewAction.next = next;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (typeof (action.goBack) === 'number') {\r\n\t\t\t\tnewAction.goBack = action.goBack;\r\n\t\t\t}\r\n\t\t\tif (typeof (action.switchTo) === 'string') {\r\n\t\t\t\tnewAction.switchTo = action.switchTo;\r\n\t\t\t}\r\n\t\t\tif (typeof (action.log) === 'string') {\r\n\t\t\t\tnewAction.log = action.log;\r\n\t\t\t}\r\n\t\t\tif (typeof (action.nextEmbedded) === 'string') {\r\n\t\t\t\tnewAction.nextEmbedded = action.nextEmbedded;\r\n\t\t\t\tlexer.usesEmbedded = true;\r\n\t\t\t}\r\n\t\t\treturn newAction;\r\n\t\t}\r\n\t}\r\n\telse if (Array.isArray(action)) {\r\n\t\tlet results: monarchCommon.FuzzyAction[] = [];\r\n\t\tfor (let i = 0, len = action.length; i < len; i++) {\r\n\t\t\tresults[i] = compileAction(lexer, ruleName, action[i]);\r\n\t\t}\r\n\t\treturn { group: results };\r\n\t}\r\n\telse if (action.cases) {\r\n\t\t// build an array of test cases\r\n\t\tlet cases: monarchCommon.IBranch[] = [];\r\n\r\n\t\t// for each case, push a test function and result value\r\n\t\tfor (let tkey in action.cases) {\r\n\t\t\tif (action.cases.hasOwnProperty(tkey)) {\r\n\t\t\t\tconst val = compileAction(lexer, ruleName, action.cases[tkey]);\r\n\r\n\t\t\t\t// what kind of case\r\n\t\t\t\tif (tkey === '@default' || tkey === '@' || tkey === '') {\r\n\t\t\t\t\tcases.push({ test: undefined, value: val, name: tkey });\r\n\t\t\t\t}\r\n\t\t\t\telse if (tkey === '@eos') {\r\n\t\t\t\t\tcases.push({ test: function (id, matches, state, eos) { return eos; }, value: val, name: tkey });\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\tcases.push(createGuard(lexer, ruleName, tkey, val)); // call separate function to avoid local variable capture\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// create a matching function\r\n\t\tconst def = lexer.defaultToken;\r\n\t\treturn {\r\n\t\t\ttest: function (id, matches, state, eos) {\r\n\t\t\t\tfor (const _case of cases) {\r\n\t\t\t\t\tconst didmatch = (!_case.test || _case.test(id, matches, state, eos));\r\n\t\t\t\t\tif (didmatch) {\r\n\t\t\t\t\t\treturn _case.value;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\treturn def;\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\telse {\r\n\t\tthrow monarchCommon.createError(lexer, 'an action must be a string, an object with a \\'token\\' or \\'cases\\' attribute, or an array of actions; in rule: ' + ruleName);\r\n\t}\r\n}\r\n\r\n/**\r\n * Helper class for creating matching rules\r\n */\r\nclass Rule implements monarchCommon.IRule {\r\n\tpublic regex: RegExp = new RegExp('');\r\n\tpublic action: monarchCommon.FuzzyAction = { token: '' };\r\n\tpublic matchOnlyAtLineStart: boolean = false;\r\n\tpublic name: string = '';\r\n\r\n\tconstructor(name: string) {\r\n\t\tthis.name = name;\r\n\t}\r\n\r\n\tpublic setRegex(lexer: monarchCommon.ILexerMin, re: string | RegExp): void {\r\n\t\tlet sregex: string;\r\n\t\tif (typeof (re) === 'string') {\r\n\t\t\tsregex = re;\r\n\t\t}\r\n\t\telse if (re instanceof RegExp) {\r\n\t\t\tsregex = (re).source;\r\n\t\t}\r\n\t\telse {\r\n\t\t\tthrow monarchCommon.createError(lexer, 'rules must start with a match string or regular expression: ' + this.name);\r\n\t\t}\r\n\r\n\t\tthis.matchOnlyAtLineStart = (sregex.length > 0 && sregex[0] === '^');\r\n\t\tthis.name = this.name + ': ' + sregex;\r\n\t\tthis.regex = compileRegExp(lexer, '^(?:' + (this.matchOnlyAtLineStart ? sregex.substr(1) : sregex) + ')');\r\n\t}\r\n\r\n\tpublic setAction(lexer: monarchCommon.ILexerMin, act: monarchCommon.IAction) {\r\n\t\tthis.action = compileAction(lexer, this.name, act);\r\n\t}\r\n}\r\n\r\n/**\r\n * Compiles a json description function into json where all regular expressions,\r\n * case matches etc, are compiled and all include rules are expanded.\r\n * We also compile the bracket definitions, supply defaults, and do many sanity checks.\r\n * If the 'jsonStrict' parameter is 'false', we allow at certain locations\r\n * regular expression objects and functions that get called during lexing.\r\n * (Currently we have no samples that need this so perhaps we should always have\r\n * jsonStrict to true).\r\n */\r\nexport function compile(languageId: string, json: IMonarchLanguage): monarchCommon.ILexer {\r\n\tif (!json || typeof (json) !== 'object') {\r\n\t\tthrow new Error('Monarch: expecting a language definition object');\r\n\t}\r\n\r\n\t// Create our lexer\r\n\tlet lexer: monarchCommon.ILexer = {};\r\n\tlexer.languageId = languageId;\r\n\tlexer.includeLF = bool(json.includeLF, false);\r\n\tlexer.noThrow = false; // raise exceptions during compilation\r\n\tlexer.maxStack = 100;\r\n\r\n\t// Set standard fields: be defensive about types\r\n\tlexer.start = (typeof json.start === 'string' ? json.start : null);\r\n\tlexer.ignoreCase = bool(json.ignoreCase, false);\r\n\tlexer.unicode = bool(json.unicode, false);\r\n\r\n\tlexer.tokenPostfix = string(json.tokenPostfix, '.' + lexer.languageId);\r\n\tlexer.defaultToken = string(json.defaultToken, 'source');\r\n\r\n\tlexer.usesEmbedded = false; // becomes true if we find a nextEmbedded action\r\n\r\n\t// For calling compileAction later on\r\n\tlet lexerMin: monarchCommon.ILexerMin = json;\r\n\tlexerMin.languageId = languageId;\r\n\tlexerMin.includeLF = lexer.includeLF;\r\n\tlexerMin.ignoreCase = lexer.ignoreCase;\r\n\tlexerMin.unicode = lexer.unicode;\r\n\tlexerMin.noThrow = lexer.noThrow;\r\n\tlexerMin.usesEmbedded = lexer.usesEmbedded;\r\n\tlexerMin.stateNames = json.tokenizer;\r\n\tlexerMin.defaultToken = lexer.defaultToken;\r\n\r\n\r\n\t// Compile an array of rules into newrules where RegExp objects are created.\r\n\tfunction addRules(state: string, newrules: monarchCommon.IRule[], rules: any[]) {\r\n\t\tfor (const rule of rules) {\r\n\r\n\t\t\tlet include = rule.include;\r\n\t\t\tif (include) {\r\n\t\t\t\tif (typeof (include) !== 'string') {\r\n\t\t\t\t\tthrow monarchCommon.createError(lexer, 'an \\'include\\' attribute must be a string at: ' + state);\r\n\t\t\t\t}\r\n\t\t\t\tif (include[0] === '@') {\r\n\t\t\t\t\tinclude = include.substr(1); // peel off starting @\r\n\t\t\t\t}\r\n\t\t\t\tif (!json.tokenizer[include]) {\r\n\t\t\t\t\tthrow monarchCommon.createError(lexer, 'include target \\'' + include + '\\' is not defined at: ' + state);\r\n\t\t\t\t}\r\n\t\t\t\taddRules(state + '.' + include, newrules, json.tokenizer[include]);\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tconst newrule = new Rule(state);\r\n\r\n\t\t\t\t// Set up new rule attributes\r\n\t\t\t\tif (Array.isArray(rule) && rule.length >= 1 && rule.length <= 3) {\r\n\t\t\t\t\tnewrule.setRegex(lexerMin, rule[0]);\r\n\t\t\t\t\tif (rule.length >= 3) {\r\n\t\t\t\t\t\tif (typeof (rule[1]) === 'string') {\r\n\t\t\t\t\t\t\tnewrule.setAction(lexerMin, { token: rule[1], next: rule[2] });\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse if (typeof (rule[1]) === 'object') {\r\n\t\t\t\t\t\t\tconst rule1 = rule[1];\r\n\t\t\t\t\t\t\trule1.next = rule[2];\r\n\t\t\t\t\t\t\tnewrule.setAction(lexerMin, rule1);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\tthrow monarchCommon.createError(lexer, 'a next state as the last element of a rule can only be given if the action is either an object or a string, at: ' + state);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tnewrule.setAction(lexerMin, rule[1]);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\tif (!rule.regex) {\r\n\t\t\t\t\t\tthrow monarchCommon.createError(lexer, 'a rule must either be an array, or an object with a \\'regex\\' or \\'include\\' field at: ' + state);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (rule.name) {\r\n\t\t\t\t\t\tif (typeof rule.name === 'string') {\r\n\t\t\t\t\t\t\tnewrule.name = rule.name;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (rule.matchOnlyAtStart) {\r\n\t\t\t\t\t\tnewrule.matchOnlyAtLineStart = bool(rule.matchOnlyAtLineStart, false);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tnewrule.setRegex(lexerMin, rule.regex);\r\n\t\t\t\t\tnewrule.setAction(lexerMin, rule.action);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tnewrules.push(newrule);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t// compile the tokenizer rules\r\n\tif (!json.tokenizer || typeof (json.tokenizer) !== 'object') {\r\n\t\tthrow monarchCommon.createError(lexer, 'a language definition must define the \\'tokenizer\\' attribute as an object');\r\n\t}\r\n\r\n\tlexer.tokenizer = [];\r\n\tfor (let key in json.tokenizer) {\r\n\t\tif (json.tokenizer.hasOwnProperty(key)) {\r\n\t\t\tif (!lexer.start) {\r\n\t\t\t\tlexer.start = key;\r\n\t\t\t}\r\n\r\n\t\t\tconst rules = json.tokenizer[key];\r\n\t\t\tlexer.tokenizer[key] = new Array();\r\n\t\t\taddRules('tokenizer.' + key, lexer.tokenizer[key], rules);\r\n\t\t}\r\n\t}\r\n\tlexer.usesEmbedded = lexerMin.usesEmbedded; // can be set during compileAction\r\n\r\n\t// Set simple brackets\r\n\tif (json.brackets) {\r\n\t\tif (!(Array.isArray(json.brackets))) {\r\n\t\t\tthrow monarchCommon.createError(lexer, 'the \\'brackets\\' attribute must be defined as an array');\r\n\t\t}\r\n\t}\r\n\telse {\r\n\t\tjson.brackets = [\r\n\t\t\t{ open: '{', close: '}', token: 'delimiter.curly' },\r\n\t\t\t{ open: '[', close: ']', token: 'delimiter.square' },\r\n\t\t\t{ open: '(', close: ')', token: 'delimiter.parenthesis' },\r\n\t\t\t{ open: '<', close: '>', token: 'delimiter.angle' }];\r\n\t}\r\n\tlet brackets: IMonarchLanguageBracket[] = [];\r\n\tfor (let el of json.brackets) {\r\n\t\tlet desc: any = el;\r\n\t\tif (desc && Array.isArray(desc) && desc.length === 3) {\r\n\t\t\tdesc = { token: desc[2], open: desc[0], close: desc[1] };\r\n\t\t}\r\n\t\tif (desc.open === desc.close) {\r\n\t\t\tthrow monarchCommon.createError(lexer, 'open and close brackets in a \\'brackets\\' attribute must be different: ' + desc.open +\r\n\t\t\t\t'\\n hint: use the \\'bracket\\' attribute if matching on equal brackets is required.');\r\n\t\t}\r\n\t\tif (typeof desc.open === 'string' && typeof desc.token === 'string' && typeof desc.close === 'string') {\r\n\t\t\tbrackets.push({\r\n\t\t\t\ttoken: desc.token + lexer.tokenPostfix,\r\n\t\t\t\topen: monarchCommon.fixCase(lexer, desc.open),\r\n\t\t\t\tclose: monarchCommon.fixCase(lexer, desc.close)\r\n\t\t\t});\r\n\t\t}\r\n\t\telse {\r\n\t\t\tthrow monarchCommon.createError(lexer, 'every element in the \\'brackets\\' array must be a \\'{open,close,token}\\' object or array');\r\n\t\t}\r\n\t}\r\n\tlexer.brackets = brackets;\r\n\r\n\t// Disable throw so the syntax highlighter goes, no matter what\r\n\tlexer.noThrow = true;\r\n\treturn lexer;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox';\r\nimport { Color } from 'vs/base/common/color';\r\nimport * as nls from 'vs/nls';\r\nimport { Codicon } from 'vs/base/common/codicons';\r\n\r\nexport interface IFindInputCheckboxOpts {\r\n\treadonly appendTitle: string;\r\n\treadonly isChecked: boolean;\r\n\treadonly inputActiveOptionBorder?: Color;\r\n\treadonly inputActiveOptionForeground?: Color;\r\n\treadonly inputActiveOptionBackground?: Color;\r\n}\r\n\r\nconst NLS_CASE_SENSITIVE_CHECKBOX_LABEL = nls.localize('caseDescription', \"Match Case\");\r\nconst NLS_WHOLE_WORD_CHECKBOX_LABEL = nls.localize('wordsDescription', \"Match Whole Word\");\r\nconst NLS_REGEX_CHECKBOX_LABEL = nls.localize('regexDescription', \"Use Regular Expression\");\r\n\r\nexport class CaseSensitiveCheckbox extends Checkbox {\r\n\tconstructor(opts: IFindInputCheckboxOpts) {\r\n\t\tsuper({\r\n\t\t\ticon: Codicon.caseSensitive,\r\n\t\t\ttitle: NLS_CASE_SENSITIVE_CHECKBOX_LABEL + opts.appendTitle,\r\n\t\t\tisChecked: opts.isChecked,\r\n\t\t\tinputActiveOptionBorder: opts.inputActiveOptionBorder,\r\n\t\t\tinputActiveOptionForeground: opts.inputActiveOptionForeground,\r\n\t\t\tinputActiveOptionBackground: opts.inputActiveOptionBackground\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class WholeWordsCheckbox extends Checkbox {\r\n\tconstructor(opts: IFindInputCheckboxOpts) {\r\n\t\tsuper({\r\n\t\t\ticon: Codicon.wholeWord,\r\n\t\t\ttitle: NLS_WHOLE_WORD_CHECKBOX_LABEL + opts.appendTitle,\r\n\t\t\tisChecked: opts.isChecked,\r\n\t\t\tinputActiveOptionBorder: opts.inputActiveOptionBorder,\r\n\t\t\tinputActiveOptionForeground: opts.inputActiveOptionForeground,\r\n\t\t\tinputActiveOptionBackground: opts.inputActiveOptionBackground\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class RegexCheckbox extends Checkbox {\r\n\tconstructor(opts: IFindInputCheckboxOpts) {\r\n\t\tsuper({\r\n\t\t\ticon: Codicon.regex,\r\n\t\t\ttitle: NLS_REGEX_CHECKBOX_LABEL + opts.appendTitle,\r\n\t\t\tisChecked: opts.isChecked,\r\n\t\t\tinputActiveOptionBorder: opts.inputActiveOptionBorder,\r\n\t\t\tinputActiveOptionForeground: opts.inputActiveOptionForeground,\r\n\t\t\tinputActiveOptionBackground: opts.inputActiveOptionBackground\r\n\t\t});\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./iconlabel';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';\r\nimport { IMatch } from 'vs/base/common/filters';\r\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\r\nimport { Range } from 'vs/base/common/range';\r\nimport { equals } from 'vs/base/common/objects';\r\nimport { isMacintosh } from 'vs/base/common/platform';\r\nimport { IHoverDelegate, IHoverDelegateOptions, IHoverDelegateTarget } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';\r\nimport { AnchorPosition } from 'vs/base/browser/ui/contextview/contextview';\r\nimport { IMarkdownString } from 'vs/base/common/htmlContent';\r\nimport { isFunction, isString } from 'vs/base/common/types';\r\nimport { domEvent } from 'vs/base/browser/event';\r\nimport { localize } from 'vs/nls';\r\nimport { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\r\n\r\nexport interface IIconLabelCreationOptions {\r\n\tsupportHighlights?: boolean;\r\n\tsupportDescriptionHighlights?: boolean;\r\n\tsupportIcons?: boolean;\r\n\thoverDelegate?: IHoverDelegate;\r\n}\r\n\r\nexport interface IIconLabelMarkdownString {\r\n\tmarkdown: IMarkdownString | string | undefined | ((token: CancellationToken) => Promise);\r\n\tmarkdownNotSupportedFallback: string | undefined;\r\n}\r\n\r\nexport interface IIconLabelValueOptions {\r\n\ttitle?: string | IIconLabelMarkdownString;\r\n\tdescriptionTitle?: string;\r\n\textraClasses?: string[];\r\n\titalic?: boolean;\r\n\tstrikethrough?: boolean;\r\n\tmatches?: IMatch[];\r\n\tlabelEscapeNewLines?: boolean;\r\n\tdescriptionMatches?: IMatch[];\r\n\treadonly separator?: string;\r\n\treadonly domId?: string;\r\n}\r\n\r\nclass FastLabelNode {\r\n\tprivate disposed: boolean | undefined;\r\n\tprivate _textContent: string | undefined;\r\n\tprivate _className: string | undefined;\r\n\tprivate _empty: boolean | undefined;\r\n\r\n\tconstructor(private _element: HTMLElement) {\r\n\t}\r\n\r\n\tget element(): HTMLElement {\r\n\t\treturn this._element;\r\n\t}\r\n\r\n\tset textContent(content: string) {\r\n\t\tif (this.disposed || content === this._textContent) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._textContent = content;\r\n\t\tthis._element.textContent = content;\r\n\t}\r\n\r\n\tset className(className: string) {\r\n\t\tif (this.disposed || className === this._className) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._className = className;\r\n\t\tthis._element.className = className;\r\n\t}\r\n\r\n\tset empty(empty: boolean) {\r\n\t\tif (this.disposed || empty === this._empty) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._empty = empty;\r\n\t\tthis._element.style.marginLeft = empty ? '0' : '';\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis.disposed = true;\r\n\t}\r\n}\r\n\r\nexport class IconLabel extends Disposable {\r\n\r\n\tprivate domNode: FastLabelNode;\r\n\r\n\tprivate nameNode: Label | LabelWithHighlights;\r\n\r\n\tprivate descriptionContainer: FastLabelNode;\r\n\tprivate descriptionNode: FastLabelNode | HighlightedLabel | undefined;\r\n\tprivate descriptionNodeFactory: () => FastLabelNode | HighlightedLabel;\r\n\r\n\tprivate labelContainer: HTMLElement;\r\n\r\n\tprivate hoverDelegate: IHoverDelegate | undefined = undefined;\r\n\tprivate readonly customHovers: Map = new Map();\r\n\r\n\tconstructor(container: HTMLElement, options?: IIconLabelCreationOptions) {\r\n\t\tsuper();\r\n\r\n\t\tthis.domNode = this._register(new FastLabelNode(dom.append(container, dom.$('.monaco-icon-label'))));\r\n\r\n\t\tthis.labelContainer = dom.append(this.domNode.element, dom.$('.monaco-icon-label-container'));\r\n\r\n\t\tconst nameContainer = dom.append(this.labelContainer, dom.$('span.monaco-icon-name-container'));\r\n\t\tthis.descriptionContainer = this._register(new FastLabelNode(dom.append(this.labelContainer, dom.$('span.monaco-icon-description-container'))));\r\n\r\n\t\tif (options?.supportHighlights) {\r\n\t\t\tthis.nameNode = new LabelWithHighlights(nameContainer, !!options.supportIcons);\r\n\t\t} else {\r\n\t\t\tthis.nameNode = new Label(nameContainer);\r\n\t\t}\r\n\r\n\t\tif (options?.supportDescriptionHighlights) {\r\n\t\t\tthis.descriptionNodeFactory = () => new HighlightedLabel(dom.append(this.descriptionContainer.element, dom.$('span.label-description')), !!options.supportIcons);\r\n\t\t} else {\r\n\t\t\tthis.descriptionNodeFactory = () => this._register(new FastLabelNode(dom.append(this.descriptionContainer.element, dom.$('span.label-description'))));\r\n\t\t}\r\n\r\n\t\tif (options?.hoverDelegate) {\r\n\t\t\tthis.hoverDelegate = options.hoverDelegate;\r\n\t\t}\r\n\t}\r\n\r\n\tsetLabel(label: string | string[], description?: string, options?: IIconLabelValueOptions): void {\r\n\t\tconst classes = ['monaco-icon-label'];\r\n\t\tif (options) {\r\n\t\t\tif (options.extraClasses) {\r\n\t\t\t\tclasses.push(...options.extraClasses);\r\n\t\t\t}\r\n\r\n\t\t\tif (options.italic) {\r\n\t\t\t\tclasses.push('italic');\r\n\t\t\t}\r\n\r\n\t\t\tif (options.strikethrough) {\r\n\t\t\t\tclasses.push('strikethrough');\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis.domNode.className = classes.join(' ');\r\n\t\tthis.setupHover(this.labelContainer, options?.title);\r\n\r\n\t\tthis.nameNode.setLabel(label, options);\r\n\r\n\t\tif (description || this.descriptionNode) {\r\n\t\t\tif (!this.descriptionNode) {\r\n\t\t\t\tthis.descriptionNode = this.descriptionNodeFactory(); // description node is created lazily on demand\r\n\t\t\t}\r\n\r\n\t\t\tif (this.descriptionNode instanceof HighlightedLabel) {\r\n\t\t\t\tthis.descriptionNode.set(description || '', options ? options.descriptionMatches : undefined);\r\n\t\t\t\tthis.setupHover(this.descriptionNode.element, options?.descriptionTitle);\r\n\t\t\t} else {\r\n\t\t\t\tthis.descriptionNode.textContent = description || '';\r\n\t\t\t\tthis.setupHover(this.descriptionNode.element, options?.descriptionTitle || '');\r\n\t\t\t\tthis.descriptionNode.empty = !description;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate setupHover(htmlElement: HTMLElement, tooltip: string | IIconLabelMarkdownString | undefined): void {\r\n\t\tconst previousCustomHover = this.customHovers.get(htmlElement);\r\n\t\tif (previousCustomHover) {\r\n\t\t\tpreviousCustomHover.dispose();\r\n\t\t\tthis.customHovers.delete(htmlElement);\r\n\t\t}\r\n\r\n\t\tif (!tooltip) {\r\n\t\t\thtmlElement.removeAttribute('title');\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!this.hoverDelegate) {\r\n\t\t\treturn this.setupNativeHover(htmlElement, tooltip);\r\n\t\t} else {\r\n\t\t\treturn this.setupCustomHover(this.hoverDelegate, htmlElement, tooltip);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static adjustXAndShowCustomHover(hoverOptions: IHoverDelegateOptions | undefined, mouseX: number | undefined, hoverDelegate: IHoverDelegate, isHovering: boolean) {\r\n\t\tif (hoverOptions && isHovering) {\r\n\t\t\tif (mouseX !== undefined) {\r\n\t\t\t\t(hoverOptions.target).x = mouseX + 10;\r\n\t\t\t}\r\n\t\t\thoverDelegate.showHover(hoverOptions);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate getTooltipForCustom(markdownTooltip: string | IIconLabelMarkdownString): (token: CancellationToken) => Promise {\r\n\t\tif (isString(markdownTooltip)) {\r\n\t\t\treturn async () => markdownTooltip;\r\n\t\t} else if (isFunction(markdownTooltip.markdown)) {\r\n\t\t\treturn markdownTooltip.markdown;\r\n\t\t} else {\r\n\t\t\tconst markdown = markdownTooltip.markdown;\r\n\t\t\treturn async () => markdown;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate setupCustomHover(hoverDelegate: IHoverDelegate, htmlElement: HTMLElement, markdownTooltip: string | IIconLabelMarkdownString): void {\r\n\t\thtmlElement.setAttribute('title', '');\r\n\t\thtmlElement.removeAttribute('title');\r\n\t\tlet tooltip = this.getTooltipForCustom(markdownTooltip);\r\n\r\n\t\t// Testing has indicated that on Windows and Linux 500 ms matches the native hovers most closely.\r\n\t\t// On Mac, the delay is 1500.\r\n\t\tconst hoverDelay = isMacintosh ? 1500 : 500;\r\n\t\tlet hoverOptions: IHoverDelegateOptions | undefined;\r\n\t\tlet mouseX: number | undefined;\r\n\t\tlet isHovering = false;\r\n\t\tlet tokenSource: CancellationTokenSource;\r\n\t\tfunction mouseOver(this: HTMLElement, e: MouseEvent): any {\r\n\t\t\tif (isHovering) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\ttokenSource = new CancellationTokenSource();\r\n\t\t\tfunction mouseLeaveOrDown(this: HTMLElement, e: MouseEvent): any {\r\n\t\t\t\tisHovering = false;\r\n\t\t\t\thoverOptions = undefined;\r\n\t\t\t\ttokenSource.dispose(true);\r\n\t\t\t\tmouseLeaveDisposable.dispose();\r\n\t\t\t\tmouseDownDisposable.dispose();\r\n\t\t\t}\r\n\t\t\tconst mouseLeaveDisposable = domEvent(htmlElement, dom.EventType.MOUSE_LEAVE, true)(mouseLeaveOrDown.bind(htmlElement));\r\n\t\t\tconst mouseDownDisposable = domEvent(htmlElement, dom.EventType.MOUSE_DOWN, true)(mouseLeaveOrDown.bind(htmlElement));\r\n\t\t\tisHovering = true;\r\n\r\n\t\t\tfunction mouseMove(this: HTMLElement, e: MouseEvent): any {\r\n\t\t\t\tmouseX = e.x;\r\n\t\t\t}\r\n\t\t\tconst mouseMoveDisposable = domEvent(htmlElement, dom.EventType.MOUSE_MOVE, true)(mouseMove.bind(htmlElement));\r\n\t\t\tsetTimeout(async () => {\r\n\t\t\t\tif (isHovering && tooltip) {\r\n\t\t\t\t\t// Re-use the already computed hover options if they exist.\r\n\t\t\t\t\tif (!hoverOptions) {\r\n\t\t\t\t\t\tconst target: IHoverDelegateTarget = {\r\n\t\t\t\t\t\t\ttargetElements: [this],\r\n\t\t\t\t\t\t\tdispose: () => { }\r\n\t\t\t\t\t\t};\r\n\t\t\t\t\t\thoverOptions = {\r\n\t\t\t\t\t\t\ttext: localize('iconLabel.loading', \"Loading...\"),\r\n\t\t\t\t\t\t\ttarget,\r\n\t\t\t\t\t\t\tanchorPosition: AnchorPosition.BELOW\r\n\t\t\t\t\t\t};\r\n\t\t\t\t\t\tIconLabel.adjustXAndShowCustomHover(hoverOptions, mouseX, hoverDelegate, isHovering);\r\n\r\n\t\t\t\t\t\tconst resolvedTooltip = await tooltip(tokenSource.token);\r\n\t\t\t\t\t\tif (resolvedTooltip) {\r\n\t\t\t\t\t\t\thoverOptions = {\r\n\t\t\t\t\t\t\t\ttext: resolvedTooltip,\r\n\t\t\t\t\t\t\t\ttarget,\r\n\t\t\t\t\t\t\t\tanchorPosition: AnchorPosition.BELOW\r\n\t\t\t\t\t\t\t};\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\t// awaiting the tooltip could take a while. Make sure we're still hovering.\r\n\t\t\t\t\tIconLabel.adjustXAndShowCustomHover(hoverOptions, mouseX, hoverDelegate, isHovering);\r\n\t\t\t\t}\r\n\t\t\t\tmouseMoveDisposable.dispose();\r\n\t\t\t}, hoverDelay);\r\n\t\t}\r\n\t\tconst mouseOverDisposable = this._register(domEvent(htmlElement, dom.EventType.MOUSE_OVER, true)(mouseOver.bind(htmlElement)));\r\n\t\tthis.customHovers.set(htmlElement, mouseOverDisposable);\r\n\t}\r\n\r\n\tprivate setupNativeHover(htmlElement: HTMLElement, tooltip: string | IIconLabelMarkdownString | undefined): void {\r\n\t\tlet stringTooltip: string = '';\r\n\t\tif (isString(tooltip)) {\r\n\t\t\tstringTooltip = tooltip;\r\n\t\t} else if (tooltip?.markdownNotSupportedFallback) {\r\n\t\t\tstringTooltip = tooltip.markdownNotSupportedFallback;\r\n\t\t}\r\n\t\thtmlElement.title = stringTooltip;\r\n\t}\r\n}\r\n\r\nclass Label {\r\n\r\n\tprivate label: string | string[] | undefined = undefined;\r\n\tprivate singleLabel: HTMLElement | undefined = undefined;\r\n\tprivate options: IIconLabelValueOptions | undefined;\r\n\r\n\tconstructor(private container: HTMLElement) { }\r\n\r\n\tsetLabel(label: string | string[], options?: IIconLabelValueOptions): void {\r\n\t\tif (this.label === label && equals(this.options, options)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.label = label;\r\n\t\tthis.options = options;\r\n\r\n\t\tif (typeof label === 'string') {\r\n\t\t\tif (!this.singleLabel) {\r\n\t\t\t\tthis.container.innerText = '';\r\n\t\t\t\tthis.container.classList.remove('multiple');\r\n\t\t\t\tthis.singleLabel = dom.append(this.container, dom.$('a.label-name', { id: options?.domId }));\r\n\t\t\t}\r\n\r\n\t\t\tthis.singleLabel.textContent = label;\r\n\t\t} else {\r\n\t\t\tthis.container.innerText = '';\r\n\t\t\tthis.container.classList.add('multiple');\r\n\t\t\tthis.singleLabel = undefined;\r\n\r\n\t\t\tfor (let i = 0; i < label.length; i++) {\r\n\t\t\t\tconst l = label[i];\r\n\t\t\t\tconst id = options?.domId && `${options?.domId}_${i}`;\r\n\r\n\t\t\t\tdom.append(this.container, dom.$('a.label-name', { id, 'data-icon-label-count': label.length, 'data-icon-label-index': i, 'role': 'treeitem' }, l));\r\n\r\n\t\t\t\tif (i < label.length - 1) {\r\n\t\t\t\t\tdom.append(this.container, dom.$('span.label-separator', undefined, options?.separator || '/'));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction splitMatches(labels: string[], separator: string, matches: IMatch[] | undefined): IMatch[][] | undefined {\r\n\tif (!matches) {\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tlet labelStart = 0;\r\n\r\n\treturn labels.map(label => {\r\n\t\tconst labelRange = { start: labelStart, end: labelStart + label.length };\r\n\r\n\t\tconst result = matches\r\n\t\t\t.map(match => Range.intersect(labelRange, match))\r\n\t\t\t.filter(range => !Range.isEmpty(range))\r\n\t\t\t.map(({ start, end }) => ({ start: start - labelStart, end: end - labelStart }));\r\n\r\n\t\tlabelStart = labelRange.end + separator.length;\r\n\t\treturn result;\r\n\t});\r\n}\r\n\r\nclass LabelWithHighlights {\r\n\r\n\tprivate label: string | string[] | undefined = undefined;\r\n\tprivate singleLabel: HighlightedLabel | undefined = undefined;\r\n\tprivate options: IIconLabelValueOptions | undefined;\r\n\r\n\tconstructor(private container: HTMLElement, private supportIcons: boolean) { }\r\n\r\n\tsetLabel(label: string | string[], options?: IIconLabelValueOptions): void {\r\n\t\tif (this.label === label && equals(this.options, options)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.label = label;\r\n\t\tthis.options = options;\r\n\r\n\t\tif (typeof label === 'string') {\r\n\t\t\tif (!this.singleLabel) {\r\n\t\t\t\tthis.container.innerText = '';\r\n\t\t\t\tthis.container.classList.remove('multiple');\r\n\t\t\t\tthis.singleLabel = new HighlightedLabel(dom.append(this.container, dom.$('a.label-name', { id: options?.domId })), this.supportIcons);\r\n\t\t\t}\r\n\r\n\t\t\tthis.singleLabel.set(label, options?.matches, undefined, options?.labelEscapeNewLines);\r\n\t\t} else {\r\n\t\t\tthis.container.innerText = '';\r\n\t\t\tthis.container.classList.add('multiple');\r\n\t\t\tthis.singleLabel = undefined;\r\n\r\n\t\t\tconst separator = options?.separator || '/';\r\n\t\t\tconst matches = splitMatches(label, separator, options?.matches);\r\n\r\n\t\t\tfor (let i = 0; i < label.length; i++) {\r\n\t\t\t\tconst l = label[i];\r\n\t\t\t\tconst m = matches ? matches[i] : undefined;\r\n\t\t\t\tconst id = options?.domId && `${options?.domId}_${i}`;\r\n\r\n\t\t\t\tconst name = dom.$('a.label-name', { id, 'data-icon-label-count': label.length, 'data-icon-label-index': i, 'role': 'treeitem' });\r\n\t\t\t\tconst highlightedLabel = new HighlightedLabel(dom.append(this.container, name), this.supportIcons);\r\n\t\t\t\thighlightedLabel.set(l, m, undefined, options?.labelEscapeNewLines);\r\n\r\n\t\t\t\tif (i < label.length - 1) {\r\n\t\t\t\t\tdom.append(name, dom.$('span.label-separator', undefined, separator));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./media/tree';\r\nimport { IDisposable, dispose, Disposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { IListOptions, List, IListStyles, MouseController, DefaultKeyboardNavigationDelegate, isInputElement, isMonacoEditor } from 'vs/base/browser/ui/list/listWidget';\r\nimport { IListVirtualDelegate, IListRenderer, IListMouseEvent, IListDragAndDrop, IListDragOverReaction, IKeyboardNavigationLabelProvider, IIdentityProvider, IKeyboardNavigationDelegate } from 'vs/base/browser/ui/list/list';\r\nimport { append, $, getDomNodePagePosition, hasParentWithClass, createStyleSheet, clearNode } from 'vs/base/browser/dom';\r\nimport { Event, Relay, Emitter, EventBufferer } from 'vs/base/common/event';\r\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { KeyCode } from 'vs/base/common/keyCodes';\r\nimport { ITreeModel, ITreeNode, ITreeRenderer, ITreeEvent, ITreeMouseEvent, ITreeFilter, ICollapseStateChangeEvent, ITreeDragAndDrop, TreeDragOverBubble, TreeVisibility, TreeFilterResult, ITreeModelSpliceEvent, TreeMouseEventTarget } from 'vs/base/browser/ui/tree/tree';\r\nimport { ISpliceable } from 'vs/base/common/sequence';\r\nimport { IDragAndDropData, StaticDND, DragAndDropData } from 'vs/base/browser/dnd';\r\nimport { range, equals, distinctES6 } from 'vs/base/common/arrays';\r\nimport { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView';\r\nimport { domEvent } from 'vs/base/browser/event';\r\nimport { fuzzyScore, FuzzyScore } from 'vs/base/common/filters';\r\nimport { getVisibleState, isFilterResult } from 'vs/base/browser/ui/tree/indexTreeModel';\r\nimport { localize } from 'vs/nls';\r\nimport { disposableTimeout } from 'vs/base/common/async';\r\nimport { isMacintosh } from 'vs/base/common/platform';\r\nimport { clamp } from 'vs/base/common/numbers';\r\nimport { SetMap } from 'vs/base/common/collections';\r\nimport { treeItemExpandedIcon, treeFilterOnTypeOnIcon, treeFilterOnTypeOffIcon, treeFilterClearIcon } from 'vs/base/browser/ui/tree/treeIcons';\r\n\r\nclass TreeElementsDragAndDropData extends ElementsDragAndDropData {\r\n\r\n\tconstructor(private data: ElementsDragAndDropData, TContext>) {\r\n\t\tsuper(data.elements.map(node => node.element));\r\n\t}\r\n}\r\n\r\nfunction asTreeDragAndDropData(data: IDragAndDropData): IDragAndDropData {\r\n\tif (data instanceof ElementsDragAndDropData) {\r\n\t\treturn new TreeElementsDragAndDropData(data);\r\n\t}\r\n\r\n\treturn data;\r\n}\r\n\r\nclass TreeNodeListDragAndDrop implements IListDragAndDrop> {\r\n\r\n\tprivate autoExpandNode: ITreeNode | undefined;\r\n\tprivate autoExpandDisposable: IDisposable = Disposable.None;\r\n\r\n\tconstructor(private modelProvider: () => ITreeModel, private dnd: ITreeDragAndDrop) { }\r\n\r\n\tgetDragURI(node: ITreeNode): string | null {\r\n\t\treturn this.dnd.getDragURI(node.element);\r\n\t}\r\n\r\n\tgetDragLabel(nodes: ITreeNode[], originalEvent: DragEvent): string | undefined {\r\n\t\tif (this.dnd.getDragLabel) {\r\n\t\t\treturn this.dnd.getDragLabel(nodes.map(node => node.element), originalEvent);\r\n\t\t}\r\n\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tonDragStart(data: IDragAndDropData, originalEvent: DragEvent): void {\r\n\t\tif (this.dnd.onDragStart) {\r\n\t\t\tthis.dnd.onDragStart(asTreeDragAndDropData(data), originalEvent);\r\n\t\t}\r\n\t}\r\n\r\n\tonDragOver(data: IDragAndDropData, targetNode: ITreeNode | undefined, targetIndex: number | undefined, originalEvent: DragEvent, raw = true): boolean | IListDragOverReaction {\r\n\t\tconst result = this.dnd.onDragOver(asTreeDragAndDropData(data), targetNode && targetNode.element, targetIndex, originalEvent);\r\n\t\tconst didChangeAutoExpandNode = this.autoExpandNode !== targetNode;\r\n\r\n\t\tif (didChangeAutoExpandNode) {\r\n\t\t\tthis.autoExpandDisposable.dispose();\r\n\t\t\tthis.autoExpandNode = targetNode;\r\n\t\t}\r\n\r\n\t\tif (typeof targetNode === 'undefined') {\r\n\t\t\treturn result;\r\n\t\t}\r\n\r\n\t\tif (didChangeAutoExpandNode && typeof result !== 'boolean' && result.autoExpand) {\r\n\t\t\tthis.autoExpandDisposable = disposableTimeout(() => {\r\n\t\t\t\tconst model = this.modelProvider();\r\n\t\t\t\tconst ref = model.getNodeLocation(targetNode);\r\n\r\n\t\t\t\tif (model.isCollapsed(ref)) {\r\n\t\t\t\t\tmodel.setCollapsed(ref, false);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis.autoExpandNode = undefined;\r\n\t\t\t}, 500);\r\n\t\t}\r\n\r\n\t\tif (typeof result === 'boolean' || !result.accept || typeof result.bubble === 'undefined' || result.feedback) {\r\n\t\t\tif (!raw) {\r\n\t\t\t\tconst accept = typeof result === 'boolean' ? result : result.accept;\r\n\t\t\t\tconst effect = typeof result === 'boolean' ? undefined : result.effect;\r\n\t\t\t\treturn { accept, effect, feedback: [targetIndex!] };\r\n\t\t\t}\r\n\r\n\t\t\treturn result;\r\n\t\t}\r\n\r\n\t\tif (result.bubble === TreeDragOverBubble.Up) {\r\n\t\t\tconst model = this.modelProvider();\r\n\t\t\tconst ref = model.getNodeLocation(targetNode);\r\n\t\t\tconst parentRef = model.getParentNodeLocation(ref);\r\n\t\t\tconst parentNode = model.getNode(parentRef);\r\n\t\t\tconst parentIndex = parentRef && model.getListIndex(parentRef);\r\n\r\n\t\t\treturn this.onDragOver(data, parentNode, parentIndex, originalEvent, false);\r\n\t\t}\r\n\r\n\t\tconst model = this.modelProvider();\r\n\t\tconst ref = model.getNodeLocation(targetNode);\r\n\t\tconst start = model.getListIndex(ref);\r\n\t\tconst length = model.getListRenderCount(ref);\r\n\r\n\t\treturn { ...result, feedback: range(start, start + length) };\r\n\t}\r\n\r\n\tdrop(data: IDragAndDropData, targetNode: ITreeNode | undefined, targetIndex: number | undefined, originalEvent: DragEvent): void {\r\n\t\tthis.autoExpandDisposable.dispose();\r\n\t\tthis.autoExpandNode = undefined;\r\n\r\n\t\tthis.dnd.drop(asTreeDragAndDropData(data), targetNode && targetNode.element, targetIndex, originalEvent);\r\n\t}\r\n\r\n\tonDragEnd(originalEvent: DragEvent): void {\r\n\t\tif (this.dnd.onDragEnd) {\r\n\t\t\tthis.dnd.onDragEnd(originalEvent);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction asListOptions(modelProvider: () => ITreeModel, options?: IAbstractTreeOptions): IListOptions> | undefined {\r\n\treturn options && {\r\n\t\t...options,\r\n\t\tidentityProvider: options.identityProvider && {\r\n\t\t\tgetId(el) {\r\n\t\t\t\treturn options.identityProvider!.getId(el.element);\r\n\t\t\t}\r\n\t\t},\r\n\t\tdnd: options.dnd && new TreeNodeListDragAndDrop(modelProvider, options.dnd),\r\n\t\tmultipleSelectionController: options.multipleSelectionController && {\r\n\t\t\tisSelectionSingleChangeEvent(e) {\r\n\t\t\t\treturn options.multipleSelectionController!.isSelectionSingleChangeEvent({ ...e, element: e.element } as any);\r\n\t\t\t},\r\n\t\t\tisSelectionRangeChangeEvent(e) {\r\n\t\t\t\treturn options.multipleSelectionController!.isSelectionRangeChangeEvent({ ...e, element: e.element } as any);\r\n\t\t\t}\r\n\t\t},\r\n\t\taccessibilityProvider: options.accessibilityProvider && {\r\n\t\t\t...options.accessibilityProvider,\r\n\t\t\tgetSetSize(node) {\r\n\t\t\t\tconst model = modelProvider();\r\n\t\t\t\tconst ref = model.getNodeLocation(node);\r\n\t\t\t\tconst parentRef = model.getParentNodeLocation(ref);\r\n\t\t\t\tconst parentNode = model.getNode(parentRef);\r\n\r\n\t\t\t\treturn parentNode.visibleChildrenCount;\r\n\t\t\t},\r\n\t\t\tgetPosInSet(node) {\r\n\t\t\t\treturn node.visibleChildIndex + 1;\r\n\t\t\t},\r\n\t\t\tisChecked: options.accessibilityProvider && options.accessibilityProvider.isChecked ? (node) => {\r\n\t\t\t\treturn options.accessibilityProvider!.isChecked!(node.element);\r\n\t\t\t} : undefined,\r\n\t\t\tgetRole: options.accessibilityProvider && options.accessibilityProvider.getRole ? (node) => {\r\n\t\t\t\treturn options.accessibilityProvider!.getRole!(node.element);\r\n\t\t\t} : () => 'treeitem',\r\n\t\t\tgetAriaLabel(e) {\r\n\t\t\t\treturn options.accessibilityProvider!.getAriaLabel(e.element);\r\n\t\t\t},\r\n\t\t\tgetWidgetAriaLabel() {\r\n\t\t\t\treturn options.accessibilityProvider!.getWidgetAriaLabel();\r\n\t\t\t},\r\n\t\t\tgetWidgetRole: options.accessibilityProvider && options.accessibilityProvider.getWidgetRole ? () => options.accessibilityProvider!.getWidgetRole!() : () => 'tree',\r\n\t\t\tgetAriaLevel: options.accessibilityProvider && options.accessibilityProvider.getAriaLevel ? (node) => options.accessibilityProvider!.getAriaLevel!(node.element) : (node) => {\r\n\t\t\t\treturn node.depth;\r\n\t\t\t},\r\n\t\t\tgetActiveDescendantId: options.accessibilityProvider.getActiveDescendantId && (node => {\r\n\t\t\t\treturn options.accessibilityProvider!.getActiveDescendantId!(node.element);\r\n\t\t\t})\r\n\t\t},\r\n\t\tkeyboardNavigationLabelProvider: options.keyboardNavigationLabelProvider && {\r\n\t\t\t...options.keyboardNavigationLabelProvider,\r\n\t\t\tgetKeyboardNavigationLabel(node) {\r\n\t\t\t\treturn options.keyboardNavigationLabelProvider!.getKeyboardNavigationLabel(node.element);\r\n\t\t\t}\r\n\t\t},\r\n\t\tenableKeyboardNavigation: options.simpleKeyboardNavigation\r\n\t};\r\n}\r\n\r\nexport class ComposedTreeDelegate implements IListVirtualDelegate {\r\n\r\n\tconstructor(private delegate: IListVirtualDelegate) { }\r\n\r\n\tgetHeight(element: N): number {\r\n\t\treturn this.delegate.getHeight(element.element);\r\n\t}\r\n\r\n\tgetTemplateId(element: N): string {\r\n\t\treturn this.delegate.getTemplateId(element.element);\r\n\t}\r\n\r\n\thasDynamicHeight(element: N): boolean {\r\n\t\treturn !!this.delegate.hasDynamicHeight && this.delegate.hasDynamicHeight(element.element);\r\n\t}\r\n\r\n\tsetDynamicHeight(element: N, height: number): void {\r\n\t\tif (this.delegate.setDynamicHeight) {\r\n\t\t\tthis.delegate.setDynamicHeight(element.element, height);\r\n\t\t}\r\n\t}\r\n}\r\n\r\ninterface ITreeListTemplateData {\r\n\treadonly container: HTMLElement;\r\n\treadonly indent: HTMLElement;\r\n\treadonly twistie: HTMLElement;\r\n\tindentGuidesDisposable: IDisposable;\r\n\treadonly templateData: T;\r\n}\r\n\r\nexport enum RenderIndentGuides {\r\n\tNone = 'none',\r\n\tOnHover = 'onHover',\r\n\tAlways = 'always'\r\n}\r\n\r\ninterface ITreeRendererOptions {\r\n\treadonly indent?: number;\r\n\treadonly renderIndentGuides?: RenderIndentGuides;\r\n\t// TODO@joao replace this with collapsible: boolean | 'ondemand'\r\n\treadonly hideTwistiesOfChildlessElements?: boolean;\r\n}\r\n\r\ninterface IRenderData {\r\n\ttemplateData: ITreeListTemplateData;\r\n\theight: number;\r\n}\r\n\r\ninterface Collection {\r\n\treadonly elements: T[];\r\n\treadonly onDidChange: Event;\r\n}\r\n\r\nclass EventCollection implements Collection {\r\n\r\n\treadonly onDidChange: Event;\r\n\r\n\tget elements(): T[] {\r\n\t\treturn this._elements;\r\n\t}\r\n\r\n\tconstructor(onDidChange: Event, private _elements: T[] = []) {\r\n\t\tthis.onDidChange = Event.forEach(onDidChange, elements => this._elements = elements);\r\n\t}\r\n}\r\n\r\nclass TreeRenderer implements IListRenderer, ITreeListTemplateData> {\r\n\r\n\tprivate static readonly DefaultIndent = 8;\r\n\r\n\treadonly templateId: string;\r\n\tprivate renderedElements = new Map>();\r\n\tprivate renderedNodes = new Map, IRenderData>();\r\n\tprivate indent: number = TreeRenderer.DefaultIndent;\r\n\tprivate hideTwistiesOfChildlessElements: boolean = false;\r\n\r\n\tprivate shouldRenderIndentGuides: boolean = false;\r\n\tprivate renderedIndentGuides = new SetMap, HTMLDivElement>();\r\n\tprivate activeIndentNodes = new Set>();\r\n\tprivate indentGuidesDisposable: IDisposable = Disposable.None;\r\n\r\n\tprivate readonly disposables = new DisposableStore();\r\n\r\n\tconstructor(\r\n\t\tprivate renderer: ITreeRenderer,\r\n\t\tprivate modelProvider: () => ITreeModel,\r\n\t\tonDidChangeCollapseState: Event>,\r\n\t\tprivate activeNodes: Collection>,\r\n\t\toptions: ITreeRendererOptions = {}\r\n\t) {\r\n\t\tthis.templateId = renderer.templateId;\r\n\t\tthis.updateOptions(options);\r\n\r\n\t\tEvent.map(onDidChangeCollapseState, e => e.node)(this.onDidChangeNodeTwistieState, this, this.disposables);\r\n\r\n\t\tif (renderer.onDidChangeTwistieState) {\r\n\t\t\trenderer.onDidChangeTwistieState(this.onDidChangeTwistieState, this, this.disposables);\r\n\t\t}\r\n\t}\r\n\r\n\tupdateOptions(options: ITreeRendererOptions = {}): void {\r\n\t\tif (typeof options.indent !== 'undefined') {\r\n\t\t\tthis.indent = clamp(options.indent, 0, 40);\r\n\t\t}\r\n\r\n\t\tif (typeof options.renderIndentGuides !== 'undefined') {\r\n\t\t\tconst shouldRenderIndentGuides = options.renderIndentGuides !== RenderIndentGuides.None;\r\n\r\n\t\t\tif (shouldRenderIndentGuides !== this.shouldRenderIndentGuides) {\r\n\t\t\t\tthis.shouldRenderIndentGuides = shouldRenderIndentGuides;\r\n\t\t\t\tthis.indentGuidesDisposable.dispose();\r\n\r\n\t\t\t\tif (shouldRenderIndentGuides) {\r\n\t\t\t\t\tconst disposables = new DisposableStore();\r\n\t\t\t\t\tthis.activeNodes.onDidChange(this._onDidChangeActiveNodes, this, disposables);\r\n\t\t\t\t\tthis.indentGuidesDisposable = disposables;\r\n\r\n\t\t\t\t\tthis._onDidChangeActiveNodes(this.activeNodes.elements);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (typeof options.hideTwistiesOfChildlessElements !== 'undefined') {\r\n\t\t\tthis.hideTwistiesOfChildlessElements = options.hideTwistiesOfChildlessElements;\r\n\t\t}\r\n\t}\r\n\r\n\trenderTemplate(container: HTMLElement): ITreeListTemplateData {\r\n\t\tconst el = append(container, $('.monaco-tl-row'));\r\n\t\tconst indent = append(el, $('.monaco-tl-indent'));\r\n\t\tconst twistie = append(el, $('.monaco-tl-twistie'));\r\n\t\tconst contents = append(el, $('.monaco-tl-contents'));\r\n\t\tconst templateData = this.renderer.renderTemplate(contents);\r\n\r\n\t\treturn { container, indent, twistie, indentGuidesDisposable: Disposable.None, templateData };\r\n\t}\r\n\r\n\trenderElement(node: ITreeNode, index: number, templateData: ITreeListTemplateData, height: number | undefined): void {\r\n\t\tif (typeof height === 'number') {\r\n\t\t\tthis.renderedNodes.set(node, { templateData, height });\r\n\t\t\tthis.renderedElements.set(node.element, node);\r\n\t\t}\r\n\r\n\t\tconst indent = TreeRenderer.DefaultIndent + (node.depth - 1) * this.indent;\r\n\t\ttemplateData.twistie.style.paddingLeft = `${indent}px`;\r\n\t\ttemplateData.indent.style.width = `${indent + this.indent - 16}px`;\r\n\r\n\t\tthis.renderTwistie(node, templateData);\r\n\r\n\t\tif (typeof height === 'number') {\r\n\t\t\tthis.renderIndentGuides(node, templateData);\r\n\t\t}\r\n\r\n\t\tthis.renderer.renderElement(node, index, templateData.templateData, height);\r\n\t}\r\n\r\n\tdisposeElement(node: ITreeNode, index: number, templateData: ITreeListTemplateData, height: number | undefined): void {\r\n\t\ttemplateData.indentGuidesDisposable.dispose();\r\n\r\n\t\tif (this.renderer.disposeElement) {\r\n\t\t\tthis.renderer.disposeElement(node, index, templateData.templateData, height);\r\n\t\t}\r\n\r\n\t\tif (typeof height === 'number') {\r\n\t\t\tthis.renderedNodes.delete(node);\r\n\t\t\tthis.renderedElements.delete(node.element);\r\n\t\t}\r\n\t}\r\n\r\n\tdisposeTemplate(templateData: ITreeListTemplateData): void {\r\n\t\tthis.renderer.disposeTemplate(templateData.templateData);\r\n\t}\r\n\r\n\tprivate onDidChangeTwistieState(element: T): void {\r\n\t\tconst node = this.renderedElements.get(element);\r\n\r\n\t\tif (!node) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.onDidChangeNodeTwistieState(node);\r\n\t}\r\n\r\n\tprivate onDidChangeNodeTwistieState(node: ITreeNode): void {\r\n\t\tconst data = this.renderedNodes.get(node);\r\n\r\n\t\tif (!data) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.renderTwistie(node, data.templateData);\r\n\t\tthis._onDidChangeActiveNodes(this.activeNodes.elements);\r\n\t\tthis.renderIndentGuides(node, data.templateData);\r\n\t}\r\n\r\n\tprivate renderTwistie(node: ITreeNode, templateData: ITreeListTemplateData) {\r\n\t\ttemplateData.twistie.classList.remove(...treeItemExpandedIcon.classNamesArray);\r\n\r\n\t\tlet twistieRendered = false;\r\n\r\n\t\tif (this.renderer.renderTwistie) {\r\n\t\t\ttwistieRendered = this.renderer.renderTwistie(node.element, templateData.twistie);\r\n\t\t}\r\n\r\n\t\tif (node.collapsible && (!this.hideTwistiesOfChildlessElements || node.visibleChildrenCount > 0)) {\r\n\t\t\tif (!twistieRendered) {\r\n\t\t\t\ttemplateData.twistie.classList.add(...treeItemExpandedIcon.classNamesArray);\r\n\t\t\t}\r\n\r\n\t\t\ttemplateData.twistie.classList.add('collapsible');\r\n\t\t\ttemplateData.twistie.classList.toggle('collapsed', node.collapsed);\r\n\t\t} else {\r\n\t\t\ttemplateData.twistie.classList.remove('collapsible', 'collapsed');\r\n\t\t}\r\n\r\n\t\tif (node.collapsible) {\r\n\t\t\ttemplateData.container.setAttribute('aria-expanded', String(!node.collapsed));\r\n\t\t} else {\r\n\t\t\ttemplateData.container.removeAttribute('aria-expanded');\r\n\t\t}\r\n\t}\r\n\r\n\tprivate renderIndentGuides(target: ITreeNode, templateData: ITreeListTemplateData): void {\r\n\t\tclearNode(templateData.indent);\r\n\t\ttemplateData.indentGuidesDisposable.dispose();\r\n\r\n\t\tif (!this.shouldRenderIndentGuides) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst disposableStore = new DisposableStore();\r\n\t\tconst model = this.modelProvider();\r\n\r\n\t\tlet node = target;\r\n\r\n\t\twhile (true) {\r\n\t\t\tconst ref = model.getNodeLocation(node);\r\n\t\t\tconst parentRef = model.getParentNodeLocation(ref);\r\n\r\n\t\t\tif (!parentRef) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tconst parent = model.getNode(parentRef);\r\n\t\t\tconst guide = $('.indent-guide', { style: `width: ${this.indent}px` });\r\n\r\n\t\t\tif (this.activeIndentNodes.has(parent)) {\r\n\t\t\t\tguide.classList.add('active');\r\n\t\t\t}\r\n\r\n\t\t\tif (templateData.indent.childElementCount === 0) {\r\n\t\t\t\ttemplateData.indent.appendChild(guide);\r\n\t\t\t} else {\r\n\t\t\t\ttemplateData.indent.insertBefore(guide, templateData.indent.firstElementChild);\r\n\t\t\t}\r\n\r\n\t\t\tthis.renderedIndentGuides.add(parent, guide);\r\n\t\t\tdisposableStore.add(toDisposable(() => this.renderedIndentGuides.delete(parent, guide)));\r\n\r\n\t\t\tnode = parent;\r\n\t\t}\r\n\r\n\t\ttemplateData.indentGuidesDisposable = disposableStore;\r\n\t}\r\n\r\n\tprivate _onDidChangeActiveNodes(nodes: ITreeNode[]): void {\r\n\t\tif (!this.shouldRenderIndentGuides) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst set = new Set>();\r\n\t\tconst model = this.modelProvider();\r\n\r\n\t\tnodes.forEach(node => {\r\n\t\t\tconst ref = model.getNodeLocation(node);\r\n\t\t\ttry {\r\n\t\t\t\tconst parentRef = model.getParentNodeLocation(ref);\r\n\r\n\t\t\t\tif (node.collapsible && node.children.length > 0 && !node.collapsed) {\r\n\t\t\t\t\tset.add(node);\r\n\t\t\t\t} else if (parentRef) {\r\n\t\t\t\t\tset.add(model.getNode(parentRef));\r\n\t\t\t\t}\r\n\t\t\t} catch {\r\n\t\t\t\t// noop\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tthis.activeIndentNodes.forEach(node => {\r\n\t\t\tif (!set.has(node)) {\r\n\t\t\t\tthis.renderedIndentGuides.forEach(node, line => line.classList.remove('active'));\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tset.forEach(node => {\r\n\t\t\tif (!this.activeIndentNodes.has(node)) {\r\n\t\t\t\tthis.renderedIndentGuides.forEach(node, line => line.classList.add('active'));\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tthis.activeIndentNodes = set;\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis.renderedNodes.clear();\r\n\t\tthis.renderedElements.clear();\r\n\t\tthis.indentGuidesDisposable.dispose();\r\n\t\tdispose(this.disposables);\r\n\t}\r\n}\r\n\r\nexport type LabelFuzzyScore = { label: string; score: FuzzyScore };\r\n\r\nclass TypeFilter implements ITreeFilter, IDisposable {\r\n\tprivate _totalCount = 0;\r\n\tget totalCount(): number { return this._totalCount; }\r\n\tprivate _matchCount = 0;\r\n\tget matchCount(): number { return this._matchCount; }\r\n\r\n\tprivate _pattern: string = '';\r\n\tprivate _lowercasePattern: string = '';\r\n\tprivate readonly disposables = new DisposableStore();\r\n\r\n\tset pattern(pattern: string) {\r\n\t\tthis._pattern = pattern;\r\n\t\tthis._lowercasePattern = pattern.toLowerCase();\r\n\t}\r\n\r\n\tconstructor(\r\n\t\tprivate tree: AbstractTree,\r\n\t\tprivate keyboardNavigationLabelProvider: IKeyboardNavigationLabelProvider,\r\n\t\tprivate _filter?: ITreeFilter\r\n\t) {\r\n\t\ttree.onWillRefilter(this.reset, this, this.disposables);\r\n\t}\r\n\r\n\tfilter(element: T, parentVisibility: TreeVisibility): TreeFilterResult {\r\n\t\tif (this._filter) {\r\n\t\t\tconst result = this._filter.filter(element, parentVisibility);\r\n\r\n\t\t\tif (this.tree.options.simpleKeyboardNavigation) {\r\n\t\t\t\treturn result;\r\n\t\t\t}\r\n\r\n\t\t\tlet visibility: TreeVisibility;\r\n\r\n\t\t\tif (typeof result === 'boolean') {\r\n\t\t\t\tvisibility = result ? TreeVisibility.Visible : TreeVisibility.Hidden;\r\n\t\t\t} else if (isFilterResult(result)) {\r\n\t\t\t\tvisibility = getVisibleState(result.visibility);\r\n\t\t\t} else {\r\n\t\t\t\tvisibility = result;\r\n\t\t\t}\r\n\r\n\t\t\tif (visibility === TreeVisibility.Hidden) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._totalCount++;\r\n\r\n\t\tif (this.tree.options.simpleKeyboardNavigation || !this._pattern) {\r\n\t\t\tthis._matchCount++;\r\n\t\t\treturn { data: FuzzyScore.Default, visibility: true };\r\n\t\t}\r\n\r\n\t\tconst label = this.keyboardNavigationLabelProvider.getKeyboardNavigationLabel(element);\r\n\t\tconst labels = Array.isArray(label) ? label : [label];\r\n\r\n\t\tfor (const l of labels) {\r\n\t\t\tconst labelStr = l && l.toString();\r\n\t\t\tif (typeof labelStr === 'undefined') {\r\n\t\t\t\treturn { data: FuzzyScore.Default, visibility: true };\r\n\t\t\t}\r\n\r\n\t\t\tconst score = fuzzyScore(this._pattern, this._lowercasePattern, 0, labelStr, labelStr.toLowerCase(), 0, true);\r\n\t\t\tif (score) {\r\n\t\t\t\tthis._matchCount++;\r\n\t\t\t\treturn labels.length === 1 ?\r\n\t\t\t\t\t{ data: score, visibility: true } :\r\n\t\t\t\t\t{ data: { label: labelStr, score: score }, visibility: true };\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (this.tree.options.filterOnType) {\r\n\t\t\treturn TreeVisibility.Recurse;\r\n\t\t} else {\r\n\t\t\treturn { data: FuzzyScore.Default, visibility: true };\r\n\t\t}\r\n\t}\r\n\r\n\tprivate reset(): void {\r\n\t\tthis._totalCount = 0;\r\n\t\tthis._matchCount = 0;\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tdispose(this.disposables);\r\n\t}\r\n}\r\n\r\nclass TypeFilterController implements IDisposable {\r\n\r\n\tprivate _enabled = false;\r\n\tget enabled(): boolean { return this._enabled; }\r\n\r\n\tprivate _pattern = '';\r\n\tget pattern(): string { return this._pattern; }\r\n\r\n\tprivate _filterOnType: boolean;\r\n\tget filterOnType(): boolean { return this._filterOnType; }\r\n\r\n\tprivate _empty: boolean = false;\r\n\r\n\tprivate readonly _onDidChangeEmptyState = new Emitter();\r\n\r\n\tprivate positionClassName = 'ne';\r\n\tprivate domNode: HTMLElement;\r\n\tprivate messageDomNode: HTMLElement;\r\n\tprivate labelDomNode: HTMLElement;\r\n\tprivate filterOnTypeDomNode: HTMLInputElement;\r\n\tprivate clearDomNode: HTMLElement;\r\n\tprivate keyboardNavigationEventFilter?: IKeyboardNavigationEventFilter;\r\n\r\n\tprivate automaticKeyboardNavigation = true;\r\n\tprivate triggered = false;\r\n\r\n\tprivate readonly _onDidChangePattern = new Emitter();\r\n\r\n\tprivate readonly enabledDisposables = new DisposableStore();\r\n\tprivate readonly disposables = new DisposableStore();\r\n\r\n\tconstructor(\r\n\t\tprivate tree: AbstractTree,\r\n\t\tmodel: ITreeModel,\r\n\t\tprivate view: List>,\r\n\t\tprivate filter: TypeFilter,\r\n\t\tprivate keyboardNavigationDelegate: IKeyboardNavigationDelegate\r\n\t) {\r\n\t\tthis.domNode = $(`.monaco-list-type-filter.${this.positionClassName}`);\r\n\t\tthis.domNode.draggable = true;\r\n\t\tdomEvent(this.domNode, 'dragstart')(this.onDragStart, this, this.disposables);\r\n\r\n\t\tthis.messageDomNode = append(view.getHTMLElement(), $(`.monaco-list-type-filter-message`));\r\n\r\n\t\tthis.labelDomNode = append(this.domNode, $('span.label'));\r\n\t\tconst controls = append(this.domNode, $('.controls'));\r\n\r\n\t\tthis._filterOnType = !!tree.options.filterOnType;\r\n\t\tthis.filterOnTypeDomNode = append(controls, $('input.filter'));\r\n\t\tthis.filterOnTypeDomNode.type = 'checkbox';\r\n\t\tthis.filterOnTypeDomNode.checked = this._filterOnType;\r\n\t\tthis.filterOnTypeDomNode.tabIndex = -1;\r\n\t\tthis.updateFilterOnTypeTitleAndIcon();\r\n\t\tdomEvent(this.filterOnTypeDomNode, 'input')(this.onDidChangeFilterOnType, this, this.disposables);\r\n\r\n\t\tthis.clearDomNode = append(controls, $('button.clear' + treeFilterClearIcon.cssSelector));\r\n\t\tthis.clearDomNode.tabIndex = -1;\r\n\t\tthis.clearDomNode.title = localize('clear', \"Clear\");\r\n\r\n\t\tthis.keyboardNavigationEventFilter = tree.options.keyboardNavigationEventFilter;\r\n\r\n\t\tmodel.onDidSplice(this.onDidSpliceModel, this, this.disposables);\r\n\t\tthis.updateOptions(tree.options);\r\n\t}\r\n\r\n\tupdateOptions(options: IAbstractTreeOptions): void {\r\n\t\tif (options.simpleKeyboardNavigation) {\r\n\t\t\tthis.disable();\r\n\t\t} else {\r\n\t\t\tthis.enable();\r\n\t\t}\r\n\r\n\t\tif (typeof options.filterOnType !== 'undefined') {\r\n\t\t\tthis._filterOnType = !!options.filterOnType;\r\n\t\t\tthis.filterOnTypeDomNode.checked = this._filterOnType;\r\n\t\t}\r\n\r\n\t\tif (typeof options.automaticKeyboardNavigation !== 'undefined') {\r\n\t\t\tthis.automaticKeyboardNavigation = options.automaticKeyboardNavigation;\r\n\t\t}\r\n\r\n\t\tthis.tree.refilter();\r\n\t\tthis.render();\r\n\r\n\t\tif (!this.automaticKeyboardNavigation) {\r\n\t\t\tthis.onEventOrInput('');\r\n\t\t}\r\n\t}\r\n\r\n\tprivate enable(): void {\r\n\t\tif (this._enabled) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst onKeyDown = Event.chain(domEvent(this.view.getHTMLElement(), 'keydown'))\r\n\t\t\t.filter(e => !isInputElement(e.target as HTMLElement) || e.target === this.filterOnTypeDomNode)\r\n\t\t\t.filter(e => e.key !== 'Dead' && !/^Media/.test(e.key))\r\n\t\t\t.map(e => new StandardKeyboardEvent(e))\r\n\t\t\t.filter(this.keyboardNavigationEventFilter || (() => true))\r\n\t\t\t.filter(() => this.automaticKeyboardNavigation || this.triggered)\r\n\t\t\t.filter(e => (this.keyboardNavigationDelegate.mightProducePrintableCharacter(e) && !(e.keyCode === KeyCode.DownArrow || e.keyCode === KeyCode.UpArrow || e.keyCode === KeyCode.LeftArrow || e.keyCode === KeyCode.RightArrow)) || ((this.pattern.length > 0 || this.triggered) && ((e.keyCode === KeyCode.Escape || e.keyCode === KeyCode.Backspace) && !e.altKey && !e.ctrlKey && !e.metaKey) || (e.keyCode === KeyCode.Backspace && (isMacintosh ? (e.altKey && !e.metaKey) : e.ctrlKey) && !e.shiftKey)))\r\n\t\t\t.forEach(e => { e.stopPropagation(); e.preventDefault(); })\r\n\t\t\t.event;\r\n\r\n\t\tconst onClear = domEvent(this.clearDomNode, 'click');\r\n\r\n\t\tEvent.chain(Event.any(onKeyDown, onClear))\r\n\t\t\t.event(this.onEventOrInput, this, this.enabledDisposables);\r\n\r\n\t\tthis.filter.pattern = '';\r\n\t\tthis.tree.refilter();\r\n\t\tthis.render();\r\n\t\tthis._enabled = true;\r\n\t\tthis.triggered = false;\r\n\t}\r\n\r\n\tprivate disable(): void {\r\n\t\tif (!this._enabled) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.domNode.remove();\r\n\t\tthis.enabledDisposables.clear();\r\n\t\tthis.tree.refilter();\r\n\t\tthis.render();\r\n\t\tthis._enabled = false;\r\n\t\tthis.triggered = false;\r\n\t}\r\n\r\n\tprivate onEventOrInput(e: MouseEvent | StandardKeyboardEvent | string): void {\r\n\t\tif (typeof e === 'string') {\r\n\t\t\tthis.onInput(e);\r\n\t\t} else if (e instanceof MouseEvent || e.keyCode === KeyCode.Escape || (e.keyCode === KeyCode.Backspace && (isMacintosh ? e.altKey : e.ctrlKey))) {\r\n\t\t\tthis.onInput('');\r\n\t\t} else if (e.keyCode === KeyCode.Backspace) {\r\n\t\t\tthis.onInput(this.pattern.length === 0 ? '' : this.pattern.substr(0, this.pattern.length - 1));\r\n\t\t} else {\r\n\t\t\tthis.onInput(this.pattern + e.browserEvent.key);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate onInput(pattern: string): void {\r\n\t\tconst container = this.view.getHTMLElement();\r\n\r\n\t\tif (pattern && !this.domNode.parentElement) {\r\n\t\t\tcontainer.append(this.domNode);\r\n\t\t} else if (!pattern && this.domNode.parentElement) {\r\n\t\t\tthis.domNode.remove();\r\n\t\t\tthis.tree.domFocus();\r\n\t\t}\r\n\r\n\t\tthis._pattern = pattern;\r\n\t\tthis._onDidChangePattern.fire(pattern);\r\n\r\n\t\tthis.filter.pattern = pattern;\r\n\t\tthis.tree.refilter();\r\n\r\n\t\tif (pattern) {\r\n\t\t\tthis.tree.focusNext(0, true, undefined, node => !FuzzyScore.isDefault(node.filterData as any as FuzzyScore));\r\n\t\t}\r\n\r\n\t\tconst focus = this.tree.getFocus();\r\n\r\n\t\tif (focus.length > 0) {\r\n\t\t\tconst element = focus[0];\r\n\r\n\t\t\tif (this.tree.getRelativeTop(element) === null) {\r\n\t\t\t\tthis.tree.reveal(element, 0.5);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis.render();\r\n\r\n\t\tif (!pattern) {\r\n\t\t\tthis.triggered = false;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate onDragStart(): void {\r\n\t\tconst container = this.view.getHTMLElement();\r\n\t\tconst { left } = getDomNodePagePosition(container);\r\n\t\tconst containerWidth = container.clientWidth;\r\n\t\tconst midContainerWidth = containerWidth / 2;\r\n\t\tconst width = this.domNode.clientWidth;\r\n\t\tconst disposables = new DisposableStore();\r\n\t\tlet positionClassName = this.positionClassName;\r\n\r\n\t\tconst updatePosition = () => {\r\n\t\t\tswitch (positionClassName) {\r\n\t\t\t\tcase 'nw':\r\n\t\t\t\t\tthis.domNode.style.top = `4px`;\r\n\t\t\t\t\tthis.domNode.style.left = `4px`;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'ne':\r\n\t\t\t\t\tthis.domNode.style.top = `4px`;\r\n\t\t\t\t\tthis.domNode.style.left = `${containerWidth - width - 6}px`;\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tconst onDragOver = (event: DragEvent) => {\r\n\t\t\tevent.preventDefault(); // needed so that the drop event fires (https://stackoverflow.com/questions/21339924/drop-event-not-firing-in-chrome)\r\n\r\n\t\t\tconst x = event.clientX - left;\r\n\t\t\tif (event.dataTransfer) {\r\n\t\t\t\tevent.dataTransfer.dropEffect = 'none';\r\n\t\t\t}\r\n\r\n\t\t\tif (x < midContainerWidth) {\r\n\t\t\t\tpositionClassName = 'nw';\r\n\t\t\t} else {\r\n\t\t\t\tpositionClassName = 'ne';\r\n\t\t\t}\r\n\r\n\t\t\tupdatePosition();\r\n\t\t};\r\n\r\n\t\tconst onDragEnd = () => {\r\n\t\t\tthis.positionClassName = positionClassName;\r\n\t\t\tthis.domNode.className = `monaco-list-type-filter ${this.positionClassName}`;\r\n\t\t\tthis.domNode.style.top = '';\r\n\t\t\tthis.domNode.style.left = '';\r\n\r\n\t\t\tdispose(disposables);\r\n\t\t};\r\n\r\n\t\tupdatePosition();\r\n\t\tthis.domNode.classList.remove(positionClassName);\r\n\r\n\t\tthis.domNode.classList.add('dragging');\r\n\t\tdisposables.add(toDisposable(() => this.domNode.classList.remove('dragging')));\r\n\r\n\t\tdomEvent(document, 'dragover')(onDragOver, null, disposables);\r\n\t\tdomEvent(this.domNode, 'dragend')(onDragEnd, null, disposables);\r\n\r\n\t\tStaticDND.CurrentDragAndDropData = new DragAndDropData('vscode-ui');\r\n\t\tdisposables.add(toDisposable(() => StaticDND.CurrentDragAndDropData = undefined));\r\n\t}\r\n\r\n\tprivate onDidSpliceModel(): void {\r\n\t\tif (!this._enabled || this.pattern.length === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.tree.refilter();\r\n\t\tthis.render();\r\n\t}\r\n\r\n\tprivate onDidChangeFilterOnType(): void {\r\n\t\tthis.tree.updateOptions({ filterOnType: this.filterOnTypeDomNode.checked });\r\n\t\tthis.tree.refilter();\r\n\t\tthis.tree.domFocus();\r\n\t\tthis.render();\r\n\t\tthis.updateFilterOnTypeTitleAndIcon();\r\n\t}\r\n\r\n\tprivate updateFilterOnTypeTitleAndIcon(): void {\r\n\t\tif (this.filterOnType) {\r\n\t\t\tthis.filterOnTypeDomNode.classList.remove(...treeFilterOnTypeOffIcon.classNamesArray);\r\n\t\t\tthis.filterOnTypeDomNode.classList.add(...treeFilterOnTypeOnIcon.classNamesArray);\r\n\t\t\tthis.filterOnTypeDomNode.title = localize('disable filter on type', \"Disable Filter on Type\");\r\n\t\t} else {\r\n\t\t\tthis.filterOnTypeDomNode.classList.remove(...treeFilterOnTypeOnIcon.classNamesArray);\r\n\t\t\tthis.filterOnTypeDomNode.classList.add(...treeFilterOnTypeOffIcon.classNamesArray);\r\n\t\t\tthis.filterOnTypeDomNode.title = localize('enable filter on type', \"Enable Filter on Type\");\r\n\t\t}\r\n\t}\r\n\r\n\tprivate render(): void {\r\n\t\tconst noMatches = this.filter.totalCount > 0 && this.filter.matchCount === 0;\r\n\r\n\t\tif (this.pattern && this.tree.options.filterOnType && noMatches) {\r\n\t\t\tthis.messageDomNode.textContent = localize('empty', \"No elements found\");\r\n\t\t\tthis._empty = true;\r\n\t\t} else {\r\n\t\t\tthis.messageDomNode.innerText = '';\r\n\t\t\tthis._empty = false;\r\n\t\t}\r\n\r\n\t\tthis.domNode.classList.toggle('no-matches', noMatches);\r\n\t\tthis.domNode.title = localize('found', \"Matched {0} out of {1} elements\", this.filter.matchCount, this.filter.totalCount);\r\n\t\tthis.labelDomNode.textContent = this.pattern.length > 16 ? '…' + this.pattern.substr(this.pattern.length - 16) : this.pattern;\r\n\r\n\t\tthis._onDidChangeEmptyState.fire(this._empty);\r\n\t}\r\n\r\n\tshouldAllowFocus(node: ITreeNode): boolean {\r\n\t\tif (!this.enabled || !this.pattern || this.filterOnType) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tif (this.filter.totalCount > 0 && this.filter.matchCount <= 1) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\treturn !FuzzyScore.isDefault(node.filterData as any as FuzzyScore);\r\n\t}\r\n\r\n\tdispose() {\r\n\t\tif (this._enabled) {\r\n\t\t\tthis.domNode.remove();\r\n\t\t\tthis.enabledDisposables.dispose();\r\n\t\t\tthis._enabled = false;\r\n\t\t\tthis.triggered = false;\r\n\t\t}\r\n\r\n\t\tthis._onDidChangePattern.dispose();\r\n\t\tdispose(this.disposables);\r\n\t}\r\n}\r\n\r\nfunction asTreeMouseEvent(event: IListMouseEvent>): ITreeMouseEvent {\r\n\tlet target: TreeMouseEventTarget = TreeMouseEventTarget.Unknown;\r\n\r\n\tif (hasParentWithClass(event.browserEvent.target as HTMLElement, 'monaco-tl-twistie', 'monaco-tl-row')) {\r\n\t\ttarget = TreeMouseEventTarget.Twistie;\r\n\t} else if (hasParentWithClass(event.browserEvent.target as HTMLElement, 'monaco-tl-contents', 'monaco-tl-row')) {\r\n\t\ttarget = TreeMouseEventTarget.Element;\r\n\t}\r\n\r\n\treturn {\r\n\t\tbrowserEvent: event.browserEvent,\r\n\t\telement: event.element ? event.element.element : null,\r\n\t\ttarget\r\n\t};\r\n}\r\n\r\nexport interface IKeyboardNavigationEventFilter {\r\n\t(e: StandardKeyboardEvent): boolean;\r\n}\r\n\r\nexport interface IAbstractTreeOptionsUpdate extends ITreeRendererOptions {\r\n\treadonly automaticKeyboardNavigation?: boolean;\r\n\treadonly simpleKeyboardNavigation?: boolean;\r\n\treadonly filterOnType?: boolean;\r\n\treadonly smoothScrolling?: boolean;\r\n\treadonly horizontalScrolling?: boolean;\r\n\treadonly expandOnlyOnDoubleClick?: boolean;\r\n\treadonly expandOnlyOnTwistieClick?: boolean | ((e: any) => boolean); // e is T\r\n}\r\n\r\nexport interface IAbstractTreeOptions extends IAbstractTreeOptionsUpdate, IListOptions {\r\n\treadonly collapseByDefault?: boolean; // defaults to false\r\n\treadonly filter?: ITreeFilter;\r\n\treadonly dnd?: ITreeDragAndDrop;\r\n\treadonly keyboardNavigationEventFilter?: IKeyboardNavigationEventFilter;\r\n\treadonly additionalScrollHeight?: number;\r\n}\r\n\r\nfunction dfs(node: ITreeNode, fn: (node: ITreeNode) => void): void {\r\n\tfn(node);\r\n\tnode.children.forEach(child => dfs(child, fn));\r\n}\r\n\r\n/**\r\n * The trait concept needs to exist at the tree level, because collapsed\r\n * tree nodes will not be known by the list.\r\n */\r\nclass Trait {\r\n\r\n\tprivate nodes: ITreeNode[] = [];\r\n\tprivate elements: T[] | undefined;\r\n\r\n\tprivate readonly _onDidChange = new Emitter>();\r\n\treadonly onDidChange = this._onDidChange.event;\r\n\r\n\tprivate _nodeSet: Set> | undefined;\r\n\tprivate get nodeSet(): Set> {\r\n\t\tif (!this._nodeSet) {\r\n\t\t\tthis._nodeSet = this.createNodeSet();\r\n\t\t}\r\n\r\n\t\treturn this._nodeSet;\r\n\t}\r\n\r\n\tconstructor(private identityProvider?: IIdentityProvider) { }\r\n\r\n\tset(nodes: ITreeNode[], browserEvent?: UIEvent): void {\r\n\t\tif (!(browserEvent as any)?.__forceEvent && equals(this.nodes, nodes)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._set(nodes, false, browserEvent);\r\n\t}\r\n\r\n\tprivate _set(nodes: ITreeNode[], silent: boolean, browserEvent?: UIEvent): void {\r\n\t\tthis.nodes = [...nodes];\r\n\t\tthis.elements = undefined;\r\n\t\tthis._nodeSet = undefined;\r\n\r\n\t\tif (!silent) {\r\n\t\t\tconst that = this;\r\n\t\t\tthis._onDidChange.fire({ get elements() { return that.get(); }, browserEvent });\r\n\t\t}\r\n\t}\r\n\r\n\tget(): T[] {\r\n\t\tif (!this.elements) {\r\n\t\t\tthis.elements = this.nodes.map(node => node.element);\r\n\t\t}\r\n\r\n\t\treturn [...this.elements];\r\n\t}\r\n\r\n\tgetNodes(): readonly ITreeNode[] {\r\n\t\treturn this.nodes;\r\n\t}\r\n\r\n\thas(node: ITreeNode): boolean {\r\n\t\treturn this.nodeSet.has(node);\r\n\t}\r\n\r\n\tonDidModelSplice({ insertedNodes, deletedNodes }: ITreeModelSpliceEvent): void {\r\n\t\tif (!this.identityProvider) {\r\n\t\t\tconst set = this.createNodeSet();\r\n\t\t\tconst visit = (node: ITreeNode) => set.delete(node);\r\n\t\t\tdeletedNodes.forEach(node => dfs(node, visit));\r\n\t\t\tthis.set([...set.values()]);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst deletedNodesIdSet = new Set();\r\n\t\tconst deletedNodesVisitor = (node: ITreeNode) => deletedNodesIdSet.add(this.identityProvider!.getId(node.element).toString());\r\n\t\tdeletedNodes.forEach(node => dfs(node, deletedNodesVisitor));\r\n\r\n\t\tconst insertedNodesMap = new Map>();\r\n\t\tconst insertedNodesVisitor = (node: ITreeNode) => insertedNodesMap.set(this.identityProvider!.getId(node.element).toString(), node);\r\n\t\tinsertedNodes.forEach(node => dfs(node, insertedNodesVisitor));\r\n\r\n\t\tconst nodes: ITreeNode[] = [];\r\n\r\n\t\tfor (const node of this.nodes) {\r\n\t\t\tconst id = this.identityProvider.getId(node.element).toString();\r\n\t\t\tconst wasDeleted = deletedNodesIdSet.has(id);\r\n\r\n\t\t\tif (!wasDeleted) {\r\n\t\t\t\tnodes.push(node);\r\n\t\t\t} else {\r\n\t\t\t\tconst insertedNode = insertedNodesMap.get(id);\r\n\r\n\t\t\t\tif (insertedNode) {\r\n\t\t\t\t\tnodes.push(insertedNode);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._set(nodes, true);\r\n\t}\r\n\r\n\tprivate createNodeSet(): Set> {\r\n\t\tconst set = new Set>();\r\n\r\n\t\tfor (const node of this.nodes) {\r\n\t\t\tset.add(node);\r\n\t\t}\r\n\r\n\t\treturn set;\r\n\t}\r\n}\r\n\r\nclass TreeNodeListMouseController extends MouseController> {\r\n\r\n\tconstructor(list: TreeNodeList, private tree: AbstractTree) {\r\n\t\tsuper(list);\r\n\t}\r\n\r\n\tprotected onViewPointer(e: IListMouseEvent>): void {\r\n\t\tif (isInputElement(e.browserEvent.target as HTMLElement) || isMonacoEditor(e.browserEvent.target as HTMLElement)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst node = e.element;\r\n\r\n\t\tif (!node) {\r\n\t\t\treturn super.onViewPointer(e);\r\n\t\t}\r\n\r\n\t\tif (this.isSelectionRangeChangeEvent(e) || this.isSelectionSingleChangeEvent(e)) {\r\n\t\t\treturn super.onViewPointer(e);\r\n\t\t}\r\n\r\n\t\tconst target = e.browserEvent.target as HTMLElement;\r\n\t\tconst onTwistie = target.classList.contains('monaco-tl-twistie')\r\n\t\t\t|| (target.classList.contains('monaco-icon-label') && target.classList.contains('folder-icon') && e.browserEvent.offsetX < 16);\r\n\r\n\t\tlet expandOnlyOnTwistieClick = false;\r\n\r\n\t\tif (typeof this.tree.expandOnlyOnTwistieClick === 'function') {\r\n\t\t\texpandOnlyOnTwistieClick = this.tree.expandOnlyOnTwistieClick(node.element);\r\n\t\t} else {\r\n\t\t\texpandOnlyOnTwistieClick = !!this.tree.expandOnlyOnTwistieClick;\r\n\t\t}\r\n\r\n\t\tif (expandOnlyOnTwistieClick && !onTwistie && e.browserEvent.detail !== 2) {\r\n\t\t\treturn super.onViewPointer(e);\r\n\t\t}\r\n\r\n\t\tif (this.tree.expandOnlyOnDoubleClick && e.browserEvent.detail !== 2 && !onTwistie) {\r\n\t\t\treturn super.onViewPointer(e);\r\n\t\t}\r\n\r\n\t\tif (node.collapsible) {\r\n\t\t\tconst model = ((this.tree as any).model as ITreeModel); // internal\r\n\t\t\tconst location = model.getNodeLocation(node);\r\n\t\t\tconst recursive = e.browserEvent.altKey;\r\n\t\t\tmodel.setCollapsed(location, undefined, recursive);\r\n\r\n\t\t\tif (expandOnlyOnTwistieClick && onTwistie) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tsuper.onViewPointer(e);\r\n\t}\r\n\r\n\tprotected onDoubleClick(e: IListMouseEvent>): void {\r\n\t\tconst onTwistie = (e.browserEvent.target as HTMLElement).classList.contains('monaco-tl-twistie');\r\n\r\n\t\tif (onTwistie) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tsuper.onDoubleClick(e);\r\n\t}\r\n}\r\n\r\ninterface ITreeNodeListOptions extends IListOptions> {\r\n\treadonly tree: AbstractTree;\r\n}\r\n\r\n/**\r\n * We use this List subclass to restore selection and focus as nodes\r\n * get rendered in the list, possibly due to a node expand() call.\r\n */\r\nclass TreeNodeList extends List> {\r\n\r\n\tconstructor(\r\n\t\tuser: string,\r\n\t\tcontainer: HTMLElement,\r\n\t\tvirtualDelegate: IListVirtualDelegate>,\r\n\t\trenderers: IListRenderer[],\r\n\t\tprivate focusTrait: Trait,\r\n\t\tprivate selectionTrait: Trait,\r\n\t\toptions: ITreeNodeListOptions\r\n\t) {\r\n\t\tsuper(user, container, virtualDelegate, renderers, options);\r\n\t}\r\n\r\n\tprotected createMouseController(options: ITreeNodeListOptions): MouseController> {\r\n\t\treturn new TreeNodeListMouseController(this, options.tree);\r\n\t}\r\n\r\n\tsplice(start: number, deleteCount: number, elements: ITreeNode[] = []): void {\r\n\t\tsuper.splice(start, deleteCount, elements);\r\n\r\n\t\tif (elements.length === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst additionalFocus: number[] = [];\r\n\t\tconst additionalSelection: number[] = [];\r\n\r\n\t\telements.forEach((node, index) => {\r\n\t\t\tif (this.focusTrait.has(node)) {\r\n\t\t\t\tadditionalFocus.push(start + index);\r\n\t\t\t}\r\n\r\n\t\t\tif (this.selectionTrait.has(node)) {\r\n\t\t\t\tadditionalSelection.push(start + index);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tif (additionalFocus.length > 0) {\r\n\t\t\tsuper.setFocus(distinctES6([...super.getFocus(), ...additionalFocus]));\r\n\t\t}\r\n\r\n\t\tif (additionalSelection.length > 0) {\r\n\t\t\tsuper.setSelection(distinctES6([...super.getSelection(), ...additionalSelection]));\r\n\t\t}\r\n\t}\r\n\r\n\tsetFocus(indexes: number[], browserEvent?: UIEvent, fromAPI = false): void {\r\n\t\tsuper.setFocus(indexes, browserEvent);\r\n\r\n\t\tif (!fromAPI) {\r\n\t\t\tthis.focusTrait.set(indexes.map(i => this.element(i)), browserEvent);\r\n\t\t}\r\n\t}\r\n\r\n\tsetSelection(indexes: number[], browserEvent?: UIEvent, fromAPI = false): void {\r\n\t\tsuper.setSelection(indexes, browserEvent);\r\n\r\n\t\tif (!fromAPI) {\r\n\t\t\tthis.selectionTrait.set(indexes.map(i => this.element(i)), browserEvent);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport abstract class AbstractTree implements IDisposable {\r\n\r\n\tprotected view: TreeNodeList;\r\n\tprivate renderers: TreeRenderer[];\r\n\tprotected model: ITreeModel;\r\n\tprivate focus: Trait;\r\n\tprivate selection: Trait;\r\n\tprivate eventBufferer = new EventBufferer();\r\n\tprivate typeFilterController?: TypeFilterController;\r\n\tprivate focusNavigationFilter: ((node: ITreeNode) => boolean) | undefined;\r\n\tprivate styleElement: HTMLStyleElement;\r\n\tprotected readonly disposables = new DisposableStore();\r\n\r\n\tget onDidChangeFocus(): Event> { return this.eventBufferer.wrapEvent(this.focus.onDidChange); }\r\n\tget onDidChangeSelection(): Event> { return this.eventBufferer.wrapEvent(this.selection.onDidChange); }\r\n\tget onMouseDblClick(): Event> { return Event.map(this.view.onMouseDblClick, asTreeMouseEvent); }\r\n\tget onPointer(): Event> { return Event.map(this.view.onPointer, asTreeMouseEvent); }\r\n\r\n\tget onDidFocus(): Event { return this.view.onDidFocus; }\r\n\r\n\tget onDidChangeCollapseState(): Event> { return this.model.onDidChangeCollapseState; }\r\n\r\n\tprivate readonly _onWillRefilter = new Emitter();\r\n\treadonly onWillRefilter: Event = this._onWillRefilter.event;\r\n\r\n\tget expandOnlyOnDoubleClick(): boolean { return this._options.expandOnlyOnDoubleClick ?? false; }\r\n\tget expandOnlyOnTwistieClick(): boolean | ((e: T) => boolean) { return typeof this._options.expandOnlyOnTwistieClick === 'undefined' ? false : this._options.expandOnlyOnTwistieClick; }\r\n\r\n\tprivate readonly _onDidUpdateOptions = new Emitter>();\r\n\r\n\tget onDidDispose(): Event { return this.view.onDidDispose; }\r\n\r\n\tconstructor(\r\n\t\tuser: string,\r\n\t\tcontainer: HTMLElement,\r\n\t\tdelegate: IListVirtualDelegate,\r\n\t\trenderers: ITreeRenderer[],\r\n\t\tprivate _options: IAbstractTreeOptions = {}\r\n\t) {\r\n\t\tconst treeDelegate = new ComposedTreeDelegate>(delegate);\r\n\r\n\t\tconst onDidChangeCollapseStateRelay = new Relay>();\r\n\t\tconst onDidChangeActiveNodes = new Relay[]>();\r\n\t\tconst activeNodes = new EventCollection(onDidChangeActiveNodes.event);\r\n\t\tthis.renderers = renderers.map(r => new TreeRenderer(r, () => this.model, onDidChangeCollapseStateRelay.event, activeNodes, _options));\r\n\t\tfor (let r of this.renderers) {\r\n\t\t\tthis.disposables.add(r);\r\n\t\t}\r\n\r\n\t\tlet filter: TypeFilter | undefined;\r\n\r\n\t\tif (_options.keyboardNavigationLabelProvider) {\r\n\t\t\tfilter = new TypeFilter(this, _options.keyboardNavigationLabelProvider, _options.filter as any as ITreeFilter);\r\n\t\t\t_options = { ..._options, filter: filter as ITreeFilter }; // TODO need typescript help here\r\n\t\t\tthis.disposables.add(filter);\r\n\t\t}\r\n\r\n\t\tthis.focus = new Trait(_options.identityProvider);\r\n\t\tthis.selection = new Trait(_options.identityProvider);\r\n\t\tthis.view = new TreeNodeList(user, container, treeDelegate, this.renderers, this.focus, this.selection, { ...asListOptions(() => this.model, _options), tree: this });\r\n\r\n\t\tthis.model = this.createModel(user, this.view, _options);\r\n\t\tonDidChangeCollapseStateRelay.input = this.model.onDidChangeCollapseState;\r\n\r\n\t\tconst onDidModelSplice = Event.forEach(this.model.onDidSplice, e => {\r\n\t\t\tthis.eventBufferer.bufferEvents(() => {\r\n\t\t\t\tthis.focus.onDidModelSplice(e);\r\n\t\t\t\tthis.selection.onDidModelSplice(e);\r\n\t\t\t});\r\n\t\t});\r\n\r\n\t\t// Make sure the `forEach` always runs\r\n\t\tonDidModelSplice(() => null, null, this.disposables);\r\n\r\n\t\t// Active nodes can change when the model changes or when focus or selection change.\r\n\t\t// We debounce it with 0 delay since these events may fire in the same stack and we only\r\n\t\t// want to run this once. It also doesn't matter if it runs on the next tick since it's only\r\n\t\t// a nice to have UI feature.\r\n\t\tonDidChangeActiveNodes.input = Event.chain(Event.any(onDidModelSplice, this.focus.onDidChange, this.selection.onDidChange))\r\n\t\t\t.debounce(() => null, 0)\r\n\t\t\t.map(() => {\r\n\t\t\t\tconst set = new Set>();\r\n\r\n\t\t\t\tfor (const node of this.focus.getNodes()) {\r\n\t\t\t\t\tset.add(node);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfor (const node of this.selection.getNodes()) {\r\n\t\t\t\t\tset.add(node);\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn [...set.values()];\r\n\t\t\t}).event;\r\n\r\n\t\tif (_options.keyboardSupport !== false) {\r\n\t\t\tconst onKeyDown = Event.chain(this.view.onKeyDown)\r\n\t\t\t\t.filter(e => !isInputElement(e.target as HTMLElement))\r\n\t\t\t\t.map(e => new StandardKeyboardEvent(e));\r\n\r\n\t\t\tonKeyDown.filter(e => e.keyCode === KeyCode.LeftArrow).on(this.onLeftArrow, this, this.disposables);\r\n\t\t\tonKeyDown.filter(e => e.keyCode === KeyCode.RightArrow).on(this.onRightArrow, this, this.disposables);\r\n\t\t\tonKeyDown.filter(e => e.keyCode === KeyCode.Space).on(this.onSpace, this, this.disposables);\r\n\t\t}\r\n\r\n\t\tif (_options.keyboardNavigationLabelProvider) {\r\n\t\t\tconst delegate = _options.keyboardNavigationDelegate || DefaultKeyboardNavigationDelegate;\r\n\t\t\tthis.typeFilterController = new TypeFilterController(this, this.model, this.view, filter!, delegate);\r\n\t\t\tthis.focusNavigationFilter = node => this.typeFilterController!.shouldAllowFocus(node);\r\n\t\t\tthis.disposables.add(this.typeFilterController!);\r\n\t\t}\r\n\r\n\t\tthis.styleElement = createStyleSheet(this.view.getHTMLElement());\r\n\t\tthis.getHTMLElement().classList.toggle('always', this._options.renderIndentGuides === RenderIndentGuides.Always);\r\n\t}\r\n\r\n\tupdateOptions(optionsUpdate: IAbstractTreeOptionsUpdate = {}): void {\r\n\t\tthis._options = { ...this._options, ...optionsUpdate };\r\n\r\n\t\tfor (const renderer of this.renderers) {\r\n\t\t\trenderer.updateOptions(optionsUpdate);\r\n\t\t}\r\n\r\n\t\tthis.view.updateOptions({\r\n\t\t\tenableKeyboardNavigation: this._options.simpleKeyboardNavigation,\r\n\t\t\tautomaticKeyboardNavigation: this._options.automaticKeyboardNavigation,\r\n\t\t\tsmoothScrolling: this._options.smoothScrolling,\r\n\t\t\thorizontalScrolling: this._options.horizontalScrolling\r\n\t\t});\r\n\r\n\t\tif (this.typeFilterController) {\r\n\t\t\tthis.typeFilterController.updateOptions(this._options);\r\n\t\t}\r\n\r\n\t\tthis._onDidUpdateOptions.fire(this._options);\r\n\r\n\t\tthis.getHTMLElement().classList.toggle('always', this._options.renderIndentGuides === RenderIndentGuides.Always);\r\n\t}\r\n\r\n\tget options(): IAbstractTreeOptions {\r\n\t\treturn this._options;\r\n\t}\r\n\r\n\t// Widget\r\n\r\n\tgetHTMLElement(): HTMLElement {\r\n\t\treturn this.view.getHTMLElement();\r\n\t}\r\n\r\n\tget scrollTop(): number {\r\n\t\treturn this.view.scrollTop;\r\n\t}\r\n\r\n\tset scrollTop(scrollTop: number) {\r\n\t\tthis.view.scrollTop = scrollTop;\r\n\t}\r\n\r\n\tdomFocus(): void {\r\n\t\tthis.view.domFocus();\r\n\t}\r\n\r\n\tlayout(height?: number, width?: number): void {\r\n\t\tthis.view.layout(height, width);\r\n\t}\r\n\r\n\tstyle(styles: IListStyles): void {\r\n\t\tconst suffix = `.${this.view.domId}`;\r\n\t\tconst content: string[] = [];\r\n\r\n\t\tif (styles.treeIndentGuidesStroke) {\r\n\t\t\tcontent.push(`.monaco-list${suffix}:hover .monaco-tl-indent > .indent-guide, .monaco-list${suffix}.always .monaco-tl-indent > .indent-guide { border-color: ${styles.treeIndentGuidesStroke.transparent(0.4)}; }`);\r\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-tl-indent > .indent-guide.active { border-color: ${styles.treeIndentGuidesStroke}; }`);\r\n\t\t}\r\n\r\n\t\tthis.styleElement.textContent = content.join('\\n');\r\n\t\tthis.view.style(styles);\r\n\t}\r\n\r\n\tcollapse(location: TRef, recursive: boolean = false): boolean {\r\n\t\treturn this.model.setCollapsed(location, true, recursive);\r\n\t}\r\n\r\n\texpand(location: TRef, recursive: boolean = false): boolean {\r\n\t\treturn this.model.setCollapsed(location, false, recursive);\r\n\t}\r\n\r\n\tisCollapsible(location: TRef): boolean {\r\n\t\treturn this.model.isCollapsible(location);\r\n\t}\r\n\r\n\tsetCollapsible(location: TRef, collapsible?: boolean): boolean {\r\n\t\treturn this.model.setCollapsible(location, collapsible);\r\n\t}\r\n\r\n\tisCollapsed(location: TRef): boolean {\r\n\t\treturn this.model.isCollapsed(location);\r\n\t}\r\n\r\n\trefilter(): void {\r\n\t\tthis._onWillRefilter.fire(undefined);\r\n\t\tthis.model.refilter();\r\n\t}\r\n\r\n\tsetSelection(elements: TRef[], browserEvent?: UIEvent): void {\r\n\t\tconst nodes = elements.map(e => this.model.getNode(e));\r\n\t\tthis.selection.set(nodes, browserEvent);\r\n\r\n\t\tconst indexes = elements.map(e => this.model.getListIndex(e)).filter(i => i > -1);\r\n\t\tthis.view.setSelection(indexes, browserEvent, true);\r\n\t}\r\n\r\n\tgetSelection(): T[] {\r\n\t\treturn this.selection.get();\r\n\t}\r\n\r\n\tsetFocus(elements: TRef[], browserEvent?: UIEvent): void {\r\n\t\tconst nodes = elements.map(e => this.model.getNode(e));\r\n\t\tthis.focus.set(nodes, browserEvent);\r\n\r\n\t\tconst indexes = elements.map(e => this.model.getListIndex(e)).filter(i => i > -1);\r\n\t\tthis.view.setFocus(indexes, browserEvent, true);\r\n\t}\r\n\r\n\tfocusNext(n = 1, loop = false, browserEvent?: UIEvent, filter = this.focusNavigationFilter): void {\r\n\t\tthis.view.focusNext(n, loop, browserEvent, filter);\r\n\t}\r\n\r\n\tgetFocus(): T[] {\r\n\t\treturn this.focus.get();\r\n\t}\r\n\r\n\treveal(location: TRef, relativeTop?: number): void {\r\n\t\tthis.model.expandTo(location);\r\n\r\n\t\tconst index = this.model.getListIndex(location);\r\n\r\n\t\tif (index === -1) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.view.reveal(index, relativeTop);\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the relative position of an element rendered in the list.\r\n\t * Returns `null` if the element isn't *entirely* in the visible viewport.\r\n\t */\r\n\tgetRelativeTop(location: TRef): number | null {\r\n\t\tconst index = this.model.getListIndex(location);\r\n\r\n\t\tif (index === -1) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\treturn this.view.getRelativeTop(index);\r\n\t}\r\n\r\n\t// List\r\n\r\n\tprivate onLeftArrow(e: StandardKeyboardEvent): void {\r\n\t\te.preventDefault();\r\n\t\te.stopPropagation();\r\n\r\n\t\tconst nodes = this.view.getFocusedElements();\r\n\r\n\t\tif (nodes.length === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst node = nodes[0];\r\n\t\tconst location = this.model.getNodeLocation(node);\r\n\t\tconst didChange = this.model.setCollapsed(location, true);\r\n\r\n\t\tif (!didChange) {\r\n\t\t\tconst parentLocation = this.model.getParentNodeLocation(location);\r\n\r\n\t\t\tif (!parentLocation) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst parentListIndex = this.model.getListIndex(parentLocation);\r\n\r\n\t\t\tthis.view.reveal(parentListIndex);\r\n\t\t\tthis.view.setFocus([parentListIndex]);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate onRightArrow(e: StandardKeyboardEvent): void {\r\n\t\te.preventDefault();\r\n\t\te.stopPropagation();\r\n\r\n\t\tconst nodes = this.view.getFocusedElements();\r\n\r\n\t\tif (nodes.length === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst node = nodes[0];\r\n\t\tconst location = this.model.getNodeLocation(node);\r\n\t\tconst didChange = this.model.setCollapsed(location, false);\r\n\r\n\t\tif (!didChange) {\r\n\t\t\tif (!node.children.some(child => child.visible)) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst [focusedIndex] = this.view.getFocus();\r\n\t\t\tconst firstChildIndex = focusedIndex + 1;\r\n\r\n\t\t\tthis.view.reveal(firstChildIndex);\r\n\t\t\tthis.view.setFocus([firstChildIndex]);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate onSpace(e: StandardKeyboardEvent): void {\r\n\t\te.preventDefault();\r\n\t\te.stopPropagation();\r\n\r\n\t\tconst nodes = this.view.getFocusedElements();\r\n\r\n\t\tif (nodes.length === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst node = nodes[0];\r\n\t\tconst location = this.model.getNodeLocation(node);\r\n\t\tconst recursive = e.browserEvent.altKey;\r\n\r\n\t\tthis.model.setCollapsed(location, undefined, recursive);\r\n\t}\r\n\r\n\tprotected abstract createModel(user: string, view: ISpliceable>, options: IAbstractTreeOptions): ITreeModel;\r\n\r\n\tdispose(): void {\r\n\t\tdispose(this.disposables);\r\n\t\tthis.view.dispose();\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { AbstractTree, IAbstractTreeOptions } from 'vs/base/browser/ui/tree/abstractTree';\r\nimport { ITreeNode, ITreeModel, ITreeRenderer, IDataSource } from 'vs/base/browser/ui/tree/tree';\r\nimport { ObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel';\r\nimport { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list';\r\nimport { IList } from 'vs/base/browser/ui/tree/indexTreeModel';\r\n\r\nexport interface IDataTreeOptions extends IAbstractTreeOptions {\r\n}\r\n\r\nexport class DataTree extends AbstractTree {\r\n\r\n\tprotected model!: ObjectTreeModel;\r\n\r\n\tprivate identityProvider: IIdentityProvider | undefined;\r\n\r\n\tconstructor(\r\n\t\tprivate user: string,\r\n\t\tcontainer: HTMLElement,\r\n\t\tdelegate: IListVirtualDelegate,\r\n\t\trenderers: ITreeRenderer[],\r\n\t\tprivate dataSource: IDataSource,\r\n\t\toptions: IDataTreeOptions = {}\r\n\t) {\r\n\t\tsuper(user, container, delegate, renderers, options as IDataTreeOptions);\r\n\t\tthis.identityProvider = options.identityProvider;\r\n\t}\r\n\r\n\tprotected createModel(user: string, view: IList>, options: IDataTreeOptions): ITreeModel {\r\n\t\treturn new ObjectTreeModel(user, view, options);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Iterable } from 'vs/base/common/iterator';\r\nimport { AbstractTree, IAbstractTreeOptions, IAbstractTreeOptionsUpdate } from 'vs/base/browser/ui/tree/abstractTree';\r\nimport { ITreeNode, ITreeModel, ITreeElement, ITreeRenderer, ITreeSorter, ICollapseStateChangeEvent } from 'vs/base/browser/ui/tree/tree';\r\nimport { ObjectTreeModel, IObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel';\r\nimport { IListVirtualDelegate, IKeyboardNavigationLabelProvider, IIdentityProvider } from 'vs/base/browser/ui/list/list';\r\nimport { Event } from 'vs/base/common/event';\r\nimport { CompressibleObjectTreeModel, ICompressedTreeNode, ICompressedTreeElement } from 'vs/base/browser/ui/tree/compressedObjectTreeModel';\r\nimport { memoize } from 'vs/base/common/decorators';\r\nimport { IList } from 'vs/base/browser/ui/tree/indexTreeModel';\r\n\r\nexport interface IObjectTreeOptions extends IAbstractTreeOptions {\r\n\treadonly sorter?: ITreeSorter;\r\n}\r\n\r\nexport interface IObjectTreeSetChildrenOptions {\r\n\r\n\t/**\r\n\t * Identity provider used to optimize splice() calls in the IndexTree. If\r\n\t * this is not present, optimized splicing is not enabled.\r\n\t *\r\n\t * Warning: if this is present, calls to `setChildren()` will not replace\r\n\t * or update nodes if their identity is the same, even if the elements are\r\n\t * different. For this, you should call `rerender()`.\r\n\t */\r\n\treadonly diffIdentityProvider?: IIdentityProvider;\r\n}\r\n\r\nexport class ObjectTree, TFilterData = void> extends AbstractTree {\r\n\r\n\tprotected model!: IObjectTreeModel;\r\n\r\n\tget onDidChangeCollapseState(): Event> { return this.model.onDidChangeCollapseState; }\r\n\r\n\tconstructor(\r\n\t\tuser: string,\r\n\t\tcontainer: HTMLElement,\r\n\t\tdelegate: IListVirtualDelegate,\r\n\t\trenderers: ITreeRenderer[],\r\n\t\toptions: IObjectTreeOptions = {}\r\n\t) {\r\n\t\tsuper(user, container, delegate, renderers, options as IObjectTreeOptions);\r\n\t}\r\n\r\n\tsetChildren(element: T | null, children: Iterable> = Iterable.empty(), options?: IObjectTreeSetChildrenOptions): void {\r\n\t\tthis.model.setChildren(element, children, options);\r\n\t}\r\n\r\n\trerender(element?: T): void {\r\n\t\tif (element === undefined) {\r\n\t\t\tthis.view.rerender();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.model.rerender(element);\r\n\t}\r\n\r\n\thasElement(element: T): boolean {\r\n\t\treturn this.model.has(element);\r\n\t}\r\n\r\n\tprotected createModel(user: string, view: IList>, options: IObjectTreeOptions): ITreeModel {\r\n\t\treturn new ObjectTreeModel(user, view, options);\r\n\t}\r\n}\r\n\r\ninterface ICompressedTreeNodeProvider {\r\n\tgetCompressedTreeNode(location: T | null): ITreeNode | null, TFilterData>;\r\n}\r\n\r\nexport interface ICompressibleTreeRenderer extends ITreeRenderer {\r\n\trenderCompressedElements(node: ITreeNode, TFilterData>, index: number, templateData: TTemplateData, height: number | undefined): void;\r\n\tdisposeCompressedElements?(node: ITreeNode, TFilterData>, index: number, templateData: TTemplateData, height: number | undefined): void;\r\n}\r\n\r\ninterface CompressibleTemplateData {\r\n\tcompressedTreeNode: ITreeNode, TFilterData> | undefined;\r\n\treadonly data: TTemplateData;\r\n}\r\n\r\nclass CompressibleRenderer, TFilterData, TTemplateData> implements ITreeRenderer> {\r\n\r\n\treadonly templateId: string;\r\n\treadonly onDidChangeTwistieState: Event | undefined;\r\n\r\n\t@memoize\r\n\tprivate get compressedTreeNodeProvider(): ICompressedTreeNodeProvider {\r\n\t\treturn this._compressedTreeNodeProvider();\r\n\t}\r\n\r\n\tconstructor(private _compressedTreeNodeProvider: () => ICompressedTreeNodeProvider, private renderer: ICompressibleTreeRenderer) {\r\n\t\tthis.templateId = renderer.templateId;\r\n\r\n\t\tif (renderer.onDidChangeTwistieState) {\r\n\t\t\tthis.onDidChangeTwistieState = renderer.onDidChangeTwistieState;\r\n\t\t}\r\n\t}\r\n\r\n\trenderTemplate(container: HTMLElement): CompressibleTemplateData {\r\n\t\tconst data = this.renderer.renderTemplate(container);\r\n\t\treturn { compressedTreeNode: undefined, data };\r\n\t}\r\n\r\n\trenderElement(node: ITreeNode, index: number, templateData: CompressibleTemplateData, height: number | undefined): void {\r\n\t\tconst compressedTreeNode = this.compressedTreeNodeProvider.getCompressedTreeNode(node.element) as ITreeNode, TFilterData>;\r\n\r\n\t\tif (compressedTreeNode.element.elements.length === 1) {\r\n\t\t\ttemplateData.compressedTreeNode = undefined;\r\n\t\t\tthis.renderer.renderElement(node, index, templateData.data, height);\r\n\t\t} else {\r\n\t\t\ttemplateData.compressedTreeNode = compressedTreeNode;\r\n\t\t\tthis.renderer.renderCompressedElements(compressedTreeNode, index, templateData.data, height);\r\n\t\t}\r\n\t}\r\n\r\n\tdisposeElement(node: ITreeNode, index: number, templateData: CompressibleTemplateData, height: number | undefined): void {\r\n\t\tif (templateData.compressedTreeNode) {\r\n\t\t\tif (this.renderer.disposeCompressedElements) {\r\n\t\t\t\tthis.renderer.disposeCompressedElements(templateData.compressedTreeNode, index, templateData.data, height);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tif (this.renderer.disposeElement) {\r\n\t\t\t\tthis.renderer.disposeElement(node, index, templateData.data, height);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tdisposeTemplate(templateData: CompressibleTemplateData): void {\r\n\t\tthis.renderer.disposeTemplate(templateData.data);\r\n\t}\r\n\r\n\trenderTwistie?(element: T, twistieElement: HTMLElement): boolean {\r\n\t\tif (this.renderer.renderTwistie) {\r\n\t\t\treturn this.renderer.renderTwistie(element, twistieElement);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\nexport interface ICompressibleKeyboardNavigationLabelProvider extends IKeyboardNavigationLabelProvider {\r\n\tgetCompressedNodeKeyboardNavigationLabel(elements: T[]): { toString(): string | undefined; } | undefined;\r\n}\r\n\r\nexport interface ICompressibleObjectTreeOptions extends IObjectTreeOptions {\r\n\treadonly keyboardNavigationLabelProvider?: ICompressibleKeyboardNavigationLabelProvider;\r\n}\r\n\r\nfunction asObjectTreeOptions(compressedTreeNodeProvider: () => ICompressedTreeNodeProvider, options?: ICompressibleObjectTreeOptions): IObjectTreeOptions | undefined {\r\n\treturn options && {\r\n\t\t...options,\r\n\t\tkeyboardNavigationLabelProvider: options.keyboardNavigationLabelProvider && {\r\n\t\t\tgetKeyboardNavigationLabel(e: T) {\r\n\t\t\t\tlet compressedTreeNode: ITreeNode, TFilterData>;\r\n\r\n\t\t\t\ttry {\r\n\t\t\t\t\tcompressedTreeNode = compressedTreeNodeProvider().getCompressedTreeNode(e) as ITreeNode, TFilterData>;\r\n\t\t\t\t} catch {\r\n\t\t\t\t\treturn options.keyboardNavigationLabelProvider!.getKeyboardNavigationLabel(e);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (compressedTreeNode.element.elements.length === 1) {\r\n\t\t\t\t\treturn options.keyboardNavigationLabelProvider!.getKeyboardNavigationLabel(e);\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn options.keyboardNavigationLabelProvider!.getCompressedNodeKeyboardNavigationLabel(compressedTreeNode.element.elements);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t};\r\n}\r\n\r\nexport interface ICompressibleObjectTreeOptionsUpdate extends IAbstractTreeOptionsUpdate {\r\n\treadonly compressionEnabled?: boolean;\r\n}\r\n\r\nexport class CompressibleObjectTree, TFilterData = void> extends ObjectTree implements ICompressedTreeNodeProvider {\r\n\r\n\tprotected model!: CompressibleObjectTreeModel;\r\n\r\n\tconstructor(\r\n\t\tuser: string,\r\n\t\tcontainer: HTMLElement,\r\n\t\tdelegate: IListVirtualDelegate,\r\n\t\trenderers: ICompressibleTreeRenderer[],\r\n\t\toptions: ICompressibleObjectTreeOptions = {}\r\n\t) {\r\n\t\tconst compressedTreeNodeProvider = () => this;\r\n\t\tconst compressibleRenderers = renderers.map(r => new CompressibleRenderer(compressedTreeNodeProvider, r));\r\n\t\tsuper(user, container, delegate, compressibleRenderers, asObjectTreeOptions(compressedTreeNodeProvider, options));\r\n\t}\r\n\r\n\tsetChildren(element: T | null, children: Iterable> = Iterable.empty(), options?: IObjectTreeSetChildrenOptions): void {\r\n\t\tthis.model.setChildren(element, children, options);\r\n\t}\r\n\r\n\tprotected createModel(user: string, view: IList>, options: ICompressibleObjectTreeOptions): ITreeModel {\r\n\t\treturn new CompressibleObjectTreeModel(user, view, options);\r\n\t}\r\n\r\n\tupdateOptions(optionsUpdate: ICompressibleObjectTreeOptionsUpdate = {}): void {\r\n\t\tsuper.updateOptions(optionsUpdate);\r\n\r\n\t\tif (typeof optionsUpdate.compressionEnabled !== 'undefined') {\r\n\t\t\tthis.model.setCompressionEnabled(optionsUpdate.compressionEnabled);\r\n\t\t}\r\n\t}\r\n\r\n\tgetCompressedTreeNode(element: T | null = null): ITreeNode | null, TFilterData> {\r\n\t\treturn this.model.getCompressedTreeNode(element);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { ComposedTreeDelegate, IAbstractTreeOptions, IAbstractTreeOptionsUpdate } from 'vs/base/browser/ui/tree/abstractTree';\r\nimport { ObjectTree, IObjectTreeOptions, CompressibleObjectTree, ICompressibleTreeRenderer, ICompressibleKeyboardNavigationLabelProvider, ICompressibleObjectTreeOptions, IObjectTreeSetChildrenOptions } from 'vs/base/browser/ui/tree/objectTree';\r\nimport { IListVirtualDelegate, IIdentityProvider, IListDragAndDrop, IListDragOverReaction } from 'vs/base/browser/ui/list/list';\r\nimport { ITreeElement, ITreeNode, ITreeRenderer, ITreeEvent, ITreeMouseEvent, ITreeSorter, ICollapseStateChangeEvent, IAsyncDataSource, ITreeDragAndDrop, TreeError, WeakMapper, ITreeFilter, TreeVisibility, TreeFilterResult } from 'vs/base/browser/ui/tree/tree';\r\nimport { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { timeout, CancelablePromise, createCancelablePromise } from 'vs/base/common/async';\r\nimport { IListStyles } from 'vs/base/browser/ui/list/listWidget';\r\nimport { Iterable } from 'vs/base/common/iterator';\r\nimport { IDragAndDropData } from 'vs/base/browser/dnd';\r\nimport { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView';\r\nimport { isPromiseCanceledError, onUnexpectedError } from 'vs/base/common/errors';\r\nimport { ICompressedTreeNode, ICompressedTreeElement } from 'vs/base/browser/ui/tree/compressedObjectTreeModel';\r\nimport { IThemable } from 'vs/base/common/styler';\r\nimport { isFilterResult, getVisibleState } from 'vs/base/browser/ui/tree/indexTreeModel';\r\nimport { treeItemLoadingIcon } from 'vs/base/browser/ui/tree/treeIcons';\r\n\r\ninterface IAsyncDataTreeNode {\r\n\telement: TInput | T;\r\n\treadonly parent: IAsyncDataTreeNode | null;\r\n\treadonly children: IAsyncDataTreeNode[];\r\n\treadonly id?: string | null;\r\n\trefreshPromise: Promise | undefined;\r\n\thasChildren: boolean;\r\n\tstale: boolean;\r\n\tslow: boolean;\r\n\tcollapsedByDefault: boolean | undefined;\r\n}\r\n\r\ninterface IAsyncDataTreeNodeRequiredProps extends Partial> {\r\n\treadonly element: TInput | T;\r\n\treadonly parent: IAsyncDataTreeNode | null;\r\n\treadonly hasChildren: boolean;\r\n}\r\n\r\nfunction createAsyncDataTreeNode(props: IAsyncDataTreeNodeRequiredProps): IAsyncDataTreeNode {\r\n\treturn {\r\n\t\t...props,\r\n\t\tchildren: [],\r\n\t\trefreshPromise: undefined,\r\n\t\tstale: true,\r\n\t\tslow: false,\r\n\t\tcollapsedByDefault: undefined\r\n\t};\r\n}\r\n\r\nfunction isAncestor(ancestor: IAsyncDataTreeNode, descendant: IAsyncDataTreeNode): boolean {\r\n\tif (!descendant.parent) {\r\n\t\treturn false;\r\n\t} else if (descendant.parent === ancestor) {\r\n\t\treturn true;\r\n\t} else {\r\n\t\treturn isAncestor(ancestor, descendant.parent);\r\n\t}\r\n}\r\n\r\nfunction intersects(node: IAsyncDataTreeNode, other: IAsyncDataTreeNode): boolean {\r\n\treturn node === other || isAncestor(node, other) || isAncestor(other, node);\r\n}\r\n\r\ninterface IDataTreeListTemplateData {\r\n\ttemplateData: T;\r\n}\r\n\r\ntype AsyncDataTreeNodeMapper = WeakMapper | null, TFilterData>, ITreeNode>;\r\n\r\nclass AsyncDataTreeNodeWrapper implements ITreeNode {\r\n\r\n\tget element(): T { return this.node.element!.element as T; }\r\n\tget children(): ITreeNode[] { return this.node.children.map(node => new AsyncDataTreeNodeWrapper(node)); }\r\n\tget depth(): number { return this.node.depth; }\r\n\tget visibleChildrenCount(): number { return this.node.visibleChildrenCount; }\r\n\tget visibleChildIndex(): number { return this.node.visibleChildIndex; }\r\n\tget collapsible(): boolean { return this.node.collapsible; }\r\n\tget collapsed(): boolean { return this.node.collapsed; }\r\n\tget visible(): boolean { return this.node.visible; }\r\n\tget filterData(): TFilterData | undefined { return this.node.filterData; }\r\n\r\n\tconstructor(private node: ITreeNode | null, TFilterData>) { }\r\n}\r\n\r\nclass AsyncDataTreeRenderer implements ITreeRenderer, TFilterData, IDataTreeListTemplateData> {\r\n\r\n\treadonly templateId: string;\r\n\tprivate renderedNodes = new Map, IDataTreeListTemplateData>();\r\n\r\n\tconstructor(\r\n\t\tprotected renderer: ITreeRenderer,\r\n\t\tprotected nodeMapper: AsyncDataTreeNodeMapper,\r\n\t\treadonly onDidChangeTwistieState: Event>\r\n\t) {\r\n\t\tthis.templateId = renderer.templateId;\r\n\t}\r\n\r\n\trenderTemplate(container: HTMLElement): IDataTreeListTemplateData {\r\n\t\tconst templateData = this.renderer.renderTemplate(container);\r\n\t\treturn { templateData };\r\n\t}\r\n\r\n\trenderElement(node: ITreeNode, TFilterData>, index: number, templateData: IDataTreeListTemplateData, height: number | undefined): void {\r\n\t\tthis.renderer.renderElement(this.nodeMapper.map(node) as ITreeNode, index, templateData.templateData, height);\r\n\t}\r\n\r\n\trenderTwistie(element: IAsyncDataTreeNode, twistieElement: HTMLElement): boolean {\r\n\t\tif (element.slow) {\r\n\t\t\ttwistieElement.classList.add(...treeItemLoadingIcon.classNamesArray);\r\n\t\t\treturn true;\r\n\t\t} else {\r\n\t\t\ttwistieElement.classList.remove(...treeItemLoadingIcon.classNamesArray);\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n\r\n\tdisposeElement(node: ITreeNode, TFilterData>, index: number, templateData: IDataTreeListTemplateData, height: number | undefined): void {\r\n\t\tif (this.renderer.disposeElement) {\r\n\t\t\tthis.renderer.disposeElement(this.nodeMapper.map(node) as ITreeNode, index, templateData.templateData, height);\r\n\t\t}\r\n\t}\r\n\r\n\tdisposeTemplate(templateData: IDataTreeListTemplateData): void {\r\n\t\tthis.renderer.disposeTemplate(templateData.templateData);\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis.renderedNodes.clear();\r\n\t}\r\n}\r\n\r\nfunction asTreeEvent(e: ITreeEvent | null>): ITreeEvent {\r\n\treturn {\r\n\t\tbrowserEvent: e.browserEvent,\r\n\t\telements: e.elements.map(e => e!.element as T)\r\n\t};\r\n}\r\n\r\nfunction asTreeMouseEvent(e: ITreeMouseEvent | null>): ITreeMouseEvent {\r\n\treturn {\r\n\t\tbrowserEvent: e.browserEvent,\r\n\t\telement: e.element && e.element.element as T,\r\n\t\ttarget: e.target\r\n\t};\r\n}\r\n\r\nclass AsyncDataTreeElementsDragAndDropData extends ElementsDragAndDropData {\r\n\r\n\tconstructor(private data: ElementsDragAndDropData, TContext>) {\r\n\t\tsuper(data.elements.map(node => node.element as T));\r\n\t}\r\n}\r\n\r\nfunction asAsyncDataTreeDragAndDropData(data: IDragAndDropData): IDragAndDropData {\r\n\tif (data instanceof ElementsDragAndDropData) {\r\n\t\treturn new AsyncDataTreeElementsDragAndDropData(data);\r\n\t}\r\n\r\n\treturn data;\r\n}\r\n\r\nclass AsyncDataTreeNodeListDragAndDrop implements IListDragAndDrop> {\r\n\r\n\tconstructor(private dnd: ITreeDragAndDrop) { }\r\n\r\n\tgetDragURI(node: IAsyncDataTreeNode): string | null {\r\n\t\treturn this.dnd.getDragURI(node.element as T);\r\n\t}\r\n\r\n\tgetDragLabel(nodes: IAsyncDataTreeNode[], originalEvent: DragEvent): string | undefined {\r\n\t\tif (this.dnd.getDragLabel) {\r\n\t\t\treturn this.dnd.getDragLabel(nodes.map(node => node.element as T), originalEvent);\r\n\t\t}\r\n\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tonDragStart(data: IDragAndDropData, originalEvent: DragEvent): void {\r\n\t\tif (this.dnd.onDragStart) {\r\n\t\t\tthis.dnd.onDragStart(asAsyncDataTreeDragAndDropData(data), originalEvent);\r\n\t\t}\r\n\t}\r\n\r\n\tonDragOver(data: IDragAndDropData, targetNode: IAsyncDataTreeNode | undefined, targetIndex: number | undefined, originalEvent: DragEvent, raw = true): boolean | IListDragOverReaction {\r\n\t\treturn this.dnd.onDragOver(asAsyncDataTreeDragAndDropData(data), targetNode && targetNode.element as T, targetIndex, originalEvent);\r\n\t}\r\n\r\n\tdrop(data: IDragAndDropData, targetNode: IAsyncDataTreeNode | undefined, targetIndex: number | undefined, originalEvent: DragEvent): void {\r\n\t\tthis.dnd.drop(asAsyncDataTreeDragAndDropData(data), targetNode && targetNode.element as T, targetIndex, originalEvent);\r\n\t}\r\n\r\n\tonDragEnd(originalEvent: DragEvent): void {\r\n\t\tif (this.dnd.onDragEnd) {\r\n\t\t\tthis.dnd.onDragEnd(originalEvent);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction asObjectTreeOptions(options?: IAsyncDataTreeOptions): IObjectTreeOptions, TFilterData> | undefined {\r\n\treturn options && {\r\n\t\t...options,\r\n\t\tcollapseByDefault: true,\r\n\t\tidentityProvider: options.identityProvider && {\r\n\t\t\tgetId(el) {\r\n\t\t\t\treturn options.identityProvider!.getId(el.element as T);\r\n\t\t\t}\r\n\t\t},\r\n\t\tdnd: options.dnd && new AsyncDataTreeNodeListDragAndDrop(options.dnd),\r\n\t\tmultipleSelectionController: options.multipleSelectionController && {\r\n\t\t\tisSelectionSingleChangeEvent(e) {\r\n\t\t\t\treturn options.multipleSelectionController!.isSelectionSingleChangeEvent({ ...e, element: e.element } as any);\r\n\t\t\t},\r\n\t\t\tisSelectionRangeChangeEvent(e) {\r\n\t\t\t\treturn options.multipleSelectionController!.isSelectionRangeChangeEvent({ ...e, element: e.element } as any);\r\n\t\t\t}\r\n\t\t},\r\n\t\taccessibilityProvider: options.accessibilityProvider && {\r\n\t\t\t...options.accessibilityProvider,\r\n\t\t\tgetPosInSet: undefined,\r\n\t\t\tgetSetSize: undefined,\r\n\t\t\tgetRole: options.accessibilityProvider!.getRole ? (el) => {\r\n\t\t\t\treturn options.accessibilityProvider!.getRole!(el.element as T);\r\n\t\t\t} : () => 'treeitem',\r\n\t\t\tisChecked: options.accessibilityProvider!.isChecked ? (e) => {\r\n\t\t\t\treturn !!(options.accessibilityProvider?.isChecked!(e.element as T));\r\n\t\t\t} : undefined,\r\n\t\t\tgetAriaLabel(e) {\r\n\t\t\t\treturn options.accessibilityProvider!.getAriaLabel(e.element as T);\r\n\t\t\t},\r\n\t\t\tgetWidgetAriaLabel() {\r\n\t\t\t\treturn options.accessibilityProvider!.getWidgetAriaLabel();\r\n\t\t\t},\r\n\t\t\tgetWidgetRole: options.accessibilityProvider!.getWidgetRole ? () => options.accessibilityProvider!.getWidgetRole!() : () => 'tree',\r\n\t\t\tgetAriaLevel: options.accessibilityProvider!.getAriaLevel && (node => {\r\n\t\t\t\treturn options.accessibilityProvider!.getAriaLevel!(node.element as T);\r\n\t\t\t}),\r\n\t\t\tgetActiveDescendantId: options.accessibilityProvider.getActiveDescendantId && (node => {\r\n\t\t\t\treturn options.accessibilityProvider!.getActiveDescendantId!(node.element as T);\r\n\t\t\t})\r\n\t\t},\r\n\t\tfilter: options.filter && {\r\n\t\t\tfilter(e, parentVisibility) {\r\n\t\t\t\treturn options.filter!.filter(e.element as T, parentVisibility);\r\n\t\t\t}\r\n\t\t},\r\n\t\tkeyboardNavigationLabelProvider: options.keyboardNavigationLabelProvider && {\r\n\t\t\t...options.keyboardNavigationLabelProvider,\r\n\t\t\tgetKeyboardNavigationLabel(e) {\r\n\t\t\t\treturn options.keyboardNavigationLabelProvider!.getKeyboardNavigationLabel(e.element as T);\r\n\t\t\t}\r\n\t\t},\r\n\t\tsorter: undefined,\r\n\t\texpandOnlyOnTwistieClick: typeof options.expandOnlyOnTwistieClick === 'undefined' ? undefined : (\r\n\t\t\ttypeof options.expandOnlyOnTwistieClick !== 'function' ? options.expandOnlyOnTwistieClick : (\r\n\t\t\t\te => (options.expandOnlyOnTwistieClick as ((e: T) => boolean))(e.element as T)\r\n\t\t\t)\r\n\t\t),\r\n\t\tadditionalScrollHeight: options.additionalScrollHeight\r\n\t};\r\n}\r\n\r\nexport interface IAsyncDataTreeOptionsUpdate extends IAbstractTreeOptionsUpdate { }\r\nexport interface IAsyncDataTreeUpdateChildrenOptions extends IObjectTreeSetChildrenOptions { }\r\n\r\nexport interface IAsyncDataTreeOptions extends IAsyncDataTreeOptionsUpdate, Pick, Exclude, 'collapseByDefault'>> {\r\n\treadonly collapseByDefault?: { (e: T): boolean; };\r\n\treadonly identityProvider?: IIdentityProvider;\r\n\treadonly sorter?: ITreeSorter;\r\n\treadonly autoExpandSingleChildren?: boolean;\r\n}\r\n\r\nexport interface IAsyncDataTreeViewState {\r\n\treadonly focus?: string[];\r\n\treadonly selection?: string[];\r\n\treadonly expanded?: string[];\r\n\treadonly scrollTop?: number;\r\n}\r\n\r\ninterface IAsyncDataTreeViewStateContext {\r\n\treadonly viewState: IAsyncDataTreeViewState;\r\n\treadonly selection: IAsyncDataTreeNode[];\r\n\treadonly focus: IAsyncDataTreeNode[];\r\n}\r\n\r\nfunction dfs(node: IAsyncDataTreeNode, fn: (node: IAsyncDataTreeNode) => void): void {\r\n\tfn(node);\r\n\tnode.children.forEach(child => dfs(child, fn));\r\n}\r\n\r\nexport class AsyncDataTree implements IDisposable, IThemable {\r\n\r\n\tprotected readonly tree: ObjectTree, TFilterData>;\r\n\tprotected readonly root: IAsyncDataTreeNode;\r\n\tprivate readonly nodes = new Map>();\r\n\tprivate readonly sorter?: ITreeSorter;\r\n\tprivate readonly collapseByDefault?: { (e: T): boolean; };\r\n\r\n\tprivate readonly subTreeRefreshPromises = new Map, Promise>();\r\n\tprivate readonly refreshPromises = new Map, CancelablePromise>>();\r\n\r\n\tprotected readonly identityProvider?: IIdentityProvider;\r\n\tprivate readonly autoExpandSingleChildren: boolean;\r\n\r\n\tprivate readonly _onDidRender = new Emitter();\r\n\tprotected readonly _onDidChangeNodeSlowState = new Emitter>();\r\n\r\n\tprotected readonly nodeMapper: AsyncDataTreeNodeMapper = new WeakMapper(node => new AsyncDataTreeNodeWrapper(node));\r\n\r\n\tprotected readonly disposables = new DisposableStore();\r\n\r\n\tget onDidChangeFocus(): Event> { return Event.map(this.tree.onDidChangeFocus, asTreeEvent); }\r\n\tget onDidChangeSelection(): Event> { return Event.map(this.tree.onDidChangeSelection, asTreeEvent); }\r\n\tget onMouseDblClick(): Event> { return Event.map(this.tree.onMouseDblClick, asTreeMouseEvent); }\r\n\tget onPointer(): Event> { return Event.map(this.tree.onPointer, asTreeMouseEvent); }\r\n\tget onDidFocus(): Event { return this.tree.onDidFocus; }\r\n\r\n\tget onDidDispose(): Event { return this.tree.onDidDispose; }\r\n\r\n\tconstructor(\r\n\t\tprotected user: string,\r\n\t\tcontainer: HTMLElement,\r\n\t\tdelegate: IListVirtualDelegate,\r\n\t\trenderers: ITreeRenderer[],\r\n\t\tprivate dataSource: IAsyncDataSource,\r\n\t\toptions: IAsyncDataTreeOptions = {}\r\n\t) {\r\n\t\tthis.identityProvider = options.identityProvider;\r\n\t\tthis.autoExpandSingleChildren = typeof options.autoExpandSingleChildren === 'undefined' ? false : options.autoExpandSingleChildren;\r\n\t\tthis.sorter = options.sorter;\r\n\t\tthis.collapseByDefault = options.collapseByDefault;\r\n\r\n\t\tthis.tree = this.createTree(user, container, delegate, renderers, options);\r\n\r\n\t\tthis.root = createAsyncDataTreeNode({\r\n\t\t\telement: undefined!,\r\n\t\t\tparent: null,\r\n\t\t\thasChildren: true\r\n\t\t});\r\n\r\n\t\tif (this.identityProvider) {\r\n\t\t\tthis.root = {\r\n\t\t\t\t...this.root,\r\n\t\t\t\tid: null\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tthis.nodes.set(null, this.root);\r\n\r\n\t\tthis.tree.onDidChangeCollapseState(this._onDidChangeCollapseState, this, this.disposables);\r\n\t}\r\n\r\n\tprotected createTree(\r\n\t\tuser: string,\r\n\t\tcontainer: HTMLElement,\r\n\t\tdelegate: IListVirtualDelegate,\r\n\t\trenderers: ITreeRenderer[],\r\n\t\toptions: IAsyncDataTreeOptions\r\n\t): ObjectTree, TFilterData> {\r\n\t\tconst objectTreeDelegate = new ComposedTreeDelegate>(delegate);\r\n\t\tconst objectTreeRenderers = renderers.map(r => new AsyncDataTreeRenderer(r, this.nodeMapper, this._onDidChangeNodeSlowState.event));\r\n\t\tconst objectTreeOptions = asObjectTreeOptions(options) || {};\r\n\r\n\t\treturn new ObjectTree(user, container, objectTreeDelegate, objectTreeRenderers, objectTreeOptions);\r\n\t}\r\n\r\n\tupdateOptions(options: IAsyncDataTreeOptionsUpdate = {}): void {\r\n\t\tthis.tree.updateOptions(options);\r\n\t}\r\n\r\n\t// Widget\r\n\r\n\tgetHTMLElement(): HTMLElement {\r\n\t\treturn this.tree.getHTMLElement();\r\n\t}\r\n\r\n\tget scrollTop(): number {\r\n\t\treturn this.tree.scrollTop;\r\n\t}\r\n\r\n\tset scrollTop(scrollTop: number) {\r\n\t\tthis.tree.scrollTop = scrollTop;\r\n\t}\r\n\r\n\tdomFocus(): void {\r\n\t\tthis.tree.domFocus();\r\n\t}\r\n\r\n\tlayout(height?: number, width?: number): void {\r\n\t\tthis.tree.layout(height, width);\r\n\t}\r\n\r\n\tstyle(styles: IListStyles): void {\r\n\t\tthis.tree.style(styles);\r\n\t}\r\n\r\n\t// Model\r\n\r\n\tgetInput(): TInput | undefined {\r\n\t\treturn this.root.element as TInput;\r\n\t}\r\n\r\n\tasync setInput(input: TInput, viewState?: IAsyncDataTreeViewState): Promise {\r\n\t\tthis.refreshPromises.forEach(promise => promise.cancel());\r\n\t\tthis.refreshPromises.clear();\r\n\r\n\t\tthis.root.element = input!;\r\n\r\n\t\tconst viewStateContext = viewState && { viewState, focus: [], selection: [] } as IAsyncDataTreeViewStateContext;\r\n\r\n\t\tawait this._updateChildren(input, true, false, viewStateContext);\r\n\r\n\t\tif (viewStateContext) {\r\n\t\t\tthis.tree.setFocus(viewStateContext.focus);\r\n\t\t\tthis.tree.setSelection(viewStateContext.selection);\r\n\t\t}\r\n\r\n\t\tif (viewState && typeof viewState.scrollTop === 'number') {\r\n\t\t\tthis.scrollTop = viewState.scrollTop;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate async _updateChildren(element: TInput | T = this.root.element, recursive = true, rerender = false, viewStateContext?: IAsyncDataTreeViewStateContext, options?: IAsyncDataTreeUpdateChildrenOptions): Promise {\r\n\t\tif (typeof this.root.element === 'undefined') {\r\n\t\t\tthrow new TreeError(this.user, 'Tree input not set');\r\n\t\t}\r\n\r\n\t\tif (this.root.refreshPromise) {\r\n\t\t\tawait this.root.refreshPromise;\r\n\t\t\tawait Event.toPromise(this._onDidRender.event);\r\n\t\t}\r\n\r\n\t\tconst node = this.getDataNode(element);\r\n\t\tawait this.refreshAndRenderNode(node, recursive, viewStateContext, options);\r\n\r\n\t\tif (rerender) {\r\n\t\t\ttry {\r\n\t\t\t\tthis.tree.rerender(node);\r\n\t\t\t} catch {\r\n\t\t\t\t// missing nodes are fine, this could've resulted from\r\n\t\t\t\t// parallel refresh calls, removing `node` altogether\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t// View\r\n\r\n\trerender(element?: T): void {\r\n\t\tif (element === undefined || element === this.root.element) {\r\n\t\t\tthis.tree.rerender();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst node = this.getDataNode(element);\r\n\t\tthis.tree.rerender(node);\r\n\t}\r\n\r\n\tcollapse(element: T, recursive: boolean = false): boolean {\r\n\t\tconst node = this.getDataNode(element);\r\n\t\treturn this.tree.collapse(node === this.root ? null : node, recursive);\r\n\t}\r\n\r\n\tasync expand(element: T, recursive: boolean = false): Promise {\r\n\t\tif (typeof this.root.element === 'undefined') {\r\n\t\t\tthrow new TreeError(this.user, 'Tree input not set');\r\n\t\t}\r\n\r\n\t\tif (this.root.refreshPromise) {\r\n\t\t\tawait this.root.refreshPromise;\r\n\t\t\tawait Event.toPromise(this._onDidRender.event);\r\n\t\t}\r\n\r\n\t\tconst node = this.getDataNode(element);\r\n\r\n\t\tif (this.tree.hasElement(node) && !this.tree.isCollapsible(node)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tif (node.refreshPromise) {\r\n\t\t\tawait this.root.refreshPromise;\r\n\t\t\tawait Event.toPromise(this._onDidRender.event);\r\n\t\t}\r\n\r\n\t\tif (node !== this.root && !node.refreshPromise && !this.tree.isCollapsed(node)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tconst result = this.tree.expand(node === this.root ? null : node, recursive);\r\n\r\n\t\tif (node.refreshPromise) {\r\n\t\t\tawait this.root.refreshPromise;\r\n\t\t\tawait Event.toPromise(this._onDidRender.event);\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tsetSelection(elements: T[], browserEvent?: UIEvent): void {\r\n\t\tconst nodes = elements.map(e => this.getDataNode(e));\r\n\t\tthis.tree.setSelection(nodes, browserEvent);\r\n\t}\r\n\r\n\tgetSelection(): T[] {\r\n\t\tconst nodes = this.tree.getSelection();\r\n\t\treturn nodes.map(n => n!.element as T);\r\n\t}\r\n\r\n\tsetFocus(elements: T[], browserEvent?: UIEvent): void {\r\n\t\tconst nodes = elements.map(e => this.getDataNode(e));\r\n\t\tthis.tree.setFocus(nodes, browserEvent);\r\n\t}\r\n\r\n\tgetFocus(): T[] {\r\n\t\tconst nodes = this.tree.getFocus();\r\n\t\treturn nodes.map(n => n!.element as T);\r\n\t}\r\n\r\n\treveal(element: T, relativeTop?: number): void {\r\n\t\tthis.tree.reveal(this.getDataNode(element), relativeTop);\r\n\t}\r\n\r\n\t// Implementation\r\n\r\n\tprivate getDataNode(element: TInput | T): IAsyncDataTreeNode {\r\n\t\tconst node: IAsyncDataTreeNode | undefined = this.nodes.get((element === this.root.element ? null : element) as T);\r\n\r\n\t\tif (!node) {\r\n\t\t\tthrow new TreeError(this.user, `Data tree node not found: ${element}`);\r\n\t\t}\r\n\r\n\t\treturn node;\r\n\t}\r\n\r\n\tprivate async refreshAndRenderNode(node: IAsyncDataTreeNode, recursive: boolean, viewStateContext?: IAsyncDataTreeViewStateContext, options?: IAsyncDataTreeUpdateChildrenOptions): Promise {\r\n\t\tawait this.refreshNode(node, recursive, viewStateContext);\r\n\t\tthis.render(node, viewStateContext, options);\r\n\t}\r\n\r\n\tprivate async refreshNode(node: IAsyncDataTreeNode, recursive: boolean, viewStateContext?: IAsyncDataTreeViewStateContext): Promise {\r\n\t\tlet result: Promise | undefined;\r\n\r\n\t\tthis.subTreeRefreshPromises.forEach((refreshPromise, refreshNode) => {\r\n\t\t\tif (!result && intersects(refreshNode, node)) {\r\n\t\t\t\tresult = refreshPromise.then(() => this.refreshNode(node, recursive, viewStateContext));\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tif (result) {\r\n\t\t\treturn result;\r\n\t\t}\r\n\r\n\t\treturn this.doRefreshSubTree(node, recursive, viewStateContext);\r\n\t}\r\n\r\n\tprivate async doRefreshSubTree(node: IAsyncDataTreeNode, recursive: boolean, viewStateContext?: IAsyncDataTreeViewStateContext): Promise {\r\n\t\tlet done: () => void;\r\n\t\tnode.refreshPromise = new Promise(c => done = c);\r\n\t\tthis.subTreeRefreshPromises.set(node, node.refreshPromise);\r\n\r\n\t\tnode.refreshPromise.finally(() => {\r\n\t\t\tnode.refreshPromise = undefined;\r\n\t\t\tthis.subTreeRefreshPromises.delete(node);\r\n\t\t});\r\n\r\n\t\ttry {\r\n\t\t\tconst childrenToRefresh = await this.doRefreshNode(node, recursive, viewStateContext);\r\n\t\t\tnode.stale = false;\r\n\r\n\t\t\tawait Promise.all(childrenToRefresh.map(child => this.doRefreshSubTree(child, recursive, viewStateContext)));\r\n\t\t} finally {\r\n\t\t\tdone!();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate async doRefreshNode(node: IAsyncDataTreeNode, recursive: boolean, viewStateContext?: IAsyncDataTreeViewStateContext): Promise[]> {\r\n\t\tnode.hasChildren = !!this.dataSource.hasChildren(node.element!);\r\n\r\n\t\tlet childrenPromise: Promise>;\r\n\r\n\t\tif (!node.hasChildren) {\r\n\t\t\tchildrenPromise = Promise.resolve(Iterable.empty());\r\n\t\t} else {\r\n\t\t\tconst slowTimeout = timeout(800);\r\n\r\n\t\t\tslowTimeout.then(() => {\r\n\t\t\t\tnode.slow = true;\r\n\t\t\t\tthis._onDidChangeNodeSlowState.fire(node);\r\n\t\t\t}, _ => null);\r\n\r\n\t\t\tchildrenPromise = this.doGetChildren(node)\r\n\t\t\t\t.finally(() => slowTimeout.cancel());\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\tconst children = await childrenPromise;\r\n\t\t\treturn this.setChildren(node, children, recursive, viewStateContext);\r\n\t\t} catch (err) {\r\n\t\t\tif (node !== this.root && this.tree.hasElement(node)) {\r\n\t\t\t\tthis.tree.collapse(node);\r\n\t\t\t}\r\n\r\n\t\t\tif (isPromiseCanceledError(err)) {\r\n\t\t\t\treturn [];\r\n\t\t\t}\r\n\r\n\t\t\tthrow err;\r\n\t\t} finally {\r\n\t\t\tif (node.slow) {\r\n\t\t\t\tnode.slow = false;\r\n\t\t\t\tthis._onDidChangeNodeSlowState.fire(node);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate doGetChildren(node: IAsyncDataTreeNode): Promise> {\r\n\t\tlet result = this.refreshPromises.get(node);\r\n\r\n\t\tif (result) {\r\n\t\t\treturn result;\r\n\t\t}\r\n\r\n\t\tresult = createCancelablePromise(async () => {\r\n\t\t\tconst children = await this.dataSource.getChildren(node.element!);\r\n\t\t\treturn this.processChildren(children);\r\n\t\t});\r\n\r\n\t\tthis.refreshPromises.set(node, result);\r\n\r\n\t\treturn result.finally(() => { this.refreshPromises.delete(node); });\r\n\t}\r\n\r\n\tprivate _onDidChangeCollapseState({ node, deep }: ICollapseStateChangeEvent | null, any>): void {\r\n\t\tif (node.element === null) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!node.collapsed && node.element.stale) {\r\n\t\t\tif (deep) {\r\n\t\t\t\tthis.collapse(node.element.element as T);\r\n\t\t\t} else {\r\n\t\t\t\tthis.refreshAndRenderNode(node.element, false)\r\n\t\t\t\t\t.catch(onUnexpectedError);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate setChildren(node: IAsyncDataTreeNode, childrenElementsIterable: Iterable, recursive: boolean, viewStateContext?: IAsyncDataTreeViewStateContext): IAsyncDataTreeNode[] {\r\n\t\tconst childrenElements = [...childrenElementsIterable];\r\n\r\n\t\t// perf: if the node was and still is a leaf, avoid all this hassle\r\n\t\tif (node.children.length === 0 && childrenElements.length === 0) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tconst nodesToForget = new Map>();\r\n\t\tconst childrenTreeNodesById = new Map, collapsed: boolean }>();\r\n\r\n\t\tfor (const child of node.children) {\r\n\t\t\tnodesToForget.set(child.element as T, child);\r\n\r\n\t\t\tif (this.identityProvider) {\r\n\t\t\t\tconst collapsed = this.tree.isCollapsed(child);\r\n\t\t\t\tchildrenTreeNodesById.set(child.id!, { node: child, collapsed });\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst childrenToRefresh: IAsyncDataTreeNode[] = [];\r\n\r\n\t\tconst children = childrenElements.map>(element => {\r\n\t\t\tconst hasChildren = !!this.dataSource.hasChildren(element);\r\n\r\n\t\t\tif (!this.identityProvider) {\r\n\t\t\t\tconst asyncDataTreeNode = createAsyncDataTreeNode({ element, parent: node, hasChildren });\r\n\r\n\t\t\t\tif (hasChildren && this.collapseByDefault && !this.collapseByDefault(element)) {\r\n\t\t\t\t\tasyncDataTreeNode.collapsedByDefault = false;\r\n\t\t\t\t\tchildrenToRefresh.push(asyncDataTreeNode);\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn asyncDataTreeNode;\r\n\t\t\t}\r\n\r\n\t\t\tconst id = this.identityProvider.getId(element).toString();\r\n\t\t\tconst result = childrenTreeNodesById.get(id);\r\n\r\n\t\t\tif (result) {\r\n\t\t\t\tconst asyncDataTreeNode = result.node;\r\n\r\n\t\t\t\tnodesToForget.delete(asyncDataTreeNode.element as T);\r\n\t\t\t\tthis.nodes.delete(asyncDataTreeNode.element as T);\r\n\t\t\t\tthis.nodes.set(element, asyncDataTreeNode);\r\n\r\n\t\t\t\tasyncDataTreeNode.element = element;\r\n\t\t\t\tasyncDataTreeNode.hasChildren = hasChildren;\r\n\r\n\t\t\t\tif (recursive) {\r\n\t\t\t\t\tif (result.collapsed) {\r\n\t\t\t\t\t\tasyncDataTreeNode.children.forEach(node => dfs(node, node => this.nodes.delete(node.element as T)));\r\n\t\t\t\t\t\tasyncDataTreeNode.children.splice(0, asyncDataTreeNode.children.length);\r\n\t\t\t\t\t\tasyncDataTreeNode.stale = true;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tchildrenToRefresh.push(asyncDataTreeNode);\r\n\t\t\t\t\t}\r\n\t\t\t\t} else if (hasChildren && this.collapseByDefault && !this.collapseByDefault(element)) {\r\n\t\t\t\t\tasyncDataTreeNode.collapsedByDefault = false;\r\n\t\t\t\t\tchildrenToRefresh.push(asyncDataTreeNode);\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn asyncDataTreeNode;\r\n\t\t\t}\r\n\r\n\t\t\tconst childAsyncDataTreeNode = createAsyncDataTreeNode({ element, parent: node, id, hasChildren });\r\n\r\n\t\t\tif (viewStateContext && viewStateContext.viewState.focus && viewStateContext.viewState.focus.indexOf(id) > -1) {\r\n\t\t\t\tviewStateContext.focus.push(childAsyncDataTreeNode);\r\n\t\t\t}\r\n\r\n\t\t\tif (viewStateContext && viewStateContext.viewState.selection && viewStateContext.viewState.selection.indexOf(id) > -1) {\r\n\t\t\t\tviewStateContext.selection.push(childAsyncDataTreeNode);\r\n\t\t\t}\r\n\r\n\t\t\tif (viewStateContext && viewStateContext.viewState.expanded && viewStateContext.viewState.expanded.indexOf(id) > -1) {\r\n\t\t\t\tchildrenToRefresh.push(childAsyncDataTreeNode);\r\n\t\t\t} else if (hasChildren && this.collapseByDefault && !this.collapseByDefault(element)) {\r\n\t\t\t\tchildAsyncDataTreeNode.collapsedByDefault = false;\r\n\t\t\t\tchildrenToRefresh.push(childAsyncDataTreeNode);\r\n\t\t\t}\r\n\r\n\t\t\treturn childAsyncDataTreeNode;\r\n\t\t});\r\n\r\n\t\tfor (const node of nodesToForget.values()) {\r\n\t\t\tdfs(node, node => this.nodes.delete(node.element as T));\r\n\t\t}\r\n\r\n\t\tfor (const child of children) {\r\n\t\t\tthis.nodes.set(child.element as T, child);\r\n\t\t}\r\n\r\n\t\tnode.children.splice(0, node.children.length, ...children);\r\n\r\n\t\t// TODO@joao this doesn't take filter into account\r\n\t\tif (node !== this.root && this.autoExpandSingleChildren && children.length === 1 && childrenToRefresh.length === 0) {\r\n\t\t\tchildren[0].collapsedByDefault = false;\r\n\t\t\tchildrenToRefresh.push(children[0]);\r\n\t\t}\r\n\r\n\t\treturn childrenToRefresh;\r\n\t}\r\n\r\n\tprotected render(node: IAsyncDataTreeNode, viewStateContext?: IAsyncDataTreeViewStateContext, options?: IAsyncDataTreeUpdateChildrenOptions): void {\r\n\t\tconst children = node.children.map(node => this.asTreeElement(node, viewStateContext));\r\n\t\tconst objectTreeOptions: IObjectTreeSetChildrenOptions> | undefined = options && {\r\n\t\t\t...options,\r\n\t\t\tdiffIdentityProvider: options!.diffIdentityProvider && {\r\n\t\t\t\tgetId(node: IAsyncDataTreeNode): { toString(): string; } {\r\n\t\t\t\t\treturn options!.diffIdentityProvider!.getId(node.element as T);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tthis.tree.setChildren(node === this.root ? null : node, children, objectTreeOptions);\r\n\r\n\t\tif (node !== this.root) {\r\n\t\t\tthis.tree.setCollapsible(node, node.hasChildren);\r\n\t\t}\r\n\r\n\t\tthis._onDidRender.fire();\r\n\t}\r\n\r\n\tprotected asTreeElement(node: IAsyncDataTreeNode, viewStateContext?: IAsyncDataTreeViewStateContext): ITreeElement> {\r\n\t\tif (node.stale) {\r\n\t\t\treturn {\r\n\t\t\t\telement: node,\r\n\t\t\t\tcollapsible: node.hasChildren,\r\n\t\t\t\tcollapsed: true\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tlet collapsed: boolean | undefined;\r\n\r\n\t\tif (viewStateContext && viewStateContext.viewState.expanded && node.id && viewStateContext.viewState.expanded.indexOf(node.id) > -1) {\r\n\t\t\tcollapsed = false;\r\n\t\t} else {\r\n\t\t\tcollapsed = node.collapsedByDefault;\r\n\t\t}\r\n\r\n\t\tnode.collapsedByDefault = undefined;\r\n\r\n\t\treturn {\r\n\t\t\telement: node,\r\n\t\t\tchildren: node.hasChildren ? Iterable.map(node.children, child => this.asTreeElement(child, viewStateContext)) : [],\r\n\t\t\tcollapsible: node.hasChildren,\r\n\t\t\tcollapsed\r\n\t\t};\r\n\t}\r\n\r\n\tprotected processChildren(children: Iterable): Iterable {\r\n\t\tif (this.sorter) {\r\n\t\t\tchildren = [...children].sort(this.sorter.compare.bind(this.sorter));\r\n\t\t}\r\n\r\n\t\treturn children;\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis.disposables.dispose();\r\n\t}\r\n}\r\n\r\ntype CompressibleAsyncDataTreeNodeMapper = WeakMapper>, TFilterData>, ITreeNode, TFilterData>>;\r\n\r\nclass CompressibleAsyncDataTreeNodeWrapper implements ITreeNode, TFilterData> {\r\n\r\n\tget element(): ICompressedTreeNode {\r\n\t\treturn {\r\n\t\t\telements: this.node.element.elements.map(e => e.element),\r\n\t\t\tincompressible: this.node.element.incompressible\r\n\t\t};\r\n\t}\r\n\r\n\tget children(): ITreeNode, TFilterData>[] { return this.node.children.map(node => new CompressibleAsyncDataTreeNodeWrapper(node)); }\r\n\tget depth(): number { return this.node.depth; }\r\n\tget visibleChildrenCount(): number { return this.node.visibleChildrenCount; }\r\n\tget visibleChildIndex(): number { return this.node.visibleChildIndex; }\r\n\tget collapsible(): boolean { return this.node.collapsible; }\r\n\tget collapsed(): boolean { return this.node.collapsed; }\r\n\tget visible(): boolean { return this.node.visible; }\r\n\tget filterData(): TFilterData | undefined { return this.node.filterData; }\r\n\r\n\tconstructor(private node: ITreeNode>, TFilterData>) { }\r\n}\r\n\r\nclass CompressibleAsyncDataTreeRenderer implements ICompressibleTreeRenderer, TFilterData, IDataTreeListTemplateData> {\r\n\r\n\treadonly templateId: string;\r\n\tprivate renderedNodes = new Map, IDataTreeListTemplateData>();\r\n\tprivate disposables: IDisposable[] = [];\r\n\r\n\tconstructor(\r\n\t\tprotected renderer: ICompressibleTreeRenderer,\r\n\t\tprotected nodeMapper: AsyncDataTreeNodeMapper,\r\n\t\tprivate compressibleNodeMapperProvider: () => CompressibleAsyncDataTreeNodeMapper,\r\n\t\treadonly onDidChangeTwistieState: Event>\r\n\t) {\r\n\t\tthis.templateId = renderer.templateId;\r\n\t}\r\n\r\n\trenderTemplate(container: HTMLElement): IDataTreeListTemplateData {\r\n\t\tconst templateData = this.renderer.renderTemplate(container);\r\n\t\treturn { templateData };\r\n\t}\r\n\r\n\trenderElement(node: ITreeNode, TFilterData>, index: number, templateData: IDataTreeListTemplateData, height: number | undefined): void {\r\n\t\tthis.renderer.renderElement(this.nodeMapper.map(node) as ITreeNode, index, templateData.templateData, height);\r\n\t}\r\n\r\n\trenderCompressedElements(node: ITreeNode>, TFilterData>, index: number, templateData: IDataTreeListTemplateData, height: number | undefined): void {\r\n\t\tthis.renderer.renderCompressedElements(this.compressibleNodeMapperProvider().map(node) as ITreeNode, TFilterData>, index, templateData.templateData, height);\r\n\t}\r\n\r\n\trenderTwistie(element: IAsyncDataTreeNode, twistieElement: HTMLElement): boolean {\r\n\t\tif (element.slow) {\r\n\t\t\ttwistieElement.classList.add(...treeItemLoadingIcon.classNamesArray);\r\n\t\t\treturn true;\r\n\t\t} else {\r\n\t\t\ttwistieElement.classList.remove(...treeItemLoadingIcon.classNamesArray);\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n\r\n\tdisposeElement(node: ITreeNode, TFilterData>, index: number, templateData: IDataTreeListTemplateData, height: number | undefined): void {\r\n\t\tif (this.renderer.disposeElement) {\r\n\t\t\tthis.renderer.disposeElement(this.nodeMapper.map(node) as ITreeNode, index, templateData.templateData, height);\r\n\t\t}\r\n\t}\r\n\r\n\tdisposeCompressedElements(node: ITreeNode>, TFilterData>, index: number, templateData: IDataTreeListTemplateData, height: number | undefined): void {\r\n\t\tif (this.renderer.disposeCompressedElements) {\r\n\t\t\tthis.renderer.disposeCompressedElements(this.compressibleNodeMapperProvider().map(node) as ITreeNode, TFilterData>, index, templateData.templateData, height);\r\n\t\t}\r\n\t}\r\n\r\n\tdisposeTemplate(templateData: IDataTreeListTemplateData): void {\r\n\t\tthis.renderer.disposeTemplate(templateData.templateData);\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis.renderedNodes.clear();\r\n\t\tthis.disposables = dispose(this.disposables);\r\n\t}\r\n}\r\n\r\nexport interface ITreeCompressionDelegate {\r\n\tisIncompressible(element: T): boolean;\r\n}\r\n\r\nfunction asCompressibleObjectTreeOptions(options?: ICompressibleAsyncDataTreeOptions): ICompressibleObjectTreeOptions, TFilterData> | undefined {\r\n\tconst objectTreeOptions = options && asObjectTreeOptions(options);\r\n\r\n\treturn objectTreeOptions && {\r\n\t\t...objectTreeOptions,\r\n\t\tkeyboardNavigationLabelProvider: objectTreeOptions.keyboardNavigationLabelProvider && {\r\n\t\t\t...objectTreeOptions.keyboardNavigationLabelProvider,\r\n\t\t\tgetCompressedNodeKeyboardNavigationLabel(els) {\r\n\t\t\t\treturn options!.keyboardNavigationLabelProvider!.getCompressedNodeKeyboardNavigationLabel(els.map(e => e.element as T));\r\n\t\t\t}\r\n\t\t}\r\n\t};\r\n}\r\n\r\nexport interface ICompressibleAsyncDataTreeOptions extends IAsyncDataTreeOptions {\r\n\treadonly keyboardNavigationLabelProvider?: ICompressibleKeyboardNavigationLabelProvider;\r\n}\r\n\r\nexport interface ICompressibleAsyncDataTreeOptionsUpdate extends IAsyncDataTreeOptionsUpdate {\r\n}\r\n\r\nexport class CompressibleAsyncDataTree extends AsyncDataTree {\r\n\r\n\tprotected readonly tree!: CompressibleObjectTree, TFilterData>;\r\n\tprotected readonly compressibleNodeMapper: CompressibleAsyncDataTreeNodeMapper = new WeakMapper(node => new CompressibleAsyncDataTreeNodeWrapper(node));\r\n\tprivate filter?: ITreeFilter;\r\n\r\n\tconstructor(\r\n\t\tuser: string,\r\n\t\tcontainer: HTMLElement,\r\n\t\tvirtualDelegate: IListVirtualDelegate,\r\n\t\tprivate compressionDelegate: ITreeCompressionDelegate,\r\n\t\trenderers: ICompressibleTreeRenderer[],\r\n\t\tdataSource: IAsyncDataSource,\r\n\t\toptions: ICompressibleAsyncDataTreeOptions = {}\r\n\t) {\r\n\t\tsuper(user, container, virtualDelegate, renderers, dataSource, options);\r\n\t\tthis.filter = options.filter;\r\n\t}\r\n\r\n\tprotected createTree(\r\n\t\tuser: string,\r\n\t\tcontainer: HTMLElement,\r\n\t\tdelegate: IListVirtualDelegate,\r\n\t\trenderers: ICompressibleTreeRenderer[],\r\n\t\toptions: ICompressibleAsyncDataTreeOptions\r\n\t): ObjectTree, TFilterData> {\r\n\t\tconst objectTreeDelegate = new ComposedTreeDelegate>(delegate);\r\n\t\tconst objectTreeRenderers = renderers.map(r => new CompressibleAsyncDataTreeRenderer(r, this.nodeMapper, () => this.compressibleNodeMapper, this._onDidChangeNodeSlowState.event));\r\n\t\tconst objectTreeOptions = asCompressibleObjectTreeOptions(options) || {};\r\n\r\n\t\treturn new CompressibleObjectTree(user, container, objectTreeDelegate, objectTreeRenderers, objectTreeOptions);\r\n\t}\r\n\r\n\tprotected asTreeElement(node: IAsyncDataTreeNode, viewStateContext?: IAsyncDataTreeViewStateContext): ICompressedTreeElement> {\r\n\t\treturn {\r\n\t\t\tincompressible: this.compressionDelegate.isIncompressible(node.element as T),\r\n\t\t\t...super.asTreeElement(node, viewStateContext)\r\n\t\t};\r\n\t}\r\n\r\n\tupdateOptions(options: ICompressibleAsyncDataTreeOptionsUpdate = {}): void {\r\n\t\tthis.tree.updateOptions(options);\r\n\t}\r\n\r\n\tprotected render(node: IAsyncDataTreeNode, viewStateContext?: IAsyncDataTreeViewStateContext): void {\r\n\t\tif (!this.identityProvider) {\r\n\t\t\treturn super.render(node, viewStateContext);\r\n\t\t}\r\n\r\n\t\t// Preserve traits across compressions. Hacky but does the trick.\r\n\t\t// This is hard to fix properly since it requires rewriting the traits\r\n\t\t// across trees and lists. Let's just keep it this way for now.\r\n\t\tconst getId = (element: T) => this.identityProvider!.getId(element).toString();\r\n\t\tconst getUncompressedIds = (nodes: IAsyncDataTreeNode[]): Set => {\r\n\t\t\tconst result = new Set();\r\n\r\n\t\t\tfor (const node of nodes) {\r\n\t\t\t\tconst compressedNode = this.tree.getCompressedTreeNode(node === this.root ? null : node);\r\n\r\n\t\t\t\tif (!compressedNode.element) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfor (const node of compressedNode.element.elements) {\r\n\t\t\t\t\tresult.add(getId(node.element as T));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn result;\r\n\t\t};\r\n\r\n\t\tconst oldSelection = getUncompressedIds(this.tree.getSelection() as IAsyncDataTreeNode[]);\r\n\t\tconst oldFocus = getUncompressedIds(this.tree.getFocus() as IAsyncDataTreeNode[]);\r\n\r\n\t\tsuper.render(node, viewStateContext);\r\n\r\n\t\tconst selection = this.getSelection();\r\n\t\tlet didChangeSelection = false;\r\n\r\n\t\tconst focus = this.getFocus();\r\n\t\tlet didChangeFocus = false;\r\n\r\n\t\tconst visit = (node: ITreeNode> | null, TFilterData>) => {\r\n\t\t\tconst compressedNode = node.element;\r\n\r\n\t\t\tif (compressedNode) {\r\n\t\t\t\tfor (let i = 0; i < compressedNode.elements.length; i++) {\r\n\t\t\t\t\tconst id = getId(compressedNode.elements[i].element as T);\r\n\t\t\t\t\tconst element = compressedNode.elements[compressedNode.elements.length - 1].element as T;\r\n\r\n\t\t\t\t\t// github.com/microsoft/vscode/issues/85938\r\n\t\t\t\t\tif (oldSelection.has(id) && selection.indexOf(element) === -1) {\r\n\t\t\t\t\t\tselection.push(element);\r\n\t\t\t\t\t\tdidChangeSelection = true;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (oldFocus.has(id) && focus.indexOf(element) === -1) {\r\n\t\t\t\t\t\tfocus.push(element);\r\n\t\t\t\t\t\tdidChangeFocus = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tnode.children.forEach(visit);\r\n\t\t};\r\n\r\n\t\tvisit(this.tree.getCompressedTreeNode(node === this.root ? null : node));\r\n\r\n\t\tif (didChangeSelection) {\r\n\t\t\tthis.setSelection(selection);\r\n\t\t}\r\n\r\n\t\tif (didChangeFocus) {\r\n\t\t\tthis.setFocus(focus);\r\n\t\t}\r\n\t}\r\n\r\n\t// For compressed async data trees, `TreeVisibility.Recurse` doesn't currently work\r\n\t// and we have to filter everything beforehand\r\n\t// Related to #85193 and #85835\r\n\tprotected processChildren(children: Iterable): Iterable {\r\n\t\tif (this.filter) {\r\n\t\t\tchildren = Iterable.filter(children, e => {\r\n\t\t\t\tconst result = this.filter!.filter(e, TreeVisibility.Visible);\r\n\t\t\t\tconst visibility = getVisibility(result);\r\n\r\n\t\t\t\tif (visibility === TreeVisibility.Recurse) {\r\n\t\t\t\t\tthrow new Error('Recursive tree visibility not supported in async data compressed trees');\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn visibility === TreeVisibility.Visible;\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\treturn super.processChildren(children);\r\n\t}\r\n}\r\n\r\nfunction getVisibility(filterResult: TreeFilterResult): TreeVisibility {\r\n\tif (typeof filterResult === 'boolean') {\r\n\t\treturn filterResult ? TreeVisibility.Visible : TreeVisibility.Hidden;\r\n\t} else if (isFilterResult(filterResult)) {\r\n\t\treturn getVisibleState(filterResult.visibility);\r\n\t} else {\r\n\t\treturn getVisibleState(filterResult);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { IDisposable, Disposable } from 'vs/base/common/lifecycle';\r\nimport { Event, Emitter } from 'vs/base/common/event';\r\n\r\nexport interface ITelemetryData {\r\n\t[key: string]: any;\r\n}\r\n\r\nexport type WorkbenchActionExecutedClassification = {\r\n\tid: { classification: 'SystemMetaData', purpose: 'FeatureInsight'; };\r\n\tfrom: { classification: 'SystemMetaData', purpose: 'FeatureInsight'; };\r\n};\r\n\r\nexport type WorkbenchActionExecutedEvent = {\r\n\tid: string;\r\n\tfrom: string;\r\n};\r\n\r\nexport interface IAction extends IDisposable {\r\n\treadonly id: string;\r\n\tlabel: string;\r\n\ttooltip: string;\r\n\tclass: string | undefined;\r\n\tenabled: boolean;\r\n\tchecked: boolean;\r\n\trun(event?: any): Promise;\r\n}\r\n\r\nexport interface IActionRunner extends IDisposable {\r\n\trun(action: IAction, context?: any): Promise;\r\n\treadonly onDidRun: Event;\r\n\treadonly onBeforeRun: Event;\r\n}\r\n\r\nexport interface IActionViewItem extends IDisposable {\r\n\tactionRunner: IActionRunner;\r\n\tsetActionContext(context: any): void;\r\n\trender(element: any /* HTMLElement */): void;\r\n\tisEnabled(): boolean;\r\n\tfocus(fromRight?: boolean): void; // TODO@isidorn what is this?\r\n\tblur(): void;\r\n}\r\n\r\nexport interface IActionViewItemProvider {\r\n\t(action: IAction): IActionViewItem | undefined;\r\n}\r\n\r\nexport interface IActionChangeEvent {\r\n\treadonly label?: string;\r\n\treadonly tooltip?: string;\r\n\treadonly class?: string;\r\n\treadonly enabled?: boolean;\r\n\treadonly checked?: boolean;\r\n}\r\n\r\nexport class Action extends Disposable implements IAction {\r\n\r\n\tprotected _onDidChange = this._register(new Emitter());\r\n\treadonly onDidChange = this._onDidChange.event;\r\n\r\n\tprotected readonly _id: string;\r\n\tprotected _label: string;\r\n\tprotected _tooltip: string | undefined;\r\n\tprotected _cssClass: string | undefined;\r\n\tprotected _enabled: boolean = true;\r\n\tprotected _checked: boolean = false;\r\n\tprotected readonly _actionCallback?: (event?: any) => Promise;\r\n\r\n\tconstructor(id: string, label: string = '', cssClass: string = '', enabled: boolean = true, actionCallback?: (event?: any) => Promise) {\r\n\t\tsuper();\r\n\t\tthis._id = id;\r\n\t\tthis._label = label;\r\n\t\tthis._cssClass = cssClass;\r\n\t\tthis._enabled = enabled;\r\n\t\tthis._actionCallback = actionCallback;\r\n\t}\r\n\r\n\tget id(): string {\r\n\t\treturn this._id;\r\n\t}\r\n\r\n\tget label(): string {\r\n\t\treturn this._label;\r\n\t}\r\n\r\n\tset label(value: string) {\r\n\t\tthis._setLabel(value);\r\n\t}\r\n\r\n\tprivate _setLabel(value: string): void {\r\n\t\tif (this._label !== value) {\r\n\t\t\tthis._label = value;\r\n\t\t\tthis._onDidChange.fire({ label: value });\r\n\t\t}\r\n\t}\r\n\r\n\tget tooltip(): string {\r\n\t\treturn this._tooltip || '';\r\n\t}\r\n\r\n\tset tooltip(value: string) {\r\n\t\tthis._setTooltip(value);\r\n\t}\r\n\r\n\tprotected _setTooltip(value: string): void {\r\n\t\tif (this._tooltip !== value) {\r\n\t\t\tthis._tooltip = value;\r\n\t\t\tthis._onDidChange.fire({ tooltip: value });\r\n\t\t}\r\n\t}\r\n\r\n\tget class(): string | undefined {\r\n\t\treturn this._cssClass;\r\n\t}\r\n\r\n\tset class(value: string | undefined) {\r\n\t\tthis._setClass(value);\r\n\t}\r\n\r\n\tprotected _setClass(value: string | undefined): void {\r\n\t\tif (this._cssClass !== value) {\r\n\t\t\tthis._cssClass = value;\r\n\t\t\tthis._onDidChange.fire({ class: value });\r\n\t\t}\r\n\t}\r\n\r\n\tget enabled(): boolean {\r\n\t\treturn this._enabled;\r\n\t}\r\n\r\n\tset enabled(value: boolean) {\r\n\t\tthis._setEnabled(value);\r\n\t}\r\n\r\n\tprotected _setEnabled(value: boolean): void {\r\n\t\tif (this._enabled !== value) {\r\n\t\t\tthis._enabled = value;\r\n\t\t\tthis._onDidChange.fire({ enabled: value });\r\n\t\t}\r\n\t}\r\n\r\n\tget checked(): boolean {\r\n\t\treturn this._checked;\r\n\t}\r\n\r\n\tset checked(value: boolean) {\r\n\t\tthis._setChecked(value);\r\n\t}\r\n\r\n\tprotected _setChecked(value: boolean): void {\r\n\t\tif (this._checked !== value) {\r\n\t\t\tthis._checked = value;\r\n\t\t\tthis._onDidChange.fire({ checked: value });\r\n\t\t}\r\n\t}\r\n\r\n\trun(event?: any, _data?: ITelemetryData): Promise {\r\n\t\tif (this._actionCallback) {\r\n\t\t\treturn this._actionCallback(event);\r\n\t\t}\r\n\r\n\t\treturn Promise.resolve(true);\r\n\t}\r\n}\r\n\r\nexport interface IRunEvent {\r\n\treadonly action: IAction;\r\n\treadonly result?: any;\r\n\treadonly error?: any;\r\n}\r\n\r\nexport class ActionRunner extends Disposable implements IActionRunner {\r\n\r\n\tprivate _onBeforeRun = this._register(new Emitter());\r\n\treadonly onBeforeRun = this._onBeforeRun.event;\r\n\r\n\tprivate _onDidRun = this._register(new Emitter());\r\n\treadonly onDidRun = this._onDidRun.event;\r\n\r\n\tasync run(action: IAction, context?: any): Promise {\r\n\t\tif (!action.enabled) {\r\n\t\t\treturn Promise.resolve(null);\r\n\t\t}\r\n\r\n\t\tthis._onBeforeRun.fire({ action: action });\r\n\r\n\t\ttry {\r\n\t\t\tconst result = await this.runAction(action, context);\r\n\t\t\tthis._onDidRun.fire({ action: action, result: result });\r\n\t\t} catch (error) {\r\n\t\t\tthis._onDidRun.fire({ action: action, error: error });\r\n\t\t}\r\n\t}\r\n\r\n\tprotected runAction(action: IAction, context?: any): Promise {\r\n\t\tconst res = context ? action.run(context) : action.run();\r\n\t\treturn Promise.resolve(res);\r\n\t}\r\n}\r\n\r\nexport class Separator extends Action {\r\n\r\n\tstatic readonly ID = 'vs.actions.separator';\r\n\r\n\tconstructor(label?: string) {\r\n\t\tsuper(Separator.ID, label, label ? 'separator text' : 'separator');\r\n\t\tthis.checked = false;\r\n\t\tthis.enabled = false;\r\n\t}\r\n}\r\n\r\nexport class SubmenuAction implements IAction {\r\n\r\n\treadonly id: string;\r\n\treadonly label: string;\r\n\treadonly class: string | undefined;\r\n\treadonly tooltip: string = '';\r\n\treadonly enabled: boolean = true;\r\n\treadonly checked: boolean = false;\r\n\r\n\tprivate readonly _actions: readonly IAction[];\r\n\r\n\tconstructor(id: string, label: string, actions: readonly IAction[], cssClass?: string) {\r\n\t\tthis.id = id;\r\n\t\tthis.label = label;\r\n\t\tthis.class = cssClass;\r\n\t\tthis._actions = actions;\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\t// there is NOTHING to dispose and the SubmenuAction should\r\n\t\t// never have anything to dispose as it is a convenience type\r\n\t\t// to bridge into the rendering world.\r\n\t}\r\n\r\n\tget actions(): readonly IAction[] {\r\n\t\treturn this._actions;\r\n\t}\r\n\r\n\tasync run(): Promise { }\r\n}\r\n\r\nexport class EmptySubmenuAction extends Action {\r\n\tstatic readonly ID = 'vs.actions.empty';\r\n\tconstructor() {\r\n\t\tsuper(EmptySubmenuAction.ID, nls.localize('submenu.empty', '(empty)'), undefined, false);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./actionbar';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport * as nls from 'vs/nls';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { IAction, IActionRunner, Action, IActionChangeEvent, ActionRunner, Separator, IActionViewItem } from 'vs/base/common/actions';\r\nimport * as types from 'vs/base/common/types';\r\nimport { EventType as TouchEventType, Gesture } from 'vs/base/browser/touch';\r\nimport { DataTransfers } from 'vs/base/browser/dnd';\r\nimport { isFirefox } from 'vs/base/browser/browser';\r\nimport { $, addDisposableListener, append, EventHelper, EventLike, EventType, removeTabIndexAndUpdateFocus } from 'vs/base/browser/dom';\r\n\r\nexport interface IBaseActionViewItemOptions {\r\n\tdraggable?: boolean;\r\n\tisMenu?: boolean;\r\n\tuseEventAsContext?: boolean;\r\n}\r\n\r\nexport class BaseActionViewItem extends Disposable implements IActionViewItem {\r\n\r\n\telement: HTMLElement | undefined;\r\n\r\n\t_context: any;\r\n\t_action: IAction;\r\n\r\n\tprivate _actionRunner: IActionRunner | undefined;\r\n\r\n\tconstructor(context: any, action: IAction, protected options: IBaseActionViewItemOptions = {}) {\r\n\t\tsuper();\r\n\r\n\t\tthis._context = context || this;\r\n\t\tthis._action = action;\r\n\r\n\t\tif (action instanceof Action) {\r\n\t\t\tthis._register(action.onDidChange(event => {\r\n\t\t\t\tif (!this.element) {\r\n\t\t\t\t\t// we have not been rendered yet, so there\r\n\t\t\t\t\t// is no point in updating the UI\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis.handleActionChangeEvent(event);\r\n\t\t\t}));\r\n\t\t}\r\n\t}\r\n\r\n\tprivate handleActionChangeEvent(event: IActionChangeEvent): void {\r\n\t\tif (event.enabled !== undefined) {\r\n\t\t\tthis.updateEnabled();\r\n\t\t}\r\n\r\n\t\tif (event.checked !== undefined) {\r\n\t\t\tthis.updateChecked();\r\n\t\t}\r\n\r\n\t\tif (event.class !== undefined) {\r\n\t\t\tthis.updateClass();\r\n\t\t}\r\n\r\n\t\tif (event.label !== undefined) {\r\n\t\t\tthis.updateLabel();\r\n\t\t\tthis.updateTooltip();\r\n\t\t}\r\n\r\n\t\tif (event.tooltip !== undefined) {\r\n\t\t\tthis.updateTooltip();\r\n\t\t}\r\n\t}\r\n\r\n\tget actionRunner(): IActionRunner {\r\n\t\tif (!this._actionRunner) {\r\n\t\t\tthis._actionRunner = this._register(new ActionRunner());\r\n\t\t}\r\n\r\n\t\treturn this._actionRunner;\r\n\t}\r\n\r\n\tset actionRunner(actionRunner: IActionRunner) {\r\n\t\tthis._actionRunner = actionRunner;\r\n\t}\r\n\r\n\tgetAction(): IAction {\r\n\t\treturn this._action;\r\n\t}\r\n\r\n\tisEnabled(): boolean {\r\n\t\treturn this._action.enabled;\r\n\t}\r\n\r\n\tsetActionContext(newContext: unknown): void {\r\n\t\tthis._context = newContext;\r\n\t}\r\n\r\n\trender(container: HTMLElement): void {\r\n\t\tconst element = this.element = container;\r\n\t\tthis._register(Gesture.addTarget(container));\r\n\r\n\t\tconst enableDragging = this.options && this.options.draggable;\r\n\t\tif (enableDragging) {\r\n\t\t\tcontainer.draggable = true;\r\n\r\n\t\t\tif (isFirefox) {\r\n\t\t\t\t// Firefox: requires to set a text data transfer to get going\r\n\t\t\t\tthis._register(addDisposableListener(container, EventType.DRAG_START, e => e.dataTransfer?.setData(DataTransfers.TEXT, this._action.label)));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._register(addDisposableListener(element, TouchEventType.Tap, e => this.onClick(e)));\r\n\r\n\t\tthis._register(addDisposableListener(element, EventType.MOUSE_DOWN, e => {\r\n\t\t\tif (!enableDragging) {\r\n\t\t\t\tEventHelper.stop(e, true); // do not run when dragging is on because that would disable it\r\n\t\t\t}\r\n\r\n\t\t\tif (this._action.enabled && e.button === 0) {\r\n\t\t\t\telement.classList.add('active');\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tif (platform.isMacintosh) {\r\n\t\t\t// macOS: allow to trigger the button when holding Ctrl+key and pressing the\r\n\t\t\t// main mouse button. This is for scenarios where e.g. some interaction forces\r\n\t\t\t// the Ctrl+key to be pressed and hold but the user still wants to interact\r\n\t\t\t// with the actions (for example quick access in quick navigation mode).\r\n\t\t\tthis._register(addDisposableListener(element, EventType.CONTEXT_MENU, e => {\r\n\t\t\t\tif (e.button === 0 && e.ctrlKey === true) {\r\n\t\t\t\t\tthis.onClick(e);\r\n\t\t\t\t}\r\n\t\t\t}));\r\n\t\t}\r\n\r\n\t\tthis._register(addDisposableListener(element, EventType.CLICK, e => {\r\n\t\t\tEventHelper.stop(e, true);\r\n\r\n\t\t\t// menus do not use the click event\r\n\t\t\tif (!(this.options && this.options.isMenu)) {\r\n\t\t\t\tplatform.setImmediate(() => this.onClick(e));\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._register(addDisposableListener(element, EventType.DBLCLICK, e => {\r\n\t\t\tEventHelper.stop(e, true);\r\n\t\t}));\r\n\r\n\t\t[EventType.MOUSE_UP, EventType.MOUSE_OUT].forEach(event => {\r\n\t\t\tthis._register(addDisposableListener(element, event, e => {\r\n\t\t\t\tEventHelper.stop(e);\r\n\t\t\t\telement.classList.remove('active');\r\n\t\t\t}));\r\n\t\t});\r\n\t}\r\n\r\n\tonClick(event: EventLike): void {\r\n\t\tEventHelper.stop(event, true);\r\n\r\n\t\tconst context = types.isUndefinedOrNull(this._context) ? this.options?.useEventAsContext ? event : undefined : this._context;\r\n\t\tthis.actionRunner.run(this._action, context);\r\n\t}\r\n\r\n\tfocus(): void {\r\n\t\tif (this.element) {\r\n\t\t\tthis.element.focus();\r\n\t\t\tthis.element.classList.add('focused');\r\n\t\t}\r\n\t}\r\n\r\n\tblur(): void {\r\n\t\tif (this.element) {\r\n\t\t\tthis.element.blur();\r\n\t\t\tthis.element.classList.remove('focused');\r\n\t\t}\r\n\t}\r\n\r\n\tprotected updateEnabled(): void {\r\n\t\t// implement in subclass\r\n\t}\r\n\r\n\tprotected updateLabel(): void {\r\n\t\t// implement in subclass\r\n\t}\r\n\r\n\tprotected updateTooltip(): void {\r\n\t\t// implement in subclass\r\n\t}\r\n\r\n\tprotected updateClass(): void {\r\n\t\t// implement in subclass\r\n\t}\r\n\r\n\tprotected updateChecked(): void {\r\n\t\t// implement in subclass\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tif (this.element) {\r\n\t\t\tthis.element.remove();\r\n\t\t\tthis.element = undefined;\r\n\t\t}\r\n\r\n\t\tsuper.dispose();\r\n\t}\r\n}\r\n\r\nexport interface IActionViewItemOptions extends IBaseActionViewItemOptions {\r\n\ticon?: boolean;\r\n\tlabel?: boolean;\r\n\tkeybinding?: string | null;\r\n}\r\n\r\nexport class ActionViewItem extends BaseActionViewItem {\r\n\r\n\tprotected label: HTMLElement | undefined;\r\n\tprotected options: IActionViewItemOptions;\r\n\r\n\tprivate cssClass?: string;\r\n\r\n\tconstructor(context: unknown, action: IAction, options: IActionViewItemOptions = {}) {\r\n\t\tsuper(context, action, options);\r\n\r\n\t\tthis.options = options;\r\n\t\tthis.options.icon = options.icon !== undefined ? options.icon : false;\r\n\t\tthis.options.label = options.label !== undefined ? options.label : true;\r\n\t\tthis.cssClass = '';\r\n\t}\r\n\r\n\trender(container: HTMLElement): void {\r\n\t\tsuper.render(container);\r\n\r\n\t\tif (this.element) {\r\n\t\t\tthis.label = append(this.element, $('a.action-label'));\r\n\t\t}\r\n\r\n\t\tif (this.label) {\r\n\t\t\tif (this._action.id === Separator.ID) {\r\n\t\t\t\tthis.label.setAttribute('role', 'presentation'); // A separator is a presentation item\r\n\t\t\t} else {\r\n\t\t\t\tif (this.options.isMenu) {\r\n\t\t\t\t\tthis.label.setAttribute('role', 'menuitem');\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis.label.setAttribute('role', 'button');\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (this.options.label && this.options.keybinding && this.element) {\r\n\t\t\tappend(this.element, $('span.keybinding')).textContent = this.options.keybinding;\r\n\t\t}\r\n\r\n\t\tthis.updateClass();\r\n\t\tthis.updateLabel();\r\n\t\tthis.updateTooltip();\r\n\t\tthis.updateEnabled();\r\n\t\tthis.updateChecked();\r\n\t}\r\n\r\n\tfocus(): void {\r\n\t\tsuper.focus();\r\n\r\n\t\tif (this.label) {\r\n\t\t\tthis.label.focus();\r\n\t\t}\r\n\t}\r\n\r\n\tupdateLabel(): void {\r\n\t\tif (this.options.label && this.label) {\r\n\t\t\tthis.label.textContent = this.getAction().label;\r\n\t\t}\r\n\t}\r\n\r\n\tupdateTooltip(): void {\r\n\t\tlet title: string | null = null;\r\n\r\n\t\tif (this.getAction().tooltip) {\r\n\t\t\ttitle = this.getAction().tooltip;\r\n\r\n\t\t} else if (!this.options.label && this.getAction().label && this.options.icon) {\r\n\t\t\ttitle = this.getAction().label;\r\n\r\n\t\t\tif (this.options.keybinding) {\r\n\t\t\t\ttitle = nls.localize({ key: 'titleLabel', comment: ['action title', 'action keybinding'] }, \"{0} ({1})\", title, this.options.keybinding);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (title && this.label) {\r\n\t\t\tthis.label.title = title;\r\n\t\t}\r\n\t}\r\n\r\n\tupdateClass(): void {\r\n\t\tif (this.cssClass && this.label) {\r\n\t\t\tthis.label.classList.remove(...this.cssClass.split(' '));\r\n\t\t}\r\n\r\n\t\tif (this.options.icon) {\r\n\t\t\tthis.cssClass = this.getAction().class;\r\n\r\n\t\t\tif (this.label) {\r\n\t\t\t\tthis.label.classList.add('codicon');\r\n\t\t\t\tif (this.cssClass) {\r\n\t\t\t\t\tthis.label.classList.add(...this.cssClass.split(' '));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tthis.updateEnabled();\r\n\t\t} else {\r\n\t\t\tif (this.label) {\r\n\t\t\t\tthis.label.classList.remove('codicon');\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tupdateEnabled(): void {\r\n\t\tif (this.getAction().enabled) {\r\n\t\t\tif (this.label) {\r\n\t\t\t\tthis.label.removeAttribute('aria-disabled');\r\n\t\t\t\tthis.label.classList.remove('disabled');\r\n\t\t\t\tthis.label.tabIndex = 0;\r\n\t\t\t}\r\n\r\n\t\t\tif (this.element) {\r\n\t\t\t\tthis.element.classList.remove('disabled');\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tif (this.label) {\r\n\t\t\t\tthis.label.setAttribute('aria-disabled', 'true');\r\n\t\t\t\tthis.label.classList.add('disabled');\r\n\t\t\t\tremoveTabIndexAndUpdateFocus(this.label);\r\n\t\t\t}\r\n\r\n\t\t\tif (this.element) {\r\n\t\t\t\tthis.element.classList.add('disabled');\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tupdateChecked(): void {\r\n\t\tif (this.label) {\r\n\t\t\tif (this.getAction().checked) {\r\n\t\t\t\tthis.label.classList.add('checked');\r\n\t\t\t} else {\r\n\t\t\t\tthis.label.classList.remove('checked');\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./actionbar';\r\nimport { Disposable, dispose } from 'vs/base/common/lifecycle';\r\nimport { IAction, IActionRunner, ActionRunner, IRunEvent, IActionViewItem, IActionViewItemProvider } from 'vs/base/common/actions';\r\nimport * as DOM from 'vs/base/browser/dom';\r\nimport * as types from 'vs/base/common/types';\r\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { Emitter } from 'vs/base/common/event';\r\nimport { IActionViewItemOptions, ActionViewItem, BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';\r\n\r\nexport const enum ActionsOrientation {\r\n\tHORIZONTAL,\r\n\tHORIZONTAL_REVERSE,\r\n\tVERTICAL,\r\n\tVERTICAL_REVERSE,\r\n}\r\n\r\nexport interface ActionTrigger {\r\n\tkeys?: KeyCode[];\r\n\tkeyDown: boolean;\r\n}\r\n\r\nexport interface IActionBarOptions {\r\n\treadonly orientation?: ActionsOrientation;\r\n\treadonly context?: any;\r\n\treadonly actionViewItemProvider?: IActionViewItemProvider;\r\n\treadonly actionRunner?: IActionRunner;\r\n\treadonly ariaLabel?: string;\r\n\treadonly animated?: boolean;\r\n\treadonly triggerKeys?: ActionTrigger;\r\n\treadonly allowContextMenu?: boolean;\r\n\treadonly preventLoopNavigation?: boolean;\r\n\treadonly ignoreOrientationForPreviousAndNextKey?: boolean;\r\n}\r\n\r\nexport interface IActionOptions extends IActionViewItemOptions {\r\n\tindex?: number;\r\n}\r\n\r\nexport class ActionBar extends Disposable implements IActionRunner {\r\n\r\n\tprivate readonly options: IActionBarOptions;\r\n\r\n\tprivate _actionRunner: IActionRunner;\r\n\tprivate _context: unknown;\r\n\tprivate readonly _orientation: ActionsOrientation;\r\n\tprivate readonly _triggerKeys: {\r\n\t\tkeys: KeyCode[];\r\n\t\tkeyDown: boolean;\r\n\t};\r\n\tprivate _actionIds: string[];\r\n\r\n\t// View Items\r\n\tviewItems: IActionViewItem[];\r\n\tprotected focusedItem?: number;\r\n\tprivate focusTracker: DOM.IFocusTracker;\r\n\r\n\t// Trigger Key Tracking\r\n\tprivate triggerKeyDown: boolean = false;\r\n\r\n\t// Elements\r\n\tdomNode: HTMLElement;\r\n\tprotected actionsList: HTMLElement;\r\n\r\n\tprivate _onDidBlur = this._register(new Emitter());\r\n\treadonly onDidBlur = this._onDidBlur.event;\r\n\r\n\tprivate _onDidCancel = this._register(new Emitter({ onFirstListenerAdd: () => this.cancelHasListener = true }));\r\n\treadonly onDidCancel = this._onDidCancel.event;\r\n\tprivate cancelHasListener = false;\r\n\r\n\tprivate _onDidRun = this._register(new Emitter());\r\n\treadonly onDidRun = this._onDidRun.event;\r\n\r\n\tprivate _onBeforeRun = this._register(new Emitter());\r\n\treadonly onBeforeRun = this._onBeforeRun.event;\r\n\r\n\tconstructor(container: HTMLElement, options: IActionBarOptions = {}) {\r\n\t\tsuper();\r\n\r\n\t\tthis.options = options;\r\n\t\tthis._context = options.context ?? null;\r\n\t\tthis._orientation = this.options.orientation ?? ActionsOrientation.HORIZONTAL;\r\n\t\tthis._triggerKeys = {\r\n\t\t\tkeyDown: this.options.triggerKeys?.keyDown ?? false,\r\n\t\t\tkeys: this.options.triggerKeys?.keys ?? [KeyCode.Enter, KeyCode.Space]\r\n\t\t};\r\n\r\n\t\tif (this.options.actionRunner) {\r\n\t\t\tthis._actionRunner = this.options.actionRunner;\r\n\t\t} else {\r\n\t\t\tthis._actionRunner = new ActionRunner();\r\n\t\t\tthis._register(this._actionRunner);\r\n\t\t}\r\n\r\n\t\tthis._register(this._actionRunner.onDidRun(e => this._onDidRun.fire(e)));\r\n\t\tthis._register(this._actionRunner.onBeforeRun(e => this._onBeforeRun.fire(e)));\r\n\r\n\t\tthis._actionIds = [];\r\n\t\tthis.viewItems = [];\r\n\t\tthis.focusedItem = undefined;\r\n\r\n\t\tthis.domNode = document.createElement('div');\r\n\t\tthis.domNode.className = 'monaco-action-bar';\r\n\r\n\t\tif (options.animated !== false) {\r\n\t\t\tthis.domNode.classList.add('animated');\r\n\t\t}\r\n\r\n\t\tlet previousKeys: KeyCode[];\r\n\t\tlet nextKeys: KeyCode[];\r\n\r\n\t\tswitch (this._orientation) {\r\n\t\t\tcase ActionsOrientation.HORIZONTAL:\r\n\t\t\t\tpreviousKeys = this.options.ignoreOrientationForPreviousAndNextKey ? [KeyCode.LeftArrow, KeyCode.UpArrow] : [KeyCode.LeftArrow];\r\n\t\t\t\tnextKeys = this.options.ignoreOrientationForPreviousAndNextKey ? [KeyCode.RightArrow, KeyCode.DownArrow] : [KeyCode.RightArrow];\r\n\t\t\t\tbreak;\r\n\t\t\tcase ActionsOrientation.HORIZONTAL_REVERSE:\r\n\t\t\t\tpreviousKeys = this.options.ignoreOrientationForPreviousAndNextKey ? [KeyCode.RightArrow, KeyCode.DownArrow] : [KeyCode.RightArrow];\r\n\t\t\t\tnextKeys = this.options.ignoreOrientationForPreviousAndNextKey ? [KeyCode.LeftArrow, KeyCode.UpArrow] : [KeyCode.LeftArrow];\r\n\t\t\t\tthis.domNode.className += ' reverse';\r\n\t\t\t\tbreak;\r\n\t\t\tcase ActionsOrientation.VERTICAL:\r\n\t\t\t\tpreviousKeys = this.options.ignoreOrientationForPreviousAndNextKey ? [KeyCode.LeftArrow, KeyCode.UpArrow] : [KeyCode.UpArrow];\r\n\t\t\t\tnextKeys = this.options.ignoreOrientationForPreviousAndNextKey ? [KeyCode.RightArrow, KeyCode.DownArrow] : [KeyCode.DownArrow];\r\n\t\t\t\tthis.domNode.className += ' vertical';\r\n\t\t\t\tbreak;\r\n\t\t\tcase ActionsOrientation.VERTICAL_REVERSE:\r\n\t\t\t\tpreviousKeys = this.options.ignoreOrientationForPreviousAndNextKey ? [KeyCode.RightArrow, KeyCode.DownArrow] : [KeyCode.DownArrow];\r\n\t\t\t\tnextKeys = this.options.ignoreOrientationForPreviousAndNextKey ? [KeyCode.LeftArrow, KeyCode.UpArrow] : [KeyCode.UpArrow];\r\n\t\t\t\tthis.domNode.className += ' vertical reverse';\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tthis._register(DOM.addDisposableListener(this.domNode, DOM.EventType.KEY_DOWN, e => {\r\n\t\t\tconst event = new StandardKeyboardEvent(e);\r\n\t\t\tlet eventHandled = true;\r\n\r\n\t\t\tif (previousKeys && (event.equals(previousKeys[0]) || event.equals(previousKeys[1]))) {\r\n\t\t\t\teventHandled = this.focusPrevious();\r\n\t\t\t} else if (nextKeys && (event.equals(nextKeys[0]) || event.equals(nextKeys[1]))) {\r\n\t\t\t\teventHandled = this.focusNext();\r\n\t\t\t} else if (event.equals(KeyCode.Escape) && this.cancelHasListener) {\r\n\t\t\t\tthis._onDidCancel.fire();\r\n\t\t\t} else if (this.isTriggerKeyEvent(event)) {\r\n\t\t\t\t// Staying out of the else branch even if not triggered\r\n\t\t\t\tif (this._triggerKeys.keyDown) {\r\n\t\t\t\t\tthis.doTrigger(event);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis.triggerKeyDown = true;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\teventHandled = false;\r\n\t\t\t}\r\n\r\n\t\t\tif (eventHandled) {\r\n\t\t\t\tevent.preventDefault();\r\n\t\t\t\tevent.stopPropagation();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._register(DOM.addDisposableListener(this.domNode, DOM.EventType.KEY_UP, e => {\r\n\t\t\tconst event = new StandardKeyboardEvent(e);\r\n\r\n\t\t\t// Run action on Enter/Space\r\n\t\t\tif (this.isTriggerKeyEvent(event)) {\r\n\t\t\t\tif (!this._triggerKeys.keyDown && this.triggerKeyDown) {\r\n\t\t\t\t\tthis.triggerKeyDown = false;\r\n\t\t\t\t\tthis.doTrigger(event);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tevent.preventDefault();\r\n\t\t\t\tevent.stopPropagation();\r\n\t\t\t}\r\n\r\n\t\t\t// Recompute focused item\r\n\t\t\telse if (event.equals(KeyCode.Tab) || event.equals(KeyMod.Shift | KeyCode.Tab)) {\r\n\t\t\t\tthis.updateFocusedItem();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis.focusTracker = this._register(DOM.trackFocus(this.domNode));\r\n\t\tthis._register(this.focusTracker.onDidBlur(() => {\r\n\t\t\tif (DOM.getActiveElement() === this.domNode || !DOM.isAncestor(DOM.getActiveElement(), this.domNode)) {\r\n\t\t\t\tthis._onDidBlur.fire();\r\n\t\t\t\tthis.focusedItem = undefined;\r\n\t\t\t\tthis.triggerKeyDown = false;\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._register(this.focusTracker.onDidFocus(() => this.updateFocusedItem()));\r\n\r\n\t\tthis.actionsList = document.createElement('ul');\r\n\t\tthis.actionsList.className = 'actions-container';\r\n\t\tthis.actionsList.setAttribute('role', 'toolbar');\r\n\r\n\t\tif (this.options.ariaLabel) {\r\n\t\t\tthis.actionsList.setAttribute('aria-label', this.options.ariaLabel);\r\n\t\t}\r\n\r\n\t\tthis.domNode.appendChild(this.actionsList);\r\n\r\n\t\tcontainer.appendChild(this.domNode);\r\n\t}\r\n\r\n\tprivate isTriggerKeyEvent(event: StandardKeyboardEvent): boolean {\r\n\t\tlet ret = false;\r\n\t\tthis._triggerKeys.keys.forEach(keyCode => {\r\n\t\t\tret = ret || event.equals(keyCode);\r\n\t\t});\r\n\r\n\t\treturn ret;\r\n\t}\r\n\r\n\tprivate updateFocusedItem(): void {\r\n\t\tfor (let i = 0; i < this.actionsList.children.length; i++) {\r\n\t\t\tconst elem = this.actionsList.children[i];\r\n\t\t\tif (DOM.isAncestor(DOM.getActiveElement(), elem)) {\r\n\t\t\t\tthis.focusedItem = i;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tget context(): any {\r\n\t\treturn this._context;\r\n\t}\r\n\r\n\tset context(context: any) {\r\n\t\tthis._context = context;\r\n\t\tthis.viewItems.forEach(i => i.setActionContext(context));\r\n\t}\r\n\r\n\tget actionRunner(): IActionRunner {\r\n\t\treturn this._actionRunner;\r\n\t}\r\n\r\n\tset actionRunner(actionRunner: IActionRunner) {\r\n\t\tif (actionRunner) {\r\n\t\t\tthis._actionRunner = actionRunner;\r\n\t\t\tthis.viewItems.forEach(item => item.actionRunner = actionRunner);\r\n\t\t}\r\n\t}\r\n\r\n\tgetContainer(): HTMLElement {\r\n\t\treturn this.domNode;\r\n\t}\r\n\r\n\tpush(arg: IAction | ReadonlyArray, options: IActionOptions = {}): void {\r\n\t\tconst actions: ReadonlyArray = Array.isArray(arg) ? arg : [arg];\r\n\r\n\t\tlet index = types.isNumber(options.index) ? options.index : null;\r\n\r\n\t\tactions.forEach((action: IAction) => {\r\n\t\t\tconst actionViewItemElement = document.createElement('li');\r\n\t\t\tactionViewItemElement.className = 'action-item';\r\n\t\t\tactionViewItemElement.setAttribute('role', 'presentation');\r\n\r\n\t\t\t// Prevent native context menu on actions\r\n\t\t\tif (!this.options.allowContextMenu) {\r\n\t\t\t\tthis._register(DOM.addDisposableListener(actionViewItemElement, DOM.EventType.CONTEXT_MENU, (e: DOM.EventLike) => {\r\n\t\t\t\t\tDOM.EventHelper.stop(e, true);\r\n\t\t\t\t}));\r\n\t\t\t}\r\n\r\n\t\t\tlet item: IActionViewItem | undefined;\r\n\r\n\t\t\tif (this.options.actionViewItemProvider) {\r\n\t\t\t\titem = this.options.actionViewItemProvider(action);\r\n\t\t\t}\r\n\r\n\t\t\tif (!item) {\r\n\t\t\t\titem = new ActionViewItem(this.context, action, options);\r\n\t\t\t}\r\n\r\n\t\t\titem.actionRunner = this._actionRunner;\r\n\t\t\titem.setActionContext(this.context);\r\n\t\t\titem.render(actionViewItemElement);\r\n\r\n\t\t\tif (index === null || index < 0 || index >= this.actionsList.children.length) {\r\n\t\t\t\tthis.actionsList.appendChild(actionViewItemElement);\r\n\t\t\t\tthis.viewItems.push(item);\r\n\t\t\t\tthis._actionIds.push(action.id);\r\n\t\t\t} else {\r\n\t\t\t\tthis.actionsList.insertBefore(actionViewItemElement, this.actionsList.children[index]);\r\n\t\t\t\tthis.viewItems.splice(index, 0, item);\r\n\t\t\t\tthis._actionIds.splice(index, 0, action.id);\r\n\t\t\t\tindex++;\r\n\t\t\t}\r\n\t\t});\r\n\t\tif (this.focusedItem) {\r\n\t\t\t// After a clear actions might be re-added to simply toggle some actions. We should preserve focus #97128\r\n\t\t\tthis.focus(this.focusedItem);\r\n\t\t}\r\n\t}\r\n\r\n\tclear(): void {\r\n\t\tdispose(this.viewItems);\r\n\t\tthis.viewItems = [];\r\n\t\tthis._actionIds = [];\r\n\t\tDOM.clearNode(this.actionsList);\r\n\t}\r\n\r\n\tfocus(index?: number): void;\r\n\tfocus(selectFirst?: boolean): void;\r\n\tfocus(arg?: number | boolean): void {\r\n\t\tlet selectFirst: boolean = false;\r\n\t\tlet index: number | undefined = undefined;\r\n\t\tif (arg === undefined) {\r\n\t\t\tselectFirst = true;\r\n\t\t} else if (typeof arg === 'number') {\r\n\t\t\tindex = arg;\r\n\t\t} else if (typeof arg === 'boolean') {\r\n\t\t\tselectFirst = arg;\r\n\t\t}\r\n\r\n\t\tif (selectFirst && typeof this.focusedItem === 'undefined') {\r\n\t\t\tconst firstEnabled = this.viewItems.findIndex(item => item.isEnabled());\r\n\t\t\t// Focus the first enabled item\r\n\t\t\tthis.focusedItem = firstEnabled === -1 ? undefined : firstEnabled;\r\n\t\t\tthis.updateFocus();\r\n\t\t} else {\r\n\t\t\tif (index !== undefined) {\r\n\t\t\t\tthis.focusedItem = index;\r\n\t\t\t}\r\n\r\n\t\t\tthis.updateFocus();\r\n\t\t}\r\n\t}\r\n\r\n\tprotected focusNext(): boolean {\r\n\t\tif (typeof this.focusedItem === 'undefined') {\r\n\t\t\tthis.focusedItem = this.viewItems.length - 1;\r\n\t\t}\r\n\r\n\t\tconst startIndex = this.focusedItem;\r\n\t\tlet item: IActionViewItem;\r\n\r\n\t\tdo {\r\n\t\t\tif (this.options.preventLoopNavigation && this.focusedItem + 1 >= this.viewItems.length) {\r\n\t\t\t\tthis.focusedItem = startIndex;\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\tthis.focusedItem = (this.focusedItem + 1) % this.viewItems.length;\r\n\t\t\titem = this.viewItems[this.focusedItem];\r\n\t\t} while (this.focusedItem !== startIndex && !item.isEnabled());\r\n\r\n\t\tif (this.focusedItem === startIndex && !item.isEnabled()) {\r\n\t\t\tthis.focusedItem = undefined;\r\n\t\t}\r\n\r\n\t\tthis.updateFocus();\r\n\t\treturn true;\r\n\t}\r\n\r\n\tprotected focusPrevious(): boolean {\r\n\t\tif (typeof this.focusedItem === 'undefined') {\r\n\t\t\tthis.focusedItem = 0;\r\n\t\t}\r\n\r\n\t\tconst startIndex = this.focusedItem;\r\n\t\tlet item: IActionViewItem;\r\n\r\n\t\tdo {\r\n\t\t\tthis.focusedItem = this.focusedItem - 1;\r\n\r\n\t\t\tif (this.focusedItem < 0) {\r\n\t\t\t\tif (this.options.preventLoopNavigation) {\r\n\t\t\t\t\tthis.focusedItem = startIndex;\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis.focusedItem = this.viewItems.length - 1;\r\n\t\t\t}\r\n\r\n\t\t\titem = this.viewItems[this.focusedItem];\r\n\t\t} while (this.focusedItem !== startIndex && !item.isEnabled());\r\n\r\n\t\tif (this.focusedItem === startIndex && !item.isEnabled()) {\r\n\t\t\tthis.focusedItem = undefined;\r\n\t\t}\r\n\r\n\t\tthis.updateFocus(true);\r\n\t\treturn true;\r\n\t}\r\n\r\n\tprotected updateFocus(fromRight?: boolean, preventScroll?: boolean): void {\r\n\t\tif (typeof this.focusedItem === 'undefined') {\r\n\t\t\tthis.actionsList.focus({ preventScroll });\r\n\t\t}\r\n\r\n\t\tfor (let i = 0; i < this.viewItems.length; i++) {\r\n\t\t\tconst item = this.viewItems[i];\r\n\t\t\tconst actionViewItem = item;\r\n\r\n\t\t\tif (i === this.focusedItem) {\r\n\t\t\t\tif (types.isFunction(actionViewItem.isEnabled)) {\r\n\t\t\t\t\tif (actionViewItem.isEnabled() && types.isFunction(actionViewItem.focus)) {\r\n\t\t\t\t\t\tactionViewItem.focus(fromRight);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tthis.actionsList.focus({ preventScroll });\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tif (types.isFunction(actionViewItem.blur)) {\r\n\t\t\t\t\tactionViewItem.blur();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate doTrigger(event: StandardKeyboardEvent): void {\r\n\t\tif (typeof this.focusedItem === 'undefined') {\r\n\t\t\treturn; //nothing to focus\r\n\t\t}\r\n\r\n\t\t// trigger action\r\n\t\tconst actionViewItem = this.viewItems[this.focusedItem];\r\n\t\tif (actionViewItem instanceof BaseActionViewItem) {\r\n\t\t\tconst context = (actionViewItem._context === null || actionViewItem._context === undefined) ? event : actionViewItem._context;\r\n\t\t\tthis.run(actionViewItem._action, context);\r\n\t\t}\r\n\t}\r\n\r\n\trun(action: IAction, context?: unknown): Promise {\r\n\t\treturn this._actionRunner.run(action, context);\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tdispose(this.viewItems);\r\n\t\tthis.viewItems = [];\r\n\r\n\t\tthis._actionIds = [];\r\n\r\n\t\tthis.getContainer().remove();\r\n\r\n\t\tsuper.dispose();\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./dropdown';\r\nimport { Gesture, EventType as GestureEventType } from 'vs/base/browser/touch';\r\nimport { ActionRunner, IAction } from 'vs/base/common/actions';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';\r\nimport { IMenuOptions } from 'vs/base/browser/ui/menu/menu';\r\nimport { KeyCode } from 'vs/base/common/keyCodes';\r\nimport { EventHelper, EventType, append, $, addDisposableListener } from 'vs/base/browser/dom';\r\nimport { IContextMenuProvider } from 'vs/base/browser/contextmenu';\r\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { Emitter } from 'vs/base/common/event';\r\n\r\nexport interface ILabelRenderer {\r\n\t(container: HTMLElement): IDisposable | null;\r\n}\r\n\r\nexport interface IBaseDropdownOptions {\r\n\tlabel?: string;\r\n\tlabelRenderer?: ILabelRenderer;\r\n}\r\n\r\nexport class BaseDropdown extends ActionRunner {\r\n\tprivate _element: HTMLElement;\r\n\tprivate boxContainer?: HTMLElement;\r\n\tprivate _label?: HTMLElement;\r\n\tprivate contents?: HTMLElement;\r\n\r\n\tprivate visible: boolean | undefined;\r\n\tprivate _onDidChangeVisibility = new Emitter();\r\n\treadonly onDidChangeVisibility = this._onDidChangeVisibility.event;\r\n\r\n\tconstructor(container: HTMLElement, options: IBaseDropdownOptions) {\r\n\t\tsuper();\r\n\r\n\t\tthis._element = append(container, $('.monaco-dropdown'));\r\n\r\n\t\tthis._label = append(this._element, $('.dropdown-label'));\r\n\r\n\t\tlet labelRenderer = options.labelRenderer;\r\n\t\tif (!labelRenderer) {\r\n\t\t\tlabelRenderer = (container: HTMLElement): IDisposable | null => {\r\n\t\t\t\tcontainer.textContent = options.label || '';\r\n\r\n\t\t\t\treturn null;\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tfor (const event of [EventType.CLICK, EventType.MOUSE_DOWN, GestureEventType.Tap]) {\r\n\t\t\tthis._register(addDisposableListener(this.element, event, e => EventHelper.stop(e, true))); // prevent default click behaviour to trigger\r\n\t\t}\r\n\r\n\t\tfor (const event of [EventType.MOUSE_DOWN, GestureEventType.Tap]) {\r\n\t\t\tthis._register(addDisposableListener(this._label, event, e => {\r\n\t\t\t\tif (e instanceof MouseEvent && e.detail > 1) {\r\n\t\t\t\t\treturn; // prevent multiple clicks to open multiple context menus (https://github.com/microsoft/vscode/issues/41363)\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (this.visible) {\r\n\t\t\t\t\tthis.hide();\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis.show();\r\n\t\t\t\t}\r\n\t\t\t}));\r\n\t\t}\r\n\r\n\t\tthis._register(addDisposableListener(this._label, EventType.KEY_UP, e => {\r\n\t\t\tconst event = new StandardKeyboardEvent(e);\r\n\t\t\tif (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) {\r\n\t\t\t\tEventHelper.stop(e, true); // https://github.com/microsoft/vscode/issues/57997\r\n\r\n\t\t\t\tif (this.visible) {\r\n\t\t\t\t\tthis.hide();\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis.show();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tconst cleanupFn = labelRenderer(this._label);\r\n\t\tif (cleanupFn) {\r\n\t\t\tthis._register(cleanupFn);\r\n\t\t}\r\n\r\n\t\tthis._register(Gesture.addTarget(this._label));\r\n\t}\r\n\r\n\tget element(): HTMLElement {\r\n\t\treturn this._element;\r\n\t}\r\n\r\n\tshow(): void {\r\n\t\tif (!this.visible) {\r\n\t\t\tthis.visible = true;\r\n\t\t\tthis._onDidChangeVisibility.fire(true);\r\n\t\t}\r\n\t}\r\n\r\n\thide(): void {\r\n\t\tif (this.visible) {\r\n\t\t\tthis.visible = false;\r\n\t\t\tthis._onDidChangeVisibility.fire(false);\r\n\t\t}\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tsuper.dispose();\r\n\t\tthis.hide();\r\n\r\n\t\tif (this.boxContainer) {\r\n\t\t\tthis.boxContainer.remove();\r\n\t\t\tthis.boxContainer = undefined;\r\n\t\t}\r\n\r\n\t\tif (this.contents) {\r\n\t\t\tthis.contents.remove();\r\n\t\t\tthis.contents = undefined;\r\n\t\t}\r\n\r\n\t\tif (this._label) {\r\n\t\t\tthis._label.remove();\r\n\t\t\tthis._label = undefined;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport interface IActionProvider {\r\n\tgetActions(): readonly IAction[];\r\n}\r\n\r\nexport interface IDropdownMenuOptions extends IBaseDropdownOptions {\r\n\tcontextMenuProvider: IContextMenuProvider;\r\n\treadonly actions?: IAction[];\r\n\treadonly actionProvider?: IActionProvider;\r\n\tmenuClassName?: string;\r\n\tmenuAsChild?: boolean; // scope down for #99448\r\n}\r\n\r\nexport class DropdownMenu extends BaseDropdown {\r\n\tprivate _contextMenuProvider: IContextMenuProvider;\r\n\tprivate _menuOptions: IMenuOptions | undefined;\r\n\tprivate _actions: readonly IAction[] = [];\r\n\tprivate actionProvider?: IActionProvider;\r\n\tprivate menuClassName: string;\r\n\tprivate menuAsChild?: boolean;\r\n\r\n\tconstructor(container: HTMLElement, options: IDropdownMenuOptions) {\r\n\t\tsuper(container, options);\r\n\r\n\t\tthis._contextMenuProvider = options.contextMenuProvider;\r\n\t\tthis.actions = options.actions || [];\r\n\t\tthis.actionProvider = options.actionProvider;\r\n\t\tthis.menuClassName = options.menuClassName || '';\r\n\t\tthis.menuAsChild = !!options.menuAsChild;\r\n\t}\r\n\r\n\tset menuOptions(options: IMenuOptions | undefined) {\r\n\t\tthis._menuOptions = options;\r\n\t}\r\n\r\n\tget menuOptions(): IMenuOptions | undefined {\r\n\t\treturn this._menuOptions;\r\n\t}\r\n\r\n\tprivate get actions(): readonly IAction[] {\r\n\t\tif (this.actionProvider) {\r\n\t\t\treturn this.actionProvider.getActions();\r\n\t\t}\r\n\r\n\t\treturn this._actions;\r\n\t}\r\n\r\n\tprivate set actions(actions: readonly IAction[]) {\r\n\t\tthis._actions = actions;\r\n\t}\r\n\r\n\tshow(): void {\r\n\t\tsuper.show();\r\n\r\n\t\tthis.element.classList.add('active');\r\n\r\n\t\tthis._contextMenuProvider.showContextMenu({\r\n\t\t\tgetAnchor: () => this.element,\r\n\t\t\tgetActions: () => this.actions,\r\n\t\t\tgetActionsContext: () => this.menuOptions ? this.menuOptions.context : null,\r\n\t\t\tgetActionViewItem: action => this.menuOptions && this.menuOptions.actionViewItemProvider ? this.menuOptions.actionViewItemProvider(action) : undefined,\r\n\t\t\tgetKeyBinding: action => this.menuOptions && this.menuOptions.getKeyBinding ? this.menuOptions.getKeyBinding(action) : undefined,\r\n\t\t\tgetMenuClassName: () => this.menuClassName,\r\n\t\t\tonHide: () => this.onHide(),\r\n\t\t\tactionRunner: this.menuOptions ? this.menuOptions.actionRunner : undefined,\r\n\t\t\tanchorAlignment: this.menuOptions ? this.menuOptions.anchorAlignment : AnchorAlignment.LEFT,\r\n\t\t\tdomForShadowRoot: this.menuAsChild ? this.element : undefined\r\n\t\t});\r\n\t}\r\n\r\n\thide(): void {\r\n\t\tsuper.hide();\r\n\t}\r\n\r\n\tprivate onHide(): void {\r\n\t\tthis.hide();\r\n\t\tthis.element.classList.remove('active');\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./dropdown';\r\nimport { IAction, IActionRunner, IActionViewItemProvider } from 'vs/base/common/actions';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';\r\nimport { ResolvedKeybinding } from 'vs/base/common/keyCodes';\r\nimport { append, $ } from 'vs/base/browser/dom';\r\nimport { Emitter } from 'vs/base/common/event';\r\nimport { BaseActionViewItem, IBaseActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems';\r\nimport { IActionProvider, DropdownMenu, IDropdownMenuOptions, ILabelRenderer } from 'vs/base/browser/ui/dropdown/dropdown';\r\nimport { IContextMenuProvider } from 'vs/base/browser/contextmenu';\r\n\r\nexport interface IKeybindingProvider {\r\n\t(action: IAction): ResolvedKeybinding | undefined;\r\n}\r\n\r\nexport interface IAnchorAlignmentProvider {\r\n\t(): AnchorAlignment;\r\n}\r\n\r\nexport interface IDropdownMenuActionViewItemOptions extends IBaseActionViewItemOptions {\r\n\treadonly actionViewItemProvider?: IActionViewItemProvider;\r\n\treadonly keybindingProvider?: IKeybindingProvider;\r\n\treadonly actionRunner?: IActionRunner;\r\n\treadonly classNames?: string[] | string;\r\n\treadonly anchorAlignmentProvider?: IAnchorAlignmentProvider;\r\n\treadonly menuAsChild?: boolean;\r\n}\r\n\r\nexport class DropdownMenuActionViewItem extends BaseActionViewItem {\r\n\tprivate menuActionsOrProvider: readonly IAction[] | IActionProvider;\r\n\tprivate dropdownMenu: DropdownMenu | undefined;\r\n\tprivate contextMenuProvider: IContextMenuProvider;\r\n\tprivate actionItem: HTMLElement | null = null;\r\n\r\n\tprivate _onDidChangeVisibility = this._register(new Emitter());\r\n\r\n\tconstructor(\r\n\t\taction: IAction,\r\n\t\tmenuActionsOrProvider: readonly IAction[] | IActionProvider,\r\n\t\tcontextMenuProvider: IContextMenuProvider,\r\n\t\tprotected options: IDropdownMenuActionViewItemOptions = {}\r\n\t) {\r\n\t\tsuper(null, action, options);\r\n\r\n\t\tthis.menuActionsOrProvider = menuActionsOrProvider;\r\n\t\tthis.contextMenuProvider = contextMenuProvider;\r\n\r\n\t\tif (this.options.actionRunner) {\r\n\t\t\tthis.actionRunner = this.options.actionRunner;\r\n\t\t}\r\n\t}\r\n\r\n\trender(container: HTMLElement): void {\r\n\t\tthis.actionItem = container;\r\n\r\n\t\tconst labelRenderer: ILabelRenderer = (el: HTMLElement): IDisposable | null => {\r\n\t\t\tthis.element = append(el, $('a.action-label'));\r\n\r\n\t\t\tlet classNames: string[] = [];\r\n\r\n\t\t\tif (typeof this.options.classNames === 'string') {\r\n\t\t\t\tclassNames = this.options.classNames.split(/\\s+/g).filter(s => !!s);\r\n\t\t\t} else if (this.options.classNames) {\r\n\t\t\t\tclassNames = this.options.classNames;\r\n\t\t\t}\r\n\r\n\t\t\t// todo@aeschli: remove codicon, should come through `this.options.classNames`\r\n\t\t\tif (!classNames.find(c => c === 'icon')) {\r\n\t\t\t\tclassNames.push('codicon');\r\n\t\t\t}\r\n\r\n\t\t\tthis.element.classList.add(...classNames);\r\n\r\n\t\t\tthis.element.tabIndex = 0;\r\n\t\t\tthis.element.setAttribute('role', 'button');\r\n\t\t\tthis.element.setAttribute('aria-haspopup', 'true');\r\n\t\t\tthis.element.setAttribute('aria-expanded', 'false');\r\n\t\t\tthis.element.title = this._action.label || '';\r\n\r\n\t\t\treturn null;\r\n\t\t};\r\n\r\n\t\tconst isActionsArray = Array.isArray(this.menuActionsOrProvider);\r\n\t\tconst options: IDropdownMenuOptions = {\r\n\t\t\tcontextMenuProvider: this.contextMenuProvider,\r\n\t\t\tlabelRenderer: labelRenderer,\r\n\t\t\tmenuAsChild: this.options.menuAsChild,\r\n\t\t\tactions: isActionsArray ? this.menuActionsOrProvider as IAction[] : undefined,\r\n\t\t\tactionProvider: isActionsArray ? undefined : this.menuActionsOrProvider as IActionProvider\r\n\t\t};\r\n\r\n\t\tthis.dropdownMenu = this._register(new DropdownMenu(container, options));\r\n\t\tthis._register(this.dropdownMenu.onDidChangeVisibility(visible => {\r\n\t\t\tthis.element?.setAttribute('aria-expanded', `${visible}`);\r\n\t\t\tthis._onDidChangeVisibility.fire(visible);\r\n\t\t}));\r\n\r\n\t\tthis.dropdownMenu.menuOptions = {\r\n\t\t\tactionViewItemProvider: this.options.actionViewItemProvider,\r\n\t\t\tactionRunner: this.actionRunner,\r\n\t\t\tgetKeyBinding: this.options.keybindingProvider,\r\n\t\t\tcontext: this._context\r\n\t\t};\r\n\r\n\t\tif (this.options.anchorAlignmentProvider) {\r\n\t\t\tconst that = this;\r\n\r\n\t\t\tthis.dropdownMenu.menuOptions = {\r\n\t\t\t\t...this.dropdownMenu.menuOptions,\r\n\t\t\t\tget anchorAlignment(): AnchorAlignment {\r\n\t\t\t\t\treturn that.options.anchorAlignmentProvider!();\r\n\t\t\t\t}\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tthis.updateEnabled();\r\n\t}\r\n\r\n\tsetActionContext(newContext: unknown): void {\r\n\t\tsuper.setActionContext(newContext);\r\n\r\n\t\tif (this.dropdownMenu) {\r\n\t\t\tif (this.dropdownMenu.menuOptions) {\r\n\t\t\t\tthis.dropdownMenu.menuOptions.context = newContext;\r\n\t\t\t} else {\r\n\t\t\t\tthis.dropdownMenu.menuOptions = { context: newContext };\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprotected updateEnabled(): void {\r\n\t\tconst disabled = !this.getAction().enabled;\r\n\t\tthis.actionItem?.classList.toggle('disabled', disabled);\r\n\t\tthis.element?.classList.toggle('disabled', disabled);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./inputBox';\r\n\r\nimport * as nls from 'vs/nls';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { MarkdownRenderOptions } from 'vs/base/browser/markdownRenderer';\r\nimport { renderFormattedText, renderText } from 'vs/base/browser/formattedTextRenderer';\r\nimport * as aria from 'vs/base/browser/ui/aria/aria';\r\nimport { IAction } from 'vs/base/common/actions';\r\nimport { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';\r\nimport { IContextViewProvider, AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';\r\nimport { Event, Emitter } from 'vs/base/common/event';\r\nimport { Widget } from 'vs/base/browser/ui/widget';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { mixin } from 'vs/base/common/objects';\r\nimport { HistoryNavigator } from 'vs/base/common/history';\r\nimport { IHistoryNavigationWidget } from 'vs/base/browser/history';\r\nimport { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';\r\nimport { ScrollbarVisibility } from 'vs/base/common/scrollable';\r\nimport { domEvent } from 'vs/base/browser/event';\r\n\r\nconst $ = dom.$;\r\n\r\nexport interface IInputOptions extends IInputBoxStyles {\r\n\treadonly placeholder?: string;\r\n\treadonly ariaLabel?: string;\r\n\treadonly type?: string;\r\n\treadonly validationOptions?: IInputValidationOptions;\r\n\treadonly flexibleHeight?: boolean;\r\n\treadonly flexibleWidth?: boolean;\r\n\treadonly flexibleMaxHeight?: number;\r\n\treadonly actions?: ReadonlyArray;\r\n}\r\n\r\nexport interface IInputBoxStyles {\r\n\treadonly inputBackground?: Color;\r\n\treadonly inputForeground?: Color;\r\n\treadonly inputBorder?: Color;\r\n\treadonly inputValidationInfoBorder?: Color;\r\n\treadonly inputValidationInfoBackground?: Color;\r\n\treadonly inputValidationInfoForeground?: Color;\r\n\treadonly inputValidationWarningBorder?: Color;\r\n\treadonly inputValidationWarningBackground?: Color;\r\n\treadonly inputValidationWarningForeground?: Color;\r\n\treadonly inputValidationErrorBorder?: Color;\r\n\treadonly inputValidationErrorBackground?: Color;\r\n\treadonly inputValidationErrorForeground?: Color;\r\n}\r\n\r\nexport interface IInputValidator {\r\n\t(value: string): IMessage | null;\r\n}\r\n\r\nexport interface IMessage {\r\n\treadonly content: string;\r\n\treadonly formatContent?: boolean; // defaults to false\r\n\treadonly type?: MessageType;\r\n}\r\n\r\nexport interface IInputValidationOptions {\r\n\tvalidation?: IInputValidator;\r\n}\r\n\r\nexport const enum MessageType {\r\n\tINFO = 1,\r\n\tWARNING = 2,\r\n\tERROR = 3\r\n}\r\n\r\nexport interface IRange {\r\n\tstart: number;\r\n\tend: number;\r\n}\r\n\r\nconst defaultOpts = {\r\n\tinputBackground: Color.fromHex('#3C3C3C'),\r\n\tinputForeground: Color.fromHex('#CCCCCC'),\r\n\tinputValidationInfoBorder: Color.fromHex('#55AAFF'),\r\n\tinputValidationInfoBackground: Color.fromHex('#063B49'),\r\n\tinputValidationWarningBorder: Color.fromHex('#B89500'),\r\n\tinputValidationWarningBackground: Color.fromHex('#352A05'),\r\n\tinputValidationErrorBorder: Color.fromHex('#BE1100'),\r\n\tinputValidationErrorBackground: Color.fromHex('#5A1D1D')\r\n};\r\n\r\nexport class InputBox extends Widget {\r\n\tprivate contextViewProvider?: IContextViewProvider;\r\n\telement: HTMLElement;\r\n\tprivate input: HTMLInputElement;\r\n\tprivate actionbar?: ActionBar;\r\n\tprivate options: IInputOptions;\r\n\tprivate message: IMessage | null;\r\n\tprivate placeholder: string;\r\n\tprivate ariaLabel: string;\r\n\tprivate validation?: IInputValidator;\r\n\tprivate state: 'idle' | 'open' | 'closed' = 'idle';\r\n\r\n\tprivate mirror: HTMLElement | undefined;\r\n\tprivate cachedHeight: number | undefined;\r\n\tprivate cachedContentHeight: number | undefined;\r\n\tprivate maxHeight: number = Number.POSITIVE_INFINITY;\r\n\tprivate scrollableElement: ScrollableElement | undefined;\r\n\r\n\tprivate inputBackground?: Color;\r\n\tprivate inputForeground?: Color;\r\n\tprivate inputBorder?: Color;\r\n\r\n\tprivate inputValidationInfoBorder?: Color;\r\n\tprivate inputValidationInfoBackground?: Color;\r\n\tprivate inputValidationInfoForeground?: Color;\r\n\tprivate inputValidationWarningBorder?: Color;\r\n\tprivate inputValidationWarningBackground?: Color;\r\n\tprivate inputValidationWarningForeground?: Color;\r\n\tprivate inputValidationErrorBorder?: Color;\r\n\tprivate inputValidationErrorBackground?: Color;\r\n\tprivate inputValidationErrorForeground?: Color;\r\n\r\n\tprivate _onDidChange = this._register(new Emitter());\r\n\tpublic readonly onDidChange: Event = this._onDidChange.event;\r\n\r\n\tprivate _onDidHeightChange = this._register(new Emitter());\r\n\tpublic readonly onDidHeightChange: Event = this._onDidHeightChange.event;\r\n\r\n\tconstructor(container: HTMLElement, contextViewProvider: IContextViewProvider | undefined, options?: IInputOptions) {\r\n\t\tsuper();\r\n\r\n\t\tthis.contextViewProvider = contextViewProvider;\r\n\t\tthis.options = options || Object.create(null);\r\n\t\tmixin(this.options, defaultOpts, false);\r\n\t\tthis.message = null;\r\n\t\tthis.placeholder = this.options.placeholder || '';\r\n\t\tthis.ariaLabel = this.options.ariaLabel || '';\r\n\r\n\t\tthis.inputBackground = this.options.inputBackground;\r\n\t\tthis.inputForeground = this.options.inputForeground;\r\n\t\tthis.inputBorder = this.options.inputBorder;\r\n\r\n\t\tthis.inputValidationInfoBorder = this.options.inputValidationInfoBorder;\r\n\t\tthis.inputValidationInfoBackground = this.options.inputValidationInfoBackground;\r\n\t\tthis.inputValidationInfoForeground = this.options.inputValidationInfoForeground;\r\n\t\tthis.inputValidationWarningBorder = this.options.inputValidationWarningBorder;\r\n\t\tthis.inputValidationWarningBackground = this.options.inputValidationWarningBackground;\r\n\t\tthis.inputValidationWarningForeground = this.options.inputValidationWarningForeground;\r\n\t\tthis.inputValidationErrorBorder = this.options.inputValidationErrorBorder;\r\n\t\tthis.inputValidationErrorBackground = this.options.inputValidationErrorBackground;\r\n\t\tthis.inputValidationErrorForeground = this.options.inputValidationErrorForeground;\r\n\r\n\t\tif (this.options.validationOptions) {\r\n\t\t\tthis.validation = this.options.validationOptions.validation;\r\n\t\t}\r\n\r\n\t\tthis.element = dom.append(container, $('.monaco-inputbox.idle'));\r\n\r\n\t\tlet tagName = this.options.flexibleHeight ? 'textarea' : 'input';\r\n\r\n\t\tlet wrapper = dom.append(this.element, $('.ibwrapper'));\r\n\t\tthis.input = dom.append(wrapper, $(tagName + '.input.empty'));\r\n\t\tthis.input.setAttribute('autocorrect', 'off');\r\n\t\tthis.input.setAttribute('autocapitalize', 'off');\r\n\t\tthis.input.setAttribute('spellcheck', 'false');\r\n\r\n\t\tthis.onfocus(this.input, () => this.element.classList.add('synthetic-focus'));\r\n\t\tthis.onblur(this.input, () => this.element.classList.remove('synthetic-focus'));\r\n\r\n\t\tif (this.options.flexibleHeight) {\r\n\t\t\tthis.maxHeight = typeof this.options.flexibleMaxHeight === 'number' ? this.options.flexibleMaxHeight : Number.POSITIVE_INFINITY;\r\n\r\n\t\t\tthis.mirror = dom.append(wrapper, $('div.mirror'));\r\n\t\t\tthis.mirror.innerText = '\\u00a0';\r\n\r\n\t\t\tthis.scrollableElement = new ScrollableElement(this.element, { vertical: ScrollbarVisibility.Auto });\r\n\r\n\t\t\tif (this.options.flexibleWidth) {\r\n\t\t\t\tthis.input.setAttribute('wrap', 'off');\r\n\t\t\t\tthis.mirror.style.whiteSpace = 'pre';\r\n\t\t\t\tthis.mirror.style.wordWrap = 'initial';\r\n\t\t\t}\r\n\r\n\t\t\tdom.append(container, this.scrollableElement.getDomNode());\r\n\t\t\tthis._register(this.scrollableElement);\r\n\r\n\t\t\t// from ScrollableElement to DOM\r\n\t\t\tthis._register(this.scrollableElement.onScroll(e => this.input.scrollTop = e.scrollTop));\r\n\r\n\t\t\tconst onSelectionChange = Event.filter(domEvent(document, 'selectionchange'), () => {\r\n\t\t\t\tconst selection = document.getSelection();\r\n\t\t\t\treturn selection?.anchorNode === wrapper;\r\n\t\t\t});\r\n\r\n\t\t\t// from DOM to ScrollableElement\r\n\t\t\tthis._register(onSelectionChange(this.updateScrollDimensions, this));\r\n\t\t\tthis._register(this.onDidHeightChange(this.updateScrollDimensions, this));\r\n\t\t} else {\r\n\t\t\tthis.input.type = this.options.type || 'text';\r\n\t\t\tthis.input.setAttribute('wrap', 'off');\r\n\t\t}\r\n\r\n\t\tif (this.ariaLabel) {\r\n\t\t\tthis.input.setAttribute('aria-label', this.ariaLabel);\r\n\t\t}\r\n\r\n\t\tif (this.placeholder) {\r\n\t\t\tthis.setPlaceHolder(this.placeholder);\r\n\t\t}\r\n\r\n\t\tthis.oninput(this.input, () => this.onValueChange());\r\n\t\tthis.onblur(this.input, () => this.onBlur());\r\n\t\tthis.onfocus(this.input, () => this.onFocus());\r\n\r\n\t\tthis.ignoreGesture(this.input);\r\n\r\n\t\tsetTimeout(() => this.updateMirror(), 0);\r\n\r\n\t\t// Support actions\r\n\t\tif (this.options.actions) {\r\n\t\t\tthis.actionbar = this._register(new ActionBar(this.element));\r\n\t\t\tthis.actionbar.push(this.options.actions, { icon: true, label: false });\r\n\t\t}\r\n\r\n\t\tthis.applyStyles();\r\n\t}\r\n\r\n\tprivate onBlur(): void {\r\n\t\tthis._hideMessage();\r\n\t}\r\n\r\n\tprivate onFocus(): void {\r\n\t\tthis._showMessage();\r\n\t}\r\n\r\n\tpublic setPlaceHolder(placeHolder: string): void {\r\n\t\tthis.placeholder = placeHolder;\r\n\t\tthis.input.setAttribute('placeholder', placeHolder);\r\n\t\tthis.input.title = placeHolder;\r\n\t}\r\n\r\n\tpublic setAriaLabel(label: string): void {\r\n\t\tthis.ariaLabel = label;\r\n\r\n\t\tif (label) {\r\n\t\t\tthis.input.setAttribute('aria-label', this.ariaLabel);\r\n\t\t} else {\r\n\t\t\tthis.input.removeAttribute('aria-label');\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getAriaLabel(): string {\r\n\t\treturn this.ariaLabel;\r\n\t}\r\n\r\n\tpublic get inputElement(): HTMLInputElement {\r\n\t\treturn this.input;\r\n\t}\r\n\r\n\tpublic get value(): string {\r\n\t\treturn this.input.value;\r\n\t}\r\n\r\n\tpublic set value(newValue: string) {\r\n\t\tif (this.input.value !== newValue) {\r\n\t\t\tthis.input.value = newValue;\r\n\t\t\tthis.onValueChange();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic get height(): number {\r\n\t\treturn typeof this.cachedHeight === 'number' ? this.cachedHeight : dom.getTotalHeight(this.element);\r\n\t}\r\n\r\n\tpublic focus(): void {\r\n\t\tthis.input.focus();\r\n\t}\r\n\r\n\tpublic blur(): void {\r\n\t\tthis.input.blur();\r\n\t}\r\n\r\n\tpublic hasFocus(): boolean {\r\n\t\treturn document.activeElement === this.input;\r\n\t}\r\n\r\n\tpublic select(range: IRange | null = null): void {\r\n\t\tthis.input.select();\r\n\r\n\t\tif (range) {\r\n\t\t\tthis.input.setSelectionRange(range.start, range.end);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic isSelectionAtEnd(): boolean {\r\n\t\treturn this.input.selectionEnd === this.input.value.length && this.input.selectionStart === this.input.selectionEnd;\r\n\t}\r\n\r\n\tpublic enable(): void {\r\n\t\tthis.input.removeAttribute('disabled');\r\n\t}\r\n\r\n\tpublic disable(): void {\r\n\t\tthis.blur();\r\n\t\tthis.input.disabled = true;\r\n\t\tthis._hideMessage();\r\n\t}\r\n\r\n\tpublic get width(): number {\r\n\t\treturn dom.getTotalWidth(this.input);\r\n\t}\r\n\r\n\tpublic set width(width: number) {\r\n\t\tif (this.options.flexibleHeight && this.options.flexibleWidth) {\r\n\t\t\t// textarea with horizontal scrolling\r\n\t\t\tlet horizontalPadding = 0;\r\n\t\t\tif (this.mirror) {\r\n\t\t\t\tconst paddingLeft = parseFloat(this.mirror.style.paddingLeft || '') || 0;\r\n\t\t\t\tconst paddingRight = parseFloat(this.mirror.style.paddingRight || '') || 0;\r\n\t\t\t\thorizontalPadding = paddingLeft + paddingRight;\r\n\t\t\t}\r\n\t\t\tthis.input.style.width = (width - horizontalPadding) + 'px';\r\n\t\t} else {\r\n\t\t\tthis.input.style.width = width + 'px';\r\n\t\t}\r\n\r\n\t\tif (this.mirror) {\r\n\t\t\tthis.mirror.style.width = width + 'px';\r\n\t\t}\r\n\t}\r\n\r\n\tpublic set paddingRight(paddingRight: number) {\r\n\t\tif (this.options.flexibleHeight && this.options.flexibleWidth) {\r\n\t\t\tthis.input.style.width = `calc(100% - ${paddingRight}px)`;\r\n\t\t} else {\r\n\t\t\tthis.input.style.paddingRight = paddingRight + 'px';\r\n\t\t}\r\n\r\n\t\tif (this.mirror) {\r\n\t\t\tthis.mirror.style.paddingRight = paddingRight + 'px';\r\n\t\t}\r\n\t}\r\n\r\n\tprivate updateScrollDimensions(): void {\r\n\t\tif (typeof this.cachedContentHeight !== 'number' || typeof this.cachedHeight !== 'number' || !this.scrollableElement) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst scrollHeight = this.cachedContentHeight;\r\n\t\tconst height = this.cachedHeight;\r\n\t\tconst scrollTop = this.input.scrollTop;\r\n\r\n\t\tthis.scrollableElement.setScrollDimensions({ scrollHeight, height });\r\n\t\tthis.scrollableElement.setScrollPosition({ scrollTop });\r\n\t}\r\n\r\n\tpublic showMessage(message: IMessage, force?: boolean): void {\r\n\t\tthis.message = message;\r\n\r\n\t\tthis.element.classList.remove('idle');\r\n\t\tthis.element.classList.remove('info');\r\n\t\tthis.element.classList.remove('warning');\r\n\t\tthis.element.classList.remove('error');\r\n\t\tthis.element.classList.add(this.classForType(message.type));\r\n\r\n\t\tconst styles = this.stylesForType(this.message.type);\r\n\t\tthis.element.style.border = styles.border ? `1px solid ${styles.border}` : '';\r\n\r\n\t\tif (this.hasFocus() || force) {\r\n\t\t\tthis._showMessage();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic hideMessage(): void {\r\n\t\tthis.message = null;\r\n\r\n\t\tthis.element.classList.remove('info');\r\n\t\tthis.element.classList.remove('warning');\r\n\t\tthis.element.classList.remove('error');\r\n\t\tthis.element.classList.add('idle');\r\n\r\n\t\tthis._hideMessage();\r\n\t\tthis.applyStyles();\r\n\t}\r\n\r\n\tpublic validate(): MessageType | undefined {\r\n\t\tlet errorMsg: IMessage | null = null;\r\n\r\n\t\tif (this.validation) {\r\n\t\t\terrorMsg = this.validation(this.value);\r\n\r\n\t\t\tif (errorMsg) {\r\n\t\t\t\tthis.inputElement.setAttribute('aria-invalid', 'true');\r\n\t\t\t\tthis.showMessage(errorMsg);\r\n\t\t\t}\r\n\t\t\telse if (this.inputElement.hasAttribute('aria-invalid')) {\r\n\t\t\t\tthis.inputElement.removeAttribute('aria-invalid');\r\n\t\t\t\tthis.hideMessage();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn errorMsg?.type;\r\n\t}\r\n\r\n\tpublic stylesForType(type: MessageType | undefined): { border: Color | undefined; background: Color | undefined; foreground: Color | undefined } {\r\n\t\tswitch (type) {\r\n\t\t\tcase MessageType.INFO: return { border: this.inputValidationInfoBorder, background: this.inputValidationInfoBackground, foreground: this.inputValidationInfoForeground };\r\n\t\t\tcase MessageType.WARNING: return { border: this.inputValidationWarningBorder, background: this.inputValidationWarningBackground, foreground: this.inputValidationWarningForeground };\r\n\t\t\tdefault: return { border: this.inputValidationErrorBorder, background: this.inputValidationErrorBackground, foreground: this.inputValidationErrorForeground };\r\n\t\t}\r\n\t}\r\n\r\n\tprivate classForType(type: MessageType | undefined): string {\r\n\t\tswitch (type) {\r\n\t\t\tcase MessageType.INFO: return 'info';\r\n\t\t\tcase MessageType.WARNING: return 'warning';\r\n\t\t\tdefault: return 'error';\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _showMessage(): void {\r\n\t\tif (!this.contextViewProvider || !this.message) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet div: HTMLElement;\r\n\t\tlet layout = () => div.style.width = dom.getTotalWidth(this.element) + 'px';\r\n\r\n\t\tthis.contextViewProvider.showContextView({\r\n\t\t\tgetAnchor: () => this.element,\r\n\t\t\tanchorAlignment: AnchorAlignment.RIGHT,\r\n\t\t\trender: (container: HTMLElement) => {\r\n\t\t\t\tif (!this.message) {\r\n\t\t\t\t\treturn null;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tdiv = dom.append(container, $('.monaco-inputbox-container'));\r\n\t\t\t\tlayout();\r\n\r\n\t\t\t\tconst renderOptions: MarkdownRenderOptions = {\r\n\t\t\t\t\tinline: true,\r\n\t\t\t\t\tclassName: 'monaco-inputbox-message'\r\n\t\t\t\t};\r\n\r\n\t\t\t\tconst spanElement = (this.message.formatContent\r\n\t\t\t\t\t? renderFormattedText(this.message.content, renderOptions)\r\n\t\t\t\t\t: renderText(this.message.content, renderOptions));\r\n\t\t\t\tspanElement.classList.add(this.classForType(this.message.type));\r\n\r\n\t\t\t\tconst styles = this.stylesForType(this.message.type);\r\n\t\t\t\tspanElement.style.backgroundColor = styles.background ? styles.background.toString() : '';\r\n\t\t\t\tspanElement.style.color = styles.foreground ? styles.foreground.toString() : '';\r\n\t\t\t\tspanElement.style.border = styles.border ? `1px solid ${styles.border}` : '';\r\n\r\n\t\t\t\tdom.append(div, spanElement);\r\n\r\n\t\t\t\treturn null;\r\n\t\t\t},\r\n\t\t\tonHide: () => {\r\n\t\t\t\tthis.state = 'closed';\r\n\t\t\t},\r\n\t\t\tlayout: layout\r\n\t\t});\r\n\r\n\t\t// ARIA Support\r\n\t\tlet alertText: string;\r\n\t\tif (this.message.type === MessageType.ERROR) {\r\n\t\t\talertText = nls.localize('alertErrorMessage', \"Error: {0}\", this.message.content);\r\n\t\t} else if (this.message.type === MessageType.WARNING) {\r\n\t\t\talertText = nls.localize('alertWarningMessage', \"Warning: {0}\", this.message.content);\r\n\t\t} else {\r\n\t\t\talertText = nls.localize('alertInfoMessage', \"Info: {0}\", this.message.content);\r\n\t\t}\r\n\r\n\t\taria.alert(alertText);\r\n\r\n\t\tthis.state = 'open';\r\n\t}\r\n\r\n\tprivate _hideMessage(): void {\r\n\t\tif (!this.contextViewProvider) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this.state === 'open') {\r\n\t\t\tthis.contextViewProvider.hideContextView();\r\n\t\t}\r\n\r\n\t\tthis.state = 'idle';\r\n\t}\r\n\r\n\tprivate onValueChange(): void {\r\n\t\tthis._onDidChange.fire(this.value);\r\n\r\n\t\tthis.validate();\r\n\t\tthis.updateMirror();\r\n\t\tthis.input.classList.toggle('empty', !this.value);\r\n\r\n\t\tif (this.state === 'open' && this.contextViewProvider) {\r\n\t\t\tthis.contextViewProvider.layout();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate updateMirror(): void {\r\n\t\tif (!this.mirror) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst value = this.value;\r\n\t\tconst lastCharCode = value.charCodeAt(value.length - 1);\r\n\t\tconst suffix = lastCharCode === 10 ? ' ' : '';\r\n\t\tconst mirrorTextContent = value + suffix;\r\n\r\n\t\tif (mirrorTextContent) {\r\n\t\t\tthis.mirror.textContent = value + suffix;\r\n\t\t} else {\r\n\t\t\tthis.mirror.innerText = '\\u00a0';\r\n\t\t}\r\n\r\n\t\tthis.layout();\r\n\t}\r\n\r\n\tpublic style(styles: IInputBoxStyles): void {\r\n\t\tthis.inputBackground = styles.inputBackground;\r\n\t\tthis.inputForeground = styles.inputForeground;\r\n\t\tthis.inputBorder = styles.inputBorder;\r\n\r\n\t\tthis.inputValidationInfoBackground = styles.inputValidationInfoBackground;\r\n\t\tthis.inputValidationInfoForeground = styles.inputValidationInfoForeground;\r\n\t\tthis.inputValidationInfoBorder = styles.inputValidationInfoBorder;\r\n\t\tthis.inputValidationWarningBackground = styles.inputValidationWarningBackground;\r\n\t\tthis.inputValidationWarningForeground = styles.inputValidationWarningForeground;\r\n\t\tthis.inputValidationWarningBorder = styles.inputValidationWarningBorder;\r\n\t\tthis.inputValidationErrorBackground = styles.inputValidationErrorBackground;\r\n\t\tthis.inputValidationErrorForeground = styles.inputValidationErrorForeground;\r\n\t\tthis.inputValidationErrorBorder = styles.inputValidationErrorBorder;\r\n\r\n\t\tthis.applyStyles();\r\n\t}\r\n\r\n\tprotected applyStyles(): void {\r\n\t\tconst background = this.inputBackground ? this.inputBackground.toString() : '';\r\n\t\tconst foreground = this.inputForeground ? this.inputForeground.toString() : '';\r\n\t\tconst border = this.inputBorder ? this.inputBorder.toString() : '';\r\n\r\n\t\tthis.element.style.backgroundColor = background;\r\n\t\tthis.element.style.color = foreground;\r\n\t\tthis.input.style.backgroundColor = 'inherit';\r\n\t\tthis.input.style.color = foreground;\r\n\r\n\t\tthis.element.style.borderWidth = border ? '1px' : '';\r\n\t\tthis.element.style.borderStyle = border ? 'solid' : '';\r\n\t\tthis.element.style.borderColor = border;\r\n\t}\r\n\r\n\tpublic layout(): void {\r\n\t\tif (!this.mirror) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst previousHeight = this.cachedContentHeight;\r\n\t\tthis.cachedContentHeight = dom.getTotalHeight(this.mirror);\r\n\r\n\t\tif (previousHeight !== this.cachedContentHeight) {\r\n\t\t\tthis.cachedHeight = Math.min(this.cachedContentHeight, this.maxHeight);\r\n\t\t\tthis.input.style.height = this.cachedHeight + 'px';\r\n\t\t\tthis._onDidHeightChange.fire(this.cachedContentHeight);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic insertAtCursor(text: string): void {\r\n\t\tconst inputElement = this.inputElement;\r\n\t\tconst start = inputElement.selectionStart;\r\n\t\tconst end = inputElement.selectionEnd;\r\n\t\tconst content = inputElement.value;\r\n\r\n\t\tif (start !== null && end !== null) {\r\n\t\t\tthis.value = content.substr(0, start) + text + content.substr(end);\r\n\t\t\tinputElement.setSelectionRange(start + 1, start + 1);\r\n\t\t\tthis.layout();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._hideMessage();\r\n\r\n\t\tthis.message = null;\r\n\r\n\t\tif (this.actionbar) {\r\n\t\t\tthis.actionbar.dispose();\r\n\t\t}\r\n\r\n\t\tsuper.dispose();\r\n\t}\r\n}\r\n\r\nexport interface IHistoryInputOptions extends IInputOptions {\r\n\thistory: string[];\r\n}\r\n\r\nexport class HistoryInputBox extends InputBox implements IHistoryNavigationWidget {\r\n\r\n\tprivate readonly history: HistoryNavigator;\r\n\r\n\tconstructor(container: HTMLElement, contextViewProvider: IContextViewProvider | undefined, options: IHistoryInputOptions) {\r\n\t\tsuper(container, contextViewProvider, options);\r\n\t\tthis.history = new HistoryNavigator(options.history, 100);\r\n\t}\r\n\r\n\tpublic addToHistory(): void {\r\n\t\tif (this.value && this.value !== this.getCurrentValue()) {\r\n\t\t\tthis.history.add(this.value);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic showNextValue(): void {\r\n\t\tif (!this.history.has(this.value)) {\r\n\t\t\tthis.addToHistory();\r\n\t\t}\r\n\r\n\t\tlet next = this.getNextValue();\r\n\t\tif (next) {\r\n\t\t\tnext = next === this.value ? this.getNextValue() : next;\r\n\t\t}\r\n\r\n\t\tif (next) {\r\n\t\t\tthis.value = next;\r\n\t\t\taria.status(this.value);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic showPreviousValue(): void {\r\n\t\tif (!this.history.has(this.value)) {\r\n\t\t\tthis.addToHistory();\r\n\t\t}\r\n\r\n\t\tlet previous = this.getPreviousValue();\r\n\t\tif (previous) {\r\n\t\t\tprevious = previous === this.value ? this.getPreviousValue() : previous;\r\n\t\t}\r\n\r\n\t\tif (previous) {\r\n\t\t\tthis.value = previous;\r\n\t\t\taria.status(this.value);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate getCurrentValue(): string | null {\r\n\t\tlet currentValue = this.history.current();\r\n\t\tif (!currentValue) {\r\n\t\t\tcurrentValue = this.history.last();\r\n\t\t\tthis.history.next();\r\n\t\t}\r\n\t\treturn currentValue;\r\n\t}\r\n\r\n\tprivate getPreviousValue(): string | null {\r\n\t\treturn this.history.previous() || this.history.first();\r\n\t}\r\n\r\n\tprivate getNextValue(): string | null {\r\n\t\treturn this.history.next() || this.history.last();\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./findInput';\r\n\r\nimport * as nls from 'vs/nls';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { IInputValidator, IInputBoxStyles, HistoryInputBox } from 'vs/base/browser/ui/inputbox/inputBox';\r\nimport { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';\r\nimport { Widget } from 'vs/base/browser/ui/widget';\r\nimport { Event, Emitter } from 'vs/base/common/event';\r\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { IMouseEvent } from 'vs/base/browser/mouseEvent';\r\nimport { KeyCode } from 'vs/base/common/keyCodes';\r\nimport { CaseSensitiveCheckbox, WholeWordsCheckbox, RegexCheckbox } from 'vs/base/browser/ui/findinput/findInputCheckboxes';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { ICheckboxStyles } from 'vs/base/browser/ui/checkbox/checkbox';\r\n\r\nexport interface IFindInputOptions extends IFindInputStyles {\r\n\treadonly placeholder?: string;\r\n\treadonly width?: number;\r\n\treadonly validation?: IInputValidator;\r\n\treadonly label: string;\r\n\treadonly flexibleHeight?: boolean;\r\n\treadonly flexibleWidth?: boolean;\r\n\treadonly flexibleMaxHeight?: number;\r\n\r\n\treadonly appendCaseSensitiveLabel?: string;\r\n\treadonly appendWholeWordsLabel?: string;\r\n\treadonly appendRegexLabel?: string;\r\n\treadonly history?: string[];\r\n}\r\n\r\nexport interface IFindInputStyles extends IInputBoxStyles {\r\n\tinputActiveOptionBorder?: Color;\r\n\tinputActiveOptionForeground?: Color;\r\n\tinputActiveOptionBackground?: Color;\r\n}\r\n\r\nconst NLS_DEFAULT_LABEL = nls.localize('defaultLabel', \"input\");\r\n\r\nexport class FindInput extends Widget {\r\n\r\n\tprivate contextViewProvider: IContextViewProvider;\r\n\tprivate placeholder: string;\r\n\tprivate validation?: IInputValidator;\r\n\tprivate label: string;\r\n\tprivate fixFocusOnOptionClickEnabled = true;\r\n\r\n\tprivate inputActiveOptionBorder?: Color;\r\n\tprivate inputActiveOptionForeground?: Color;\r\n\tprivate inputActiveOptionBackground?: Color;\r\n\tprivate inputBackground?: Color;\r\n\tprivate inputForeground?: Color;\r\n\tprivate inputBorder?: Color;\r\n\r\n\tprivate inputValidationInfoBorder?: Color;\r\n\tprivate inputValidationInfoBackground?: Color;\r\n\tprivate inputValidationInfoForeground?: Color;\r\n\tprivate inputValidationWarningBorder?: Color;\r\n\tprivate inputValidationWarningBackground?: Color;\r\n\tprivate inputValidationWarningForeground?: Color;\r\n\tprivate inputValidationErrorBorder?: Color;\r\n\tprivate inputValidationErrorBackground?: Color;\r\n\tprivate inputValidationErrorForeground?: Color;\r\n\r\n\tprivate regex: RegexCheckbox;\r\n\tprivate wholeWords: WholeWordsCheckbox;\r\n\tprivate caseSensitive: CaseSensitiveCheckbox;\r\n\tpublic domNode: HTMLElement;\r\n\tpublic inputBox: HistoryInputBox;\r\n\r\n\tprivate readonly _onDidOptionChange = this._register(new Emitter());\r\n\tpublic readonly onDidOptionChange: Event = this._onDidOptionChange.event;\r\n\r\n\tprivate readonly _onKeyDown = this._register(new Emitter());\r\n\tpublic readonly onKeyDown: Event = this._onKeyDown.event;\r\n\r\n\tprivate readonly _onMouseDown = this._register(new Emitter());\r\n\tpublic readonly onMouseDown: Event = this._onMouseDown.event;\r\n\r\n\tprivate readonly _onInput = this._register(new Emitter());\r\n\r\n\tprivate readonly _onKeyUp = this._register(new Emitter());\r\n\r\n\tprivate _onCaseSensitiveKeyDown = this._register(new Emitter());\r\n\tpublic readonly onCaseSensitiveKeyDown: Event = this._onCaseSensitiveKeyDown.event;\r\n\r\n\tprivate _onRegexKeyDown = this._register(new Emitter());\r\n\tpublic readonly onRegexKeyDown: Event = this._onRegexKeyDown.event;\r\n\r\n\tconstructor(parent: HTMLElement | null, contextViewProvider: IContextViewProvider, private readonly _showOptionButtons: boolean, options: IFindInputOptions) {\r\n\t\tsuper();\r\n\t\tthis.contextViewProvider = contextViewProvider;\r\n\t\tthis.placeholder = options.placeholder || '';\r\n\t\tthis.validation = options.validation;\r\n\t\tthis.label = options.label || NLS_DEFAULT_LABEL;\r\n\r\n\t\tthis.inputActiveOptionBorder = options.inputActiveOptionBorder;\r\n\t\tthis.inputActiveOptionForeground = options.inputActiveOptionForeground;\r\n\t\tthis.inputActiveOptionBackground = options.inputActiveOptionBackground;\r\n\t\tthis.inputBackground = options.inputBackground;\r\n\t\tthis.inputForeground = options.inputForeground;\r\n\t\tthis.inputBorder = options.inputBorder;\r\n\r\n\t\tthis.inputValidationInfoBorder = options.inputValidationInfoBorder;\r\n\t\tthis.inputValidationInfoBackground = options.inputValidationInfoBackground;\r\n\t\tthis.inputValidationInfoForeground = options.inputValidationInfoForeground;\r\n\t\tthis.inputValidationWarningBorder = options.inputValidationWarningBorder;\r\n\t\tthis.inputValidationWarningBackground = options.inputValidationWarningBackground;\r\n\t\tthis.inputValidationWarningForeground = options.inputValidationWarningForeground;\r\n\t\tthis.inputValidationErrorBorder = options.inputValidationErrorBorder;\r\n\t\tthis.inputValidationErrorBackground = options.inputValidationErrorBackground;\r\n\t\tthis.inputValidationErrorForeground = options.inputValidationErrorForeground;\r\n\r\n\t\tconst appendCaseSensitiveLabel = options.appendCaseSensitiveLabel || '';\r\n\t\tconst appendWholeWordsLabel = options.appendWholeWordsLabel || '';\r\n\t\tconst appendRegexLabel = options.appendRegexLabel || '';\r\n\t\tconst history = options.history || [];\r\n\t\tconst flexibleHeight = !!options.flexibleHeight;\r\n\t\tconst flexibleWidth = !!options.flexibleWidth;\r\n\t\tconst flexibleMaxHeight = options.flexibleMaxHeight;\r\n\r\n\t\tthis.domNode = document.createElement('div');\r\n\t\tthis.domNode.classList.add('monaco-findInput');\r\n\r\n\t\tthis.inputBox = this._register(new HistoryInputBox(this.domNode, this.contextViewProvider, {\r\n\t\t\tplaceholder: this.placeholder || '',\r\n\t\t\tariaLabel: this.label || '',\r\n\t\t\tvalidationOptions: {\r\n\t\t\t\tvalidation: this.validation\r\n\t\t\t},\r\n\t\t\tinputBackground: this.inputBackground,\r\n\t\t\tinputForeground: this.inputForeground,\r\n\t\t\tinputBorder: this.inputBorder,\r\n\t\t\tinputValidationInfoBackground: this.inputValidationInfoBackground,\r\n\t\t\tinputValidationInfoForeground: this.inputValidationInfoForeground,\r\n\t\t\tinputValidationInfoBorder: this.inputValidationInfoBorder,\r\n\t\t\tinputValidationWarningBackground: this.inputValidationWarningBackground,\r\n\t\t\tinputValidationWarningForeground: this.inputValidationWarningForeground,\r\n\t\t\tinputValidationWarningBorder: this.inputValidationWarningBorder,\r\n\t\t\tinputValidationErrorBackground: this.inputValidationErrorBackground,\r\n\t\t\tinputValidationErrorForeground: this.inputValidationErrorForeground,\r\n\t\t\tinputValidationErrorBorder: this.inputValidationErrorBorder,\r\n\t\t\thistory,\r\n\t\t\tflexibleHeight,\r\n\t\t\tflexibleWidth,\r\n\t\t\tflexibleMaxHeight\r\n\t\t}));\r\n\r\n\t\tthis.regex = this._register(new RegexCheckbox({\r\n\t\t\tappendTitle: appendRegexLabel,\r\n\t\t\tisChecked: false,\r\n\t\t\tinputActiveOptionBorder: this.inputActiveOptionBorder,\r\n\t\t\tinputActiveOptionForeground: this.inputActiveOptionForeground,\r\n\t\t\tinputActiveOptionBackground: this.inputActiveOptionBackground\r\n\t\t}));\r\n\t\tthis._register(this.regex.onChange(viaKeyboard => {\r\n\t\t\tthis._onDidOptionChange.fire(viaKeyboard);\r\n\t\t\tif (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {\r\n\t\t\t\tthis.inputBox.focus();\r\n\t\t\t}\r\n\t\t\tthis.validate();\r\n\t\t}));\r\n\t\tthis._register(this.regex.onKeyDown(e => {\r\n\t\t\tthis._onRegexKeyDown.fire(e);\r\n\t\t}));\r\n\r\n\t\tthis.wholeWords = this._register(new WholeWordsCheckbox({\r\n\t\t\tappendTitle: appendWholeWordsLabel,\r\n\t\t\tisChecked: false,\r\n\t\t\tinputActiveOptionBorder: this.inputActiveOptionBorder,\r\n\t\t\tinputActiveOptionForeground: this.inputActiveOptionForeground,\r\n\t\t\tinputActiveOptionBackground: this.inputActiveOptionBackground\r\n\t\t}));\r\n\t\tthis._register(this.wholeWords.onChange(viaKeyboard => {\r\n\t\t\tthis._onDidOptionChange.fire(viaKeyboard);\r\n\t\t\tif (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {\r\n\t\t\t\tthis.inputBox.focus();\r\n\t\t\t}\r\n\t\t\tthis.validate();\r\n\t\t}));\r\n\r\n\t\tthis.caseSensitive = this._register(new CaseSensitiveCheckbox({\r\n\t\t\tappendTitle: appendCaseSensitiveLabel,\r\n\t\t\tisChecked: false,\r\n\t\t\tinputActiveOptionBorder: this.inputActiveOptionBorder,\r\n\t\t\tinputActiveOptionForeground: this.inputActiveOptionForeground,\r\n\t\t\tinputActiveOptionBackground: this.inputActiveOptionBackground\r\n\t\t}));\r\n\t\tthis._register(this.caseSensitive.onChange(viaKeyboard => {\r\n\t\t\tthis._onDidOptionChange.fire(viaKeyboard);\r\n\t\t\tif (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {\r\n\t\t\t\tthis.inputBox.focus();\r\n\t\t\t}\r\n\t\t\tthis.validate();\r\n\t\t}));\r\n\t\tthis._register(this.caseSensitive.onKeyDown(e => {\r\n\t\t\tthis._onCaseSensitiveKeyDown.fire(e);\r\n\t\t}));\r\n\r\n\t\tif (this._showOptionButtons) {\r\n\t\t\tthis.inputBox.paddingRight = this.caseSensitive.width() + this.wholeWords.width() + this.regex.width();\r\n\t\t}\r\n\r\n\t\t// Arrow-Key support to navigate between options\r\n\t\tlet indexes = [this.caseSensitive.domNode, this.wholeWords.domNode, this.regex.domNode];\r\n\t\tthis.onkeydown(this.domNode, (event: IKeyboardEvent) => {\r\n\t\t\tif (event.equals(KeyCode.LeftArrow) || event.equals(KeyCode.RightArrow) || event.equals(KeyCode.Escape)) {\r\n\t\t\t\tlet index = indexes.indexOf(document.activeElement);\r\n\t\t\t\tif (index >= 0) {\r\n\t\t\t\t\tlet newIndex: number = -1;\r\n\t\t\t\t\tif (event.equals(KeyCode.RightArrow)) {\r\n\t\t\t\t\t\tnewIndex = (index + 1) % indexes.length;\r\n\t\t\t\t\t} else if (event.equals(KeyCode.LeftArrow)) {\r\n\t\t\t\t\t\tif (index === 0) {\r\n\t\t\t\t\t\t\tnewIndex = indexes.length - 1;\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tnewIndex = index - 1;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (event.equals(KeyCode.Escape)) {\r\n\t\t\t\t\t\tindexes[index].blur();\r\n\t\t\t\t\t\tthis.inputBox.focus();\r\n\t\t\t\t\t} else if (newIndex >= 0) {\r\n\t\t\t\t\t\tindexes[newIndex].focus();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tdom.EventHelper.stop(event, true);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\r\n\r\n\t\tlet controls = document.createElement('div');\r\n\t\tcontrols.className = 'controls';\r\n\t\tcontrols.style.display = this._showOptionButtons ? 'block' : 'none';\r\n\t\tcontrols.appendChild(this.caseSensitive.domNode);\r\n\t\tcontrols.appendChild(this.wholeWords.domNode);\r\n\t\tcontrols.appendChild(this.regex.domNode);\r\n\r\n\t\tthis.domNode.appendChild(controls);\r\n\r\n\t\tif (parent) {\r\n\t\t\tparent.appendChild(this.domNode);\r\n\t\t}\r\n\r\n\t\tthis.onkeydown(this.inputBox.inputElement, (e) => this._onKeyDown.fire(e));\r\n\t\tthis.onkeyup(this.inputBox.inputElement, (e) => this._onKeyUp.fire(e));\r\n\t\tthis.oninput(this.inputBox.inputElement, (e) => this._onInput.fire());\r\n\t\tthis.onmousedown(this.inputBox.inputElement, (e) => this._onMouseDown.fire(e));\r\n\t}\r\n\r\n\tpublic enable(): void {\r\n\t\tthis.domNode.classList.remove('disabled');\r\n\t\tthis.inputBox.enable();\r\n\t\tthis.regex.enable();\r\n\t\tthis.wholeWords.enable();\r\n\t\tthis.caseSensitive.enable();\r\n\t}\r\n\r\n\tpublic disable(): void {\r\n\t\tthis.domNode.classList.add('disabled');\r\n\t\tthis.inputBox.disable();\r\n\t\tthis.regex.disable();\r\n\t\tthis.wholeWords.disable();\r\n\t\tthis.caseSensitive.disable();\r\n\t}\r\n\r\n\tpublic setFocusInputOnOptionClick(value: boolean): void {\r\n\t\tthis.fixFocusOnOptionClickEnabled = value;\r\n\t}\r\n\r\n\tpublic setEnabled(enabled: boolean): void {\r\n\t\tif (enabled) {\r\n\t\t\tthis.enable();\r\n\t\t} else {\r\n\t\t\tthis.disable();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getValue(): string {\r\n\t\treturn this.inputBox.value;\r\n\t}\r\n\r\n\tpublic setValue(value: string): void {\r\n\t\tif (this.inputBox.value !== value) {\r\n\t\t\tthis.inputBox.value = value;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic style(styles: IFindInputStyles): void {\r\n\t\tthis.inputActiveOptionBorder = styles.inputActiveOptionBorder;\r\n\t\tthis.inputActiveOptionForeground = styles.inputActiveOptionForeground;\r\n\t\tthis.inputActiveOptionBackground = styles.inputActiveOptionBackground;\r\n\t\tthis.inputBackground = styles.inputBackground;\r\n\t\tthis.inputForeground = styles.inputForeground;\r\n\t\tthis.inputBorder = styles.inputBorder;\r\n\r\n\t\tthis.inputValidationInfoBackground = styles.inputValidationInfoBackground;\r\n\t\tthis.inputValidationInfoForeground = styles.inputValidationInfoForeground;\r\n\t\tthis.inputValidationInfoBorder = styles.inputValidationInfoBorder;\r\n\t\tthis.inputValidationWarningBackground = styles.inputValidationWarningBackground;\r\n\t\tthis.inputValidationWarningForeground = styles.inputValidationWarningForeground;\r\n\t\tthis.inputValidationWarningBorder = styles.inputValidationWarningBorder;\r\n\t\tthis.inputValidationErrorBackground = styles.inputValidationErrorBackground;\r\n\t\tthis.inputValidationErrorForeground = styles.inputValidationErrorForeground;\r\n\t\tthis.inputValidationErrorBorder = styles.inputValidationErrorBorder;\r\n\r\n\t\tthis.applyStyles();\r\n\t}\r\n\r\n\tprotected applyStyles(): void {\r\n\t\tif (this.domNode) {\r\n\t\t\tconst checkBoxStyles: ICheckboxStyles = {\r\n\t\t\t\tinputActiveOptionBorder: this.inputActiveOptionBorder,\r\n\t\t\t\tinputActiveOptionForeground: this.inputActiveOptionForeground,\r\n\t\t\t\tinputActiveOptionBackground: this.inputActiveOptionBackground,\r\n\t\t\t};\r\n\t\t\tthis.regex.style(checkBoxStyles);\r\n\t\t\tthis.wholeWords.style(checkBoxStyles);\r\n\t\t\tthis.caseSensitive.style(checkBoxStyles);\r\n\r\n\t\t\tconst inputBoxStyles: IInputBoxStyles = {\r\n\t\t\t\tinputBackground: this.inputBackground,\r\n\t\t\t\tinputForeground: this.inputForeground,\r\n\t\t\t\tinputBorder: this.inputBorder,\r\n\t\t\t\tinputValidationInfoBackground: this.inputValidationInfoBackground,\r\n\t\t\t\tinputValidationInfoForeground: this.inputValidationInfoForeground,\r\n\t\t\t\tinputValidationInfoBorder: this.inputValidationInfoBorder,\r\n\t\t\t\tinputValidationWarningBackground: this.inputValidationWarningBackground,\r\n\t\t\t\tinputValidationWarningForeground: this.inputValidationWarningForeground,\r\n\t\t\t\tinputValidationWarningBorder: this.inputValidationWarningBorder,\r\n\t\t\t\tinputValidationErrorBackground: this.inputValidationErrorBackground,\r\n\t\t\t\tinputValidationErrorForeground: this.inputValidationErrorForeground,\r\n\t\t\t\tinputValidationErrorBorder: this.inputValidationErrorBorder\r\n\t\t\t};\r\n\t\t\tthis.inputBox.style(inputBoxStyles);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic select(): void {\r\n\t\tthis.inputBox.select();\r\n\t}\r\n\r\n\tpublic focus(): void {\r\n\t\tthis.inputBox.focus();\r\n\t}\r\n\r\n\tpublic getCaseSensitive(): boolean {\r\n\t\treturn this.caseSensitive.checked;\r\n\t}\r\n\r\n\tpublic setCaseSensitive(value: boolean): void {\r\n\t\tthis.caseSensitive.checked = value;\r\n\t}\r\n\r\n\tpublic getWholeWords(): boolean {\r\n\t\treturn this.wholeWords.checked;\r\n\t}\r\n\r\n\tpublic setWholeWords(value: boolean): void {\r\n\t\tthis.wholeWords.checked = value;\r\n\t}\r\n\r\n\tpublic getRegex(): boolean {\r\n\t\treturn this.regex.checked;\r\n\t}\r\n\r\n\tpublic setRegex(value: boolean): void {\r\n\t\tthis.regex.checked = value;\r\n\t\tthis.validate();\r\n\t}\r\n\r\n\tpublic focusOnCaseSensitive(): void {\r\n\t\tthis.caseSensitive.focus();\r\n\t}\r\n\r\n\tprivate _lastHighlightFindOptions: number = 0;\r\n\tpublic highlightFindOptions(): void {\r\n\t\tthis.domNode.classList.remove('highlight-' + (this._lastHighlightFindOptions));\r\n\t\tthis._lastHighlightFindOptions = 1 - this._lastHighlightFindOptions;\r\n\t\tthis.domNode.classList.add('highlight-' + (this._lastHighlightFindOptions));\r\n\t}\r\n\r\n\tpublic validate(): void {\r\n\t\tthis.inputBox.validate();\r\n\t}\r\n\r\n\tpublic clearMessage(): void {\r\n\t\tthis.inputBox.hideMessage();\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./findInput';\r\n\r\nimport * as nls from 'vs/nls';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { IInputValidator, IInputBoxStyles, HistoryInputBox } from 'vs/base/browser/ui/inputbox/inputBox';\r\nimport { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';\r\nimport { Widget } from 'vs/base/browser/ui/widget';\r\nimport { Event, Emitter } from 'vs/base/common/event';\r\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { IMouseEvent } from 'vs/base/browser/mouseEvent';\r\nimport { KeyCode } from 'vs/base/common/keyCodes';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { ICheckboxStyles, Checkbox } from 'vs/base/browser/ui/checkbox/checkbox';\r\nimport { IFindInputCheckboxOpts } from 'vs/base/browser/ui/findinput/findInputCheckboxes';\r\nimport { Codicon } from 'vs/base/common/codicons';\r\n\r\nexport interface IReplaceInputOptions extends IReplaceInputStyles {\r\n\treadonly placeholder?: string;\r\n\treadonly validation?: IInputValidator;\r\n\treadonly label: string;\r\n\treadonly flexibleHeight?: boolean;\r\n\treadonly flexibleWidth?: boolean;\r\n\treadonly flexibleMaxHeight?: number;\r\n\r\n\treadonly appendPreserveCaseLabel?: string;\r\n\treadonly history?: string[];\r\n}\r\n\r\nexport interface IReplaceInputStyles extends IInputBoxStyles {\r\n\tinputActiveOptionBorder?: Color;\r\n\tinputActiveOptionForeground?: Color;\r\n\tinputActiveOptionBackground?: Color;\r\n}\r\n\r\nconst NLS_DEFAULT_LABEL = nls.localize('defaultLabel', \"input\");\r\nconst NLS_PRESERVE_CASE_LABEL = nls.localize('label.preserveCaseCheckbox', \"Preserve Case\");\r\n\r\nexport class PreserveCaseCheckbox extends Checkbox {\r\n\tconstructor(opts: IFindInputCheckboxOpts) {\r\n\t\tsuper({\r\n\t\t\t// TODO: does this need its own icon?\r\n\t\t\ticon: Codicon.preserveCase,\r\n\t\t\ttitle: NLS_PRESERVE_CASE_LABEL + opts.appendTitle,\r\n\t\t\tisChecked: opts.isChecked,\r\n\t\t\tinputActiveOptionBorder: opts.inputActiveOptionBorder,\r\n\t\t\tinputActiveOptionForeground: opts.inputActiveOptionForeground,\r\n\t\t\tinputActiveOptionBackground: opts.inputActiveOptionBackground\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class ReplaceInput extends Widget {\r\n\r\n\tprivate contextViewProvider: IContextViewProvider | undefined;\r\n\tprivate placeholder: string;\r\n\tprivate validation?: IInputValidator;\r\n\tprivate label: string;\r\n\tprivate fixFocusOnOptionClickEnabled = true;\r\n\r\n\tprivate inputActiveOptionBorder?: Color;\r\n\tprivate inputActiveOptionForeground?: Color;\r\n\tprivate inputActiveOptionBackground?: Color;\r\n\tprivate inputBackground?: Color;\r\n\tprivate inputForeground?: Color;\r\n\tprivate inputBorder?: Color;\r\n\r\n\tprivate inputValidationInfoBorder?: Color;\r\n\tprivate inputValidationInfoBackground?: Color;\r\n\tprivate inputValidationInfoForeground?: Color;\r\n\tprivate inputValidationWarningBorder?: Color;\r\n\tprivate inputValidationWarningBackground?: Color;\r\n\tprivate inputValidationWarningForeground?: Color;\r\n\tprivate inputValidationErrorBorder?: Color;\r\n\tprivate inputValidationErrorBackground?: Color;\r\n\tprivate inputValidationErrorForeground?: Color;\r\n\r\n\tprivate preserveCase: PreserveCaseCheckbox;\r\n\tprivate cachedOptionsWidth: number = 0;\r\n\tpublic domNode: HTMLElement;\r\n\tpublic inputBox: HistoryInputBox;\r\n\r\n\tprivate readonly _onDidOptionChange = this._register(new Emitter());\r\n\tpublic readonly onDidOptionChange: Event = this._onDidOptionChange.event;\r\n\r\n\tprivate readonly _onKeyDown = this._register(new Emitter());\r\n\tpublic readonly onKeyDown: Event = this._onKeyDown.event;\r\n\r\n\tprivate readonly _onMouseDown = this._register(new Emitter());\r\n\r\n\tprivate readonly _onInput = this._register(new Emitter());\r\n\r\n\tprivate readonly _onKeyUp = this._register(new Emitter());\r\n\r\n\tprivate _onPreserveCaseKeyDown = this._register(new Emitter());\r\n\tpublic readonly onPreserveCaseKeyDown: Event = this._onPreserveCaseKeyDown.event;\r\n\r\n\tconstructor(parent: HTMLElement | null, contextViewProvider: IContextViewProvider | undefined, private readonly _showOptionButtons: boolean, options: IReplaceInputOptions) {\r\n\t\tsuper();\r\n\t\tthis.contextViewProvider = contextViewProvider;\r\n\t\tthis.placeholder = options.placeholder || '';\r\n\t\tthis.validation = options.validation;\r\n\t\tthis.label = options.label || NLS_DEFAULT_LABEL;\r\n\r\n\t\tthis.inputActiveOptionBorder = options.inputActiveOptionBorder;\r\n\t\tthis.inputActiveOptionForeground = options.inputActiveOptionForeground;\r\n\t\tthis.inputActiveOptionBackground = options.inputActiveOptionBackground;\r\n\t\tthis.inputBackground = options.inputBackground;\r\n\t\tthis.inputForeground = options.inputForeground;\r\n\t\tthis.inputBorder = options.inputBorder;\r\n\r\n\t\tthis.inputValidationInfoBorder = options.inputValidationInfoBorder;\r\n\t\tthis.inputValidationInfoBackground = options.inputValidationInfoBackground;\r\n\t\tthis.inputValidationInfoForeground = options.inputValidationInfoForeground;\r\n\t\tthis.inputValidationWarningBorder = options.inputValidationWarningBorder;\r\n\t\tthis.inputValidationWarningBackground = options.inputValidationWarningBackground;\r\n\t\tthis.inputValidationWarningForeground = options.inputValidationWarningForeground;\r\n\t\tthis.inputValidationErrorBorder = options.inputValidationErrorBorder;\r\n\t\tthis.inputValidationErrorBackground = options.inputValidationErrorBackground;\r\n\t\tthis.inputValidationErrorForeground = options.inputValidationErrorForeground;\r\n\r\n\t\tconst appendPreserveCaseLabel = options.appendPreserveCaseLabel || '';\r\n\t\tconst history = options.history || [];\r\n\t\tconst flexibleHeight = !!options.flexibleHeight;\r\n\t\tconst flexibleWidth = !!options.flexibleWidth;\r\n\t\tconst flexibleMaxHeight = options.flexibleMaxHeight;\r\n\r\n\t\tthis.domNode = document.createElement('div');\r\n\t\tthis.domNode.classList.add('monaco-findInput');\r\n\r\n\t\tthis.inputBox = this._register(new HistoryInputBox(this.domNode, this.contextViewProvider, {\r\n\t\t\tariaLabel: this.label || '',\r\n\t\t\tplaceholder: this.placeholder || '',\r\n\t\t\tvalidationOptions: {\r\n\t\t\t\tvalidation: this.validation\r\n\t\t\t},\r\n\t\t\tinputBackground: this.inputBackground,\r\n\t\t\tinputForeground: this.inputForeground,\r\n\t\t\tinputBorder: this.inputBorder,\r\n\t\t\tinputValidationInfoBackground: this.inputValidationInfoBackground,\r\n\t\t\tinputValidationInfoForeground: this.inputValidationInfoForeground,\r\n\t\t\tinputValidationInfoBorder: this.inputValidationInfoBorder,\r\n\t\t\tinputValidationWarningBackground: this.inputValidationWarningBackground,\r\n\t\t\tinputValidationWarningForeground: this.inputValidationWarningForeground,\r\n\t\t\tinputValidationWarningBorder: this.inputValidationWarningBorder,\r\n\t\t\tinputValidationErrorBackground: this.inputValidationErrorBackground,\r\n\t\t\tinputValidationErrorForeground: this.inputValidationErrorForeground,\r\n\t\t\tinputValidationErrorBorder: this.inputValidationErrorBorder,\r\n\t\t\thistory,\r\n\t\t\tflexibleHeight,\r\n\t\t\tflexibleWidth,\r\n\t\t\tflexibleMaxHeight\r\n\t\t}));\r\n\r\n\t\tthis.preserveCase = this._register(new PreserveCaseCheckbox({\r\n\t\t\tappendTitle: appendPreserveCaseLabel,\r\n\t\t\tisChecked: false,\r\n\t\t\tinputActiveOptionBorder: this.inputActiveOptionBorder,\r\n\t\t\tinputActiveOptionForeground: this.inputActiveOptionForeground,\r\n\t\t\tinputActiveOptionBackground: this.inputActiveOptionBackground,\r\n\t\t}));\r\n\t\tthis._register(this.preserveCase.onChange(viaKeyboard => {\r\n\t\t\tthis._onDidOptionChange.fire(viaKeyboard);\r\n\t\t\tif (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {\r\n\t\t\t\tthis.inputBox.focus();\r\n\t\t\t}\r\n\t\t\tthis.validate();\r\n\t\t}));\r\n\t\tthis._register(this.preserveCase.onKeyDown(e => {\r\n\t\t\tthis._onPreserveCaseKeyDown.fire(e);\r\n\t\t}));\r\n\r\n\t\tif (this._showOptionButtons) {\r\n\t\t\tthis.cachedOptionsWidth = this.preserveCase.width();\r\n\t\t} else {\r\n\t\t\tthis.cachedOptionsWidth = 0;\r\n\t\t}\r\n\r\n\t\t// Arrow-Key support to navigate between options\r\n\t\tlet indexes = [this.preserveCase.domNode];\r\n\t\tthis.onkeydown(this.domNode, (event: IKeyboardEvent) => {\r\n\t\t\tif (event.equals(KeyCode.LeftArrow) || event.equals(KeyCode.RightArrow) || event.equals(KeyCode.Escape)) {\r\n\t\t\t\tlet index = indexes.indexOf(document.activeElement);\r\n\t\t\t\tif (index >= 0) {\r\n\t\t\t\t\tlet newIndex: number = -1;\r\n\t\t\t\t\tif (event.equals(KeyCode.RightArrow)) {\r\n\t\t\t\t\t\tnewIndex = (index + 1) % indexes.length;\r\n\t\t\t\t\t} else if (event.equals(KeyCode.LeftArrow)) {\r\n\t\t\t\t\t\tif (index === 0) {\r\n\t\t\t\t\t\t\tnewIndex = indexes.length - 1;\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tnewIndex = index - 1;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (event.equals(KeyCode.Escape)) {\r\n\t\t\t\t\t\tindexes[index].blur();\r\n\t\t\t\t\t\tthis.inputBox.focus();\r\n\t\t\t\t\t} else if (newIndex >= 0) {\r\n\t\t\t\t\t\tindexes[newIndex].focus();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tdom.EventHelper.stop(event, true);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\r\n\r\n\t\tlet controls = document.createElement('div');\r\n\t\tcontrols.className = 'controls';\r\n\t\tcontrols.style.display = this._showOptionButtons ? 'block' : 'none';\r\n\t\tcontrols.appendChild(this.preserveCase.domNode);\r\n\r\n\t\tthis.domNode.appendChild(controls);\r\n\r\n\t\tif (parent) {\r\n\t\t\tparent.appendChild(this.domNode);\r\n\t\t}\r\n\r\n\t\tthis.onkeydown(this.inputBox.inputElement, (e) => this._onKeyDown.fire(e));\r\n\t\tthis.onkeyup(this.inputBox.inputElement, (e) => this._onKeyUp.fire(e));\r\n\t\tthis.oninput(this.inputBox.inputElement, (e) => this._onInput.fire());\r\n\t\tthis.onmousedown(this.inputBox.inputElement, (e) => this._onMouseDown.fire(e));\r\n\t}\r\n\r\n\tpublic enable(): void {\r\n\t\tthis.domNode.classList.remove('disabled');\r\n\t\tthis.inputBox.enable();\r\n\t\tthis.preserveCase.enable();\r\n\t}\r\n\r\n\tpublic disable(): void {\r\n\t\tthis.domNode.classList.add('disabled');\r\n\t\tthis.inputBox.disable();\r\n\t\tthis.preserveCase.disable();\r\n\t}\r\n\r\n\tpublic setEnabled(enabled: boolean): void {\r\n\t\tif (enabled) {\r\n\t\t\tthis.enable();\r\n\t\t} else {\r\n\t\t\tthis.disable();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic style(styles: IReplaceInputStyles): void {\r\n\t\tthis.inputActiveOptionBorder = styles.inputActiveOptionBorder;\r\n\t\tthis.inputActiveOptionForeground = styles.inputActiveOptionForeground;\r\n\t\tthis.inputActiveOptionBackground = styles.inputActiveOptionBackground;\r\n\t\tthis.inputBackground = styles.inputBackground;\r\n\t\tthis.inputForeground = styles.inputForeground;\r\n\t\tthis.inputBorder = styles.inputBorder;\r\n\r\n\t\tthis.inputValidationInfoBackground = styles.inputValidationInfoBackground;\r\n\t\tthis.inputValidationInfoForeground = styles.inputValidationInfoForeground;\r\n\t\tthis.inputValidationInfoBorder = styles.inputValidationInfoBorder;\r\n\t\tthis.inputValidationWarningBackground = styles.inputValidationWarningBackground;\r\n\t\tthis.inputValidationWarningForeground = styles.inputValidationWarningForeground;\r\n\t\tthis.inputValidationWarningBorder = styles.inputValidationWarningBorder;\r\n\t\tthis.inputValidationErrorBackground = styles.inputValidationErrorBackground;\r\n\t\tthis.inputValidationErrorForeground = styles.inputValidationErrorForeground;\r\n\t\tthis.inputValidationErrorBorder = styles.inputValidationErrorBorder;\r\n\r\n\t\tthis.applyStyles();\r\n\t}\r\n\r\n\tprotected applyStyles(): void {\r\n\t\tif (this.domNode) {\r\n\t\t\tconst checkBoxStyles: ICheckboxStyles = {\r\n\t\t\t\tinputActiveOptionBorder: this.inputActiveOptionBorder,\r\n\t\t\t\tinputActiveOptionForeground: this.inputActiveOptionForeground,\r\n\t\t\t\tinputActiveOptionBackground: this.inputActiveOptionBackground,\r\n\t\t\t};\r\n\t\t\tthis.preserveCase.style(checkBoxStyles);\r\n\r\n\t\t\tconst inputBoxStyles: IInputBoxStyles = {\r\n\t\t\t\tinputBackground: this.inputBackground,\r\n\t\t\t\tinputForeground: this.inputForeground,\r\n\t\t\t\tinputBorder: this.inputBorder,\r\n\t\t\t\tinputValidationInfoBackground: this.inputValidationInfoBackground,\r\n\t\t\t\tinputValidationInfoForeground: this.inputValidationInfoForeground,\r\n\t\t\t\tinputValidationInfoBorder: this.inputValidationInfoBorder,\r\n\t\t\t\tinputValidationWarningBackground: this.inputValidationWarningBackground,\r\n\t\t\t\tinputValidationWarningForeground: this.inputValidationWarningForeground,\r\n\t\t\t\tinputValidationWarningBorder: this.inputValidationWarningBorder,\r\n\t\t\t\tinputValidationErrorBackground: this.inputValidationErrorBackground,\r\n\t\t\t\tinputValidationErrorForeground: this.inputValidationErrorForeground,\r\n\t\t\t\tinputValidationErrorBorder: this.inputValidationErrorBorder\r\n\t\t\t};\r\n\t\t\tthis.inputBox.style(inputBoxStyles);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic select(): void {\r\n\t\tthis.inputBox.select();\r\n\t}\r\n\r\n\tpublic focus(): void {\r\n\t\tthis.inputBox.focus();\r\n\t}\r\n\r\n\tpublic getPreserveCase(): boolean {\r\n\t\treturn this.preserveCase.checked;\r\n\t}\r\n\r\n\tpublic setPreserveCase(value: boolean): void {\r\n\t\tthis.preserveCase.checked = value;\r\n\t}\r\n\r\n\tpublic focusOnPreserve(): void {\r\n\t\tthis.preserveCase.focus();\r\n\t}\r\n\r\n\tpublic validate(): void {\r\n\t\tif (this.inputBox) {\r\n\t\t\tthis.inputBox.validate();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic set width(newWidth: number) {\r\n\t\tthis.inputBox.paddingRight = this.cachedOptionsWidth;\r\n\t\tthis.inputBox.width = newWidth;\r\n\t\tthis.domNode.style.width = newWidth + 'px';\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tsuper.dispose();\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { IActionRunner, IAction, SubmenuAction, Separator, IActionViewItemProvider, EmptySubmenuAction } from 'vs/base/common/actions';\r\nimport { ActionBar, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';\r\nimport { ResolvedKeybinding, KeyCode } from 'vs/base/common/keyCodes';\r\nimport { EventType, EventHelper, EventLike, removeTabIndexAndUpdateFocus, isAncestor, addDisposableListener, append, $, clearNode, createStyleSheet, isInShadowDOM, getActiveElement, Dimension, IDomNodePagePosition } from 'vs/base/browser/dom';\r\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { RunOnceScheduler } from 'vs/base/common/async';\r\nimport { DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';\r\nimport { ScrollbarVisibility, ScrollEvent } from 'vs/base/common/scrollable';\r\nimport { Event } from 'vs/base/common/event';\r\nimport { AnchorAlignment, layout, LayoutAnchorPosition } from 'vs/base/browser/ui/contextview/contextview';\r\nimport { isLinux, isMacintosh } from 'vs/base/common/platform';\r\nimport { Codicon, registerCodicon } from 'vs/base/common/codicons';\r\nimport { BaseActionViewItem, ActionViewItem, IActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems';\r\nimport { formatRule } from 'vs/base/browser/ui/codicons/codiconStyles';\r\nimport { isFirefox } from 'vs/base/browser/browser';\r\nimport { StandardMouseEvent } from 'vs/base/browser/mouseEvent';\r\nimport { stripIcons } from 'vs/base/common/iconLabels';\r\n\r\nexport const MENU_MNEMONIC_REGEX = /\\(&([^\\s&])\\)|(^|[^&])&([^\\s&])/;\r\nexport const MENU_ESCAPED_MNEMONIC_REGEX = /(&)?(&)([^\\s&])/g;\r\n\r\nconst menuSelectionIcon = registerCodicon('menu-selection', Codicon.check);\r\nconst menuSubmenuIcon = registerCodicon('menu-submenu', Codicon.chevronRight);\r\n\r\nexport enum Direction {\r\n\tRight,\r\n\tLeft\r\n}\r\n\r\nexport interface IMenuOptions {\r\n\tcontext?: any;\r\n\tactionViewItemProvider?: IActionViewItemProvider;\r\n\tactionRunner?: IActionRunner;\r\n\tgetKeyBinding?: (action: IAction) => ResolvedKeybinding | undefined;\r\n\tariaLabel?: string;\r\n\tenableMnemonics?: boolean;\r\n\tanchorAlignment?: AnchorAlignment;\r\n\texpandDirection?: Direction;\r\n\tuseEventAsContext?: boolean;\r\n\tsubmenuIds?: Set;\r\n}\r\n\r\nexport interface IMenuStyles {\r\n\tshadowColor?: Color;\r\n\tborderColor?: Color;\r\n\tforegroundColor?: Color;\r\n\tbackgroundColor?: Color;\r\n\tselectionForegroundColor?: Color;\r\n\tselectionBackgroundColor?: Color;\r\n\tselectionBorderColor?: Color;\r\n\tseparatorColor?: Color;\r\n}\r\n\r\ninterface ISubMenuData {\r\n\tparent: Menu;\r\n\tsubmenu?: Menu;\r\n}\r\n\r\nexport class Menu extends ActionBar {\r\n\tprivate mnemonics: Map>;\r\n\tprivate readonly menuDisposables: DisposableStore;\r\n\tprivate scrollableElement: DomScrollableElement;\r\n\tprivate menuElement: HTMLElement;\r\n\tstatic globalStyleSheet: HTMLStyleElement;\r\n\tprotected styleSheet: HTMLStyleElement | undefined;\r\n\r\n\tconstructor(container: HTMLElement, actions: ReadonlyArray, options: IMenuOptions = {}) {\r\n\t\tcontainer.classList.add('monaco-menu-container');\r\n\t\tcontainer.setAttribute('role', 'presentation');\r\n\t\tconst menuElement = document.createElement('div');\r\n\t\tmenuElement.classList.add('monaco-menu');\r\n\t\tmenuElement.setAttribute('role', 'presentation');\r\n\r\n\t\tsuper(menuElement, {\r\n\t\t\torientation: ActionsOrientation.VERTICAL,\r\n\t\t\tactionViewItemProvider: action => this.doGetActionViewItem(action, options, parentData),\r\n\t\t\tcontext: options.context,\r\n\t\t\tactionRunner: options.actionRunner,\r\n\t\t\tariaLabel: options.ariaLabel,\r\n\t\t\ttriggerKeys: { keys: [KeyCode.Enter, ...(isMacintosh || isLinux ? [KeyCode.Space] : [])], keyDown: true }\r\n\t\t});\r\n\r\n\t\tthis.menuElement = menuElement;\r\n\r\n\t\tthis.actionsList.setAttribute('role', 'menu');\r\n\r\n\t\tthis.actionsList.tabIndex = 0;\r\n\r\n\t\tthis.menuDisposables = this._register(new DisposableStore());\r\n\r\n\t\tthis.initializeStyleSheet(container);\r\n\r\n\t\taddDisposableListener(menuElement, EventType.KEY_DOWN, (e) => {\r\n\t\t\tconst event = new StandardKeyboardEvent(e);\r\n\r\n\t\t\t// Stop tab navigation of menus\r\n\t\t\tif (event.equals(KeyCode.Tab)) {\r\n\t\t\t\te.preventDefault();\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tif (options.enableMnemonics) {\r\n\t\t\tthis.menuDisposables.add(addDisposableListener(menuElement, EventType.KEY_DOWN, (e) => {\r\n\t\t\t\tconst key = e.key.toLocaleLowerCase();\r\n\t\t\t\tif (this.mnemonics.has(key)) {\r\n\t\t\t\t\tEventHelper.stop(e, true);\r\n\t\t\t\t\tconst actions = this.mnemonics.get(key)!;\r\n\r\n\t\t\t\t\tif (actions.length === 1) {\r\n\t\t\t\t\t\tif (actions[0] instanceof SubmenuMenuActionViewItem && actions[0].container) {\r\n\t\t\t\t\t\t\tthis.focusItemByElement(actions[0].container);\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tactions[0].onClick(e);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (actions.length > 1) {\r\n\t\t\t\t\t\tconst action = actions.shift();\r\n\t\t\t\t\t\tif (action && action.container) {\r\n\t\t\t\t\t\t\tthis.focusItemByElement(action.container);\r\n\t\t\t\t\t\t\tactions.push(action);\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tthis.mnemonics.set(key, actions);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}));\r\n\t\t}\r\n\r\n\t\tif (isLinux) {\r\n\t\t\tthis._register(addDisposableListener(menuElement, EventType.KEY_DOWN, e => {\r\n\t\t\t\tconst event = new StandardKeyboardEvent(e);\r\n\r\n\t\t\t\tif (event.equals(KeyCode.Home) || event.equals(KeyCode.PageUp)) {\r\n\t\t\t\t\tthis.focusedItem = this.viewItems.length - 1;\r\n\t\t\t\t\tthis.focusNext();\r\n\t\t\t\t\tEventHelper.stop(e, true);\r\n\t\t\t\t} else if (event.equals(KeyCode.End) || event.equals(KeyCode.PageDown)) {\r\n\t\t\t\t\tthis.focusedItem = 0;\r\n\t\t\t\t\tthis.focusPrevious();\r\n\t\t\t\t\tEventHelper.stop(e, true);\r\n\t\t\t\t}\r\n\t\t\t}));\r\n\t\t}\r\n\r\n\t\tthis._register(addDisposableListener(this.domNode, EventType.MOUSE_OUT, e => {\r\n\t\t\tlet relatedTarget = e.relatedTarget as HTMLElement;\r\n\t\t\tif (!isAncestor(relatedTarget, this.domNode)) {\r\n\t\t\t\tthis.focusedItem = undefined;\r\n\t\t\t\tthis.updateFocus();\r\n\t\t\t\te.stopPropagation();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._register(addDisposableListener(this.actionsList, EventType.MOUSE_OVER, e => {\r\n\t\t\tlet target = e.target as HTMLElement;\r\n\t\t\tif (!target || !isAncestor(target, this.actionsList) || target === this.actionsList) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\twhile (target.parentElement !== this.actionsList && target.parentElement !== null) {\r\n\t\t\t\ttarget = target.parentElement;\r\n\t\t\t}\r\n\r\n\t\t\tif (target.classList.contains('action-item')) {\r\n\t\t\t\tconst lastFocusedItem = this.focusedItem;\r\n\t\t\t\tthis.setFocusedItem(target);\r\n\r\n\t\t\t\tif (lastFocusedItem !== this.focusedItem) {\r\n\t\t\t\t\tthis.updateFocus();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tlet parentData: ISubMenuData = {\r\n\t\t\tparent: this\r\n\t\t};\r\n\r\n\t\tthis.mnemonics = new Map>();\r\n\r\n\t\t// Scroll Logic\r\n\t\tthis.scrollableElement = this._register(new DomScrollableElement(menuElement, {\r\n\t\t\talwaysConsumeMouseWheel: true,\r\n\t\t\thorizontal: ScrollbarVisibility.Hidden,\r\n\t\t\tvertical: ScrollbarVisibility.Visible,\r\n\t\t\tverticalScrollbarSize: 7,\r\n\t\t\thandleMouseWheel: true,\r\n\t\t\tuseShadows: true\r\n\t\t}));\r\n\r\n\t\tconst scrollElement = this.scrollableElement.getDomNode();\r\n\t\tscrollElement.style.position = '';\r\n\r\n\t\tthis._register(addDisposableListener(scrollElement, EventType.MOUSE_UP, e => {\r\n\t\t\t// Absorb clicks in menu dead space https://github.com/microsoft/vscode/issues/63575\r\n\t\t\t// We do this on the scroll element so the scroll bar doesn't dismiss the menu either\r\n\t\t\te.preventDefault();\r\n\t\t}));\r\n\r\n\t\tmenuElement.style.maxHeight = `${Math.max(10, window.innerHeight - container.getBoundingClientRect().top - 35)}px`;\r\n\r\n\t\tactions = actions.filter(a => {\r\n\t\t\tif (options.submenuIds?.has(a.id)) {\r\n\t\t\t\tconsole.warn(`Found submenu cycle: ${a.id}`);\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\treturn true;\r\n\t\t});\r\n\r\n\t\tthis.push(actions, { icon: true, label: true, isMenu: true });\r\n\r\n\t\tcontainer.appendChild(this.scrollableElement.getDomNode());\r\n\t\tthis.scrollableElement.scanDomNode();\r\n\r\n\t\tthis.viewItems.filter(item => !(item instanceof MenuSeparatorActionViewItem)).forEach((item, index, array) => {\r\n\t\t\t(item as BaseMenuActionViewItem).updatePositionInSet(index + 1, array.length);\r\n\t\t});\r\n\t}\r\n\r\n\tprivate initializeStyleSheet(container: HTMLElement): void {\r\n\t\tif (isInShadowDOM(container)) {\r\n\t\t\tthis.styleSheet = createStyleSheet(container);\r\n\t\t\tthis.styleSheet.textContent = MENU_WIDGET_CSS;\r\n\t\t} else {\r\n\t\t\tif (!Menu.globalStyleSheet) {\r\n\t\t\t\tMenu.globalStyleSheet = createStyleSheet();\r\n\t\t\t\tMenu.globalStyleSheet.textContent = MENU_WIDGET_CSS;\r\n\t\t\t}\r\n\r\n\t\t\tthis.styleSheet = Menu.globalStyleSheet;\r\n\t\t}\r\n\t}\r\n\r\n\tstyle(style: IMenuStyles): void {\r\n\t\tconst container = this.getContainer();\r\n\r\n\t\tconst fgColor = style.foregroundColor ? `${style.foregroundColor}` : '';\r\n\t\tconst bgColor = style.backgroundColor ? `${style.backgroundColor}` : '';\r\n\t\tconst border = style.borderColor ? `1px solid ${style.borderColor}` : '';\r\n\t\tconst shadow = style.shadowColor ? `0 2px 4px ${style.shadowColor}` : '';\r\n\r\n\t\tcontainer.style.border = border;\r\n\t\tthis.domNode.style.color = fgColor;\r\n\t\tthis.domNode.style.backgroundColor = bgColor;\r\n\t\tcontainer.style.boxShadow = shadow;\r\n\r\n\t\tif (this.viewItems) {\r\n\t\t\tthis.viewItems.forEach(item => {\r\n\t\t\t\tif (item instanceof BaseMenuActionViewItem || item instanceof MenuSeparatorActionViewItem) {\r\n\t\t\t\t\titem.style(style);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tgetContainer(): HTMLElement {\r\n\t\treturn this.scrollableElement.getDomNode();\r\n\t}\r\n\r\n\tget onScroll(): Event {\r\n\t\treturn this.scrollableElement.onScroll;\r\n\t}\r\n\r\n\tprivate focusItemByElement(element: HTMLElement) {\r\n\t\tconst lastFocusedItem = this.focusedItem;\r\n\t\tthis.setFocusedItem(element);\r\n\r\n\t\tif (lastFocusedItem !== this.focusedItem) {\r\n\t\t\tthis.updateFocus();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate setFocusedItem(element: HTMLElement): void {\r\n\t\tfor (let i = 0; i < this.actionsList.children.length; i++) {\r\n\t\t\tlet elem = this.actionsList.children[i];\r\n\t\t\tif (element === elem) {\r\n\t\t\t\tthis.focusedItem = i;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprotected updateFocus(fromRight?: boolean): void {\r\n\t\tsuper.updateFocus(fromRight, true);\r\n\r\n\t\tif (typeof this.focusedItem !== 'undefined') {\r\n\t\t\t// Workaround for #80047 caused by an issue in chromium\r\n\t\t\t// https://bugs.chromium.org/p/chromium/issues/detail?id=414283\r\n\t\t\t// When that's fixed, just call this.scrollableElement.scanDomNode()\r\n\t\t\tthis.scrollableElement.setScrollPosition({\r\n\t\t\t\tscrollTop: Math.round(this.menuElement.scrollTop)\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tprivate doGetActionViewItem(action: IAction, options: IMenuOptions, parentData: ISubMenuData): BaseActionViewItem {\r\n\t\tif (action instanceof Separator) {\r\n\t\t\treturn new MenuSeparatorActionViewItem(options.context, action, { icon: true });\r\n\t\t} else if (action instanceof SubmenuAction) {\r\n\t\t\tconst menuActionViewItem = new SubmenuMenuActionViewItem(action, action.actions, parentData, { ...options, submenuIds: new Set([...(options.submenuIds || []), action.id]) });\r\n\r\n\t\t\tif (options.enableMnemonics) {\r\n\t\t\t\tconst mnemonic = menuActionViewItem.getMnemonic();\r\n\t\t\t\tif (mnemonic && menuActionViewItem.isEnabled()) {\r\n\t\t\t\t\tlet actionViewItems: BaseMenuActionViewItem[] = [];\r\n\t\t\t\t\tif (this.mnemonics.has(mnemonic)) {\r\n\t\t\t\t\t\tactionViewItems = this.mnemonics.get(mnemonic)!;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tactionViewItems.push(menuActionViewItem);\r\n\r\n\t\t\t\t\tthis.mnemonics.set(mnemonic, actionViewItems);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn menuActionViewItem;\r\n\t\t} else {\r\n\t\t\tconst menuItemOptions: IMenuItemOptions = { enableMnemonics: options.enableMnemonics, useEventAsContext: options.useEventAsContext };\r\n\t\t\tif (options.getKeyBinding) {\r\n\t\t\t\tconst keybinding = options.getKeyBinding(action);\r\n\t\t\t\tif (keybinding) {\r\n\t\t\t\t\tconst keybindingLabel = keybinding.getLabel();\r\n\r\n\t\t\t\t\tif (keybindingLabel) {\r\n\t\t\t\t\t\tmenuItemOptions.keybinding = keybindingLabel;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tconst menuActionViewItem = new BaseMenuActionViewItem(options.context, action, menuItemOptions);\r\n\r\n\t\t\tif (options.enableMnemonics) {\r\n\t\t\t\tconst mnemonic = menuActionViewItem.getMnemonic();\r\n\t\t\t\tif (mnemonic && menuActionViewItem.isEnabled()) {\r\n\t\t\t\t\tlet actionViewItems: BaseMenuActionViewItem[] = [];\r\n\t\t\t\t\tif (this.mnemonics.has(mnemonic)) {\r\n\t\t\t\t\t\tactionViewItems = this.mnemonics.get(mnemonic)!;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tactionViewItems.push(menuActionViewItem);\r\n\r\n\t\t\t\t\tthis.mnemonics.set(mnemonic, actionViewItems);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn menuActionViewItem;\r\n\t\t}\r\n\t}\r\n}\r\n\r\ninterface IMenuItemOptions extends IActionViewItemOptions {\r\n\tenableMnemonics?: boolean;\r\n}\r\n\r\nclass BaseMenuActionViewItem extends BaseActionViewItem {\r\n\r\n\tpublic container: HTMLElement | undefined;\r\n\r\n\tprotected options: IMenuItemOptions;\r\n\tprotected item: HTMLElement | undefined;\r\n\r\n\tprivate runOnceToEnableMouseUp: RunOnceScheduler;\r\n\tprivate label: HTMLElement | undefined;\r\n\tprivate check: HTMLElement | undefined;\r\n\tprivate mnemonic: string | undefined;\r\n\tprivate cssClass: string;\r\n\tprotected menuStyle: IMenuStyles | undefined;\r\n\r\n\tconstructor(ctx: unknown, action: IAction, options: IMenuItemOptions = {}) {\r\n\t\toptions.isMenu = true;\r\n\t\tsuper(action, action, options);\r\n\r\n\t\tthis.options = options;\r\n\t\tthis.options.icon = options.icon !== undefined ? options.icon : false;\r\n\t\tthis.options.label = options.label !== undefined ? options.label : true;\r\n\t\tthis.cssClass = '';\r\n\r\n\t\t// Set mnemonic\r\n\t\tif (this.options.label && options.enableMnemonics) {\r\n\t\t\tlet label = this.getAction().label;\r\n\t\t\tif (label) {\r\n\t\t\t\tlet matches = MENU_MNEMONIC_REGEX.exec(label);\r\n\t\t\t\tif (matches) {\r\n\t\t\t\t\tthis.mnemonic = (!!matches[1] ? matches[1] : matches[3]).toLocaleLowerCase();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Add mouse up listener later to avoid accidental clicks\r\n\t\tthis.runOnceToEnableMouseUp = new RunOnceScheduler(() => {\r\n\t\t\tif (!this.element) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tthis._register(addDisposableListener(this.element, EventType.MOUSE_UP, e => {\r\n\t\t\t\t// removed default prevention as it conflicts\r\n\t\t\t\t// with BaseActionViewItem #101537\r\n\t\t\t\t// add back if issues arise and link new issue\r\n\t\t\t\tEventHelper.stop(e, true);\r\n\r\n\t\t\t\t// See https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Interact_with_the_clipboard\r\n\t\t\t\t// > Writing to the clipboard\r\n\t\t\t\t// > You can use the \"cut\" and \"copy\" commands without any special\r\n\t\t\t\t// permission if you are using them in a short-lived event handler\r\n\t\t\t\t// for a user action (for example, a click handler).\r\n\r\n\t\t\t\t// => to get the Copy and Paste context menu actions working on Firefox,\r\n\t\t\t\t// there should be no timeout here\r\n\t\t\t\tif (isFirefox) {\r\n\t\t\t\t\tconst mouseEvent = new StandardMouseEvent(e);\r\n\r\n\t\t\t\t\t// Allowing right click to trigger the event causes the issue described below,\r\n\t\t\t\t\t// but since the solution below does not work in FF, we must disable right click\r\n\t\t\t\t\tif (mouseEvent.rightButton) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tthis.onClick(e);\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// In all other cases, set timout to allow context menu cancellation to trigger\r\n\t\t\t\t// otherwise the action will destroy the menu and a second context menu\r\n\t\t\t\t// will still trigger for right click.\r\n\t\t\t\telse {\r\n\t\t\t\t\tsetTimeout(() => {\r\n\t\t\t\t\t\tthis.onClick(e);\r\n\t\t\t\t\t}, 0);\r\n\t\t\t\t}\r\n\t\t\t}));\r\n\r\n\t\t\tthis._register(addDisposableListener(this.element, EventType.CONTEXT_MENU, e => {\r\n\t\t\t\tEventHelper.stop(e, true);\r\n\t\t\t}));\r\n\t\t}, 100);\r\n\r\n\t\tthis._register(this.runOnceToEnableMouseUp);\r\n\t}\r\n\r\n\trender(container: HTMLElement): void {\r\n\t\tsuper.render(container);\r\n\r\n\t\tif (!this.element) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.container = container;\r\n\r\n\t\tthis.item = append(this.element, $('a.action-menu-item'));\r\n\t\tif (this._action.id === Separator.ID) {\r\n\t\t\t// A separator is a presentation item\r\n\t\t\tthis.item.setAttribute('role', 'presentation');\r\n\t\t} else {\r\n\t\t\tthis.item.setAttribute('role', 'menuitem');\r\n\t\t\tif (this.mnemonic) {\r\n\t\t\t\tthis.item.setAttribute('aria-keyshortcuts', `${this.mnemonic}`);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis.check = append(this.item, $('span.menu-item-check' + menuSelectionIcon.cssSelector));\r\n\t\tthis.check.setAttribute('role', 'none');\r\n\r\n\t\tthis.label = append(this.item, $('span.action-label'));\r\n\r\n\t\tif (this.options.label && this.options.keybinding) {\r\n\t\t\tappend(this.item, $('span.keybinding')).textContent = this.options.keybinding;\r\n\t\t}\r\n\r\n\t\t// Adds mouse up listener to actually run the action\r\n\t\tthis.runOnceToEnableMouseUp.schedule();\r\n\r\n\t\tthis.updateClass();\r\n\t\tthis.updateLabel();\r\n\t\tthis.updateTooltip();\r\n\t\tthis.updateEnabled();\r\n\t\tthis.updateChecked();\r\n\t}\r\n\r\n\tblur(): void {\r\n\t\tsuper.blur();\r\n\t\tthis.applyStyle();\r\n\t}\r\n\r\n\tfocus(): void {\r\n\t\tsuper.focus();\r\n\r\n\t\tif (this.item) {\r\n\t\t\tthis.item.focus();\r\n\t\t}\r\n\r\n\t\tthis.applyStyle();\r\n\t}\r\n\r\n\tupdatePositionInSet(pos: number, setSize: number): void {\r\n\t\tif (this.item) {\r\n\t\t\tthis.item.setAttribute('aria-posinset', `${pos}`);\r\n\t\t\tthis.item.setAttribute('aria-setsize', `${setSize}`);\r\n\t\t}\r\n\t}\r\n\r\n\tupdateLabel(): void {\r\n\t\tif (!this.label) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this.options.label) {\r\n\t\t\tclearNode(this.label);\r\n\r\n\t\t\tlet label = stripIcons(this.getAction().label);\r\n\t\t\tif (label) {\r\n\t\t\t\tconst cleanLabel = cleanMnemonic(label);\r\n\t\t\t\tif (!this.options.enableMnemonics) {\r\n\t\t\t\t\tlabel = cleanLabel;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis.label.setAttribute('aria-label', cleanLabel.replace(/&&/g, '&'));\r\n\r\n\t\t\t\tconst matches = MENU_MNEMONIC_REGEX.exec(label);\r\n\r\n\t\t\t\tif (matches) {\r\n\t\t\t\t\tlabel = strings.escape(label);\r\n\r\n\t\t\t\t\t// This is global, reset it\r\n\t\t\t\t\tMENU_ESCAPED_MNEMONIC_REGEX.lastIndex = 0;\r\n\t\t\t\t\tlet escMatch = MENU_ESCAPED_MNEMONIC_REGEX.exec(label);\r\n\r\n\t\t\t\t\t// We can't use negative lookbehind so if we match our negative and skip\r\n\t\t\t\t\twhile (escMatch && escMatch[1]) {\r\n\t\t\t\t\t\tescMatch = MENU_ESCAPED_MNEMONIC_REGEX.exec(label);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tconst replaceDoubleEscapes = (str: string) => str.replace(/&&/g, '&');\r\n\r\n\t\t\t\t\tif (escMatch) {\r\n\t\t\t\t\t\tthis.label.append(\r\n\t\t\t\t\t\t\tstrings.ltrim(replaceDoubleEscapes(label.substr(0, escMatch.index)), ' '),\r\n\t\t\t\t\t\t\t$('u', { 'aria-hidden': 'true' },\r\n\t\t\t\t\t\t\t\tescMatch[3]),\r\n\t\t\t\t\t\t\tstrings.rtrim(replaceDoubleEscapes(label.substr(escMatch.index + escMatch[0].length)), ' '));\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tthis.label.innerText = replaceDoubleEscapes(label).trim();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (this.item) {\r\n\t\t\t\t\t\tthis.item.setAttribute('aria-keyshortcuts', (!!matches[1] ? matches[1] : matches[3]).toLocaleLowerCase());\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis.label.innerText = label.replace(/&&/g, '&').trim();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tupdateTooltip(): void {\r\n\t\tlet title: string | null = null;\r\n\r\n\t\tif (this.getAction().tooltip) {\r\n\t\t\ttitle = this.getAction().tooltip;\r\n\r\n\t\t} else if (!this.options.label && this.getAction().label && this.options.icon) {\r\n\t\t\ttitle = this.getAction().label;\r\n\r\n\t\t\tif (this.options.keybinding) {\r\n\t\t\t\ttitle = nls.localize({ key: 'titleLabel', comment: ['action title', 'action keybinding'] }, \"{0} ({1})\", title, this.options.keybinding);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (title && this.item) {\r\n\t\t\tthis.item.title = title;\r\n\t\t}\r\n\t}\r\n\r\n\tupdateClass(): void {\r\n\t\tif (this.cssClass && this.item) {\r\n\t\t\tthis.item.classList.remove(...this.cssClass.split(' '));\r\n\t\t}\r\n\t\tif (this.options.icon && this.label) {\r\n\t\t\tthis.cssClass = this.getAction().class || '';\r\n\t\t\tthis.label.classList.add('icon');\r\n\t\t\tif (this.cssClass) {\r\n\t\t\t\tthis.label.classList.add(...this.cssClass.split(' '));\r\n\t\t\t}\r\n\t\t\tthis.updateEnabled();\r\n\t\t} else if (this.label) {\r\n\t\t\tthis.label.classList.remove('icon');\r\n\t\t}\r\n\t}\r\n\r\n\tupdateEnabled(): void {\r\n\t\tif (this.getAction().enabled) {\r\n\t\t\tif (this.element) {\r\n\t\t\t\tthis.element.classList.remove('disabled');\r\n\t\t\t}\r\n\r\n\t\t\tif (this.item) {\r\n\t\t\t\tthis.item.classList.remove('disabled');\r\n\t\t\t\tthis.item.tabIndex = 0;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tif (this.element) {\r\n\t\t\t\tthis.element.classList.add('disabled');\r\n\t\t\t}\r\n\r\n\t\t\tif (this.item) {\r\n\t\t\t\tthis.item.classList.add('disabled');\r\n\t\t\t\tremoveTabIndexAndUpdateFocus(this.item);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tupdateChecked(): void {\r\n\t\tif (!this.item) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this.getAction().checked) {\r\n\t\t\tthis.item.classList.add('checked');\r\n\t\t\tthis.item.setAttribute('role', 'menuitemcheckbox');\r\n\t\t\tthis.item.setAttribute('aria-checked', 'true');\r\n\t\t} else {\r\n\t\t\tthis.item.classList.remove('checked');\r\n\t\t\tthis.item.setAttribute('role', 'menuitem');\r\n\t\t\tthis.item.setAttribute('aria-checked', 'false');\r\n\t\t}\r\n\t}\r\n\r\n\tgetMnemonic(): string | undefined {\r\n\t\treturn this.mnemonic;\r\n\t}\r\n\r\n\tprotected applyStyle(): void {\r\n\t\tif (!this.menuStyle) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst isSelected = this.element && this.element.classList.contains('focused');\r\n\t\tconst fgColor = isSelected && this.menuStyle.selectionForegroundColor ? this.menuStyle.selectionForegroundColor : this.menuStyle.foregroundColor;\r\n\t\tconst bgColor = isSelected && this.menuStyle.selectionBackgroundColor ? this.menuStyle.selectionBackgroundColor : undefined;\r\n\t\tconst border = isSelected && this.menuStyle.selectionBorderColor ? `thin solid ${this.menuStyle.selectionBorderColor}` : '';\r\n\r\n\t\tif (this.item) {\r\n\t\t\tthis.item.style.color = fgColor ? fgColor.toString() : '';\r\n\t\t\tthis.item.style.backgroundColor = bgColor ? bgColor.toString() : '';\r\n\t\t}\r\n\r\n\t\tif (this.check) {\r\n\t\t\tthis.check.style.color = fgColor ? fgColor.toString() : '';\r\n\t\t}\r\n\r\n\t\tif (this.container) {\r\n\t\t\tthis.container.style.border = border;\r\n\t\t}\r\n\t}\r\n\r\n\tstyle(style: IMenuStyles): void {\r\n\t\tthis.menuStyle = style;\r\n\t\tthis.applyStyle();\r\n\t}\r\n}\r\n\r\nclass SubmenuMenuActionViewItem extends BaseMenuActionViewItem {\r\n\tprivate mysubmenu: Menu | null = null;\r\n\tprivate submenuContainer: HTMLElement | undefined;\r\n\tprivate submenuIndicator: HTMLElement | undefined;\r\n\tprivate readonly submenuDisposables = this._register(new DisposableStore());\r\n\tprivate mouseOver: boolean = false;\r\n\tprivate showScheduler: RunOnceScheduler;\r\n\tprivate hideScheduler: RunOnceScheduler;\r\n\tprivate expandDirection: Direction;\r\n\r\n\tconstructor(\r\n\t\taction: IAction,\r\n\t\tprivate submenuActions: ReadonlyArray,\r\n\t\tprivate parentData: ISubMenuData,\r\n\t\tprivate submenuOptions?: IMenuOptions\r\n\t) {\r\n\t\tsuper(action, action, submenuOptions);\r\n\r\n\t\tthis.expandDirection = submenuOptions && submenuOptions.expandDirection !== undefined ? submenuOptions.expandDirection : Direction.Right;\r\n\r\n\t\tthis.showScheduler = new RunOnceScheduler(() => {\r\n\t\t\tif (this.mouseOver) {\r\n\t\t\t\tthis.cleanupExistingSubmenu(false);\r\n\t\t\t\tthis.createSubmenu(false);\r\n\t\t\t}\r\n\t\t}, 250);\r\n\r\n\t\tthis.hideScheduler = new RunOnceScheduler(() => {\r\n\t\t\tif (this.element && (!isAncestor(getActiveElement(), this.element) && this.parentData.submenu === this.mysubmenu)) {\r\n\t\t\t\tthis.parentData.parent.focus(false);\r\n\t\t\t\tthis.cleanupExistingSubmenu(true);\r\n\t\t\t}\r\n\t\t}, 750);\r\n\t}\r\n\r\n\trender(container: HTMLElement): void {\r\n\t\tsuper.render(container);\r\n\r\n\t\tif (!this.element) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this.item) {\r\n\t\t\tthis.item.classList.add('monaco-submenu-item');\r\n\t\t\tthis.item.tabIndex = 0;\r\n\t\t\tthis.item.setAttribute('aria-haspopup', 'true');\r\n\t\t\tthis.updateAriaExpanded('false');\r\n\t\t\tthis.submenuIndicator = append(this.item, $('span.submenu-indicator' + menuSubmenuIcon.cssSelector));\r\n\t\t\tthis.submenuIndicator.setAttribute('aria-hidden', 'true');\r\n\t\t}\r\n\r\n\t\tthis._register(addDisposableListener(this.element, EventType.KEY_UP, e => {\r\n\t\t\tlet event = new StandardKeyboardEvent(e);\r\n\t\t\tif (event.equals(KeyCode.RightArrow) || event.equals(KeyCode.Enter)) {\r\n\t\t\t\tEventHelper.stop(e, true);\r\n\r\n\t\t\t\tthis.createSubmenu(true);\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._register(addDisposableListener(this.element, EventType.KEY_DOWN, e => {\r\n\t\t\tlet event = new StandardKeyboardEvent(e);\r\n\r\n\t\t\tif (getActiveElement() === this.item) {\r\n\t\t\t\tif (event.equals(KeyCode.RightArrow) || event.equals(KeyCode.Enter)) {\r\n\t\t\t\t\tEventHelper.stop(e, true);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._register(addDisposableListener(this.element, EventType.MOUSE_OVER, e => {\r\n\t\t\tif (!this.mouseOver) {\r\n\t\t\t\tthis.mouseOver = true;\r\n\r\n\t\t\t\tthis.showScheduler.schedule();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._register(addDisposableListener(this.element, EventType.MOUSE_LEAVE, e => {\r\n\t\t\tthis.mouseOver = false;\r\n\t\t}));\r\n\r\n\t\tthis._register(addDisposableListener(this.element, EventType.FOCUS_OUT, e => {\r\n\t\t\tif (this.element && !isAncestor(getActiveElement(), this.element)) {\r\n\t\t\t\tthis.hideScheduler.schedule();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._register(this.parentData.parent.onScroll(() => {\r\n\t\t\tthis.parentData.parent.focus(false);\r\n\t\t\tthis.cleanupExistingSubmenu(false);\r\n\t\t}));\r\n\t}\r\n\r\n\tupdateEnabled(): void {\r\n\t\t// override on submenu entry\r\n\t\t// native menus do not observe enablement on sumbenus\r\n\t\t// we mimic that behavior\r\n\t}\r\n\r\n\tonClick(e: EventLike): void {\r\n\t\t// stop clicking from trying to run an action\r\n\t\tEventHelper.stop(e, true);\r\n\r\n\t\tthis.cleanupExistingSubmenu(false);\r\n\t\tthis.createSubmenu(true);\r\n\t}\r\n\r\n\tprivate cleanupExistingSubmenu(force: boolean): void {\r\n\t\tif (this.parentData.submenu && (force || (this.parentData.submenu !== this.mysubmenu))) {\r\n\r\n\t\t\t// disposal may throw if the submenu has already been removed\r\n\t\t\ttry {\r\n\t\t\t\tthis.parentData.submenu.dispose();\r\n\t\t\t} catch { }\r\n\r\n\t\t\tthis.parentData.submenu = undefined;\r\n\t\t\tthis.updateAriaExpanded('false');\r\n\t\t\tif (this.submenuContainer) {\r\n\t\t\t\tthis.submenuDisposables.clear();\r\n\t\t\t\tthis.submenuContainer = undefined;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate calculateSubmenuMenuLayout(windowDimensions: Dimension, submenu: Dimension, entry: IDomNodePagePosition, expandDirection: Direction): { top: number, left: number } {\r\n\t\tconst ret = { top: 0, left: 0 };\r\n\r\n\t\t// Start with horizontal\r\n\t\tret.left = layout(windowDimensions.width, submenu.width, { position: expandDirection === Direction.Right ? LayoutAnchorPosition.Before : LayoutAnchorPosition.After, offset: entry.left, size: entry.width });\r\n\r\n\t\t// We don't have enough room to layout the menu fully, so we are overlapping the menu\r\n\t\tif (ret.left >= entry.left && ret.left < entry.left + entry.width) {\r\n\t\t\tif (entry.left + 10 + submenu.width <= windowDimensions.width) {\r\n\t\t\t\tret.left = entry.left + 10;\r\n\t\t\t}\r\n\r\n\t\t\tentry.top += 10;\r\n\t\t\tentry.height = 0;\r\n\t\t}\r\n\r\n\t\t// Now that we have a horizontal position, try layout vertically\r\n\t\tret.top = layout(windowDimensions.height, submenu.height, { position: LayoutAnchorPosition.Before, offset: entry.top, size: 0 });\r\n\r\n\t\t// We didn't have enough room below, but we did above, so we shift down to align the menu\r\n\t\tif (ret.top + submenu.height === entry.top && ret.top + entry.height + submenu.height <= windowDimensions.height) {\r\n\t\t\tret.top += entry.height;\r\n\t\t}\r\n\r\n\t\treturn ret;\r\n\t}\r\n\r\n\tprivate createSubmenu(selectFirstItem = true): void {\r\n\t\tif (!this.element) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!this.parentData.submenu) {\r\n\t\t\tthis.updateAriaExpanded('true');\r\n\t\t\tthis.submenuContainer = append(this.element, $('div.monaco-submenu'));\r\n\t\t\tthis.submenuContainer.classList.add('menubar-menu-items-holder', 'context-view');\r\n\r\n\t\t\t// Set the top value of the menu container before construction\r\n\t\t\t// This allows the menu constructor to calculate the proper max height\r\n\t\t\tconst computedStyles = getComputedStyle(this.parentData.parent.domNode);\r\n\t\t\tconst paddingTop = parseFloat(computedStyles.paddingTop || '0') || 0;\r\n\t\t\t// this.submenuContainer.style.top = `${this.element.offsetTop - this.parentData.parent.scrollOffset - paddingTop}px`;\r\n\t\t\tthis.submenuContainer.style.zIndex = '1';\r\n\t\t\tthis.submenuContainer.style.position = 'fixed';\r\n\t\t\tthis.submenuContainer.style.top = '0';\r\n\t\t\tthis.submenuContainer.style.left = '0';\r\n\r\n\t\t\tthis.parentData.submenu = new Menu(this.submenuContainer, this.submenuActions.length ? this.submenuActions : [new EmptySubmenuAction()], this.submenuOptions);\r\n\t\t\tif (this.menuStyle) {\r\n\t\t\t\tthis.parentData.submenu.style(this.menuStyle);\r\n\t\t\t}\r\n\r\n\t\t\t// layout submenu\r\n\t\t\tconst entryBox = this.element.getBoundingClientRect();\r\n\t\t\tconst entryBoxUpdated = {\r\n\t\t\t\ttop: entryBox.top - paddingTop,\r\n\t\t\t\tleft: entryBox.left,\r\n\t\t\t\theight: entryBox.height + 2 * paddingTop,\r\n\t\t\t\twidth: entryBox.width\r\n\t\t\t};\r\n\r\n\t\t\tconst viewBox = this.submenuContainer.getBoundingClientRect();\r\n\r\n\t\t\tconst { top, left } = this.calculateSubmenuMenuLayout(new Dimension(window.innerWidth, window.innerHeight), Dimension.lift(viewBox), entryBoxUpdated, this.expandDirection);\r\n\t\t\tthis.submenuContainer.style.left = `${left}px`;\r\n\t\t\tthis.submenuContainer.style.top = `${top}px`;\r\n\r\n\t\t\tthis.submenuDisposables.add(addDisposableListener(this.submenuContainer, EventType.KEY_UP, e => {\r\n\t\t\t\tlet event = new StandardKeyboardEvent(e);\r\n\t\t\t\tif (event.equals(KeyCode.LeftArrow)) {\r\n\t\t\t\t\tEventHelper.stop(e, true);\r\n\r\n\t\t\t\t\tthis.parentData.parent.focus();\r\n\r\n\t\t\t\t\tthis.cleanupExistingSubmenu(true);\r\n\t\t\t\t}\r\n\t\t\t}));\r\n\r\n\t\t\tthis.submenuDisposables.add(addDisposableListener(this.submenuContainer, EventType.KEY_DOWN, e => {\r\n\t\t\t\tlet event = new StandardKeyboardEvent(e);\r\n\t\t\t\tif (event.equals(KeyCode.LeftArrow)) {\r\n\t\t\t\t\tEventHelper.stop(e, true);\r\n\t\t\t\t}\r\n\t\t\t}));\r\n\r\n\r\n\t\t\tthis.submenuDisposables.add(this.parentData.submenu.onDidCancel(() => {\r\n\t\t\t\tthis.parentData.parent.focus();\r\n\r\n\t\t\t\tthis.cleanupExistingSubmenu(true);\r\n\t\t\t}));\r\n\r\n\t\t\tthis.parentData.submenu.focus(selectFirstItem);\r\n\r\n\t\t\tthis.mysubmenu = this.parentData.submenu;\r\n\t\t} else {\r\n\t\t\tthis.parentData.submenu.focus(false);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate updateAriaExpanded(value: string): void {\r\n\t\tif (this.item) {\r\n\t\t\tthis.item?.setAttribute('aria-expanded', value);\r\n\t\t}\r\n\t}\r\n\r\n\tprotected applyStyle(): void {\r\n\t\tsuper.applyStyle();\r\n\r\n\t\tif (!this.menuStyle) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst isSelected = this.element && this.element.classList.contains('focused');\r\n\t\tconst fgColor = isSelected && this.menuStyle.selectionForegroundColor ? this.menuStyle.selectionForegroundColor : this.menuStyle.foregroundColor;\r\n\r\n\t\tif (this.submenuIndicator) {\r\n\t\t\tthis.submenuIndicator.style.color = fgColor ? `${fgColor}` : '';\r\n\t\t}\r\n\r\n\t\tif (this.parentData.submenu) {\r\n\t\t\tthis.parentData.submenu.style(this.menuStyle);\r\n\t\t}\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tsuper.dispose();\r\n\r\n\t\tthis.hideScheduler.dispose();\r\n\r\n\t\tif (this.mysubmenu) {\r\n\t\t\tthis.mysubmenu.dispose();\r\n\t\t\tthis.mysubmenu = null;\r\n\t\t}\r\n\r\n\t\tif (this.submenuContainer) {\r\n\t\t\tthis.submenuContainer = undefined;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass MenuSeparatorActionViewItem extends ActionViewItem {\r\n\tstyle(style: IMenuStyles): void {\r\n\t\tif (this.label) {\r\n\t\t\tthis.label.style.borderBottomColor = style.separatorColor ? `${style.separatorColor}` : '';\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport function cleanMnemonic(label: string): string {\r\n\tconst regex = MENU_MNEMONIC_REGEX;\r\n\r\n\tconst matches = regex.exec(label);\r\n\tif (!matches) {\r\n\t\treturn label;\r\n\t}\r\n\r\n\tconst mnemonicInText = !matches[1];\r\n\r\n\treturn label.replace(regex, mnemonicInText ? '$2$3' : '').trim();\r\n}\r\n\r\nlet MENU_WIDGET_CSS: string = /* css */`\r\n.monaco-menu {\r\n\tfont-size: 13px;\r\n\r\n}\r\n\r\n${formatRule(menuSelectionIcon)}\r\n${formatRule(menuSubmenuIcon)}\r\n\r\n.monaco-menu .monaco-action-bar {\r\n\ttext-align: right;\r\n\toverflow: hidden;\r\n\twhite-space: nowrap;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar .actions-container {\r\n\tdisplay: flex;\r\n\tmargin: 0 auto;\r\n\tpadding: 0;\r\n\twidth: 100%;\r\n\tjustify-content: flex-end;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .actions-container {\r\n\tdisplay: inline-block;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.reverse .actions-container {\r\n\tflex-direction: row-reverse;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar .action-item {\r\n\tcursor: pointer;\r\n\tdisplay: inline-block;\r\n\ttransition: transform 50ms ease;\r\n\tposition: relative; /* DO NOT REMOVE - this is the key to preventing the ghosting icon bug in Chrome 42 */\r\n}\r\n\r\n.monaco-menu .monaco-action-bar .action-item.disabled {\r\n\tcursor: default;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.animated .action-item.active {\r\n\ttransform: scale(1.272019649, 1.272019649); /* 1.272019649 = √φ */\r\n}\r\n\r\n.monaco-menu .monaco-action-bar .action-item .icon,\r\n.monaco-menu .monaco-action-bar .action-item .codicon {\r\n\tdisplay: inline-block;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar .action-item .codicon {\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar .action-label {\r\n\tfont-size: 11px;\r\n\tmargin-right: 4px;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar .action-item.disabled .action-label,\r\n.monaco-menu .monaco-action-bar .action-item.disabled .action-label:hover {\r\n\topacity: 0.4;\r\n}\r\n\r\n/* Vertical actions */\r\n\r\n.monaco-menu .monaco-action-bar.vertical {\r\n\ttext-align: left;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .action-item {\r\n\tdisplay: block;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .action-label.separator {\r\n\tdisplay: block;\r\n\tborder-bottom: 1px solid #bbb;\r\n\tpadding-top: 1px;\r\n\tmargin-left: .8em;\r\n\tmargin-right: .8em;\r\n}\r\n\r\n.monaco-menu .secondary-actions .monaco-action-bar .action-label {\r\n\tmargin-left: 6px;\r\n}\r\n\r\n/* Action Items */\r\n.monaco-menu .monaco-action-bar .action-item.select-container {\r\n\toverflow: hidden; /* somehow the dropdown overflows its container, we prevent it here to not push */\r\n\tflex: 1;\r\n\tmax-width: 170px;\r\n\tmin-width: 60px;\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n\tjustify-content: center;\r\n\tmargin-right: 10px;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical {\r\n\tmargin-left: 0;\r\n\toverflow: visible;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .actions-container {\r\n\tdisplay: block;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .action-item {\r\n\tpadding: 0;\r\n\ttransform: none;\r\n\tdisplay: flex;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .action-item.active {\r\n\ttransform: none;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .action-menu-item {\r\n\tflex: 1 1 auto;\r\n\tdisplay: flex;\r\n\theight: 2em;\r\n\talign-items: center;\r\n\tposition: relative;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .action-label {\r\n\tflex: 1 1 auto;\r\n\ttext-decoration: none;\r\n\tpadding: 0 1em;\r\n\tbackground: none;\r\n\tfont-size: 12px;\r\n\tline-height: 1;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .keybinding,\r\n.monaco-menu .monaco-action-bar.vertical .submenu-indicator {\r\n\tdisplay: inline-block;\r\n\tflex: 2 1 auto;\r\n\tpadding: 0 1em;\r\n\ttext-align: right;\r\n\tfont-size: 12px;\r\n\tline-height: 1;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .submenu-indicator {\r\n\theight: 100%;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .submenu-indicator.codicon {\r\n\tfont-size: 16px !important;\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .submenu-indicator.codicon::before {\r\n\tmargin-left: auto;\r\n\tmargin-right: -20px;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .action-item.disabled .keybinding,\r\n.monaco-menu .monaco-action-bar.vertical .action-item.disabled .submenu-indicator {\r\n\topacity: 0.4;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .action-label:not(.separator) {\r\n\tdisplay: inline-block;\r\n\tbox-sizing: border-box;\r\n\tmargin: 0;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .action-item {\r\n\tposition: static;\r\n\toverflow: visible;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .action-item .monaco-submenu {\r\n\tposition: absolute;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .action-label.separator {\r\n\tpadding: 0.5em 0 0 0;\r\n\tmargin-bottom: 0.5em;\r\n\twidth: 100%;\r\n\theight: 0px !important;\r\n\tmargin-left: .8em !important;\r\n\tmargin-right: .8em !important;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .action-label.separator.text {\r\n\tpadding: 0.7em 1em 0.1em 1em;\r\n\tfont-weight: bold;\r\n\topacity: 1;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .action-label:hover {\r\n\tcolor: inherit;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .menu-item-check {\r\n\tposition: absolute;\r\n\tvisibility: hidden;\r\n\twidth: 1em;\r\n\theight: 100%;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .action-menu-item.checked .menu-item-check {\r\n\tvisibility: visible;\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n\tjustify-content: center;\r\n}\r\n\r\n/* Context Menu */\r\n\r\n.context-view.monaco-menu-container {\r\n\toutline: 0;\r\n\tborder: none;\r\n\tanimation: fadeIn 0.083s linear;\r\n\t-webkit-app-region: no-drag;\r\n}\r\n\r\n.context-view.monaco-menu-container :focus,\r\n.context-view.monaco-menu-container .monaco-action-bar.vertical:focus,\r\n.context-view.monaco-menu-container .monaco-action-bar.vertical :focus {\r\n\toutline: 0;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .action-item {\r\n\tborder: thin solid transparent; /* prevents jumping behaviour on hover or focus */\r\n}\r\n\r\n\r\n/* High Contrast Theming */\r\n:host-context(.hc-black) .context-view.monaco-menu-container {\r\n\tbox-shadow: none;\r\n}\r\n\r\n:host-context(.hc-black) .monaco-menu .monaco-action-bar.vertical .action-item.focused {\r\n\tbackground: none;\r\n}\r\n\r\n/* Vertical Action Bar Styles */\r\n\r\n.monaco-menu .monaco-action-bar.vertical {\r\n\tpadding: .5em 0;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .action-menu-item {\r\n\theight: 1.8em;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .action-label:not(.separator),\r\n.monaco-menu .monaco-action-bar.vertical .keybinding {\r\n\tfont-size: inherit;\r\n\tpadding: 0 2em;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .menu-item-check {\r\n\tfont-size: inherit;\r\n\twidth: 2em;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .action-label.separator {\r\n\tfont-size: inherit;\r\n\tpadding: 0.2em 0 0 0;\r\n\tmargin-bottom: 0.2em;\r\n}\r\n\r\n:host-context(.linux) .monaco-menu .monaco-action-bar.vertical .action-label.separator {\r\n\tmargin-left: 0;\r\n\tmargin-right: 0;\r\n}\r\n\r\n.monaco-menu .monaco-action-bar.vertical .submenu-indicator {\r\n\tfont-size: 60%;\r\n\tpadding: 0 1.8em;\r\n}\r\n\r\n:host-context(.linux) .monaco-menu .monaco-action-bar.vertical .submenu-indicator {\r\n\theight: 100%;\r\n\tmask-size: 10px 10px;\r\n\t-webkit-mask-size: 10px 10px;\r\n}\r\n\r\n.monaco-menu .action-item {\r\n\tcursor: default;\r\n}\r\n\r\n/* Arrows */\r\n.monaco-scrollable-element > .scrollbar > .scra {\r\n\tcursor: pointer;\r\n\tfont-size: 11px !important;\r\n}\r\n\r\n.monaco-scrollable-element > .visible {\r\n\topacity: 1;\r\n\r\n\t/* Background rule added for IE9 - to allow clicks on dom node */\r\n\tbackground:rgba(0,0,0,0);\r\n\r\n\ttransition: opacity 100ms linear;\r\n}\r\n.monaco-scrollable-element > .invisible {\r\n\topacity: 0;\r\n\tpointer-events: none;\r\n}\r\n.monaco-scrollable-element > .invisible.fade {\r\n\ttransition: opacity 800ms linear;\r\n}\r\n\r\n/* Scrollable Content Inset Shadow */\r\n.monaco-scrollable-element > .shadow {\r\n\tposition: absolute;\r\n\tdisplay: none;\r\n}\r\n.monaco-scrollable-element > .shadow.top {\r\n\tdisplay: block;\r\n\ttop: 0;\r\n\tleft: 3px;\r\n\theight: 3px;\r\n\twidth: 100%;\r\n\tbox-shadow: #DDD 0 6px 6px -6px inset;\r\n}\r\n.monaco-scrollable-element > .shadow.left {\r\n\tdisplay: block;\r\n\ttop: 3px;\r\n\tleft: 0;\r\n\theight: 100%;\r\n\twidth: 3px;\r\n\tbox-shadow: #DDD 6px 0 6px -6px inset;\r\n}\r\n.monaco-scrollable-element > .shadow.top-left-corner {\r\n\tdisplay: block;\r\n\ttop: 0;\r\n\tleft: 0;\r\n\theight: 3px;\r\n\twidth: 3px;\r\n}\r\n.monaco-scrollable-element > .shadow.top.left {\r\n\tbox-shadow: #DDD 6px 6px 6px -6px inset;\r\n}\r\n\r\n/* ---------- Default Style ---------- */\r\n\r\n:host-context(.vs) .monaco-scrollable-element > .scrollbar > .slider {\r\n\tbackground: rgba(100, 100, 100, .4);\r\n}\r\n:host-context(.vs-dark) .monaco-scrollable-element > .scrollbar > .slider {\r\n\tbackground: rgba(121, 121, 121, .4);\r\n}\r\n:host-context(.hc-black) .monaco-scrollable-element > .scrollbar > .slider {\r\n\tbackground: rgba(111, 195, 223, .6);\r\n}\r\n\r\n.monaco-scrollable-element > .scrollbar > .slider:hover {\r\n\tbackground: rgba(100, 100, 100, .7);\r\n}\r\n:host-context(.hc-black) .monaco-scrollable-element > .scrollbar > .slider:hover {\r\n\tbackground: rgba(111, 195, 223, .8);\r\n}\r\n\r\n.monaco-scrollable-element > .scrollbar > .slider.active {\r\n\tbackground: rgba(0, 0, 0, .6);\r\n}\r\n:host-context(.vs-dark) .monaco-scrollable-element > .scrollbar > .slider.active {\r\n\tbackground: rgba(191, 191, 191, .4);\r\n}\r\n:host-context(.hc-black) .monaco-scrollable-element > .scrollbar > .slider.active {\r\n\tbackground: rgba(111, 195, 223, 1);\r\n}\r\n\r\n:host-context(.vs-dark) .monaco-scrollable-element .shadow.top {\r\n\tbox-shadow: none;\r\n}\r\n\r\n:host-context(.vs-dark) .monaco-scrollable-element .shadow.left {\r\n\tbox-shadow: #000 6px 0 6px -6px inset;\r\n}\r\n\r\n:host-context(.vs-dark) .monaco-scrollable-element .shadow.top.left {\r\n\tbox-shadow: #000 6px 6px 6px -6px inset;\r\n}\r\n\r\n:host-context(.hc-black) .monaco-scrollable-element .shadow.top {\r\n\tbox-shadow: none;\r\n}\r\n\r\n:host-context(.hc-black) .monaco-scrollable-element .shadow.left {\r\n\tbox-shadow: none;\r\n}\r\n\r\n:host-context(.hc-black) .monaco-scrollable-element .shadow.top.left {\r\n\tbox-shadow: none;\r\n}\r\n`;\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./media/quickInput';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { InputBox, IRange, MessageType, IInputBoxStyles } from 'vs/base/browser/ui/inputbox/inputBox';\r\nimport { IDisposable, Disposable } from 'vs/base/common/lifecycle';\r\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport Severity from 'vs/base/common/severity';\r\nimport { StandardMouseEvent } from 'vs/base/browser/mouseEvent';\r\n\r\nconst $ = dom.$;\r\n\r\nexport class QuickInputBox extends Disposable {\r\n\r\n\tprivate container: HTMLElement;\r\n\tprivate inputBox: InputBox;\r\n\r\n\tconstructor(\r\n\t\tprivate parent: HTMLElement\r\n\t) {\r\n\t\tsuper();\r\n\t\tthis.container = dom.append(this.parent, $('.quick-input-box'));\r\n\t\tthis.inputBox = this._register(new InputBox(this.container, undefined));\r\n\t}\r\n\r\n\tonKeyDown = (handler: (event: StandardKeyboardEvent) => void): IDisposable => {\r\n\t\treturn dom.addDisposableListener(this.inputBox.inputElement, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => {\r\n\t\t\thandler(new StandardKeyboardEvent(e));\r\n\t\t});\r\n\t};\r\n\r\n\tonMouseDown = (handler: (event: StandardMouseEvent) => void): IDisposable => {\r\n\t\treturn dom.addDisposableListener(this.inputBox.inputElement, dom.EventType.MOUSE_DOWN, (e: MouseEvent) => {\r\n\t\t\thandler(new StandardMouseEvent(e));\r\n\t\t});\r\n\t};\r\n\r\n\tonDidChange = (handler: (event: string) => void): IDisposable => {\r\n\t\treturn this.inputBox.onDidChange(handler);\r\n\t};\r\n\r\n\tget value() {\r\n\t\treturn this.inputBox.value;\r\n\t}\r\n\r\n\tset value(value: string) {\r\n\t\tthis.inputBox.value = value;\r\n\t}\r\n\r\n\tselect(range: IRange | null = null): void {\r\n\t\tthis.inputBox.select(range);\r\n\t}\r\n\r\n\tisSelectionAtEnd(): boolean {\r\n\t\treturn this.inputBox.isSelectionAtEnd();\r\n\t}\r\n\r\n\tget placeholder() {\r\n\t\treturn this.inputBox.inputElement.getAttribute('placeholder') || '';\r\n\t}\r\n\r\n\tset placeholder(placeholder: string) {\r\n\t\tthis.inputBox.setPlaceHolder(placeholder);\r\n\t}\r\n\r\n\tget ariaLabel() {\r\n\t\treturn this.inputBox.getAriaLabel();\r\n\t}\r\n\r\n\tset ariaLabel(ariaLabel: string) {\r\n\t\tthis.inputBox.setAriaLabel(ariaLabel);\r\n\t}\r\n\r\n\tget password() {\r\n\t\treturn this.inputBox.inputElement.type === 'password';\r\n\t}\r\n\r\n\tset password(password: boolean) {\r\n\t\tthis.inputBox.inputElement.type = password ? 'password' : 'text';\r\n\t}\r\n\r\n\tsetAttribute(name: string, value: string): void {\r\n\t\tthis.inputBox.inputElement.setAttribute(name, value);\r\n\t}\r\n\r\n\tremoveAttribute(name: string): void {\r\n\t\tthis.inputBox.inputElement.removeAttribute(name);\r\n\t}\r\n\r\n\tshowDecoration(decoration: Severity): void {\r\n\t\tif (decoration === Severity.Ignore) {\r\n\t\t\tthis.inputBox.hideMessage();\r\n\t\t} else {\r\n\t\t\tthis.inputBox.showMessage({ type: decoration === Severity.Info ? MessageType.INFO : decoration === Severity.Warning ? MessageType.WARNING : MessageType.ERROR, content: '' });\r\n\t\t}\r\n\t}\r\n\r\n\tstylesForType(decoration: Severity) {\r\n\t\treturn this.inputBox.stylesForType(decoration === Severity.Info ? MessageType.INFO : decoration === Severity.Warning ? MessageType.WARNING : MessageType.ERROR);\r\n\t}\r\n\r\n\tsetFocus(): void {\r\n\t\tthis.inputBox.focus();\r\n\t}\r\n\r\n\tlayout(): void {\r\n\t\tthis.inputBox.layout();\r\n\t}\r\n\r\n\tstyle(styles: IInputBoxStyles): void {\r\n\t\tthis.inputBox.style(styles);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport * as types from 'vs/base/common/types';\r\nimport * as arrays from 'vs/base/common/arrays';\r\n\r\nfunction exceptionToErrorMessage(exception: any, verbose: boolean): string {\r\n\tif (verbose && (exception.stack || exception.stacktrace)) {\r\n\t\treturn nls.localize('stackTrace.format', \"{0}: {1}\", detectSystemErrorMessage(exception), stackToString(exception.stack) || stackToString(exception.stacktrace));\r\n\t}\r\n\r\n\treturn detectSystemErrorMessage(exception);\r\n}\r\n\r\nfunction stackToString(stack: string[] | string | undefined): string | undefined {\r\n\tif (Array.isArray(stack)) {\r\n\t\treturn stack.join('\\n');\r\n\t}\r\n\r\n\treturn stack;\r\n}\r\n\r\nfunction detectSystemErrorMessage(exception: any): string {\r\n\r\n\t// See https://nodejs.org/api/errors.html#errors_class_system_error\r\n\tif (typeof exception.code === 'string' && typeof exception.errno === 'number' && typeof exception.syscall === 'string') {\r\n\t\treturn nls.localize('nodeExceptionMessage', \"A system error occurred ({0})\", exception.message);\r\n\t}\r\n\r\n\treturn exception.message || nls.localize('error.defaultMessage', \"An unknown error occurred. Please consult the log for more details.\");\r\n}\r\n\r\n/**\r\n * Tries to generate a human readable error message out of the error. If the verbose parameter\r\n * is set to true, the error message will include stacktrace details if provided.\r\n *\r\n * @returns A string containing the error message.\r\n */\r\nexport function toErrorMessage(error: any = null, verbose: boolean = false): string {\r\n\tif (!error) {\r\n\t\treturn nls.localize('error.defaultMessage', \"An unknown error occurred. Please consult the log for more details.\");\r\n\t}\r\n\r\n\tif (Array.isArray(error)) {\r\n\t\tconst errors: any[] = arrays.coalesce(error);\r\n\t\tconst msg = toErrorMessage(errors[0], verbose);\r\n\r\n\t\tif (errors.length > 1) {\r\n\t\t\treturn nls.localize('error.moreErrors', \"{0} ({1} errors in total)\", msg, errors.length);\r\n\t\t}\r\n\r\n\t\treturn msg;\r\n\t}\r\n\r\n\tif (types.isString(error)) {\r\n\t\treturn error;\r\n\t}\r\n\r\n\tif (error.detail) {\r\n\t\tconst detail = error.detail;\r\n\r\n\t\tif (detail.error) {\r\n\t\t\treturn exceptionToErrorMessage(detail.error, verbose);\r\n\t\t}\r\n\r\n\t\tif (detail.exception) {\r\n\t\t\treturn exceptionToErrorMessage(detail.exception, verbose);\r\n\t\t}\r\n\t}\r\n\r\n\tif (error.stack) {\r\n\t\treturn exceptionToErrorMessage(error, verbose);\r\n\t}\r\n\r\n\tif (error.message) {\r\n\t\treturn error.message;\r\n\t}\r\n\r\n\treturn nls.localize('error.defaultMessage', \"An unknown error occurred. Please consult the log for more details.\");\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { OperatingSystem } from 'vs/base/common/platform';\r\n\r\nexport interface ModifierLabels {\r\n\treadonly ctrlKey: string;\r\n\treadonly shiftKey: string;\r\n\treadonly altKey: string;\r\n\treadonly metaKey: string;\r\n\treadonly separator: string;\r\n}\r\n\r\nexport interface Modifiers {\r\n\treadonly ctrlKey: boolean;\r\n\treadonly shiftKey: boolean;\r\n\treadonly altKey: boolean;\r\n\treadonly metaKey: boolean;\r\n}\r\n\r\nexport interface KeyLabelProvider {\r\n\t(keybinding: T): string | null;\r\n}\r\n\r\nexport class ModifierLabelProvider {\r\n\r\n\tpublic readonly modifierLabels: ModifierLabels[];\r\n\r\n\tconstructor(mac: ModifierLabels, windows: ModifierLabels, linux: ModifierLabels = windows) {\r\n\t\tthis.modifierLabels = [null!]; // index 0 will never me accessed.\r\n\t\tthis.modifierLabels[OperatingSystem.Macintosh] = mac;\r\n\t\tthis.modifierLabels[OperatingSystem.Windows] = windows;\r\n\t\tthis.modifierLabels[OperatingSystem.Linux] = linux;\r\n\t}\r\n\r\n\tpublic toLabel(OS: OperatingSystem, parts: T[], keyLabelProvider: KeyLabelProvider): string | null {\r\n\t\tif (parts.length === 0) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst result: string[] = [];\r\n\t\tfor (let i = 0, len = parts.length; i < len; i++) {\r\n\t\t\tconst part = parts[i];\r\n\t\t\tconst keyLabel = keyLabelProvider(part);\r\n\t\t\tif (keyLabel === null) {\r\n\t\t\t\t// this keybinding cannot be expressed...\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t\tresult[i] = _simpleAsString(part, keyLabel, this.modifierLabels[OS]);\r\n\t\t}\r\n\t\treturn result.join(' ');\r\n\t}\r\n}\r\n\r\n/**\r\n * A label provider that prints modifiers in a suitable format for displaying in the UI.\r\n */\r\nexport const UILabelProvider = new ModifierLabelProvider(\r\n\t{\r\n\t\tctrlKey: '⌃',\r\n\t\tshiftKey: '⇧',\r\n\t\taltKey: '⌥',\r\n\t\tmetaKey: '⌘',\r\n\t\tseparator: '',\r\n\t},\r\n\t{\r\n\t\tctrlKey: nls.localize({ key: 'ctrlKey', comment: ['This is the short form for the Control key on the keyboard'] }, \"Ctrl\"),\r\n\t\tshiftKey: nls.localize({ key: 'shiftKey', comment: ['This is the short form for the Shift key on the keyboard'] }, \"Shift\"),\r\n\t\taltKey: nls.localize({ key: 'altKey', comment: ['This is the short form for the Alt key on the keyboard'] }, \"Alt\"),\r\n\t\tmetaKey: nls.localize({ key: 'windowsKey', comment: ['This is the short form for the Windows key on the keyboard'] }, \"Windows\"),\r\n\t\tseparator: '+',\r\n\t},\r\n\t{\r\n\t\tctrlKey: nls.localize({ key: 'ctrlKey', comment: ['This is the short form for the Control key on the keyboard'] }, \"Ctrl\"),\r\n\t\tshiftKey: nls.localize({ key: 'shiftKey', comment: ['This is the short form for the Shift key on the keyboard'] }, \"Shift\"),\r\n\t\taltKey: nls.localize({ key: 'altKey', comment: ['This is the short form for the Alt key on the keyboard'] }, \"Alt\"),\r\n\t\tmetaKey: nls.localize({ key: 'superKey', comment: ['This is the short form for the Super key on the keyboard'] }, \"Super\"),\r\n\t\tseparator: '+',\r\n\t}\r\n);\r\n\r\n/**\r\n * A label provider that prints modifiers in a suitable format for ARIA.\r\n */\r\nexport const AriaLabelProvider = new ModifierLabelProvider(\r\n\t{\r\n\t\tctrlKey: nls.localize({ key: 'ctrlKey.long', comment: ['This is the long form for the Control key on the keyboard'] }, \"Control\"),\r\n\t\tshiftKey: nls.localize({ key: 'shiftKey.long', comment: ['This is the long form for the Shift key on the keyboard'] }, \"Shift\"),\r\n\t\taltKey: nls.localize({ key: 'altKey.long', comment: ['This is the long form for the Alt key on the keyboard'] }, \"Alt\"),\r\n\t\tmetaKey: nls.localize({ key: 'cmdKey.long', comment: ['This is the long form for the Command key on the keyboard'] }, \"Command\"),\r\n\t\tseparator: '+',\r\n\t},\r\n\t{\r\n\t\tctrlKey: nls.localize({ key: 'ctrlKey.long', comment: ['This is the long form for the Control key on the keyboard'] }, \"Control\"),\r\n\t\tshiftKey: nls.localize({ key: 'shiftKey.long', comment: ['This is the long form for the Shift key on the keyboard'] }, \"Shift\"),\r\n\t\taltKey: nls.localize({ key: 'altKey.long', comment: ['This is the long form for the Alt key on the keyboard'] }, \"Alt\"),\r\n\t\tmetaKey: nls.localize({ key: 'windowsKey.long', comment: ['This is the long form for the Windows key on the keyboard'] }, \"Windows\"),\r\n\t\tseparator: '+',\r\n\t},\r\n\t{\r\n\t\tctrlKey: nls.localize({ key: 'ctrlKey.long', comment: ['This is the long form for the Control key on the keyboard'] }, \"Control\"),\r\n\t\tshiftKey: nls.localize({ key: 'shiftKey.long', comment: ['This is the long form for the Shift key on the keyboard'] }, \"Shift\"),\r\n\t\taltKey: nls.localize({ key: 'altKey.long', comment: ['This is the long form for the Alt key on the keyboard'] }, \"Alt\"),\r\n\t\tmetaKey: nls.localize({ key: 'superKey.long', comment: ['This is the long form for the Super key on the keyboard'] }, \"Super\"),\r\n\t\tseparator: '+',\r\n\t}\r\n);\r\n\r\nfunction _simpleAsString(modifiers: Modifiers, key: string, labels: ModifierLabels): string {\r\n\tif (key === null) {\r\n\t\treturn '';\r\n\t}\r\n\r\n\tconst result: string[] = [];\r\n\r\n\t// translate modifier keys: Ctrl-Shift-Alt-Meta\r\n\tif (modifiers.ctrlKey) {\r\n\t\tresult.push(labels.ctrlKey);\r\n\t}\r\n\r\n\tif (modifiers.shiftKey) {\r\n\t\tresult.push(labels.shiftKey);\r\n\t}\r\n\r\n\tif (modifiers.altKey) {\r\n\t\tresult.push(labels.altKey);\r\n\t}\r\n\r\n\tif (modifiers.metaKey) {\r\n\t\tresult.push(labels.metaKey);\r\n\t}\r\n\r\n\t// the actual key\r\n\tif (key !== '') {\r\n\t\tresult.push(key);\r\n\t}\r\n\r\n\treturn result.join(labels.separator);\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./keybindingLabel';\r\nimport { equals } from 'vs/base/common/objects';\r\nimport { OperatingSystem } from 'vs/base/common/platform';\r\nimport { ResolvedKeybinding, ResolvedKeybindingPart } from 'vs/base/common/keyCodes';\r\nimport { UILabelProvider } from 'vs/base/common/keybindingLabels';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { localize } from 'vs/nls';\r\n\r\nconst $ = dom.$;\r\n\r\nexport interface PartMatches {\r\n\tctrlKey?: boolean;\r\n\tshiftKey?: boolean;\r\n\taltKey?: boolean;\r\n\tmetaKey?: boolean;\r\n\tkeyCode?: boolean;\r\n}\r\n\r\nexport interface Matches {\r\n\tfirstPart: PartMatches;\r\n\tchordPart: PartMatches;\r\n}\r\n\r\nexport interface KeybindingLabelOptions {\r\n\trenderUnboundKeybindings: boolean;\r\n}\r\n\r\nexport class KeybindingLabel {\r\n\r\n\tprivate domNode: HTMLElement;\r\n\tprivate keybinding: ResolvedKeybinding | undefined;\r\n\tprivate matches: Matches | undefined;\r\n\tprivate didEverRender: boolean;\r\n\r\n\tconstructor(container: HTMLElement, private os: OperatingSystem, private options?: KeybindingLabelOptions) {\r\n\t\tthis.domNode = dom.append(container, $('.monaco-keybinding'));\r\n\t\tthis.didEverRender = false;\r\n\t\tcontainer.appendChild(this.domNode);\r\n\t}\r\n\r\n\tset(keybinding: ResolvedKeybinding | undefined, matches?: Matches) {\r\n\t\tif (this.didEverRender && this.keybinding === keybinding && KeybindingLabel.areSame(this.matches, matches)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.keybinding = keybinding;\r\n\t\tthis.matches = matches;\r\n\t\tthis.render();\r\n\t}\r\n\r\n\tprivate render() {\r\n\t\tdom.clearNode(this.domNode);\r\n\r\n\t\tif (this.keybinding) {\r\n\t\t\tlet [firstPart, chordPart] = this.keybinding.getParts();\r\n\t\t\tif (firstPart) {\r\n\t\t\t\tthis.renderPart(this.domNode, firstPart, this.matches ? this.matches.firstPart : null);\r\n\t\t\t}\r\n\t\t\tif (chordPart) {\r\n\t\t\t\tdom.append(this.domNode, $('span.monaco-keybinding-key-chord-separator', undefined, ' '));\r\n\t\t\t\tthis.renderPart(this.domNode, chordPart, this.matches ? this.matches.chordPart : null);\r\n\t\t\t}\r\n\t\t\tthis.domNode.title = this.keybinding.getAriaLabel() || '';\r\n\t\t} else if (this.options && this.options.renderUnboundKeybindings) {\r\n\t\t\tthis.renderUnbound(this.domNode);\r\n\t\t}\r\n\r\n\t\tthis.didEverRender = true;\r\n\t}\r\n\r\n\tprivate renderPart(parent: HTMLElement, part: ResolvedKeybindingPart, match: PartMatches | null) {\r\n\t\tconst modifierLabels = UILabelProvider.modifierLabels[this.os];\r\n\t\tif (part.ctrlKey) {\r\n\t\t\tthis.renderKey(parent, modifierLabels.ctrlKey, Boolean(match?.ctrlKey), modifierLabels.separator);\r\n\t\t}\r\n\t\tif (part.shiftKey) {\r\n\t\t\tthis.renderKey(parent, modifierLabels.shiftKey, Boolean(match?.shiftKey), modifierLabels.separator);\r\n\t\t}\r\n\t\tif (part.altKey) {\r\n\t\t\tthis.renderKey(parent, modifierLabels.altKey, Boolean(match?.altKey), modifierLabels.separator);\r\n\t\t}\r\n\t\tif (part.metaKey) {\r\n\t\t\tthis.renderKey(parent, modifierLabels.metaKey, Boolean(match?.metaKey), modifierLabels.separator);\r\n\t\t}\r\n\t\tconst keyLabel = part.keyLabel;\r\n\t\tif (keyLabel) {\r\n\t\t\tthis.renderKey(parent, keyLabel, Boolean(match?.keyCode), '');\r\n\t\t}\r\n\t}\r\n\r\n\tprivate renderKey(parent: HTMLElement, label: string, highlight: boolean, separator: string): void {\r\n\t\tdom.append(parent, $('span.monaco-keybinding-key' + (highlight ? '.highlight' : ''), undefined, label));\r\n\t\tif (separator) {\r\n\t\t\tdom.append(parent, $('span.monaco-keybinding-key-separator', undefined, separator));\r\n\t\t}\r\n\t}\r\n\r\n\tprivate renderUnbound(parent: HTMLElement): void {\r\n\t\tdom.append(parent, $('span.monaco-keybinding-key', undefined, localize('unbound', \"Unbound\")));\r\n\t}\r\n\r\n\tprivate static areSame(a: Matches | undefined, b: Matches | undefined): boolean {\r\n\t\tif (a === b || (!a && !b)) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn !!a && !!b && equals(a.firstPart, b.firstPart) && equals(a.chordPart, b.chordPart);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./media/quickInput';\r\nimport { IListVirtualDelegate, IListRenderer } from 'vs/base/browser/ui/list/list';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { dispose, IDisposable } from 'vs/base/common/lifecycle';\r\nimport { IQuickPickItem, IQuickPickItemButtonEvent, IQuickPickSeparator } from 'vs/base/parts/quickinput/common/quickInput';\r\nimport { IMatch } from 'vs/base/common/filters';\r\nimport { matchesFuzzyIconAware, parseLabelWithIcons } from 'vs/base/common/iconLabels';\r\nimport { compareAnything } from 'vs/base/common/comparers';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { KeyCode } from 'vs/base/common/keyCodes';\r\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { IconLabel, IIconLabelValueOptions } from 'vs/base/browser/ui/iconLabel/iconLabel';\r\nimport { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';\r\nimport { memoize } from 'vs/base/common/decorators';\r\nimport { range } from 'vs/base/common/arrays';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';\r\nimport { Action } from 'vs/base/common/actions';\r\nimport { getIconClass } from 'vs/base/parts/quickinput/browser/quickInputUtils';\r\nimport { withNullAsUndefined } from 'vs/base/common/types';\r\nimport { IQuickInputOptions } from 'vs/base/parts/quickinput/browser/quickInput';\r\nimport { IListOptions, List, IListStyles, IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';\r\nimport { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel';\r\nimport { localize } from 'vs/nls';\r\n\r\nconst $ = dom.$;\r\n\r\ninterface IListElement {\r\n\treadonly index: number;\r\n\treadonly item: IQuickPickItem;\r\n\treadonly saneLabel: string;\r\n\treadonly saneMeta?: string;\r\n\treadonly saneAriaLabel: string;\r\n\treadonly saneDescription?: string;\r\n\treadonly saneDetail?: string;\r\n\treadonly labelHighlights?: IMatch[];\r\n\treadonly descriptionHighlights?: IMatch[];\r\n\treadonly detailHighlights?: IMatch[];\r\n\treadonly checked: boolean;\r\n\treadonly separator?: IQuickPickSeparator;\r\n\treadonly fireButtonTriggered: (event: IQuickPickItemButtonEvent) => void;\r\n}\r\n\r\nclass ListElement implements IListElement, IDisposable {\r\n\tindex!: number;\r\n\titem!: IQuickPickItem;\r\n\tsaneLabel!: string;\r\n\tsaneMeta!: string;\r\n\tsaneAriaLabel!: string;\r\n\tsaneDescription?: string;\r\n\tsaneDetail?: string;\r\n\thidden = false;\r\n\tprivate readonly _onChecked = new Emitter();\r\n\tonChecked = this._onChecked.event;\r\n\t_checked?: boolean;\r\n\tget checked() {\r\n\t\treturn !!this._checked;\r\n\t}\r\n\tset checked(value: boolean) {\r\n\t\tif (value !== this._checked) {\r\n\t\t\tthis._checked = value;\r\n\t\t\tthis._onChecked.fire(value);\r\n\t\t}\r\n\t}\r\n\tseparator?: IQuickPickSeparator;\r\n\tlabelHighlights?: IMatch[];\r\n\tdescriptionHighlights?: IMatch[];\r\n\tdetailHighlights?: IMatch[];\r\n\tfireButtonTriggered!: (event: IQuickPickItemButtonEvent) => void;\r\n\r\n\tconstructor(init: IListElement) {\r\n\t\tObject.assign(this, init);\r\n\t}\r\n\r\n\tdispose() {\r\n\t\tthis._onChecked.dispose();\r\n\t}\r\n}\r\n\r\ninterface IListElementTemplateData {\r\n\tentry: HTMLDivElement;\r\n\tcheckbox: HTMLInputElement;\r\n\tlabel: IconLabel;\r\n\tkeybinding: KeybindingLabel;\r\n\tdetail: HighlightedLabel;\r\n\tseparator: HTMLDivElement;\r\n\tactionBar: ActionBar;\r\n\telement: ListElement;\r\n\ttoDisposeElement: IDisposable[];\r\n\ttoDisposeTemplate: IDisposable[];\r\n}\r\n\r\nclass ListElementRenderer implements IListRenderer {\r\n\r\n\tstatic readonly ID = 'listelement';\r\n\r\n\tget templateId() {\r\n\t\treturn ListElementRenderer.ID;\r\n\t}\r\n\r\n\trenderTemplate(container: HTMLElement): IListElementTemplateData {\r\n\t\tconst data: IListElementTemplateData = Object.create(null);\r\n\t\tdata.toDisposeElement = [];\r\n\t\tdata.toDisposeTemplate = [];\r\n\r\n\t\tdata.entry = dom.append(container, $('.quick-input-list-entry'));\r\n\r\n\t\t// Checkbox\r\n\t\tconst label = dom.append(data.entry, $('label.quick-input-list-label'));\r\n\t\tdata.toDisposeTemplate.push(dom.addStandardDisposableListener(label, dom.EventType.CLICK, e => {\r\n\t\t\tif (!data.checkbox.offsetParent) { // If checkbox not visible:\r\n\t\t\t\te.preventDefault(); // Prevent toggle of checkbox when it is immediately shown afterwards. #91740\r\n\t\t\t}\r\n\t\t}));\r\n\t\tdata.checkbox = dom.append(label, $('input.quick-input-list-checkbox'));\r\n\t\tdata.checkbox.type = 'checkbox';\r\n\t\tdata.toDisposeTemplate.push(dom.addStandardDisposableListener(data.checkbox, dom.EventType.CHANGE, e => {\r\n\t\t\tdata.element.checked = data.checkbox.checked;\r\n\t\t}));\r\n\r\n\t\t// Rows\r\n\t\tconst rows = dom.append(label, $('.quick-input-list-rows'));\r\n\t\tconst row1 = dom.append(rows, $('.quick-input-list-row'));\r\n\t\tconst row2 = dom.append(rows, $('.quick-input-list-row'));\r\n\r\n\t\t// Label\r\n\t\tdata.label = new IconLabel(row1, { supportHighlights: true, supportDescriptionHighlights: true, supportIcons: true });\r\n\r\n\t\t// Keybinding\r\n\t\tconst keybindingContainer = dom.append(row1, $('.quick-input-list-entry-keybinding'));\r\n\t\tdata.keybinding = new KeybindingLabel(keybindingContainer, platform.OS);\r\n\r\n\t\t// Detail\r\n\t\tconst detailContainer = dom.append(row2, $('.quick-input-list-label-meta'));\r\n\t\tdata.detail = new HighlightedLabel(detailContainer, true);\r\n\r\n\t\t// Separator\r\n\t\tdata.separator = dom.append(data.entry, $('.quick-input-list-separator'));\r\n\r\n\t\t// Actions\r\n\t\tdata.actionBar = new ActionBar(data.entry);\r\n\t\tdata.actionBar.domNode.classList.add('quick-input-list-entry-action-bar');\r\n\t\tdata.toDisposeTemplate.push(data.actionBar);\r\n\r\n\t\treturn data;\r\n\t}\r\n\r\n\trenderElement(element: ListElement, index: number, data: IListElementTemplateData): void {\r\n\t\tdata.toDisposeElement = dispose(data.toDisposeElement);\r\n\t\tdata.element = element;\r\n\t\tdata.checkbox.checked = element.checked;\r\n\t\tdata.toDisposeElement.push(element.onChecked(checked => data.checkbox.checked = checked));\r\n\r\n\t\tconst { labelHighlights, descriptionHighlights, detailHighlights } = element;\r\n\r\n\t\t// Label\r\n\t\tconst options: IIconLabelValueOptions = Object.create(null);\r\n\t\toptions.matches = labelHighlights || [];\r\n\t\toptions.descriptionTitle = element.saneDescription;\r\n\t\toptions.descriptionMatches = descriptionHighlights || [];\r\n\t\toptions.extraClasses = element.item.iconClasses;\r\n\t\toptions.italic = element.item.italic;\r\n\t\toptions.strikethrough = element.item.strikethrough;\r\n\t\tdata.label.setLabel(element.saneLabel, element.saneDescription, options);\r\n\r\n\t\t// Keybinding\r\n\t\tdata.keybinding.set(element.item.keybinding);\r\n\r\n\t\t// Meta\r\n\t\tdata.detail.set(element.saneDetail, detailHighlights);\r\n\r\n\t\t// Separator\r\n\t\tif (element.separator && element.separator.label) {\r\n\t\t\tdata.separator.textContent = element.separator.label;\r\n\t\t\tdata.separator.style.display = '';\r\n\t\t} else {\r\n\t\t\tdata.separator.style.display = 'none';\r\n\t\t}\r\n\t\tdata.entry.classList.toggle('quick-input-list-separator-border', !!element.separator);\r\n\r\n\t\t// Actions\r\n\t\tdata.actionBar.clear();\r\n\t\tconst buttons = element.item.buttons;\r\n\t\tif (buttons && buttons.length) {\r\n\t\t\tdata.actionBar.push(buttons.map((button, index) => {\r\n\t\t\t\tlet cssClasses = button.iconClass || (button.iconPath ? getIconClass(button.iconPath) : undefined);\r\n\t\t\t\tif (button.alwaysVisible) {\r\n\t\t\t\t\tcssClasses = cssClasses ? `${cssClasses} always-visible` : 'always-visible';\r\n\t\t\t\t}\r\n\t\t\t\tconst action = new Action(`id-${index}`, '', cssClasses, true, async () => {\r\n\t\t\t\t\telement.fireButtonTriggered({\r\n\t\t\t\t\t\tbutton,\r\n\t\t\t\t\t\titem: element.item\r\n\t\t\t\t\t});\r\n\t\t\t\t});\r\n\t\t\t\taction.tooltip = button.tooltip || '';\r\n\t\t\t\treturn action;\r\n\t\t\t}), { icon: true, label: false });\r\n\t\t\tdata.entry.classList.add('has-actions');\r\n\t\t} else {\r\n\t\t\tdata.entry.classList.remove('has-actions');\r\n\t\t}\r\n\t}\r\n\r\n\tdisposeElement(element: ListElement, index: number, data: IListElementTemplateData): void {\r\n\t\tdata.toDisposeElement = dispose(data.toDisposeElement);\r\n\t}\r\n\r\n\tdisposeTemplate(data: IListElementTemplateData): void {\r\n\t\tdata.toDisposeElement = dispose(data.toDisposeElement);\r\n\t\tdata.toDisposeTemplate = dispose(data.toDisposeTemplate);\r\n\t}\r\n}\r\n\r\nclass ListElementDelegate implements IListVirtualDelegate {\r\n\r\n\tgetHeight(element: ListElement): number {\r\n\t\treturn element.saneDetail ? 44 : 22;\r\n\t}\r\n\r\n\tgetTemplateId(element: ListElement): string {\r\n\t\treturn ListElementRenderer.ID;\r\n\t}\r\n}\r\n\r\nexport enum QuickInputListFocus {\r\n\tFirst = 1,\r\n\tSecond,\r\n\tLast,\r\n\tNext,\r\n\tPrevious,\r\n\tNextPage,\r\n\tPreviousPage\r\n}\r\n\r\nexport class QuickInputList {\r\n\r\n\treadonly id: string;\r\n\tprivate container: HTMLElement;\r\n\tprivate list: List;\r\n\tprivate inputElements: Array = [];\r\n\tprivate elements: ListElement[] = [];\r\n\tprivate elementsToIndexes = new Map();\r\n\tmatchOnDescription = false;\r\n\tmatchOnDetail = false;\r\n\tmatchOnLabel = true;\r\n\tmatchOnMeta = true;\r\n\tsortByLabel = true;\r\n\tprivate readonly _onChangedAllVisibleChecked = new Emitter();\r\n\tonChangedAllVisibleChecked: Event = this._onChangedAllVisibleChecked.event;\r\n\tprivate readonly _onChangedCheckedCount = new Emitter();\r\n\tonChangedCheckedCount: Event = this._onChangedCheckedCount.event;\r\n\tprivate readonly _onChangedVisibleCount = new Emitter();\r\n\tonChangedVisibleCount: Event = this._onChangedVisibleCount.event;\r\n\tprivate readonly _onChangedCheckedElements = new Emitter();\r\n\tonChangedCheckedElements: Event = this._onChangedCheckedElements.event;\r\n\tprivate readonly _onButtonTriggered = new Emitter>();\r\n\tonButtonTriggered = this._onButtonTriggered.event;\r\n\tprivate readonly _onKeyDown = new Emitter();\r\n\tonKeyDown: Event = this._onKeyDown.event;\r\n\tprivate readonly _onLeave = new Emitter();\r\n\tonLeave: Event = this._onLeave.event;\r\n\tprivate _fireCheckedEvents = true;\r\n\tprivate elementDisposables: IDisposable[] = [];\r\n\tprivate disposables: IDisposable[] = [];\r\n\r\n\tconstructor(\r\n\t\tprivate parent: HTMLElement,\r\n\t\tid: string,\r\n\t\toptions: IQuickInputOptions,\r\n\t) {\r\n\t\tthis.id = id;\r\n\t\tthis.container = dom.append(this.parent, $('.quick-input-list'));\r\n\t\tconst delegate = new ListElementDelegate();\r\n\t\tconst accessibilityProvider = new QuickInputAccessibilityProvider();\r\n\t\tthis.list = options.createList('QuickInput', this.container, delegate, [new ListElementRenderer()], {\r\n\t\t\tidentityProvider: { getId: element => element.saneLabel },\r\n\t\t\tsetRowLineHeight: false,\r\n\t\t\tmultipleSelectionSupport: false,\r\n\t\t\thorizontalScrolling: false,\r\n\t\t\taccessibilityProvider\r\n\t\t} as IListOptions);\r\n\t\tthis.list.getHTMLElement().id = id;\r\n\t\tthis.disposables.push(this.list);\r\n\t\tthis.disposables.push(this.list.onKeyDown(e => {\r\n\t\t\tconst event = new StandardKeyboardEvent(e);\r\n\t\t\tswitch (event.keyCode) {\r\n\t\t\t\tcase KeyCode.Space:\r\n\t\t\t\t\tthis.toggleCheckbox();\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase KeyCode.KEY_A:\r\n\t\t\t\t\tif (platform.isMacintosh ? e.metaKey : e.ctrlKey) {\r\n\t\t\t\t\t\tthis.list.setFocus(range(this.list.length));\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase KeyCode.UpArrow:\r\n\t\t\t\t\tconst focus1 = this.list.getFocus();\r\n\t\t\t\t\tif (focus1.length === 1 && focus1[0] === 0) {\r\n\t\t\t\t\t\tthis._onLeave.fire();\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase KeyCode.DownArrow:\r\n\t\t\t\t\tconst focus2 = this.list.getFocus();\r\n\t\t\t\t\tif (focus2.length === 1 && focus2[0] === this.list.length - 1) {\r\n\t\t\t\t\t\tthis._onLeave.fire();\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tthis._onKeyDown.fire(event);\r\n\t\t}));\r\n\t\tthis.disposables.push(this.list.onMouseDown(e => {\r\n\t\t\tif (e.browserEvent.button !== 2) {\r\n\t\t\t\t// Works around / fixes #64350.\r\n\t\t\t\te.browserEvent.preventDefault();\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis.disposables.push(dom.addDisposableListener(this.container, dom.EventType.CLICK, e => {\r\n\t\t\tif (e.x || e.y) { // Avoid 'click' triggered by 'space' on checkbox.\r\n\t\t\t\tthis._onLeave.fire();\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis.disposables.push(this.list.onMouseMiddleClick(e => {\r\n\t\t\tthis._onLeave.fire();\r\n\t\t}));\r\n\t\tthis.disposables.push(this.list.onContextMenu(e => {\r\n\t\t\tif (typeof e.index === 'number') {\r\n\t\t\t\te.browserEvent.preventDefault();\r\n\r\n\t\t\t\t// we want to treat a context menu event as\r\n\t\t\t\t// a gesture to open the item at the index\r\n\t\t\t\t// since we do not have any context menu\r\n\t\t\t\t// this enables for example macOS to Ctrl-\r\n\t\t\t\t// click on an item to open it.\r\n\t\t\t\tthis.list.setSelection([e.index]);\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis.disposables.push(\r\n\t\t\tthis._onChangedAllVisibleChecked,\r\n\t\t\tthis._onChangedCheckedCount,\r\n\t\t\tthis._onChangedVisibleCount,\r\n\t\t\tthis._onChangedCheckedElements,\r\n\t\t\tthis._onButtonTriggered,\r\n\t\t\tthis._onLeave,\r\n\t\t\tthis._onKeyDown\r\n\t\t);\r\n\t}\r\n\r\n\t@memoize\r\n\tget onDidChangeFocus() {\r\n\t\treturn Event.map(this.list.onDidChangeFocus, e => e.elements.map(e => e.item));\r\n\t}\r\n\r\n\t@memoize\r\n\tget onDidChangeSelection() {\r\n\t\treturn Event.map(this.list.onDidChangeSelection, e => ({ items: e.elements.map(e => e.item), event: e.browserEvent }));\r\n\t}\r\n\r\n\tgetAllVisibleChecked() {\r\n\t\treturn this.allVisibleChecked(this.elements, false);\r\n\t}\r\n\r\n\tprivate allVisibleChecked(elements: ListElement[], whenNoneVisible = true) {\r\n\t\tfor (let i = 0, n = elements.length; i < n; i++) {\r\n\t\t\tconst element = elements[i];\r\n\t\t\tif (!element.hidden) {\r\n\t\t\t\tif (!element.checked) {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t} else {\r\n\t\t\t\t\twhenNoneVisible = true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn whenNoneVisible;\r\n\t}\r\n\r\n\tgetCheckedCount() {\r\n\t\tlet count = 0;\r\n\t\tconst elements = this.elements;\r\n\t\tfor (let i = 0, n = elements.length; i < n; i++) {\r\n\t\t\tif (elements[i].checked) {\r\n\t\t\t\tcount++;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn count;\r\n\t}\r\n\r\n\tgetVisibleCount() {\r\n\t\tlet count = 0;\r\n\t\tconst elements = this.elements;\r\n\t\tfor (let i = 0, n = elements.length; i < n; i++) {\r\n\t\t\tif (!elements[i].hidden) {\r\n\t\t\t\tcount++;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn count;\r\n\t}\r\n\r\n\tsetAllVisibleChecked(checked: boolean) {\r\n\t\ttry {\r\n\t\t\tthis._fireCheckedEvents = false;\r\n\t\t\tthis.elements.forEach(element => {\r\n\t\t\t\tif (!element.hidden) {\r\n\t\t\t\t\telement.checked = checked;\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t} finally {\r\n\t\t\tthis._fireCheckedEvents = true;\r\n\t\t\tthis.fireCheckedEvents();\r\n\t\t}\r\n\t}\r\n\r\n\tsetElements(inputElements: Array): void {\r\n\t\tthis.elementDisposables = dispose(this.elementDisposables);\r\n\t\tconst fireButtonTriggered = (event: IQuickPickItemButtonEvent) => this.fireButtonTriggered(event);\r\n\t\tthis.inputElements = inputElements;\r\n\t\tthis.elements = inputElements.reduce((result, item, index) => {\r\n\t\t\tif (item.type !== 'separator') {\r\n\t\t\t\tconst previous = index && inputElements[index - 1];\r\n\t\t\t\tconst saneLabel = item.label && item.label.replace(/\\r?\\n/g, ' ');\r\n\t\t\t\tconst saneMeta = item.meta && item.meta.replace(/\\r?\\n/g, ' ');\r\n\t\t\t\tconst saneDescription = item.description && item.description.replace(/\\r?\\n/g, ' ');\r\n\t\t\t\tconst saneDetail = item.detail && item.detail.replace(/\\r?\\n/g, ' ');\r\n\t\t\t\tconst saneAriaLabel = item.ariaLabel || [saneLabel, saneDescription, saneDetail]\r\n\t\t\t\t\t.map(s => s && parseLabelWithIcons(s).text)\r\n\t\t\t\t\t.filter(s => !!s)\r\n\t\t\t\t\t.join(', ');\r\n\r\n\t\t\t\tresult.push(new ListElement({\r\n\t\t\t\t\tindex,\r\n\t\t\t\t\titem,\r\n\t\t\t\t\tsaneLabel,\r\n\t\t\t\t\tsaneMeta,\r\n\t\t\t\t\tsaneAriaLabel,\r\n\t\t\t\t\tsaneDescription,\r\n\t\t\t\t\tsaneDetail,\r\n\t\t\t\t\tlabelHighlights: item.highlights?.label,\r\n\t\t\t\t\tdescriptionHighlights: item.highlights?.description,\r\n\t\t\t\t\tdetailHighlights: item.highlights?.detail,\r\n\t\t\t\t\tchecked: false,\r\n\t\t\t\t\tseparator: previous && previous.type === 'separator' ? previous : undefined,\r\n\t\t\t\t\tfireButtonTriggered\r\n\t\t\t\t}));\r\n\t\t\t}\r\n\t\t\treturn result;\r\n\t\t}, [] as ListElement[]);\r\n\t\tthis.elementDisposables.push(...this.elements);\r\n\t\tthis.elementDisposables.push(...this.elements.map(element => element.onChecked(() => this.fireCheckedEvents())));\r\n\r\n\t\tthis.elementsToIndexes = this.elements.reduce((map, element, index) => {\r\n\t\t\tmap.set(element.item, index);\r\n\t\t\treturn map;\r\n\t\t}, new Map());\r\n\t\tthis.list.splice(0, this.list.length); // Clear focus and selection first, sending the events when the list is empty.\r\n\t\tthis.list.splice(0, this.list.length, this.elements);\r\n\t\tthis._onChangedVisibleCount.fire(this.elements.length);\r\n\t}\r\n\r\n\tgetFocusedElements() {\r\n\t\treturn this.list.getFocusedElements()\r\n\t\t\t.map(e => e.item);\r\n\t}\r\n\r\n\tsetFocusedElements(items: IQuickPickItem[]) {\r\n\t\tthis.list.setFocus(items\r\n\t\t\t.filter(item => this.elementsToIndexes.has(item))\r\n\t\t\t.map(item => this.elementsToIndexes.get(item)!));\r\n\t\tif (items.length > 0) {\r\n\t\t\tconst focused = this.list.getFocus()[0];\r\n\t\t\tif (typeof focused === 'number') {\r\n\t\t\t\tthis.list.reveal(focused);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tgetActiveDescendant() {\r\n\t\treturn this.list.getHTMLElement().getAttribute('aria-activedescendant');\r\n\t}\r\n\r\n\tsetSelectedElements(items: IQuickPickItem[]) {\r\n\t\tthis.list.setSelection(items\r\n\t\t\t.filter(item => this.elementsToIndexes.has(item))\r\n\t\t\t.map(item => this.elementsToIndexes.get(item)!));\r\n\t}\r\n\r\n\tgetCheckedElements() {\r\n\t\treturn this.elements.filter(e => e.checked)\r\n\t\t\t.map(e => e.item);\r\n\t}\r\n\r\n\tsetCheckedElements(items: IQuickPickItem[]) {\r\n\t\ttry {\r\n\t\t\tthis._fireCheckedEvents = false;\r\n\t\t\tconst checked = new Set();\r\n\t\t\tfor (const item of items) {\r\n\t\t\t\tchecked.add(item);\r\n\t\t\t}\r\n\t\t\tfor (const element of this.elements) {\r\n\t\t\t\telement.checked = checked.has(element.item);\r\n\t\t\t}\r\n\t\t} finally {\r\n\t\t\tthis._fireCheckedEvents = true;\r\n\t\t\tthis.fireCheckedEvents();\r\n\t\t}\r\n\t}\r\n\r\n\tset enabled(value: boolean) {\r\n\t\tthis.list.getHTMLElement().style.pointerEvents = value ? '' : 'none';\r\n\t}\r\n\r\n\tfocus(what: QuickInputListFocus): void {\r\n\t\tif (!this.list.length) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (what === QuickInputListFocus.Next && this.list.getFocus()[0] === this.list.length - 1) {\r\n\t\t\twhat = QuickInputListFocus.First;\r\n\t\t}\r\n\r\n\t\tif (what === QuickInputListFocus.Previous && this.list.getFocus()[0] === 0) {\r\n\t\t\twhat = QuickInputListFocus.Last;\r\n\t\t}\r\n\r\n\t\tif (what === QuickInputListFocus.Second && this.list.length < 2) {\r\n\t\t\twhat = QuickInputListFocus.First;\r\n\t\t}\r\n\r\n\t\tswitch (what) {\r\n\t\t\tcase QuickInputListFocus.First:\r\n\t\t\t\tthis.list.focusFirst();\r\n\t\t\t\tbreak;\r\n\t\t\tcase QuickInputListFocus.Second:\r\n\t\t\t\tthis.list.focusNth(1);\r\n\t\t\t\tbreak;\r\n\t\t\tcase QuickInputListFocus.Last:\r\n\t\t\t\tthis.list.focusLast();\r\n\t\t\t\tbreak;\r\n\t\t\tcase QuickInputListFocus.Next:\r\n\t\t\t\tthis.list.focusNext();\r\n\t\t\t\tbreak;\r\n\t\t\tcase QuickInputListFocus.Previous:\r\n\t\t\t\tthis.list.focusPrevious();\r\n\t\t\t\tbreak;\r\n\t\t\tcase QuickInputListFocus.NextPage:\r\n\t\t\t\tthis.list.focusNextPage();\r\n\t\t\t\tbreak;\r\n\t\t\tcase QuickInputListFocus.PreviousPage:\r\n\t\t\t\tthis.list.focusPreviousPage();\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tconst focused = this.list.getFocus()[0];\r\n\t\tif (typeof focused === 'number') {\r\n\t\t\tthis.list.reveal(focused);\r\n\t\t}\r\n\t}\r\n\r\n\tclearFocus() {\r\n\t\tthis.list.setFocus([]);\r\n\t}\r\n\r\n\tdomFocus() {\r\n\t\tthis.list.domFocus();\r\n\t}\r\n\r\n\tlayout(maxHeight?: number): void {\r\n\t\tthis.list.getHTMLElement().style.maxHeight = maxHeight ? `calc(${Math.floor(maxHeight / 44) * 44}px)` : '';\r\n\t\tthis.list.layout();\r\n\t}\r\n\r\n\tfilter(query: string): boolean {\r\n\t\tif (!(this.sortByLabel || this.matchOnLabel || this.matchOnDescription || this.matchOnDetail)) {\r\n\t\t\tthis.list.layout();\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tquery = query.trim();\r\n\r\n\t\t// Reset filtering\r\n\t\tif (!query || !(this.matchOnLabel || this.matchOnDescription || this.matchOnDetail)) {\r\n\t\t\tthis.elements.forEach(element => {\r\n\t\t\t\telement.labelHighlights = undefined;\r\n\t\t\t\telement.descriptionHighlights = undefined;\r\n\t\t\t\telement.detailHighlights = undefined;\r\n\t\t\t\telement.hidden = false;\r\n\t\t\t\tconst previous = element.index && this.inputElements[element.index - 1];\r\n\t\t\t\telement.separator = previous && previous.type === 'separator' ? previous : undefined;\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\t// Filter by value (since we support icons in labels, use $(..) aware fuzzy matching)\r\n\t\telse {\r\n\t\t\tthis.elements.forEach(element => {\r\n\t\t\t\tconst labelHighlights = this.matchOnLabel ? withNullAsUndefined(matchesFuzzyIconAware(query, parseLabelWithIcons(element.saneLabel))) : undefined;\r\n\t\t\t\tconst descriptionHighlights = this.matchOnDescription ? withNullAsUndefined(matchesFuzzyIconAware(query, parseLabelWithIcons(element.saneDescription || ''))) : undefined;\r\n\t\t\t\tconst detailHighlights = this.matchOnDetail ? withNullAsUndefined(matchesFuzzyIconAware(query, parseLabelWithIcons(element.saneDetail || ''))) : undefined;\r\n\t\t\t\tconst metaHighlights = this.matchOnMeta ? withNullAsUndefined(matchesFuzzyIconAware(query, parseLabelWithIcons(element.saneMeta || ''))) : undefined;\r\n\r\n\t\t\t\tif (labelHighlights || descriptionHighlights || detailHighlights || metaHighlights) {\r\n\t\t\t\t\telement.labelHighlights = labelHighlights;\r\n\t\t\t\t\telement.descriptionHighlights = descriptionHighlights;\r\n\t\t\t\t\telement.detailHighlights = detailHighlights;\r\n\t\t\t\t\telement.hidden = false;\r\n\t\t\t\t} else {\r\n\t\t\t\t\telement.labelHighlights = undefined;\r\n\t\t\t\t\telement.descriptionHighlights = undefined;\r\n\t\t\t\t\telement.detailHighlights = undefined;\r\n\t\t\t\t\telement.hidden = !element.item.alwaysShow;\r\n\t\t\t\t}\r\n\t\t\t\telement.separator = undefined;\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tconst shownElements = this.elements.filter(element => !element.hidden);\r\n\r\n\t\t// Sort by value\r\n\t\tif (this.sortByLabel && query) {\r\n\t\t\tconst normalizedSearchValue = query.toLowerCase();\r\n\t\t\tshownElements.sort((a, b) => {\r\n\t\t\t\treturn compareEntries(a, b, normalizedSearchValue);\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tthis.elementsToIndexes = shownElements.reduce((map, element, index) => {\r\n\t\t\tmap.set(element.item, index);\r\n\t\t\treturn map;\r\n\t\t}, new Map());\r\n\t\tthis.list.splice(0, this.list.length, shownElements);\r\n\t\tthis.list.setFocus([]);\r\n\t\tthis.list.layout();\r\n\r\n\t\tthis._onChangedAllVisibleChecked.fire(this.getAllVisibleChecked());\r\n\t\tthis._onChangedVisibleCount.fire(shownElements.length);\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\ttoggleCheckbox() {\r\n\t\ttry {\r\n\t\t\tthis._fireCheckedEvents = false;\r\n\t\t\tconst elements = this.list.getFocusedElements();\r\n\t\t\tconst allChecked = this.allVisibleChecked(elements);\r\n\t\t\tfor (const element of elements) {\r\n\t\t\t\telement.checked = !allChecked;\r\n\t\t\t}\r\n\t\t} finally {\r\n\t\t\tthis._fireCheckedEvents = true;\r\n\t\t\tthis.fireCheckedEvents();\r\n\t\t}\r\n\t}\r\n\r\n\tdisplay(display: boolean) {\r\n\t\tthis.container.style.display = display ? '' : 'none';\r\n\t}\r\n\r\n\tisDisplayed() {\r\n\t\treturn this.container.style.display !== 'none';\r\n\t}\r\n\r\n\tdispose() {\r\n\t\tthis.elementDisposables = dispose(this.elementDisposables);\r\n\t\tthis.disposables = dispose(this.disposables);\r\n\t}\r\n\r\n\tprivate fireCheckedEvents() {\r\n\t\tif (this._fireCheckedEvents) {\r\n\t\t\tthis._onChangedAllVisibleChecked.fire(this.getAllVisibleChecked());\r\n\t\t\tthis._onChangedCheckedCount.fire(this.getCheckedCount());\r\n\t\t\tthis._onChangedCheckedElements.fire(this.getCheckedElements());\r\n\t\t}\r\n\t}\r\n\r\n\tprivate fireButtonTriggered(event: IQuickPickItemButtonEvent) {\r\n\t\tthis._onButtonTriggered.fire(event);\r\n\t}\r\n\r\n\tstyle(styles: IListStyles) {\r\n\t\tthis.list.style(styles);\r\n\t}\r\n}\r\n\r\nfunction compareEntries(elementA: ListElement, elementB: ListElement, lookFor: string): number {\r\n\r\n\tconst labelHighlightsA = elementA.labelHighlights || [];\r\n\tconst labelHighlightsB = elementB.labelHighlights || [];\r\n\tif (labelHighlightsA.length && !labelHighlightsB.length) {\r\n\t\treturn -1;\r\n\t}\r\n\r\n\tif (!labelHighlightsA.length && labelHighlightsB.length) {\r\n\t\treturn 1;\r\n\t}\r\n\r\n\tif (labelHighlightsA.length === 0 && labelHighlightsB.length === 0) {\r\n\t\treturn 0;\r\n\t}\r\n\r\n\treturn compareAnything(elementA.saneLabel, elementB.saneLabel, lookFor);\r\n}\r\n\r\nclass QuickInputAccessibilityProvider implements IListAccessibilityProvider {\r\n\r\n\tgetWidgetAriaLabel(): string {\r\n\t\treturn localize('quickInput', \"Quick Input\");\r\n\t}\r\n\r\n\tgetAriaLabel(element: ListElement): string | null {\r\n\t\treturn element.saneAriaLabel;\r\n\t}\r\n\r\n\tgetWidgetRole() {\r\n\t\treturn 'listbox';\r\n\t}\r\n\r\n\tgetRole() {\r\n\t\treturn 'option';\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./media/quickInput';\r\nimport { IQuickPickItem, IPickOptions, IQuickNavigateConfiguration, IQuickPick, IQuickInput, IQuickInputButton, IQuickPickItemButtonEvent, QuickPickInput, IQuickPickSeparator, IKeyMods, IQuickPickAcceptEvent, NO_KEY_MODS, ItemActivation } from 'vs/base/parts/quickinput/common/quickInput';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { QuickInputList, QuickInputListFocus } from './quickInputList';\r\nimport { QuickInputBox } from './quickInputBox';\r\nimport { KeyCode } from 'vs/base/common/keyCodes';\r\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { localize } from 'vs/nls';\r\nimport { CountBadge, ICountBadgetyles } from 'vs/base/browser/ui/countBadge/countBadge';\r\nimport { ProgressBar, IProgressBarStyles } from 'vs/base/browser/ui/progressbar/progressbar';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { Button, IButtonStyles } from 'vs/base/browser/ui/button/button';\r\nimport { dispose, Disposable, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport Severity from 'vs/base/common/severity';\r\nimport { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';\r\nimport { Action } from 'vs/base/common/actions';\r\nimport { equals } from 'vs/base/common/arrays';\r\nimport { TimeoutTimer } from 'vs/base/common/async';\r\nimport { getIconClass } from 'vs/base/parts/quickinput/browser/quickInputUtils';\r\nimport { IListVirtualDelegate, IListRenderer } from 'vs/base/browser/ui/list/list';\r\nimport { List, IListOptions, IListStyles } from 'vs/base/browser/ui/list/listWidget';\r\nimport { IInputBoxStyles } from 'vs/base/browser/ui/inputbox/inputBox';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { registerCodicon, Codicon } from 'vs/base/common/codicons';\r\nimport { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';\r\nimport { escape } from 'vs/base/common/strings';\r\nimport { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';\r\n\r\nexport interface IQuickInputOptions {\r\n\tidPrefix: string;\r\n\tcontainer: HTMLElement;\r\n\tignoreFocusOut(): boolean;\r\n\tisScreenReaderOptimized(): boolean;\r\n\tbackKeybindingLabel(): string | undefined;\r\n\tsetContextKey(id?: string): void;\r\n\treturnFocus(): void;\r\n\tcreateList(\r\n\t\tuser: string,\r\n\t\tcontainer: HTMLElement,\r\n\t\tdelegate: IListVirtualDelegate,\r\n\t\trenderers: IListRenderer[],\r\n\t\toptions: IListOptions,\r\n\t): List;\r\n\tstyles: IQuickInputStyles;\r\n}\r\n\r\nexport interface IQuickInputStyles {\r\n\twidget: IQuickInputWidgetStyles;\r\n\tinputBox: IInputBoxStyles;\r\n\tcountBadge: ICountBadgetyles;\r\n\tbutton: IButtonStyles;\r\n\tprogressBar: IProgressBarStyles;\r\n\tlist: IListStyles & { listInactiveFocusForeground?: Color; pickerGroupBorder?: Color; pickerGroupForeground?: Color; };\r\n}\r\n\r\nexport interface IQuickInputWidgetStyles {\r\n\tquickInputBackground?: Color;\r\n\tquickInputForeground?: Color;\r\n\tquickInputTitleBackground?: Color;\r\n\tcontrastBorder?: Color;\r\n\twidgetShadow?: Color;\r\n}\r\n\r\nconst $ = dom.$;\r\n\r\ntype Writeable = { -readonly [P in keyof T]: T[P] };\r\n\r\n\r\nconst backButtonIcon = registerCodicon('quick-input-back', Codicon.arrowLeft);\r\n\r\nconst backButton = {\r\n\ticonClass: backButtonIcon.classNames,\r\n\ttooltip: localize('quickInput.back', \"Back\"),\r\n\thandle: -1 // TODO\r\n};\r\n\r\ninterface QuickInputUI {\r\n\tcontainer: HTMLElement;\r\n\tstyleSheet: HTMLStyleElement;\r\n\tleftActionBar: ActionBar;\r\n\ttitleBar: HTMLElement;\r\n\ttitle: HTMLElement;\r\n\tdescription1: HTMLElement;\r\n\tdescription2: HTMLElement;\r\n\trightActionBar: ActionBar;\r\n\tcheckAll: HTMLInputElement;\r\n\tfilterContainer: HTMLElement;\r\n\tinputBox: QuickInputBox;\r\n\tvisibleCountContainer: HTMLElement;\r\n\tvisibleCount: CountBadge;\r\n\tcountContainer: HTMLElement;\r\n\tcount: CountBadge;\r\n\tokContainer: HTMLElement;\r\n\tok: Button;\r\n\tmessage: HTMLElement;\r\n\tcustomButtonContainer: HTMLElement;\r\n\tcustomButton: Button;\r\n\tprogressBar: ProgressBar;\r\n\tlist: QuickInputList;\r\n\tonDidAccept: Event;\r\n\tonDidCustom: Event;\r\n\tonDidTriggerButton: Event;\r\n\tignoreFocusOut: boolean;\r\n\tkeyMods: Writeable;\r\n\tisScreenReaderOptimized(): boolean;\r\n\tshow(controller: QuickInput): void;\r\n\tsetVisibilities(visibilities: Visibilities): void;\r\n\tsetComboboxAccessibility(enabled: boolean): void;\r\n\tsetEnabled(enabled: boolean): void;\r\n\tsetContextKey(contextKey?: string): void;\r\n\thide(): void;\r\n}\r\n\r\ntype Visibilities = {\r\n\ttitle?: boolean;\r\n\tdescription?: boolean;\r\n\tcheckAll?: boolean;\r\n\tinputBox?: boolean;\r\n\tcheckBox?: boolean;\r\n\tvisibleCount?: boolean;\r\n\tcount?: boolean;\r\n\tmessage?: boolean;\r\n\tlist?: boolean;\r\n\tok?: boolean;\r\n\tcustomButton?: boolean;\r\n\tprogressBar?: boolean;\r\n};\r\n\r\nclass QuickInput extends Disposable implements IQuickInput {\r\n\r\n\tprivate _title: string | undefined;\r\n\tprivate _description: string | undefined;\r\n\tprivate _steps: number | undefined;\r\n\tprivate _totalSteps: number | undefined;\r\n\tprotected visible = false;\r\n\tprivate _enabled = true;\r\n\tprivate _contextKey: string | undefined;\r\n\tprivate _busy = false;\r\n\tprivate _ignoreFocusOut = false;\r\n\tprivate _buttons: IQuickInputButton[] = [];\r\n\tprivate buttonsUpdated = false;\r\n\tprivate readonly onDidTriggerButtonEmitter = this._register(new Emitter());\r\n\tprivate readonly onDidHideEmitter = this._register(new Emitter());\r\n\tprivate readonly onDisposeEmitter = this._register(new Emitter());\r\n\r\n\tprotected readonly visibleDisposables = this._register(new DisposableStore());\r\n\r\n\tprivate busyDelay: TimeoutTimer | undefined;\r\n\r\n\tconstructor(\r\n\t\tprotected ui: QuickInputUI\r\n\t) {\r\n\t\tsuper();\r\n\t}\r\n\r\n\tget title() {\r\n\t\treturn this._title;\r\n\t}\r\n\r\n\tset title(title: string | undefined) {\r\n\t\tthis._title = title;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget description() {\r\n\t\treturn this._description;\r\n\t}\r\n\r\n\tset description(description: string | undefined) {\r\n\t\tthis._description = description;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget step() {\r\n\t\treturn this._steps;\r\n\t}\r\n\r\n\tset step(step: number | undefined) {\r\n\t\tthis._steps = step;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget totalSteps() {\r\n\t\treturn this._totalSteps;\r\n\t}\r\n\r\n\tset totalSteps(totalSteps: number | undefined) {\r\n\t\tthis._totalSteps = totalSteps;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget enabled() {\r\n\t\treturn this._enabled;\r\n\t}\r\n\r\n\tset enabled(enabled: boolean) {\r\n\t\tthis._enabled = enabled;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget contextKey() {\r\n\t\treturn this._contextKey;\r\n\t}\r\n\r\n\tset contextKey(contextKey: string | undefined) {\r\n\t\tthis._contextKey = contextKey;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget busy() {\r\n\t\treturn this._busy;\r\n\t}\r\n\r\n\tset busy(busy: boolean) {\r\n\t\tthis._busy = busy;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget ignoreFocusOut() {\r\n\t\treturn this._ignoreFocusOut;\r\n\t}\r\n\r\n\tset ignoreFocusOut(ignoreFocusOut: boolean) {\r\n\t\tthis._ignoreFocusOut = ignoreFocusOut;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget buttons() {\r\n\t\treturn this._buttons;\r\n\t}\r\n\r\n\tset buttons(buttons: IQuickInputButton[]) {\r\n\t\tthis._buttons = buttons;\r\n\t\tthis.buttonsUpdated = true;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tshow(): void {\r\n\t\tif (this.visible) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis.visibleDisposables.add(\r\n\t\t\tthis.ui.onDidTriggerButton(button => {\r\n\t\t\t\tif (this.buttons.indexOf(button) !== -1) {\r\n\t\t\t\t\tthis.onDidTriggerButtonEmitter.fire(button);\r\n\t\t\t\t}\r\n\t\t\t}),\r\n\t\t);\r\n\t\tthis.ui.show(this);\r\n\t\tthis.visible = true;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\thide(): void {\r\n\t\tif (!this.visible) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis.ui.hide();\r\n\t}\r\n\r\n\tdidHide(): void {\r\n\t\tthis.visible = false;\r\n\t\tthis.visibleDisposables.clear();\r\n\t\tthis.onDidHideEmitter.fire();\r\n\t}\r\n\r\n\treadonly onDidHide = this.onDidHideEmitter.event;\r\n\r\n\tprotected update() {\r\n\t\tif (!this.visible) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst title = this.getTitle();\r\n\t\tif (title && this.ui.title.textContent !== title) {\r\n\t\t\tthis.ui.title.textContent = title;\r\n\t\t} else if (!title && this.ui.title.innerHTML !== ' ') {\r\n\t\t\tthis.ui.title.innerText = '\\u00a0;';\r\n\t\t}\r\n\t\tconst description = this.getDescription();\r\n\t\tif (this.ui.description1.textContent !== description) {\r\n\t\t\tthis.ui.description1.textContent = description;\r\n\t\t}\r\n\t\tif (this.ui.description2.textContent !== description) {\r\n\t\t\tthis.ui.description2.textContent = description;\r\n\t\t}\r\n\t\tif (this.busy && !this.busyDelay) {\r\n\t\t\tthis.busyDelay = new TimeoutTimer();\r\n\t\t\tthis.busyDelay.setIfNotSet(() => {\r\n\t\t\t\tif (this.visible) {\r\n\t\t\t\t\tthis.ui.progressBar.infinite();\r\n\t\t\t\t}\r\n\t\t\t}, 800);\r\n\t\t}\r\n\t\tif (!this.busy && this.busyDelay) {\r\n\t\t\tthis.ui.progressBar.stop();\r\n\t\t\tthis.busyDelay.cancel();\r\n\t\t\tthis.busyDelay = undefined;\r\n\t\t}\r\n\t\tif (this.buttonsUpdated) {\r\n\t\t\tthis.buttonsUpdated = false;\r\n\t\t\tthis.ui.leftActionBar.clear();\r\n\t\t\tconst leftButtons = this.buttons.filter(button => button === backButton);\r\n\t\t\tthis.ui.leftActionBar.push(leftButtons.map((button, index) => {\r\n\t\t\t\tconst action = new Action(`id-${index}`, '', button.iconClass || getIconClass(button.iconPath), true, async () => {\r\n\t\t\t\t\tthis.onDidTriggerButtonEmitter.fire(button);\r\n\t\t\t\t});\r\n\t\t\t\taction.tooltip = button.tooltip || '';\r\n\t\t\t\treturn action;\r\n\t\t\t}), { icon: true, label: false });\r\n\t\t\tthis.ui.rightActionBar.clear();\r\n\t\t\tconst rightButtons = this.buttons.filter(button => button !== backButton);\r\n\t\t\tthis.ui.rightActionBar.push(rightButtons.map((button, index) => {\r\n\t\t\t\tconst action = new Action(`id-${index}`, '', button.iconClass || getIconClass(button.iconPath), true, async () => {\r\n\t\t\t\t\tthis.onDidTriggerButtonEmitter.fire(button);\r\n\t\t\t\t});\r\n\t\t\t\taction.tooltip = button.tooltip || '';\r\n\t\t\t\treturn action;\r\n\t\t\t}), { icon: true, label: false });\r\n\t\t}\r\n\t\tthis.ui.ignoreFocusOut = this.ignoreFocusOut;\r\n\t\tthis.ui.setEnabled(this.enabled);\r\n\t\tthis.ui.setContextKey(this.contextKey);\r\n\t}\r\n\r\n\tprivate getTitle() {\r\n\t\tif (this.title && this.step) {\r\n\t\t\treturn `${this.title} (${this.getSteps()})`;\r\n\t\t}\r\n\t\tif (this.title) {\r\n\t\t\treturn this.title;\r\n\t\t}\r\n\t\tif (this.step) {\r\n\t\t\treturn this.getSteps();\r\n\t\t}\r\n\t\treturn '';\r\n\t}\r\n\r\n\tprivate getDescription() {\r\n\t\treturn this.description || '';\r\n\t}\r\n\r\n\tprivate getSteps() {\r\n\t\tif (this.step && this.totalSteps) {\r\n\t\t\treturn localize('quickInput.steps', \"{0}/{1}\", this.step, this.totalSteps);\r\n\t\t}\r\n\t\tif (this.step) {\r\n\t\t\treturn String(this.step);\r\n\t\t}\r\n\t\treturn '';\r\n\t}\r\n\r\n\tprotected showMessageDecoration(severity: Severity) {\r\n\t\tthis.ui.inputBox.showDecoration(severity);\r\n\t\tif (severity === Severity.Error) {\r\n\t\t\tconst styles = this.ui.inputBox.stylesForType(severity);\r\n\t\t\tthis.ui.message.style.color = styles.foreground ? `${styles.foreground}` : '';\r\n\t\t\tthis.ui.message.style.backgroundColor = styles.background ? `${styles.background}` : '';\r\n\t\t\tthis.ui.message.style.border = styles.border ? `1px solid ${styles.border}` : '';\r\n\t\t\tthis.ui.message.style.paddingBottom = '4px';\r\n\t\t} else {\r\n\t\t\tthis.ui.message.style.color = '';\r\n\t\t\tthis.ui.message.style.backgroundColor = '';\r\n\t\t\tthis.ui.message.style.border = '';\r\n\t\t\tthis.ui.message.style.paddingBottom = '';\r\n\t\t}\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis.hide();\r\n\t\tthis.onDisposeEmitter.fire();\r\n\r\n\t\tsuper.dispose();\r\n\t}\r\n}\r\n\r\nclass QuickPick extends QuickInput implements IQuickPick {\r\n\r\n\tprivate static readonly DEFAULT_ARIA_LABEL = localize('quickInputBox.ariaLabel', \"Type to narrow down results.\");\r\n\r\n\tprivate _value = '';\r\n\tprivate _ariaLabel: string | undefined;\r\n\tprivate _placeholder: string | undefined;\r\n\tprivate readonly onDidChangeValueEmitter = this._register(new Emitter());\r\n\tprivate readonly onDidAcceptEmitter = this._register(new Emitter());\r\n\tprivate readonly onDidCustomEmitter = this._register(new Emitter());\r\n\tprivate _items: Array = [];\r\n\tprivate itemsUpdated = false;\r\n\tprivate _canSelectMany = false;\r\n\tprivate _canAcceptInBackground = false;\r\n\tprivate _matchOnDescription = false;\r\n\tprivate _matchOnDetail = false;\r\n\tprivate _matchOnLabel = true;\r\n\tprivate _sortByLabel = true;\r\n\tprivate _autoFocusOnList = true;\r\n\tprivate _itemActivation = this.ui.isScreenReaderOptimized() ? ItemActivation.NONE /* https://github.com/microsoft/vscode/issues/57501 */ : ItemActivation.FIRST;\r\n\tprivate _activeItems: T[] = [];\r\n\tprivate activeItemsUpdated = false;\r\n\tprivate activeItemsToConfirm: T[] | null = [];\r\n\tprivate readonly onDidChangeActiveEmitter = this._register(new Emitter());\r\n\tprivate _selectedItems: T[] = [];\r\n\tprivate selectedItemsUpdated = false;\r\n\tprivate selectedItemsToConfirm: T[] | null = [];\r\n\tprivate readonly onDidChangeSelectionEmitter = this._register(new Emitter());\r\n\tprivate readonly onDidTriggerItemButtonEmitter = this._register(new Emitter>());\r\n\tprivate _valueSelection: Readonly<[number, number]> | undefined;\r\n\tprivate valueSelectionUpdated = true;\r\n\tprivate _validationMessage: string | undefined;\r\n\tprivate _lastValidationMessage: string | undefined;\r\n\tprivate _ok: boolean | 'default' = 'default';\r\n\tprivate _customButton = false;\r\n\tprivate _customButtonLabel: string | undefined;\r\n\tprivate _customButtonHover: string | undefined;\r\n\tprivate _quickNavigate: IQuickNavigateConfiguration | undefined;\r\n\tprivate _hideInput: boolean | undefined;\r\n\tprivate _hideCheckAll: boolean | undefined;\r\n\r\n\tget quickNavigate() {\r\n\t\treturn this._quickNavigate;\r\n\t}\r\n\r\n\tset quickNavigate(quickNavigate: IQuickNavigateConfiguration | undefined) {\r\n\t\tthis._quickNavigate = quickNavigate;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget value() {\r\n\t\treturn this._value;\r\n\t}\r\n\r\n\tset value(value: string) {\r\n\t\tthis._value = value || '';\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tfilterValue = (value: string) => value;\r\n\r\n\tset ariaLabel(ariaLabel: string | undefined) {\r\n\t\tthis._ariaLabel = ariaLabel;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget ariaLabel() {\r\n\t\treturn this._ariaLabel;\r\n\t}\r\n\r\n\tget placeholder() {\r\n\t\treturn this._placeholder;\r\n\t}\r\n\r\n\tset placeholder(placeholder: string | undefined) {\r\n\t\tthis._placeholder = placeholder;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tonDidChangeValue = this.onDidChangeValueEmitter.event;\r\n\r\n\tonDidAccept = this.onDidAcceptEmitter.event;\r\n\r\n\tget items() {\r\n\t\treturn this._items;\r\n\t}\r\n\r\n\tset items(items: Array) {\r\n\t\tthis._items = items;\r\n\t\tthis.itemsUpdated = true;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget canSelectMany() {\r\n\t\treturn this._canSelectMany;\r\n\t}\r\n\r\n\tset canSelectMany(canSelectMany: boolean) {\r\n\t\tthis._canSelectMany = canSelectMany;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget canAcceptInBackground() {\r\n\t\treturn this._canAcceptInBackground;\r\n\t}\r\n\r\n\tset canAcceptInBackground(canAcceptInBackground: boolean) {\r\n\t\tthis._canAcceptInBackground = canAcceptInBackground;\r\n\t}\r\n\r\n\tget matchOnDescription() {\r\n\t\treturn this._matchOnDescription;\r\n\t}\r\n\r\n\tset matchOnDescription(matchOnDescription: boolean) {\r\n\t\tthis._matchOnDescription = matchOnDescription;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget matchOnDetail() {\r\n\t\treturn this._matchOnDetail;\r\n\t}\r\n\r\n\tset matchOnDetail(matchOnDetail: boolean) {\r\n\t\tthis._matchOnDetail = matchOnDetail;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget matchOnLabel() {\r\n\t\treturn this._matchOnLabel;\r\n\t}\r\n\r\n\tset matchOnLabel(matchOnLabel: boolean) {\r\n\t\tthis._matchOnLabel = matchOnLabel;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget sortByLabel() {\r\n\t\treturn this._sortByLabel;\r\n\t}\r\n\r\n\tset sortByLabel(sortByLabel: boolean) {\r\n\t\tthis._sortByLabel = sortByLabel;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget autoFocusOnList() {\r\n\t\treturn this._autoFocusOnList;\r\n\t}\r\n\r\n\tset autoFocusOnList(autoFocusOnList: boolean) {\r\n\t\tthis._autoFocusOnList = autoFocusOnList;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget itemActivation() {\r\n\t\treturn this._itemActivation;\r\n\t}\r\n\r\n\tset itemActivation(itemActivation: ItemActivation) {\r\n\t\tthis._itemActivation = itemActivation;\r\n\t}\r\n\r\n\tget activeItems() {\r\n\t\treturn this._activeItems;\r\n\t}\r\n\r\n\tset activeItems(activeItems: T[]) {\r\n\t\tthis._activeItems = activeItems;\r\n\t\tthis.activeItemsUpdated = true;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tonDidChangeActive = this.onDidChangeActiveEmitter.event;\r\n\r\n\tget selectedItems() {\r\n\t\treturn this._selectedItems;\r\n\t}\r\n\r\n\tset selectedItems(selectedItems: T[]) {\r\n\t\tthis._selectedItems = selectedItems;\r\n\t\tthis.selectedItemsUpdated = true;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget keyMods() {\r\n\t\tif (this._quickNavigate) {\r\n\t\t\t// Disable keyMods when quick navigate is enabled\r\n\t\t\t// because in this model the interaction is purely\r\n\t\t\t// keyboard driven and Ctrl/Alt are typically\r\n\t\t\t// pressed and hold during this interaction.\r\n\t\t\treturn NO_KEY_MODS;\r\n\t\t}\r\n\t\treturn this.ui.keyMods;\r\n\t}\r\n\r\n\tset valueSelection(valueSelection: Readonly<[number, number]>) {\r\n\t\tthis._valueSelection = valueSelection;\r\n\t\tthis.valueSelectionUpdated = true;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget validationMessage() {\r\n\t\treturn this._validationMessage;\r\n\t}\r\n\r\n\tset validationMessage(validationMessage: string | undefined) {\r\n\t\tthis._validationMessage = validationMessage;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget customButton() {\r\n\t\treturn this._customButton;\r\n\t}\r\n\r\n\tset customButton(showCustomButton: boolean) {\r\n\t\tthis._customButton = showCustomButton;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget customLabel() {\r\n\t\treturn this._customButtonLabel;\r\n\t}\r\n\r\n\tset customLabel(label: string | undefined) {\r\n\t\tthis._customButtonLabel = label;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget customHover() {\r\n\t\treturn this._customButtonHover;\r\n\t}\r\n\r\n\tset customHover(hover: string | undefined) {\r\n\t\tthis._customButtonHover = hover;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget ok() {\r\n\t\treturn this._ok;\r\n\t}\r\n\r\n\tset ok(showOkButton: boolean | 'default') {\r\n\t\tthis._ok = showOkButton;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tget hideInput() {\r\n\t\treturn !!this._hideInput;\r\n\t}\r\n\r\n\tset hideInput(hideInput: boolean) {\r\n\t\tthis._hideInput = hideInput;\r\n\t\tthis.update();\r\n\t}\r\n\r\n\tonDidChangeSelection = this.onDidChangeSelectionEmitter.event;\r\n\r\n\tonDidTriggerItemButton = this.onDidTriggerItemButtonEmitter.event;\r\n\r\n\tprivate trySelectFirst() {\r\n\t\tif (this.autoFocusOnList) {\r\n\t\t\tif (!this.canSelectMany) {\r\n\t\t\t\tthis.ui.list.focus(QuickInputListFocus.First);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tshow() {\r\n\t\tif (!this.visible) {\r\n\t\t\tthis.visibleDisposables.add(\r\n\t\t\t\tthis.ui.inputBox.onDidChange(value => {\r\n\t\t\t\t\tif (value === this.value) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tthis._value = value;\r\n\t\t\t\t\tconst didFilter = this.ui.list.filter(this.filterValue(this.ui.inputBox.value));\r\n\t\t\t\t\tif (didFilter) {\r\n\t\t\t\t\t\tthis.trySelectFirst();\r\n\t\t\t\t\t}\r\n\t\t\t\t\tthis.onDidChangeValueEmitter.fire(value);\r\n\t\t\t\t}));\r\n\t\t\tthis.visibleDisposables.add(this.ui.inputBox.onMouseDown(event => {\r\n\t\t\t\tif (!this.autoFocusOnList) {\r\n\t\t\t\t\tthis.ui.list.clearFocus();\r\n\t\t\t\t}\r\n\t\t\t}));\r\n\t\t\tthis.visibleDisposables.add((this._hideInput ? this.ui.list : this.ui.inputBox).onKeyDown((event: KeyboardEvent | StandardKeyboardEvent) => {\r\n\t\t\t\tswitch (event.keyCode) {\r\n\t\t\t\t\tcase KeyCode.DownArrow:\r\n\t\t\t\t\t\tthis.ui.list.focus(QuickInputListFocus.Next);\r\n\t\t\t\t\t\tif (this.canSelectMany) {\r\n\t\t\t\t\t\t\tthis.ui.list.domFocus();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tdom.EventHelper.stop(event, true);\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tcase KeyCode.UpArrow:\r\n\t\t\t\t\t\tif (this.ui.list.getFocusedElements().length) {\r\n\t\t\t\t\t\t\tthis.ui.list.focus(QuickInputListFocus.Previous);\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tthis.ui.list.focus(QuickInputListFocus.Last);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (this.canSelectMany) {\r\n\t\t\t\t\t\t\tthis.ui.list.domFocus();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tdom.EventHelper.stop(event, true);\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tcase KeyCode.PageDown:\r\n\t\t\t\t\t\tthis.ui.list.focus(QuickInputListFocus.NextPage);\r\n\t\t\t\t\t\tif (this.canSelectMany) {\r\n\t\t\t\t\t\t\tthis.ui.list.domFocus();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tdom.EventHelper.stop(event, true);\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tcase KeyCode.PageUp:\r\n\t\t\t\t\t\tthis.ui.list.focus(QuickInputListFocus.PreviousPage);\r\n\t\t\t\t\t\tif (this.canSelectMany) {\r\n\t\t\t\t\t\t\tthis.ui.list.domFocus();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tdom.EventHelper.stop(event, true);\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tcase KeyCode.RightArrow:\r\n\t\t\t\t\t\tif (!this._canAcceptInBackground) {\r\n\t\t\t\t\t\t\treturn; // needs to be enabled\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif (!this.ui.inputBox.isSelectionAtEnd()) {\r\n\t\t\t\t\t\t\treturn; // ensure input box selection at end\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif (this.activeItems[0]) {\r\n\t\t\t\t\t\t\tthis._selectedItems = [this.activeItems[0]];\r\n\t\t\t\t\t\t\tthis.onDidChangeSelectionEmitter.fire(this.selectedItems);\r\n\t\t\t\t\t\t\tthis.onDidAcceptEmitter.fire({ inBackground: true });\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tcase KeyCode.Home:\r\n\t\t\t\t\t\tif ((event.ctrlKey || event.metaKey) && !event.shiftKey && !event.altKey) {\r\n\t\t\t\t\t\t\tthis.ui.list.focus(QuickInputListFocus.First);\r\n\t\t\t\t\t\t\tdom.EventHelper.stop(event, true);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tcase KeyCode.End:\r\n\t\t\t\t\t\tif ((event.ctrlKey || event.metaKey) && !event.shiftKey && !event.altKey) {\r\n\t\t\t\t\t\t\tthis.ui.list.focus(QuickInputListFocus.Last);\r\n\t\t\t\t\t\t\tdom.EventHelper.stop(event, true);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}));\r\n\t\t\tthis.visibleDisposables.add(this.ui.onDidAccept(() => {\r\n\t\t\t\tif (!this.canSelectMany && this.activeItems[0]) {\r\n\t\t\t\t\tthis._selectedItems = [this.activeItems[0]];\r\n\t\t\t\t\tthis.onDidChangeSelectionEmitter.fire(this.selectedItems);\r\n\t\t\t\t}\r\n\t\t\t\tthis.onDidAcceptEmitter.fire({ inBackground: false });\r\n\t\t\t}));\r\n\t\t\tthis.visibleDisposables.add(this.ui.onDidCustom(() => {\r\n\t\t\t\tthis.onDidCustomEmitter.fire();\r\n\t\t\t}));\r\n\t\t\tthis.visibleDisposables.add(this.ui.list.onDidChangeFocus(focusedItems => {\r\n\t\t\t\tif (this.activeItemsUpdated) {\r\n\t\t\t\t\treturn; // Expect another event.\r\n\t\t\t\t}\r\n\t\t\t\tif (this.activeItemsToConfirm !== this._activeItems && equals(focusedItems, this._activeItems, (a, b) => a === b)) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\tthis._activeItems = focusedItems as T[];\r\n\t\t\t\tthis.onDidChangeActiveEmitter.fire(focusedItems as T[]);\r\n\t\t\t}));\r\n\t\t\tthis.visibleDisposables.add(this.ui.list.onDidChangeSelection(({ items: selectedItems, event }) => {\r\n\t\t\t\tif (this.canSelectMany) {\r\n\t\t\t\t\tif (selectedItems.length) {\r\n\t\t\t\t\t\tthis.ui.list.setSelectedElements([]);\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\tif (this.selectedItemsToConfirm !== this._selectedItems && equals(selectedItems, this._selectedItems, (a, b) => a === b)) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\tthis._selectedItems = selectedItems as T[];\r\n\t\t\t\tthis.onDidChangeSelectionEmitter.fire(selectedItems as T[]);\r\n\t\t\t\tif (selectedItems.length) {\r\n\t\t\t\t\tthis.onDidAcceptEmitter.fire({ inBackground: event instanceof MouseEvent && event.button === 1 /* mouse middle click */ });\r\n\t\t\t\t}\r\n\t\t\t}));\r\n\t\t\tthis.visibleDisposables.add(this.ui.list.onChangedCheckedElements(checkedItems => {\r\n\t\t\t\tif (!this.canSelectMany) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\tif (this.selectedItemsToConfirm !== this._selectedItems && equals(checkedItems, this._selectedItems, (a, b) => a === b)) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\tthis._selectedItems = checkedItems as T[];\r\n\t\t\t\tthis.onDidChangeSelectionEmitter.fire(checkedItems as T[]);\r\n\t\t\t}));\r\n\t\t\tthis.visibleDisposables.add(this.ui.list.onButtonTriggered(event => this.onDidTriggerItemButtonEmitter.fire(event as IQuickPickItemButtonEvent)));\r\n\t\t\tthis.visibleDisposables.add(this.registerQuickNavigation());\r\n\t\t\tthis.valueSelectionUpdated = true;\r\n\t\t}\r\n\t\tsuper.show(); // TODO: Why have show() bubble up while update() trickles down? (Could move setComboboxAccessibility() here.)\r\n\t}\r\n\r\n\tprivate registerQuickNavigation() {\r\n\t\treturn dom.addDisposableListener(this.ui.container, dom.EventType.KEY_UP, e => {\r\n\t\t\tif (this.canSelectMany || !this._quickNavigate) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst keyboardEvent: StandardKeyboardEvent = new StandardKeyboardEvent(e);\r\n\t\t\tconst keyCode = keyboardEvent.keyCode;\r\n\r\n\t\t\t// Select element when keys are pressed that signal it\r\n\t\t\tconst quickNavKeys = this._quickNavigate.keybindings;\r\n\t\t\tconst wasTriggerKeyPressed = quickNavKeys.some(k => {\r\n\t\t\t\tconst [firstPart, chordPart] = k.getParts();\r\n\t\t\t\tif (chordPart) {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (firstPart.shiftKey && keyCode === KeyCode.Shift) {\r\n\t\t\t\t\tif (keyboardEvent.ctrlKey || keyboardEvent.altKey || keyboardEvent.metaKey) {\r\n\t\t\t\t\t\treturn false; // this is an optimistic check for the shift key being used to navigate back in quick input\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (firstPart.altKey && keyCode === KeyCode.Alt) {\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (firstPart.ctrlKey && keyCode === KeyCode.Ctrl) {\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (firstPart.metaKey && keyCode === KeyCode.Meta) {\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn false;\r\n\t\t\t});\r\n\r\n\t\t\tif (wasTriggerKeyPressed) {\r\n\t\t\t\tif (this.activeItems[0]) {\r\n\t\t\t\t\tthis._selectedItems = [this.activeItems[0]];\r\n\t\t\t\t\tthis.onDidChangeSelectionEmitter.fire(this.selectedItems);\r\n\t\t\t\t\tthis.onDidAcceptEmitter.fire({ inBackground: false });\r\n\t\t\t\t}\r\n\t\t\t\t// Unset quick navigate after press. It is only valid once\r\n\t\t\t\t// and should not result in any behaviour change afterwards\r\n\t\t\t\t// if the picker remains open because there was no active item\r\n\t\t\t\tthis._quickNavigate = undefined;\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprotected update() {\r\n\t\tif (!this.visible) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tlet hideInput = false;\r\n\t\tlet inputShownJustForScreenReader = false;\r\n\t\tif (!!this._hideInput && this._items.length > 0) {\r\n\t\t\tif (this.ui.isScreenReaderOptimized()) {\r\n\t\t\t\t// Always show input if screen reader attached https://github.com/microsoft/vscode/issues/94360\r\n\t\t\t\tinputShownJustForScreenReader = true;\r\n\t\t\t} else {\r\n\t\t\t\thideInput = true;\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis.ui.container.classList.toggle('hidden-input', hideInput && !this.description);\r\n\t\tconst visibilities: Visibilities = {\r\n\t\t\ttitle: !!this.title || !!this.step || !!this.buttons.length,\r\n\t\t\tdescription: !!this.description,\r\n\t\t\tcheckAll: this.canSelectMany && !this._hideCheckAll,\r\n\t\t\tcheckBox: this.canSelectMany,\r\n\t\t\tinputBox: !hideInput,\r\n\t\t\tprogressBar: !hideInput,\r\n\t\t\tvisibleCount: true,\r\n\t\t\tcount: this.canSelectMany,\r\n\t\t\tok: this.ok === 'default' ? this.canSelectMany : this.ok,\r\n\t\t\tlist: true,\r\n\t\t\tmessage: !!this.validationMessage,\r\n\t\t\tcustomButton: this.customButton\r\n\t\t};\r\n\t\tthis.ui.setVisibilities(visibilities);\r\n\t\tsuper.update();\r\n\t\tif (this.ui.inputBox.value !== this.value) {\r\n\t\t\tthis.ui.inputBox.value = this.value;\r\n\t\t}\r\n\t\tif (this.valueSelectionUpdated) {\r\n\t\t\tthis.valueSelectionUpdated = false;\r\n\t\t\tthis.ui.inputBox.select(this._valueSelection && { start: this._valueSelection[0], end: this._valueSelection[1] });\r\n\t\t}\r\n\t\tif (this.ui.inputBox.placeholder !== (this.placeholder || '')) {\r\n\t\t\tthis.ui.inputBox.placeholder = (this.placeholder || '');\r\n\t\t}\r\n\t\tif (inputShownJustForScreenReader) {\r\n\t\t\tthis.ui.inputBox.ariaLabel = '';\r\n\t\t} else {\r\n\t\t\tconst ariaLabel = this.ariaLabel || this.placeholder || QuickPick.DEFAULT_ARIA_LABEL;\r\n\t\t\tif (this.ui.inputBox.ariaLabel !== ariaLabel) {\r\n\t\t\t\tthis.ui.inputBox.ariaLabel = ariaLabel;\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis.ui.list.matchOnDescription = this.matchOnDescription;\r\n\t\tthis.ui.list.matchOnDetail = this.matchOnDetail;\r\n\t\tthis.ui.list.matchOnLabel = this.matchOnLabel;\r\n\t\tthis.ui.list.sortByLabel = this.sortByLabel;\r\n\t\tif (this.itemsUpdated) {\r\n\t\t\tthis.itemsUpdated = false;\r\n\t\t\tthis.ui.list.setElements(this.items);\r\n\t\t\tthis.ui.list.filter(this.filterValue(this.ui.inputBox.value));\r\n\t\t\tthis.ui.checkAll.checked = this.ui.list.getAllVisibleChecked();\r\n\t\t\tthis.ui.visibleCount.setCount(this.ui.list.getVisibleCount());\r\n\t\t\tthis.ui.count.setCount(this.ui.list.getCheckedCount());\r\n\t\t\tswitch (this._itemActivation) {\r\n\t\t\t\tcase ItemActivation.NONE:\r\n\t\t\t\t\tthis._itemActivation = ItemActivation.FIRST; // only valid once, then unset\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase ItemActivation.SECOND:\r\n\t\t\t\t\tthis.ui.list.focus(QuickInputListFocus.Second);\r\n\t\t\t\t\tthis._itemActivation = ItemActivation.FIRST; // only valid once, then unset\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase ItemActivation.LAST:\r\n\t\t\t\t\tthis.ui.list.focus(QuickInputListFocus.Last);\r\n\t\t\t\t\tthis._itemActivation = ItemActivation.FIRST; // only valid once, then unset\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tdefault:\r\n\t\t\t\t\tthis.trySelectFirst();\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (this.ui.container.classList.contains('show-checkboxes') !== !!this.canSelectMany) {\r\n\t\t\tif (this.canSelectMany) {\r\n\t\t\t\tthis.ui.list.clearFocus();\r\n\t\t\t} else {\r\n\t\t\t\tthis.trySelectFirst();\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (this.activeItemsUpdated) {\r\n\t\t\tthis.activeItemsUpdated = false;\r\n\t\t\tthis.activeItemsToConfirm = this._activeItems;\r\n\t\t\tthis.ui.list.setFocusedElements(this.activeItems);\r\n\t\t\tif (this.activeItemsToConfirm === this._activeItems) {\r\n\t\t\t\tthis.activeItemsToConfirm = null;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (this.selectedItemsUpdated) {\r\n\t\t\tthis.selectedItemsUpdated = false;\r\n\t\t\tthis.selectedItemsToConfirm = this._selectedItems;\r\n\t\t\tif (this.canSelectMany) {\r\n\t\t\t\tthis.ui.list.setCheckedElements(this.selectedItems);\r\n\t\t\t} else {\r\n\t\t\t\tthis.ui.list.setSelectedElements(this.selectedItems);\r\n\t\t\t}\r\n\t\t\tif (this.selectedItemsToConfirm === this._selectedItems) {\r\n\t\t\t\tthis.selectedItemsToConfirm = null;\r\n\t\t\t}\r\n\t\t}\r\n\t\tconst validationMessage = this.validationMessage || '';\r\n\t\tif (this._lastValidationMessage !== validationMessage) {\r\n\t\t\tthis._lastValidationMessage = validationMessage;\r\n\t\t\tdom.reset(this.ui.message, ...renderLabelWithIcons(escape(validationMessage)));\r\n\t\t\tthis.showMessageDecoration(this.validationMessage ? Severity.Error : Severity.Ignore);\r\n\t\t}\r\n\t\tthis.ui.customButton.label = this.customLabel || '';\r\n\t\tthis.ui.customButton.element.title = this.customHover || '';\r\n\t\tthis.ui.setComboboxAccessibility(true);\r\n\t\tif (!visibilities.inputBox) {\r\n\t\t\t// we need to move focus into the tree to detect keybindings\r\n\t\t\t// properly when the input box is not visible (quick nav)\r\n\t\t\tthis.ui.list.domFocus();\r\n\r\n\t\t\t// Focus the first element in the list if multiselect is enabled\r\n\t\t\tif (this.canSelectMany) {\r\n\t\t\t\tthis.ui.list.focus(QuickInputListFocus.First);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class QuickInputController extends Disposable {\r\n\tprivate static readonly MAX_WIDTH = 600; // Max total width of quick input widget\r\n\r\n\tprivate idPrefix: string;\r\n\tprivate ui: QuickInputUI | undefined;\r\n\tprivate dimension?: dom.IDimension;\r\n\tprivate titleBarOffset?: number;\r\n\tprivate comboboxAccessibility = false;\r\n\tprivate enabled = true;\r\n\tprivate readonly onDidAcceptEmitter = this._register(new Emitter());\r\n\tprivate readonly onDidCustomEmitter = this._register(new Emitter());\r\n\tprivate readonly onDidTriggerButtonEmitter = this._register(new Emitter());\r\n\tprivate keyMods: Writeable = { ctrlCmd: false, alt: false };\r\n\r\n\tprivate controller: QuickInput | null = null;\r\n\r\n\tprivate parentElement: HTMLElement;\r\n\tprivate styles: IQuickInputStyles;\r\n\r\n\tprivate onShowEmitter = this._register(new Emitter());\r\n\treadonly onShow = this.onShowEmitter.event;\r\n\r\n\tprivate onHideEmitter = this._register(new Emitter());\r\n\treadonly onHide = this.onHideEmitter.event;\r\n\r\n\tprivate previousFocusElement?: HTMLElement;\r\n\r\n\tconstructor(private options: IQuickInputOptions) {\r\n\t\tsuper();\r\n\t\tthis.idPrefix = options.idPrefix;\r\n\t\tthis.parentElement = options.container;\r\n\t\tthis.styles = options.styles;\r\n\t\tthis.registerKeyModsListeners();\r\n\t}\r\n\r\n\tprivate registerKeyModsListeners() {\r\n\t\tconst listener = (e: KeyboardEvent | MouseEvent) => {\r\n\t\t\tthis.keyMods.ctrlCmd = e.ctrlKey || e.metaKey;\r\n\t\t\tthis.keyMods.alt = e.altKey;\r\n\t\t};\r\n\t\tthis._register(dom.addDisposableListener(window, dom.EventType.KEY_DOWN, listener, true));\r\n\t\tthis._register(dom.addDisposableListener(window, dom.EventType.KEY_UP, listener, true));\r\n\t\tthis._register(dom.addDisposableListener(window, dom.EventType.MOUSE_DOWN, listener, true));\r\n\t}\r\n\r\n\tprivate getUI() {\r\n\t\tif (this.ui) {\r\n\t\t\treturn this.ui;\r\n\t\t}\r\n\r\n\t\tconst container = dom.append(this.parentElement, $('.quick-input-widget.show-file-icons'));\r\n\t\tcontainer.tabIndex = -1;\r\n\t\tcontainer.style.display = 'none';\r\n\r\n\t\tconst styleSheet = dom.createStyleSheet(container);\r\n\r\n\t\tconst titleBar = dom.append(container, $('.quick-input-titlebar'));\r\n\r\n\t\tconst leftActionBar = this._register(new ActionBar(titleBar));\r\n\t\tleftActionBar.domNode.classList.add('quick-input-left-action-bar');\r\n\r\n\t\tconst title = dom.append(titleBar, $('.quick-input-title'));\r\n\r\n\t\tconst rightActionBar = this._register(new ActionBar(titleBar));\r\n\t\trightActionBar.domNode.classList.add('quick-input-right-action-bar');\r\n\r\n\t\tconst description1 = dom.append(container, $('.quick-input-description'));\r\n\t\tconst headerContainer = dom.append(container, $('.quick-input-header'));\r\n\r\n\t\tconst checkAll = dom.append(headerContainer, $('input.quick-input-check-all'));\r\n\t\tcheckAll.type = 'checkbox';\r\n\t\tthis._register(dom.addStandardDisposableListener(checkAll, dom.EventType.CHANGE, e => {\r\n\t\t\tconst checked = checkAll.checked;\r\n\t\t\tlist.setAllVisibleChecked(checked);\r\n\t\t}));\r\n\t\tthis._register(dom.addDisposableListener(checkAll, dom.EventType.CLICK, e => {\r\n\t\t\tif (e.x || e.y) { // Avoid 'click' triggered by 'space'...\r\n\t\t\t\tinputBox.setFocus();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tconst description2 = dom.append(headerContainer, $('.quick-input-description'));\r\n\t\tconst extraContainer = dom.append(headerContainer, $('.quick-input-and-message'));\r\n\t\tconst filterContainer = dom.append(extraContainer, $('.quick-input-filter'));\r\n\r\n\t\tconst inputBox = this._register(new QuickInputBox(filterContainer));\r\n\t\tinputBox.setAttribute('aria-describedby', `${this.idPrefix}message`);\r\n\r\n\t\tconst visibleCountContainer = dom.append(filterContainer, $('.quick-input-visible-count'));\r\n\t\tvisibleCountContainer.setAttribute('aria-live', 'polite');\r\n\t\tvisibleCountContainer.setAttribute('aria-atomic', 'true');\r\n\t\tconst visibleCount = new CountBadge(visibleCountContainer, { countFormat: localize({ key: 'quickInput.visibleCount', comment: ['This tells the user how many items are shown in a list of items to select from. The items can be anything. Currently not visible, but read by screen readers.'] }, \"{0} Results\") });\r\n\r\n\t\tconst countContainer = dom.append(filterContainer, $('.quick-input-count'));\r\n\t\tcountContainer.setAttribute('aria-live', 'polite');\r\n\t\tconst count = new CountBadge(countContainer, { countFormat: localize({ key: 'quickInput.countSelected', comment: ['This tells the user how many items are selected in a list of items to select from. The items can be anything.'] }, \"{0} Selected\") });\r\n\r\n\t\tconst okContainer = dom.append(headerContainer, $('.quick-input-action'));\r\n\t\tconst ok = new Button(okContainer);\r\n\t\tok.label = localize('ok', \"OK\");\r\n\t\tthis._register(ok.onDidClick(e => {\r\n\t\t\tthis.onDidAcceptEmitter.fire();\r\n\t\t}));\r\n\r\n\t\tconst customButtonContainer = dom.append(headerContainer, $('.quick-input-action'));\r\n\t\tconst customButton = new Button(customButtonContainer);\r\n\t\tcustomButton.label = localize('custom', \"Custom\");\r\n\t\tthis._register(customButton.onDidClick(e => {\r\n\t\t\tthis.onDidCustomEmitter.fire();\r\n\t\t}));\r\n\r\n\t\tconst message = dom.append(extraContainer, $(`#${this.idPrefix}message.quick-input-message`));\r\n\r\n\t\tconst progressBar = new ProgressBar(container);\r\n\t\tprogressBar.getContainer().classList.add('quick-input-progress');\r\n\r\n\t\tconst list = this._register(new QuickInputList(container, this.idPrefix + 'list', this.options));\r\n\t\tthis._register(list.onChangedAllVisibleChecked(checked => {\r\n\t\t\tcheckAll.checked = checked;\r\n\t\t}));\r\n\t\tthis._register(list.onChangedVisibleCount(c => {\r\n\t\t\tvisibleCount.setCount(c);\r\n\t\t}));\r\n\t\tthis._register(list.onChangedCheckedCount(c => {\r\n\t\t\tcount.setCount(c);\r\n\t\t}));\r\n\t\tthis._register(list.onLeave(() => {\r\n\t\t\t// Defer to avoid the input field reacting to the triggering key.\r\n\t\t\tsetTimeout(() => {\r\n\t\t\t\tinputBox.setFocus();\r\n\t\t\t\tif (this.controller instanceof QuickPick && this.controller.canSelectMany) {\r\n\t\t\t\t\tlist.clearFocus();\r\n\t\t\t\t}\r\n\t\t\t}, 0);\r\n\t\t}));\r\n\t\tthis._register(list.onDidChangeFocus(() => {\r\n\t\t\tif (this.comboboxAccessibility) {\r\n\t\t\t\tthis.getUI().inputBox.setAttribute('aria-activedescendant', this.getUI().list.getActiveDescendant() || '');\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tconst focusTracker = dom.trackFocus(container);\r\n\t\tthis._register(focusTracker);\r\n\t\tthis._register(dom.addDisposableListener(container, dom.EventType.FOCUS, e => {\r\n\t\t\tthis.previousFocusElement = e.relatedTarget instanceof HTMLElement ? e.relatedTarget : undefined;\r\n\t\t}, true));\r\n\t\tthis._register(focusTracker.onDidBlur(() => {\r\n\t\t\tif (!this.getUI().ignoreFocusOut && !this.options.ignoreFocusOut()) {\r\n\t\t\t\tthis.hide();\r\n\t\t\t}\r\n\t\t\tthis.previousFocusElement = undefined;\r\n\t\t}));\r\n\t\tthis._register(dom.addDisposableListener(container, dom.EventType.FOCUS, (e: FocusEvent) => {\r\n\t\t\tinputBox.setFocus();\r\n\t\t}));\r\n\t\tthis._register(dom.addDisposableListener(container, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => {\r\n\t\t\tconst event = new StandardKeyboardEvent(e);\r\n\t\t\tswitch (event.keyCode) {\r\n\t\t\t\tcase KeyCode.Enter:\r\n\t\t\t\t\tdom.EventHelper.stop(e, true);\r\n\t\t\t\t\tthis.onDidAcceptEmitter.fire();\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase KeyCode.Escape:\r\n\t\t\t\t\tdom.EventHelper.stop(e, true);\r\n\t\t\t\t\tthis.hide();\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase KeyCode.Tab:\r\n\t\t\t\t\tif (!event.altKey && !event.ctrlKey && !event.metaKey) {\r\n\t\t\t\t\t\tconst selectors = ['.action-label.codicon'];\r\n\t\t\t\t\t\tif (container.classList.contains('show-checkboxes')) {\r\n\t\t\t\t\t\t\tselectors.push('input');\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tselectors.push('input[type=text]');\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (this.getUI().list.isDisplayed()) {\r\n\t\t\t\t\t\t\tselectors.push('.monaco-list');\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tconst stops = container.querySelectorAll(selectors.join(', '));\r\n\t\t\t\t\t\tif (event.shiftKey && event.target === stops[0]) {\r\n\t\t\t\t\t\t\tdom.EventHelper.stop(e, true);\r\n\t\t\t\t\t\t\tstops[stops.length - 1].focus();\r\n\t\t\t\t\t\t} else if (!event.shiftKey && event.target === stops[stops.length - 1]) {\r\n\t\t\t\t\t\t\tdom.EventHelper.stop(e, true);\r\n\t\t\t\t\t\t\tstops[0].focus();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis.ui = {\r\n\t\t\tcontainer,\r\n\t\t\tstyleSheet,\r\n\t\t\tleftActionBar,\r\n\t\t\ttitleBar,\r\n\t\t\ttitle,\r\n\t\t\tdescription1,\r\n\t\t\tdescription2,\r\n\t\t\trightActionBar,\r\n\t\t\tcheckAll,\r\n\t\t\tfilterContainer,\r\n\t\t\tinputBox,\r\n\t\t\tvisibleCountContainer,\r\n\t\t\tvisibleCount,\r\n\t\t\tcountContainer,\r\n\t\t\tcount,\r\n\t\t\tokContainer,\r\n\t\t\tok,\r\n\t\t\tmessage,\r\n\t\t\tcustomButtonContainer,\r\n\t\t\tcustomButton,\r\n\t\t\tprogressBar,\r\n\t\t\tlist,\r\n\t\t\tonDidAccept: this.onDidAcceptEmitter.event,\r\n\t\t\tonDidCustom: this.onDidCustomEmitter.event,\r\n\t\t\tonDidTriggerButton: this.onDidTriggerButtonEmitter.event,\r\n\t\t\tignoreFocusOut: false,\r\n\t\t\tkeyMods: this.keyMods,\r\n\t\t\tisScreenReaderOptimized: () => this.options.isScreenReaderOptimized(),\r\n\t\t\tshow: controller => this.show(controller),\r\n\t\t\thide: () => this.hide(),\r\n\t\t\tsetVisibilities: visibilities => this.setVisibilities(visibilities),\r\n\t\t\tsetComboboxAccessibility: enabled => this.setComboboxAccessibility(enabled),\r\n\t\t\tsetEnabled: enabled => this.setEnabled(enabled),\r\n\t\t\tsetContextKey: contextKey => this.options.setContextKey(contextKey),\r\n\t\t};\r\n\t\tthis.updateStyles();\r\n\t\treturn this.ui;\r\n\t}\r\n\r\n\tpick>(picks: Promise[]> | QuickPickInput[], options: O = {}, token: CancellationToken = CancellationToken.None): Promise<(O extends { canPickMany: true } ? T[] : T) | undefined> {\r\n\t\ttype R = (O extends { canPickMany: true } ? T[] : T) | undefined;\r\n\t\treturn new Promise((doResolve, reject) => {\r\n\t\t\tlet resolve = (result: R) => {\r\n\t\t\t\tresolve = doResolve;\r\n\t\t\t\tif (options.onKeyMods) {\r\n\t\t\t\t\toptions.onKeyMods(input.keyMods);\r\n\t\t\t\t}\r\n\t\t\t\tdoResolve(result);\r\n\t\t\t};\r\n\t\t\tif (token.isCancellationRequested) {\r\n\t\t\t\tresolve(undefined);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tconst input = this.createQuickPick();\r\n\t\t\tlet activeItem: T | undefined;\r\n\t\t\tconst disposables = [\r\n\t\t\t\tinput,\r\n\t\t\t\tinput.onDidAccept(() => {\r\n\t\t\t\t\tif (input.canSelectMany) {\r\n\t\t\t\t\t\tresolve(input.selectedItems.slice());\r\n\t\t\t\t\t\tinput.hide();\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tconst result = input.activeItems[0];\r\n\t\t\t\t\t\tif (result) {\r\n\t\t\t\t\t\t\tresolve(result);\r\n\t\t\t\t\t\t\tinput.hide();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}),\r\n\t\t\t\tinput.onDidChangeActive(items => {\r\n\t\t\t\t\tconst focused = items[0];\r\n\t\t\t\t\tif (focused && options.onDidFocus) {\r\n\t\t\t\t\t\toptions.onDidFocus(focused);\r\n\t\t\t\t\t}\r\n\t\t\t\t}),\r\n\t\t\t\tinput.onDidChangeSelection(items => {\r\n\t\t\t\t\tif (!input.canSelectMany) {\r\n\t\t\t\t\t\tconst result = items[0];\r\n\t\t\t\t\t\tif (result) {\r\n\t\t\t\t\t\t\tresolve(result);\r\n\t\t\t\t\t\t\tinput.hide();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}),\r\n\t\t\t\tinput.onDidTriggerItemButton(event => options.onDidTriggerItemButton && options.onDidTriggerItemButton({\r\n\t\t\t\t\t...event,\r\n\t\t\t\t\tremoveItem: () => {\r\n\t\t\t\t\t\tconst index = input.items.indexOf(event.item);\r\n\t\t\t\t\t\tif (index !== -1) {\r\n\t\t\t\t\t\t\tconst items = input.items.slice();\r\n\t\t\t\t\t\t\titems.splice(index, 1);\r\n\t\t\t\t\t\t\tinput.items = items;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t})),\r\n\t\t\t\tinput.onDidChangeValue(value => {\r\n\t\t\t\t\tif (activeItem && !value && (input.activeItems.length !== 1 || input.activeItems[0] !== activeItem)) {\r\n\t\t\t\t\t\tinput.activeItems = [activeItem];\r\n\t\t\t\t\t}\r\n\t\t\t\t}),\r\n\t\t\t\ttoken.onCancellationRequested(() => {\r\n\t\t\t\t\tinput.hide();\r\n\t\t\t\t}),\r\n\t\t\t\tinput.onDidHide(() => {\r\n\t\t\t\t\tdispose(disposables);\r\n\t\t\t\t\tresolve(undefined);\r\n\t\t\t\t}),\r\n\t\t\t];\r\n\t\t\tinput.canSelectMany = !!options.canPickMany;\r\n\t\t\tinput.placeholder = options.placeHolder;\r\n\t\t\tinput.ignoreFocusOut = !!options.ignoreFocusLost;\r\n\t\t\tinput.matchOnDescription = !!options.matchOnDescription;\r\n\t\t\tinput.matchOnDetail = !!options.matchOnDetail;\r\n\t\t\tinput.matchOnLabel = (options.matchOnLabel === undefined) || options.matchOnLabel; // default to true\r\n\t\t\tinput.autoFocusOnList = (options.autoFocusOnList === undefined) || options.autoFocusOnList; // default to true\r\n\t\t\tinput.quickNavigate = options.quickNavigate;\r\n\t\t\tinput.contextKey = options.contextKey;\r\n\t\t\tinput.busy = true;\r\n\t\t\tPromise.all[], T | undefined>([picks, options.activeItem])\r\n\t\t\t\t.then(([items, _activeItem]) => {\r\n\t\t\t\t\tactiveItem = _activeItem;\r\n\t\t\t\t\tinput.busy = false;\r\n\t\t\t\t\tinput.items = items;\r\n\t\t\t\t\tif (input.canSelectMany) {\r\n\t\t\t\t\t\tinput.selectedItems = items.filter(item => item.type !== 'separator' && item.picked) as T[];\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (activeItem) {\r\n\t\t\t\t\t\tinput.activeItems = [activeItem];\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\tinput.show();\r\n\t\t\tPromise.resolve(picks).then(undefined, err => {\r\n\t\t\t\treject(err);\r\n\t\t\t\tinput.hide();\r\n\t\t\t});\r\n\t\t});\r\n\t}\r\n\r\n\tcreateQuickPick(): IQuickPick {\r\n\t\tconst ui = this.getUI();\r\n\t\treturn new QuickPick(ui);\r\n\t}\r\n\r\n\tprivate show(controller: QuickInput) {\r\n\t\tconst ui = this.getUI();\r\n\t\tthis.onShowEmitter.fire();\r\n\t\tconst oldController = this.controller;\r\n\t\tthis.controller = controller;\r\n\t\tif (oldController) {\r\n\t\t\toldController.didHide();\r\n\t\t}\r\n\r\n\t\tthis.setEnabled(true);\r\n\t\tui.leftActionBar.clear();\r\n\t\tui.title.textContent = '';\r\n\t\tui.description1.textContent = '';\r\n\t\tui.description2.textContent = '';\r\n\t\tui.rightActionBar.clear();\r\n\t\tui.checkAll.checked = false;\r\n\t\t// ui.inputBox.value = ''; Avoid triggering an event.\r\n\t\tui.inputBox.placeholder = '';\r\n\t\tui.inputBox.password = false;\r\n\t\tui.inputBox.showDecoration(Severity.Ignore);\r\n\t\tui.visibleCount.setCount(0);\r\n\t\tui.count.setCount(0);\r\n\t\tdom.reset(ui.message);\r\n\t\tui.progressBar.stop();\r\n\t\tui.list.setElements([]);\r\n\t\tui.list.matchOnDescription = false;\r\n\t\tui.list.matchOnDetail = false;\r\n\t\tui.list.matchOnLabel = true;\r\n\t\tui.list.sortByLabel = true;\r\n\t\tui.ignoreFocusOut = false;\r\n\t\tthis.setComboboxAccessibility(false);\r\n\t\tui.inputBox.ariaLabel = '';\r\n\r\n\t\tconst backKeybindingLabel = this.options.backKeybindingLabel();\r\n\t\tbackButton.tooltip = backKeybindingLabel ? localize('quickInput.backWithKeybinding', \"Back ({0})\", backKeybindingLabel) : localize('quickInput.back', \"Back\");\r\n\r\n\t\tui.container.style.display = '';\r\n\t\tthis.updateLayout();\r\n\t\tui.inputBox.setFocus();\r\n\t}\r\n\r\n\tprivate setVisibilities(visibilities: Visibilities) {\r\n\t\tconst ui = this.getUI();\r\n\t\tui.title.style.display = visibilities.title ? '' : 'none';\r\n\t\tui.description1.style.display = visibilities.description && (visibilities.inputBox || visibilities.checkAll) ? '' : 'none';\r\n\t\tui.description2.style.display = visibilities.description && !(visibilities.inputBox || visibilities.checkAll) ? '' : 'none';\r\n\t\tui.checkAll.style.display = visibilities.checkAll ? '' : 'none';\r\n\t\tui.filterContainer.style.display = visibilities.inputBox ? '' : 'none';\r\n\t\tui.visibleCountContainer.style.display = visibilities.visibleCount ? '' : 'none';\r\n\t\tui.countContainer.style.display = visibilities.count ? '' : 'none';\r\n\t\tui.okContainer.style.display = visibilities.ok ? '' : 'none';\r\n\t\tui.customButtonContainer.style.display = visibilities.customButton ? '' : 'none';\r\n\t\tui.message.style.display = visibilities.message ? '' : 'none';\r\n\t\tui.progressBar.getContainer().style.display = visibilities.progressBar ? '' : 'none';\r\n\t\tui.list.display(!!visibilities.list);\r\n\t\tui.container.classList[visibilities.checkBox ? 'add' : 'remove']('show-checkboxes');\r\n\t\tthis.updateLayout(); // TODO\r\n\t}\r\n\r\n\tprivate setComboboxAccessibility(enabled: boolean) {\r\n\t\tif (enabled !== this.comboboxAccessibility) {\r\n\t\t\tconst ui = this.getUI();\r\n\t\t\tthis.comboboxAccessibility = enabled;\r\n\t\t\tif (this.comboboxAccessibility) {\r\n\t\t\t\tui.inputBox.setAttribute('role', 'combobox');\r\n\t\t\t\tui.inputBox.setAttribute('aria-haspopup', 'true');\r\n\t\t\t\tui.inputBox.setAttribute('aria-autocomplete', 'list');\r\n\t\t\t\tui.inputBox.setAttribute('aria-activedescendant', ui.list.getActiveDescendant() || '');\r\n\t\t\t} else {\r\n\t\t\t\tui.inputBox.removeAttribute('role');\r\n\t\t\t\tui.inputBox.removeAttribute('aria-haspopup');\r\n\t\t\t\tui.inputBox.removeAttribute('aria-autocomplete');\r\n\t\t\t\tui.inputBox.removeAttribute('aria-activedescendant');\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate setEnabled(enabled: boolean) {\r\n\t\tif (enabled !== this.enabled) {\r\n\t\t\tthis.enabled = enabled;\r\n\t\t\tfor (const item of this.getUI().leftActionBar.viewItems) {\r\n\t\t\t\t(item as ActionViewItem).getAction().enabled = enabled;\r\n\t\t\t}\r\n\t\t\tfor (const item of this.getUI().rightActionBar.viewItems) {\r\n\t\t\t\t(item as ActionViewItem).getAction().enabled = enabled;\r\n\t\t\t}\r\n\t\t\tthis.getUI().checkAll.disabled = !enabled;\r\n\t\t\t// this.getUI().inputBox.enabled = enabled; Avoid loosing focus.\r\n\t\t\tthis.getUI().ok.enabled = enabled;\r\n\t\t\tthis.getUI().list.enabled = enabled;\r\n\t\t}\r\n\t}\r\n\r\n\thide() {\r\n\t\tconst controller = this.controller;\r\n\t\tif (controller) {\r\n\t\t\tconst focusChanged = !this.ui?.container.contains(document.activeElement);\r\n\t\t\tthis.controller = null;\r\n\t\t\tthis.onHideEmitter.fire();\r\n\t\t\tthis.getUI().container.style.display = 'none';\r\n\t\t\tif (!focusChanged) {\r\n\t\t\t\tif (this.previousFocusElement && this.previousFocusElement.offsetParent) {\r\n\t\t\t\t\tthis.previousFocusElement.focus();\r\n\t\t\t\t\tthis.previousFocusElement = undefined;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis.options.returnFocus();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tcontroller.didHide();\r\n\t\t}\r\n\t}\r\n\r\n\tlayout(dimension: dom.IDimension, titleBarOffset: number): void {\r\n\t\tthis.dimension = dimension;\r\n\t\tthis.titleBarOffset = titleBarOffset;\r\n\t\tthis.updateLayout();\r\n\t}\r\n\r\n\tprivate updateLayout() {\r\n\t\tif (this.ui) {\r\n\t\t\tthis.ui.container.style.top = `${this.titleBarOffset}px`;\r\n\r\n\t\t\tconst style = this.ui.container.style;\r\n\t\t\tconst width = Math.min(this.dimension!.width * 0.62 /* golden cut */, QuickInputController.MAX_WIDTH);\r\n\t\t\tstyle.width = width + 'px';\r\n\t\t\tstyle.marginLeft = '-' + (width / 2) + 'px';\r\n\r\n\t\t\tthis.ui.inputBox.layout();\r\n\t\t\tthis.ui.list.layout(this.dimension && this.dimension.height * 0.4);\r\n\t\t}\r\n\t}\r\n\r\n\tapplyStyles(styles: IQuickInputStyles) {\r\n\t\tthis.styles = styles;\r\n\t\tthis.updateStyles();\r\n\t}\r\n\r\n\tprivate updateStyles() {\r\n\t\tif (this.ui) {\r\n\t\t\tconst {\r\n\t\t\t\tquickInputTitleBackground,\r\n\t\t\t\tquickInputBackground,\r\n\t\t\t\tquickInputForeground,\r\n\t\t\t\tcontrastBorder,\r\n\t\t\t\twidgetShadow,\r\n\t\t\t} = this.styles.widget;\r\n\t\t\tthis.ui.titleBar.style.backgroundColor = quickInputTitleBackground ? quickInputTitleBackground.toString() : '';\r\n\t\t\tthis.ui.container.style.backgroundColor = quickInputBackground ? quickInputBackground.toString() : '';\r\n\t\t\tthis.ui.container.style.color = quickInputForeground ? quickInputForeground.toString() : '';\r\n\t\t\tthis.ui.container.style.border = contrastBorder ? `1px solid ${contrastBorder}` : '';\r\n\t\t\tthis.ui.container.style.boxShadow = widgetShadow ? `0 0 8px 2px ${widgetShadow}` : '';\r\n\t\t\tthis.ui.inputBox.style(this.styles.inputBox);\r\n\t\t\tthis.ui.count.style(this.styles.countBadge);\r\n\t\t\tthis.ui.ok.style(this.styles.button);\r\n\t\t\tthis.ui.customButton.style(this.styles.button);\r\n\t\t\tthis.ui.progressBar.style(this.styles.progressBar);\r\n\t\t\tthis.ui.list.style(this.styles.list);\r\n\r\n\t\t\tconst content: string[] = [];\r\n\t\t\tif (this.styles.list.listInactiveFocusForeground) {\r\n\t\t\t\tcontent.push(`.monaco-list .monaco-list-row.focused { color: ${this.styles.list.listInactiveFocusForeground}; }`);\r\n\t\t\t\tcontent.push(`.monaco-list .monaco-list-row.focused:hover { color: ${this.styles.list.listInactiveFocusForeground}; }`); // overwrite :hover style in this case!\r\n\t\t\t}\r\n\t\t\tif (this.styles.list.pickerGroupBorder) {\r\n\t\t\t\tcontent.push(`.quick-input-list .quick-input-list-entry { border-top-color: ${this.styles.list.pickerGroupBorder}; }`);\r\n\t\t\t}\r\n\t\t\tif (this.styles.list.pickerGroupForeground) {\r\n\t\t\t\tcontent.push(`.quick-input-list .quick-input-list-separator { color: ${this.styles.list.pickerGroupForeground}; }`);\r\n\t\t\t}\r\n\t\t\tconst newStyles = content.join('\\n');\r\n\t\t\tif (newStyles !== this.ui.styleSheet.textContent) {\r\n\t\t\t\tthis.ui.styleSheet.textContent = newStyles;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { Action } from 'vs/base/common/actions';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { IContextMenuService } from 'vs/platform/contextview/browser/contextView';\r\nimport { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';\r\nimport { IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { Codicon } from 'vs/base/common/codicons';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\n\r\nexport interface IDiffLinesChange {\r\n\treadonly originalStartLineNumber: number;\r\n\treadonly originalEndLineNumber: number;\r\n\treadonly modifiedStartLineNumber: number;\r\n\treadonly modifiedEndLineNumber: number;\r\n\treadonly originalModel: ITextModel;\r\n\tviewLineCounts: number[] | null;\r\n}\r\n\r\nexport class InlineDiffMargin extends Disposable {\r\n\tprivate readonly _diffActions: HTMLElement;\r\n\r\n\tprivate _visibility: boolean = false;\r\n\r\n\tget visibility(): boolean {\r\n\t\treturn this._visibility;\r\n\t}\r\n\r\n\tset visibility(_visibility: boolean) {\r\n\t\tif (this._visibility !== _visibility) {\r\n\t\t\tthis._visibility = _visibility;\r\n\r\n\t\t\tif (_visibility) {\r\n\t\t\t\tthis._diffActions.style.visibility = 'visible';\r\n\t\t\t} else {\r\n\t\t\t\tthis._diffActions.style.visibility = 'hidden';\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _viewZoneId: string,\r\n\t\tprivate readonly _marginDomNode: HTMLElement,\r\n\t\tpublic readonly editor: CodeEditorWidget,\r\n\t\tpublic readonly diff: IDiffLinesChange,\r\n\t\tprivate readonly _contextMenuService: IContextMenuService,\r\n\t\tprivate readonly _clipboardService: IClipboardService\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\t// make sure the diff margin shows above overlay.\r\n\t\tthis._marginDomNode.style.zIndex = '10';\r\n\r\n\t\tthis._diffActions = document.createElement('div');\r\n\t\tthis._diffActions.className = Codicon.lightBulb.classNames + ' lightbulb-glyph';\r\n\t\tthis._diffActions.style.position = 'absolute';\r\n\t\tconst lineHeight = editor.getOption(EditorOption.lineHeight);\r\n\t\tconst lineFeed = editor.getModel()!.getEOL();\r\n\t\tthis._diffActions.style.right = '0px';\r\n\t\tthis._diffActions.style.visibility = 'hidden';\r\n\t\tthis._diffActions.style.height = `${lineHeight}px`;\r\n\t\tthis._diffActions.style.lineHeight = `${lineHeight}px`;\r\n\t\tthis._marginDomNode.appendChild(this._diffActions);\r\n\r\n\t\tconst actions: Action[] = [];\r\n\r\n\t\t// default action\r\n\t\tactions.push(new Action(\r\n\t\t\t'diff.clipboard.copyDeletedContent',\r\n\t\t\tdiff.originalEndLineNumber > diff.modifiedStartLineNumber\r\n\t\t\t\t? nls.localize('diff.clipboard.copyDeletedLinesContent.label', \"Copy deleted lines\")\r\n\t\t\t\t: nls.localize('diff.clipboard.copyDeletedLinesContent.single.label', \"Copy deleted line\"),\r\n\t\t\tundefined,\r\n\t\t\ttrue,\r\n\t\t\tasync () => {\r\n\t\t\t\tconst range = new Range(diff.originalStartLineNumber, 1, diff.originalEndLineNumber + 1, 1);\r\n\t\t\t\tconst deletedText = diff.originalModel.getValueInRange(range);\r\n\t\t\t\tawait this._clipboardService.writeText(deletedText);\r\n\t\t\t}\r\n\t\t));\r\n\r\n\t\tlet currentLineNumberOffset = 0;\r\n\t\tlet copyLineAction: Action | undefined = undefined;\r\n\t\tif (diff.originalEndLineNumber > diff.modifiedStartLineNumber) {\r\n\t\t\tcopyLineAction = new Action(\r\n\t\t\t\t'diff.clipboard.copyDeletedLineContent',\r\n\t\t\t\tnls.localize('diff.clipboard.copyDeletedLineContent.label', \"Copy deleted line ({0})\", diff.originalStartLineNumber),\r\n\t\t\t\tundefined,\r\n\t\t\t\ttrue,\r\n\t\t\t\tasync () => {\r\n\t\t\t\t\tconst lineContent = diff.originalModel.getLineContent(diff.originalStartLineNumber + currentLineNumberOffset);\r\n\t\t\t\t\tawait this._clipboardService.writeText(lineContent);\r\n\t\t\t\t}\r\n\t\t\t);\r\n\r\n\t\t\tactions.push(copyLineAction);\r\n\t\t}\r\n\r\n\t\tconst readOnly = editor.getOption(EditorOption.readOnly);\r\n\t\tif (!readOnly) {\r\n\t\t\tactions.push(new Action('diff.inline.revertChange', nls.localize('diff.inline.revertChange.label', \"Revert this change\"), undefined, true, async () => {\r\n\t\t\t\tconst range = new Range(diff.originalStartLineNumber, 1, diff.originalEndLineNumber, diff.originalModel.getLineMaxColumn(diff.originalEndLineNumber));\r\n\t\t\t\tconst deletedText = diff.originalModel.getValueInRange(range);\r\n\t\t\t\tif (diff.modifiedEndLineNumber === 0) {\r\n\t\t\t\t\t// deletion only\r\n\t\t\t\t\tconst column = editor.getModel()!.getLineMaxColumn(diff.modifiedStartLineNumber);\r\n\t\t\t\t\teditor.executeEdits('diffEditor', [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\trange: new Range(diff.modifiedStartLineNumber, column, diff.modifiedStartLineNumber, column),\r\n\t\t\t\t\t\t\ttext: lineFeed + deletedText\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tconst column = editor.getModel()!.getLineMaxColumn(diff.modifiedEndLineNumber);\r\n\t\t\t\t\teditor.executeEdits('diffEditor', [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\trange: new Range(diff.modifiedStartLineNumber, 1, diff.modifiedEndLineNumber, column),\r\n\t\t\t\t\t\t\ttext: deletedText\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]);\r\n\t\t\t\t}\r\n\r\n\t\t\t}));\r\n\t\t}\r\n\r\n\t\tconst showContextMenu = (x: number, y: number) => {\r\n\t\t\tthis._contextMenuService.showContextMenu({\r\n\t\t\t\tgetAnchor: () => {\r\n\t\t\t\t\treturn {\r\n\t\t\t\t\t\tx,\r\n\t\t\t\t\t\ty\r\n\t\t\t\t\t};\r\n\t\t\t\t},\r\n\t\t\t\tgetActions: () => {\r\n\t\t\t\t\tif (copyLineAction) {\r\n\t\t\t\t\t\tcopyLineAction.label = nls.localize('diff.clipboard.copyDeletedLineContent.label', \"Copy deleted line ({0})\", diff.originalStartLineNumber + currentLineNumberOffset);\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn actions;\r\n\t\t\t\t},\r\n\t\t\t\tautoSelectFirstItem: true\r\n\t\t\t});\r\n\t\t};\r\n\r\n\t\tthis._register(dom.addStandardDisposableListener(this._diffActions, 'mousedown', e => {\r\n\t\t\tconst { top, height } = dom.getDomNodePagePosition(this._diffActions);\r\n\t\t\tlet pad = Math.floor(lineHeight / 3);\r\n\t\t\te.preventDefault();\r\n\r\n\t\t\tshowContextMenu(e.posx, top + height + pad);\r\n\r\n\t\t}));\r\n\r\n\t\tthis._register(editor.onMouseMove((e: IEditorMouseEvent) => {\r\n\t\t\tif (e.target.type === MouseTargetType.CONTENT_VIEW_ZONE || e.target.type === MouseTargetType.GUTTER_VIEW_ZONE) {\r\n\t\t\t\tconst viewZoneId = e.target.detail.viewZoneId;\r\n\r\n\t\t\t\tif (viewZoneId === this._viewZoneId) {\r\n\t\t\t\t\tthis.visibility = true;\r\n\t\t\t\t\tcurrentLineNumberOffset = this._updateLightBulbPosition(this._marginDomNode, e.event.browserEvent.y, lineHeight);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis.visibility = false;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tthis.visibility = false;\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._register(editor.onMouseDown((e: IEditorMouseEvent) => {\r\n\t\t\tif (!e.event.rightButton) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (e.target.type === MouseTargetType.CONTENT_VIEW_ZONE || e.target.type === MouseTargetType.GUTTER_VIEW_ZONE) {\r\n\t\t\t\tconst viewZoneId = e.target.detail.viewZoneId;\r\n\r\n\t\t\t\tif (viewZoneId === this._viewZoneId) {\r\n\t\t\t\t\te.event.preventDefault();\r\n\t\t\t\t\tcurrentLineNumberOffset = this._updateLightBulbPosition(this._marginDomNode, e.event.browserEvent.y, lineHeight);\r\n\t\t\t\t\tshowContextMenu(e.event.posx, e.event.posy + lineHeight);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\tprivate _updateLightBulbPosition(marginDomNode: HTMLElement, y: number, lineHeight: number): number {\r\n\t\tconst { top } = dom.getDomNodePagePosition(marginDomNode);\r\n\t\tconst offset = y - top;\r\n\t\tconst lineNumberOffset = Math.floor(offset / lineHeight);\r\n\t\tconst newTop = lineNumberOffset * lineHeight;\r\n\t\tthis._diffActions.style.top = `${newTop}px`;\r\n\t\tif (this.diff.viewLineCounts) {\r\n\t\t\tlet acc = 0;\r\n\t\t\tfor (let i = 0; i < this.diff.viewLineCounts.length; i++) {\r\n\t\t\t\tacc += this.diff.viewLineCounts[i];\r\n\t\t\t\tif (lineNumberOffset < acc) {\r\n\t\t\t\t\treturn i;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn lineNumberOffset;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport { ScrollbarVisibility } from 'vs/base/common/scrollable';\r\nimport { FontInfo } from 'vs/editor/common/config/fontInfo';\r\nimport { Constants } from 'vs/base/common/uint';\r\nimport { USUAL_WORD_SEPARATORS } from 'vs/editor/common/model/wordHelper';\r\nimport { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';\r\nimport { IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry';\r\nimport { IJSONSchema } from 'vs/base/common/jsonSchema';\r\n\r\n//#region typed options\r\n\r\n/**\r\n * Configuration options for auto closing quotes and brackets\r\n */\r\nexport type EditorAutoClosingStrategy = 'always' | 'languageDefined' | 'beforeWhitespace' | 'never';\r\n\r\n/**\r\n * Configuration options for auto wrapping quotes and brackets\r\n */\r\nexport type EditorAutoSurroundStrategy = 'languageDefined' | 'quotes' | 'brackets' | 'never';\r\n\r\n/**\r\n * Configuration options for typing over closing quotes or brackets\r\n */\r\nexport type EditorAutoClosingOvertypeStrategy = 'always' | 'auto' | 'never';\r\n\r\n/**\r\n * Configuration options for auto indentation in the editor\r\n */\r\nexport const enum EditorAutoIndentStrategy {\r\n\tNone = 0,\r\n\tKeep = 1,\r\n\tBrackets = 2,\r\n\tAdvanced = 3,\r\n\tFull = 4\r\n}\r\n\r\n/**\r\n * Configuration options for the editor.\r\n */\r\nexport interface IEditorOptions {\r\n\t/**\r\n\t * This editor is used inside a diff editor.\r\n\t */\r\n\tinDiffEditor?: boolean;\r\n\t/**\r\n\t * The aria label for the editor's textarea (when it is focused).\r\n\t */\r\n\tariaLabel?: string;\r\n\t/**\r\n\t * The `tabindex` property of the editor's textarea\r\n\t */\r\n\ttabIndex?: number;\r\n\t/**\r\n\t * Render vertical lines at the specified columns.\r\n\t * Defaults to empty array.\r\n\t */\r\n\trulers?: (number | IRulerOption)[];\r\n\t/**\r\n\t * A string containing the word separators used when doing word navigation.\r\n\t * Defaults to `~!@#$%^&*()-=+[{]}\\\\|;:\\'\",.<>/?\r\n\t */\r\n\twordSeparators?: string;\r\n\t/**\r\n\t * Enable Linux primary clipboard.\r\n\t * Defaults to true.\r\n\t */\r\n\tselectionClipboard?: boolean;\r\n\t/**\r\n\t * Control the rendering of line numbers.\r\n\t * If it is a function, it will be invoked when rendering a line number and the return value will be rendered.\r\n\t * Otherwise, if it is a truey, line numbers will be rendered normally (equivalent of using an identity function).\r\n\t * Otherwise, line numbers will not be rendered.\r\n\t * Defaults to `on`.\r\n\t */\r\n\tlineNumbers?: LineNumbersType;\r\n\t/**\r\n\t * Controls the minimal number of visible leading and trailing lines surrounding the cursor.\r\n\t * Defaults to 0.\r\n\t*/\r\n\tcursorSurroundingLines?: number;\r\n\t/**\r\n\t * Controls when `cursorSurroundingLines` should be enforced\r\n\t * Defaults to `default`, `cursorSurroundingLines` is not enforced when cursor position is changed\r\n\t * by mouse.\r\n\t*/\r\n\tcursorSurroundingLinesStyle?: 'default' | 'all';\r\n\t/**\r\n\t * Render last line number when the file ends with a newline.\r\n\t * Defaults to true.\r\n\t*/\r\n\trenderFinalNewline?: boolean;\r\n\t/**\r\n\t * Remove unusual line terminators like LINE SEPARATOR (LS), PARAGRAPH SEPARATOR (PS).\r\n\t * Defaults to 'prompt'.\r\n\t */\r\n\tunusualLineTerminators?: 'auto' | 'off' | 'prompt';\r\n\t/**\r\n\t * Should the corresponding line be selected when clicking on the line number?\r\n\t * Defaults to true.\r\n\t */\r\n\tselectOnLineNumbers?: boolean;\r\n\t/**\r\n\t * Control the width of line numbers, by reserving horizontal space for rendering at least an amount of digits.\r\n\t * Defaults to 5.\r\n\t */\r\n\tlineNumbersMinChars?: number;\r\n\t/**\r\n\t * Enable the rendering of the glyph margin.\r\n\t * Defaults to true in vscode and to false in monaco-editor.\r\n\t */\r\n\tglyphMargin?: boolean;\r\n\t/**\r\n\t * The width reserved for line decorations (in px).\r\n\t * Line decorations are placed between line numbers and the editor content.\r\n\t * You can pass in a string in the format floating point followed by \"ch\". e.g. 1.3ch.\r\n\t * Defaults to 10.\r\n\t */\r\n\tlineDecorationsWidth?: number | string;\r\n\t/**\r\n\t * When revealing the cursor, a virtual padding (px) is added to the cursor, turning it into a rectangle.\r\n\t * This virtual padding ensures that the cursor gets revealed before hitting the edge of the viewport.\r\n\t * Defaults to 30 (px).\r\n\t */\r\n\trevealHorizontalRightPadding?: number;\r\n\t/**\r\n\t * Render the editor selection with rounded borders.\r\n\t * Defaults to true.\r\n\t */\r\n\troundedSelection?: boolean;\r\n\t/**\r\n\t * Class name to be added to the editor.\r\n\t */\r\n\textraEditorClassName?: string;\r\n\t/**\r\n\t * Should the editor be read only.\r\n\t * Defaults to false.\r\n\t */\r\n\treadOnly?: boolean;\r\n\t/**\r\n\t * Enable linked editing.\r\n\t * Defaults to false.\r\n\t */\r\n\tlinkedEditing?: boolean;\r\n\t/**\r\n\t * deprecated, use linkedEditing instead\r\n\t */\r\n\trenameOnType?: boolean;\r\n\t/**\r\n\t * Should the editor render validation decorations.\r\n\t * Defaults to editable.\r\n\t */\r\n\trenderValidationDecorations?: 'editable' | 'on' | 'off';\r\n\t/**\r\n\t * Control the behavior and rendering of the scrollbars.\r\n\t */\r\n\tscrollbar?: IEditorScrollbarOptions;\r\n\t/**\r\n\t * Control the behavior and rendering of the minimap.\r\n\t */\r\n\tminimap?: IEditorMinimapOptions;\r\n\t/**\r\n\t * Control the behavior of the find widget.\r\n\t */\r\n\tfind?: IEditorFindOptions;\r\n\t/**\r\n\t * Display overflow widgets as `fixed`.\r\n\t * Defaults to `false`.\r\n\t */\r\n\tfixedOverflowWidgets?: boolean;\r\n\t/**\r\n\t * The number of vertical lanes the overview ruler should render.\r\n\t * Defaults to 3.\r\n\t */\r\n\toverviewRulerLanes?: number;\r\n\t/**\r\n\t * Controls if a border should be drawn around the overview ruler.\r\n\t * Defaults to `true`.\r\n\t */\r\n\toverviewRulerBorder?: boolean;\r\n\t/**\r\n\t * Control the cursor animation style, possible values are 'blink', 'smooth', 'phase', 'expand' and 'solid'.\r\n\t * Defaults to 'blink'.\r\n\t */\r\n\tcursorBlinking?: 'blink' | 'smooth' | 'phase' | 'expand' | 'solid';\r\n\t/**\r\n\t * Zoom the font in the editor when using the mouse wheel in combination with holding Ctrl.\r\n\t * Defaults to false.\r\n\t */\r\n\tmouseWheelZoom?: boolean;\r\n\t/**\r\n\t * Control the mouse pointer style, either 'text' or 'default' or 'copy'\r\n\t * Defaults to 'text'\r\n\t */\r\n\tmouseStyle?: 'text' | 'default' | 'copy';\r\n\t/**\r\n\t * Enable smooth caret animation.\r\n\t * Defaults to false.\r\n\t */\r\n\tcursorSmoothCaretAnimation?: boolean;\r\n\t/**\r\n\t * Control the cursor style, either 'block' or 'line'.\r\n\t * Defaults to 'line'.\r\n\t */\r\n\tcursorStyle?: 'line' | 'block' | 'underline' | 'line-thin' | 'block-outline' | 'underline-thin';\r\n\t/**\r\n\t * Control the width of the cursor when cursorStyle is set to 'line'\r\n\t */\r\n\tcursorWidth?: number;\r\n\t/**\r\n\t * Enable font ligatures.\r\n\t * Defaults to false.\r\n\t */\r\n\tfontLigatures?: boolean | string;\r\n\t/**\r\n\t * Disable the use of `transform: translate3d(0px, 0px, 0px)` for the editor margin and lines layers.\r\n\t * The usage of `transform: translate3d(0px, 0px, 0px)` acts as a hint for browsers to create an extra layer.\r\n\t * Defaults to false.\r\n\t */\r\n\tdisableLayerHinting?: boolean;\r\n\t/**\r\n\t * Disable the optimizations for monospace fonts.\r\n\t * Defaults to false.\r\n\t */\r\n\tdisableMonospaceOptimizations?: boolean;\r\n\t/**\r\n\t * Should the cursor be hidden in the overview ruler.\r\n\t * Defaults to false.\r\n\t */\r\n\thideCursorInOverviewRuler?: boolean;\r\n\t/**\r\n\t * Enable that scrolling can go one screen size after the last line.\r\n\t * Defaults to true.\r\n\t */\r\n\tscrollBeyondLastLine?: boolean;\r\n\t/**\r\n\t * Enable that scrolling can go beyond the last column by a number of columns.\r\n\t * Defaults to 5.\r\n\t */\r\n\tscrollBeyondLastColumn?: number;\r\n\t/**\r\n\t * Enable that the editor animates scrolling to a position.\r\n\t * Defaults to false.\r\n\t */\r\n\tsmoothScrolling?: boolean;\r\n\t/**\r\n\t * Enable that the editor will install an interval to check if its container dom node size has changed.\r\n\t * Enabling this might have a severe performance impact.\r\n\t * Defaults to false.\r\n\t */\r\n\tautomaticLayout?: boolean;\r\n\t/**\r\n\t * Control the wrapping of the editor.\r\n\t * When `wordWrap` = \"off\", the lines will never wrap.\r\n\t * When `wordWrap` = \"on\", the lines will wrap at the viewport width.\r\n\t * When `wordWrap` = \"wordWrapColumn\", the lines will wrap at `wordWrapColumn`.\r\n\t * When `wordWrap` = \"bounded\", the lines will wrap at min(viewport width, wordWrapColumn).\r\n\t * Defaults to \"off\".\r\n\t */\r\n\twordWrap?: 'off' | 'on' | 'wordWrapColumn' | 'bounded';\r\n\t/**\r\n\t * Override the `wordWrap` setting.\r\n\t */\r\n\twordWrapOverride1?: 'off' | 'on' | 'inherit';\r\n\t/**\r\n\t * Override the `wordWrapOverride1` setting.\r\n\t */\r\n\twordWrapOverride2?: 'off' | 'on' | 'inherit';\r\n\t/**\r\n\t * Control the wrapping of the editor.\r\n\t * When `wordWrap` = \"off\", the lines will never wrap.\r\n\t * When `wordWrap` = \"on\", the lines will wrap at the viewport width.\r\n\t * When `wordWrap` = \"wordWrapColumn\", the lines will wrap at `wordWrapColumn`.\r\n\t * When `wordWrap` = \"bounded\", the lines will wrap at min(viewport width, wordWrapColumn).\r\n\t * Defaults to 80.\r\n\t */\r\n\twordWrapColumn?: number;\r\n\t/**\r\n\t * Control indentation of wrapped lines. Can be: 'none', 'same', 'indent' or 'deepIndent'.\r\n\t * Defaults to 'same' in vscode and to 'none' in monaco-editor.\r\n\t */\r\n\twrappingIndent?: 'none' | 'same' | 'indent' | 'deepIndent';\r\n\t/**\r\n\t * Controls the wrapping strategy to use.\r\n\t * Defaults to 'simple'.\r\n\t */\r\n\twrappingStrategy?: 'simple' | 'advanced';\r\n\t/**\r\n\t * Configure word wrapping characters. A break will be introduced before these characters.\r\n\t * Defaults to '([{‘“〈《「『【〔([{「£¥$£¥++'.\r\n\t */\r\n\twordWrapBreakBeforeCharacters?: string;\r\n\t/**\r\n\t * Configure word wrapping characters. A break will be introduced after these characters.\r\n\t * Defaults to ' \\t})]?|/&.,;¢°′″‰℃、。。、¢,.:;?!%・・ゝゞヽヾーァィゥェォッャュョヮヵヶぁぃぅぇぉっゃゅょゎゕゖㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ々〻ァィゥェォャュョッー”〉》」』】〕)]}」'.\r\n\t */\r\n\twordWrapBreakAfterCharacters?: string;\r\n\t/**\r\n\t * Performance guard: Stop rendering a line after x characters.\r\n\t * Defaults to 10000.\r\n\t * Use -1 to never stop rendering\r\n\t */\r\n\tstopRenderingLineAfter?: number;\r\n\t/**\r\n\t * Configure the editor's hover.\r\n\t */\r\n\thover?: IEditorHoverOptions;\r\n\t/**\r\n\t * Enable detecting links and making them clickable.\r\n\t * Defaults to true.\r\n\t */\r\n\tlinks?: boolean;\r\n\t/**\r\n\t * Enable inline color decorators and color picker rendering.\r\n\t */\r\n\tcolorDecorators?: boolean;\r\n\t/**\r\n\t * Control the behaviour of comments in the editor.\r\n\t */\r\n\tcomments?: IEditorCommentsOptions;\r\n\t/**\r\n\t * Enable custom contextmenu.\r\n\t * Defaults to true.\r\n\t */\r\n\tcontextmenu?: boolean;\r\n\t/**\r\n\t * A multiplier to be used on the `deltaX` and `deltaY` of mouse wheel scroll events.\r\n\t * Defaults to 1.\r\n\t */\r\n\tmouseWheelScrollSensitivity?: number;\r\n\t/**\r\n\t * FastScrolling mulitplier speed when pressing `Alt`\r\n\t * Defaults to 5.\r\n\t */\r\n\tfastScrollSensitivity?: number;\r\n\t/**\r\n\t * Enable that the editor scrolls only the predominant axis. Prevents horizontal drift when scrolling vertically on a trackpad.\r\n\t * Defaults to true.\r\n\t */\r\n\tscrollPredominantAxis?: boolean;\r\n\t/**\r\n\t * Enable that the selection with the mouse and keys is doing column selection.\r\n\t * Defaults to false.\r\n\t */\r\n\tcolumnSelection?: boolean;\r\n\t/**\r\n\t * The modifier to be used to add multiple cursors with the mouse.\r\n\t * Defaults to 'alt'\r\n\t */\r\n\tmultiCursorModifier?: 'ctrlCmd' | 'alt';\r\n\t/**\r\n\t * Merge overlapping selections.\r\n\t * Defaults to true\r\n\t */\r\n\tmultiCursorMergeOverlapping?: boolean;\r\n\t/**\r\n\t * Configure the behaviour when pasting a text with the line count equal to the cursor count.\r\n\t * Defaults to 'spread'.\r\n\t */\r\n\tmultiCursorPaste?: 'spread' | 'full';\r\n\t/**\r\n\t * Configure the editor's accessibility support.\r\n\t * Defaults to 'auto'. It is best to leave this to 'auto'.\r\n\t */\r\n\taccessibilitySupport?: 'auto' | 'off' | 'on';\r\n\t/**\r\n\t * Controls the number of lines in the editor that can be read out by a screen reader\r\n\t */\r\n\taccessibilityPageSize?: number;\r\n\t/**\r\n\t * Suggest options.\r\n\t */\r\n\tsuggest?: ISuggestOptions;\r\n\t/**\r\n\t * Smart select opptions;\r\n\t */\r\n\tsmartSelect?: ISmartSelectOptions;\r\n\t/**\r\n\t *\r\n\t */\r\n\tgotoLocation?: IGotoLocationOptions;\r\n\t/**\r\n\t * Enable quick suggestions (shadow suggestions)\r\n\t * Defaults to true.\r\n\t */\r\n\tquickSuggestions?: boolean | IQuickSuggestionsOptions;\r\n\t/**\r\n\t * Quick suggestions show delay (in ms)\r\n\t * Defaults to 10 (ms)\r\n\t */\r\n\tquickSuggestionsDelay?: number;\r\n\t/**\r\n\t * Controls the spacing around the editor.\r\n\t */\r\n\tpadding?: IEditorPaddingOptions;\r\n\t/**\r\n\t * Parameter hint options.\r\n\t */\r\n\tparameterHints?: IEditorParameterHintOptions;\r\n\t/**\r\n\t * Options for auto closing brackets.\r\n\t * Defaults to language defined behavior.\r\n\t */\r\n\tautoClosingBrackets?: EditorAutoClosingStrategy;\r\n\t/**\r\n\t * Options for auto closing quotes.\r\n\t * Defaults to language defined behavior.\r\n\t */\r\n\tautoClosingQuotes?: EditorAutoClosingStrategy;\r\n\t/**\r\n\t * Options for typing over closing quotes or brackets.\r\n\t */\r\n\tautoClosingOvertype?: EditorAutoClosingOvertypeStrategy;\r\n\t/**\r\n\t * Options for auto surrounding.\r\n\t * Defaults to always allowing auto surrounding.\r\n\t */\r\n\tautoSurround?: EditorAutoSurroundStrategy;\r\n\t/**\r\n\t * Controls whether the editor should automatically adjust the indentation when users type, paste, move or indent lines.\r\n\t * Defaults to advanced.\r\n\t */\r\n\tautoIndent?: 'none' | 'keep' | 'brackets' | 'advanced' | 'full';\r\n\t/**\r\n\t * Emulate selection behaviour of tab characters when using spaces for indentation.\r\n\t * This means selection will stick to tab stops.\r\n\t */\r\n\tstickyTabStops?: boolean;\r\n\t/**\r\n\t * Enable format on type.\r\n\t * Defaults to false.\r\n\t */\r\n\tformatOnType?: boolean;\r\n\t/**\r\n\t * Enable format on paste.\r\n\t * Defaults to false.\r\n\t */\r\n\tformatOnPaste?: boolean;\r\n\t/**\r\n\t * Controls if the editor should allow to move selections via drag and drop.\r\n\t * Defaults to false.\r\n\t */\r\n\tdragAndDrop?: boolean;\r\n\t/**\r\n\t * Enable the suggestion box to pop-up on trigger characters.\r\n\t * Defaults to true.\r\n\t */\r\n\tsuggestOnTriggerCharacters?: boolean;\r\n\t/**\r\n\t * Accept suggestions on ENTER.\r\n\t * Defaults to 'on'.\r\n\t */\r\n\tacceptSuggestionOnEnter?: 'on' | 'smart' | 'off';\r\n\t/**\r\n\t * Accept suggestions on provider defined characters.\r\n\t * Defaults to true.\r\n\t */\r\n\tacceptSuggestionOnCommitCharacter?: boolean;\r\n\t/**\r\n\t * Enable snippet suggestions. Default to 'true'.\r\n\t */\r\n\tsnippetSuggestions?: 'top' | 'bottom' | 'inline' | 'none';\r\n\t/**\r\n\t * Copying without a selection copies the current line.\r\n\t */\r\n\temptySelectionClipboard?: boolean;\r\n\t/**\r\n\t * Syntax highlighting is copied.\r\n\t */\r\n\tcopyWithSyntaxHighlighting?: boolean;\r\n\t/**\r\n\t * The history mode for suggestions.\r\n\t */\r\n\tsuggestSelection?: 'first' | 'recentlyUsed' | 'recentlyUsedByPrefix';\r\n\t/**\r\n\t * The font size for the suggest widget.\r\n\t * Defaults to the editor font size.\r\n\t */\r\n\tsuggestFontSize?: number;\r\n\t/**\r\n\t * The line height for the suggest widget.\r\n\t * Defaults to the editor line height.\r\n\t */\r\n\tsuggestLineHeight?: number;\r\n\t/**\r\n\t * Enable tab completion.\r\n\t */\r\n\ttabCompletion?: 'on' | 'off' | 'onlySnippets';\r\n\t/**\r\n\t * Enable selection highlight.\r\n\t * Defaults to true.\r\n\t */\r\n\tselectionHighlight?: boolean;\r\n\t/**\r\n\t * Enable semantic occurrences highlight.\r\n\t * Defaults to true.\r\n\t */\r\n\toccurrencesHighlight?: boolean;\r\n\t/**\r\n\t * Show code lens\r\n\t * Defaults to true.\r\n\t */\r\n\tcodeLens?: boolean;\r\n\t/**\r\n\t * Code lens font family. Defaults to editor font family.\r\n\t */\r\n\tcodeLensFontFamily?: string;\r\n\t/**\r\n\t * Code lens font size. Default to 90% of the editor font size\r\n\t */\r\n\tcodeLensFontSize?: number;\r\n\t/**\r\n\t * Control the behavior and rendering of the code action lightbulb.\r\n\t */\r\n\tlightbulb?: IEditorLightbulbOptions;\r\n\t/**\r\n\t * Timeout for running code actions on save.\r\n\t */\r\n\tcodeActionsOnSaveTimeout?: number;\r\n\t/**\r\n\t * Enable code folding.\r\n\t * Defaults to true.\r\n\t */\r\n\tfolding?: boolean;\r\n\t/**\r\n\t * Selects the folding strategy. 'auto' uses the strategies contributed for the current document, 'indentation' uses the indentation based folding strategy.\r\n\t * Defaults to 'auto'.\r\n\t */\r\n\tfoldingStrategy?: 'auto' | 'indentation';\r\n\t/**\r\n\t * Enable highlight for folded regions.\r\n\t * Defaults to true.\r\n\t */\r\n\tfoldingHighlight?: boolean;\r\n\t/**\r\n\t * Controls whether the fold actions in the gutter stay always visible or hide unless the mouse is over the gutter.\r\n\t * Defaults to 'mouseover'.\r\n\t */\r\n\tshowFoldingControls?: 'always' | 'mouseover';\r\n\t/**\r\n\t * Controls whether clicking on the empty content after a folded line will unfold the line.\r\n\t * Defaults to false.\r\n\t */\r\n\tunfoldOnClickAfterEndOfLine?: boolean;\r\n\t/**\r\n\t * Enable highlighting of matching brackets.\r\n\t * Defaults to 'always'.\r\n\t */\r\n\tmatchBrackets?: 'never' | 'near' | 'always';\r\n\t/**\r\n\t * Enable rendering of whitespace.\r\n\t * Defaults to none.\r\n\t */\r\n\trenderWhitespace?: 'none' | 'boundary' | 'selection' | 'trailing' | 'all';\r\n\t/**\r\n\t * Enable rendering of control characters.\r\n\t * Defaults to false.\r\n\t */\r\n\trenderControlCharacters?: boolean;\r\n\t/**\r\n\t * Enable rendering of indent guides.\r\n\t * Defaults to true.\r\n\t */\r\n\trenderIndentGuides?: boolean;\r\n\t/**\r\n\t * Enable highlighting of the active indent guide.\r\n\t * Defaults to true.\r\n\t */\r\n\thighlightActiveIndentGuide?: boolean;\r\n\t/**\r\n\t * Enable rendering of current line highlight.\r\n\t * Defaults to all.\r\n\t */\r\n\trenderLineHighlight?: 'none' | 'gutter' | 'line' | 'all';\r\n\t/**\r\n\t * Control if the current line highlight should be rendered only the editor is focused.\r\n\t * Defaults to false.\r\n\t */\r\n\trenderLineHighlightOnlyWhenFocus?: boolean;\r\n\t/**\r\n\t * Inserting and deleting whitespace follows tab stops.\r\n\t */\r\n\tuseTabStops?: boolean;\r\n\t/**\r\n\t * The font family\r\n\t */\r\n\tfontFamily?: string;\r\n\t/**\r\n\t * The font weight\r\n\t */\r\n\tfontWeight?: string;\r\n\t/**\r\n\t * The font size\r\n\t */\r\n\tfontSize?: number;\r\n\t/**\r\n\t * The line height\r\n\t */\r\n\tlineHeight?: number;\r\n\t/**\r\n\t * The letter spacing\r\n\t */\r\n\tletterSpacing?: number;\r\n\t/**\r\n\t * Controls fading out of unused variables.\r\n\t */\r\n\tshowUnused?: boolean;\r\n\t/**\r\n\t * Controls whether to focus the inline editor in the peek widget by default.\r\n\t * Defaults to false.\r\n\t */\r\n\tpeekWidgetDefaultFocus?: 'tree' | 'editor';\r\n\t/**\r\n\t * Controls whether the definition link opens element in the peek widget.\r\n\t * Defaults to false.\r\n\t */\r\n\tdefinitionLinkOpensInPeek?: boolean;\r\n\t/**\r\n\t * Controls strikethrough deprecated variables.\r\n\t */\r\n\tshowDeprecated?: boolean;\r\n\t/**\r\n\t * Control the behavior and rendering of the inline hints.\r\n\t */\r\n\tinlineHints?: IEditorInlineHintsOptions;\r\n}\r\n\r\n/**\r\n * @internal\r\n * The width of the minimap gutter, in pixels.\r\n */\r\nexport const MINIMAP_GUTTER_WIDTH = 8;\r\n\r\n/**\r\n * Configuration options for the diff editor.\r\n */\r\nexport interface IDiffEditorOptions extends IEditorOptions {\r\n\t/**\r\n\t * Allow the user to resize the diff editor split view.\r\n\t * Defaults to true.\r\n\t */\r\n\tenableSplitViewResizing?: boolean;\r\n\t/**\r\n\t * Render the differences in two side-by-side editors.\r\n\t * Defaults to true.\r\n\t */\r\n\trenderSideBySide?: boolean;\r\n\t/**\r\n\t * Timeout in milliseconds after which diff computation is cancelled.\r\n\t * Defaults to 5000.\r\n\t */\r\n\tmaxComputationTime?: number;\r\n\t/**\r\n\t * Compute the diff by ignoring leading/trailing whitespace\r\n\t * Defaults to true.\r\n\t */\r\n\tignoreTrimWhitespace?: boolean;\r\n\t/**\r\n\t * Render +/- indicators for added/deleted changes.\r\n\t * Defaults to true.\r\n\t */\r\n\trenderIndicators?: boolean;\r\n\t/**\r\n\t * Original model should be editable?\r\n\t * Defaults to false.\r\n\t */\r\n\toriginalEditable?: boolean;\r\n\t/**\r\n\t * Should the diff editor enable code lens?\r\n\t * Defaults to false.\r\n\t */\r\n\tdiffCodeLens?: boolean;\r\n\t/**\r\n\t * Is the diff editor inside another editor\r\n\t * Defaults to false\r\n\t */\r\n\tisInEmbeddedEditor?: boolean;\r\n\t/**\r\n\t * Is the diff editor should render overview ruler\r\n\t * Defaults to true\r\n\t */\r\n\trenderOverviewRuler?: boolean;\r\n\t/**\r\n\t * Control the wrapping of the diff editor.\r\n\t */\r\n\tdiffWordWrap?: 'off' | 'on' | 'inherit';\r\n}\r\n\r\n//#endregion\r\n\r\n/**\r\n * An event describing that the configuration of the editor has changed.\r\n */\r\nexport class ConfigurationChangedEvent {\r\n\tprivate readonly _values: boolean[];\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tconstructor(values: boolean[]) {\r\n\t\tthis._values = values;\r\n\t}\r\n\tpublic hasChanged(id: EditorOption): boolean {\r\n\t\treturn this._values[id];\r\n\t}\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport class ValidatedEditorOptions {\r\n\tprivate readonly _values: any[] = [];\r\n\tpublic _read(option: EditorOption): T {\r\n\t\treturn this._values[option];\r\n\t}\r\n\tpublic get(id: T): FindComputedEditorOptionValueById {\r\n\t\treturn this._values[id];\r\n\t}\r\n\tpublic _write(option: EditorOption, value: T): void {\r\n\t\tthis._values[option] = value;\r\n\t}\r\n}\r\n\r\n/**\r\n * All computed editor options.\r\n */\r\nexport interface IComputedEditorOptions {\r\n\tget(id: T): FindComputedEditorOptionValueById;\r\n}\r\n\r\n//#region IEditorOption\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface IEnvironmentalOptions {\r\n\treadonly memory: ComputeOptionsMemory | null;\r\n\treadonly outerWidth: number;\r\n\treadonly outerHeight: number;\r\n\treadonly fontInfo: FontInfo;\r\n\treadonly extraEditorClassName: string;\r\n\treadonly isDominatedByLongLines: boolean;\r\n\treadonly viewLineCount: number;\r\n\treadonly lineNumbersDigitCount: number;\r\n\treadonly emptySelectionClipboard: boolean;\r\n\treadonly pixelRatio: number;\r\n\treadonly tabFocusMode: boolean;\r\n\treadonly accessibilitySupport: AccessibilitySupport;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport class ComputeOptionsMemory {\r\n\r\n\tpublic stableMinimapLayoutInput: IMinimapLayoutInput | null;\r\n\tpublic stableFitMaxMinimapScale: number;\r\n\tpublic stableFitRemainingWidth: number;\r\n\r\n\tconstructor() {\r\n\t\tthis.stableMinimapLayoutInput = null;\r\n\t\tthis.stableFitMaxMinimapScale = 0;\r\n\t\tthis.stableFitRemainingWidth = 0;\r\n\t}\r\n}\r\n\r\nexport interface IEditorOption {\r\n\treadonly id: K1;\r\n\treadonly name: string;\r\n\tdefaultValue: V;\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\treadonly schema: IConfigurationPropertySchema | { [path: string]: IConfigurationPropertySchema; } | undefined;\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tvalidate(input: any): V;\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tcompute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: V): V;\r\n}\r\n\r\ntype PossibleKeyName0 = { [K in keyof IEditorOptions]: IEditorOptions[K] extends V | undefined ? K : never }[keyof IEditorOptions];\r\ntype PossibleKeyName = NonNullable>;\r\n\r\n/**\r\n * @internal\r\n */\r\nabstract class BaseEditorOption implements IEditorOption {\r\n\r\n\tpublic readonly id: K1;\r\n\tpublic readonly name: string;\r\n\tpublic readonly defaultValue: V;\r\n\tpublic readonly schema: IConfigurationPropertySchema | { [path: string]: IConfigurationPropertySchema; } | undefined;\r\n\r\n\tconstructor(id: K1, name: string, defaultValue: V, schema?: IConfigurationPropertySchema | { [path: string]: IConfigurationPropertySchema; }) {\r\n\t\tthis.id = id;\r\n\t\tthis.name = name;\r\n\t\tthis.defaultValue = defaultValue;\r\n\t\tthis.schema = schema;\r\n\t}\r\n\r\n\tpublic abstract validate(input: any): V;\r\n\r\n\tpublic compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: V): V {\r\n\t\treturn value;\r\n\t}\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nabstract class ComputedEditorOption implements IEditorOption {\r\n\r\n\tpublic readonly id: K1;\r\n\tpublic readonly name: '_never_';\r\n\tpublic readonly defaultValue: V;\r\n\tpublic readonly deps: EditorOption[] | null;\r\n\tpublic readonly schema: IConfigurationPropertySchema | undefined = undefined;\r\n\r\n\tconstructor(id: K1, deps: EditorOption[] | null = null) {\r\n\t\tthis.id = id;\r\n\t\tthis.name = '_never_';\r\n\t\tthis.defaultValue = undefined;\r\n\t\tthis.deps = deps;\r\n\t}\r\n\r\n\tpublic validate(input: any): V {\r\n\t\treturn this.defaultValue;\r\n\t}\r\n\r\n\tpublic abstract compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: V): V;\r\n}\r\n\r\nclass SimpleEditorOption implements IEditorOption {\r\n\r\n\tpublic readonly id: K1;\r\n\tpublic readonly name: PossibleKeyName;\r\n\tpublic readonly defaultValue: V;\r\n\tpublic readonly schema: IConfigurationPropertySchema | undefined;\r\n\r\n\tconstructor(id: K1, name: PossibleKeyName, defaultValue: V, schema?: IConfigurationPropertySchema) {\r\n\t\tthis.id = id;\r\n\t\tthis.name = name;\r\n\t\tthis.defaultValue = defaultValue;\r\n\t\tthis.schema = schema;\r\n\t}\r\n\r\n\tpublic validate(input: any): V {\r\n\t\tif (typeof input === 'undefined') {\r\n\t\t\treturn this.defaultValue;\r\n\t\t}\r\n\t\treturn input as any;\r\n\t}\r\n\r\n\tpublic compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: V): V {\r\n\t\treturn value;\r\n\t}\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport function boolean(value: any, defaultValue: boolean): boolean {\r\n\tif (typeof value === 'undefined') {\r\n\t\treturn defaultValue;\r\n\t}\r\n\tif (value === 'false') {\r\n\t\t// treat the string 'false' as false\r\n\t\treturn false;\r\n\t}\r\n\treturn Boolean(value);\r\n}\r\n\r\nclass EditorBooleanOption extends SimpleEditorOption {\r\n\r\n\tconstructor(id: K1, name: PossibleKeyName, defaultValue: boolean, schema: IConfigurationPropertySchema | undefined = undefined) {\r\n\t\tif (typeof schema !== 'undefined') {\r\n\t\t\tschema.type = 'boolean';\r\n\t\t\tschema.default = defaultValue;\r\n\t\t}\r\n\t\tsuper(id, name, defaultValue, schema);\r\n\t}\r\n\r\n\tpublic validate(input: any): boolean {\r\n\t\treturn boolean(input, this.defaultValue);\r\n\t}\r\n}\r\n\r\nclass EditorIntOption extends SimpleEditorOption {\r\n\r\n\tpublic static clampedInt(value: any, defaultValue: T, minimum: number, maximum: number): number | T {\r\n\t\tif (typeof value === 'undefined') {\r\n\t\t\treturn defaultValue;\r\n\t\t}\r\n\t\tlet r = parseInt(value, 10);\r\n\t\tif (isNaN(r)) {\r\n\t\t\treturn defaultValue;\r\n\t\t}\r\n\t\tr = Math.max(minimum, r);\r\n\t\tr = Math.min(maximum, r);\r\n\t\treturn r | 0;\r\n\t}\r\n\r\n\tpublic readonly minimum: number;\r\n\tpublic readonly maximum: number;\r\n\r\n\tconstructor(id: K1, name: PossibleKeyName, defaultValue: number, minimum: number, maximum: number, schema: IConfigurationPropertySchema | undefined = undefined) {\r\n\t\tif (typeof schema !== 'undefined') {\r\n\t\t\tschema.type = 'integer';\r\n\t\t\tschema.default = defaultValue;\r\n\t\t\tschema.minimum = minimum;\r\n\t\t\tschema.maximum = maximum;\r\n\t\t}\r\n\t\tsuper(id, name, defaultValue, schema);\r\n\t\tthis.minimum = minimum;\r\n\t\tthis.maximum = maximum;\r\n\t}\r\n\r\n\tpublic validate(input: any): number {\r\n\t\treturn EditorIntOption.clampedInt(input, this.defaultValue, this.minimum, this.maximum);\r\n\t}\r\n}\r\n\r\nclass EditorFloatOption extends SimpleEditorOption {\r\n\r\n\tpublic static clamp(n: number, min: number, max: number): number {\r\n\t\tif (n < min) {\r\n\t\t\treturn min;\r\n\t\t}\r\n\t\tif (n > max) {\r\n\t\t\treturn max;\r\n\t\t}\r\n\t\treturn n;\r\n\t}\r\n\r\n\tpublic static float(value: any, defaultValue: number): number {\r\n\t\tif (typeof value === 'number') {\r\n\t\t\treturn value;\r\n\t\t}\r\n\t\tif (typeof value === 'undefined') {\r\n\t\t\treturn defaultValue;\r\n\t\t}\r\n\t\tconst r = parseFloat(value);\r\n\t\treturn (isNaN(r) ? defaultValue : r);\r\n\t}\r\n\r\n\tpublic readonly validationFn: (value: number) => number;\r\n\r\n\tconstructor(id: K1, name: PossibleKeyName, defaultValue: number, validationFn: (value: number) => number, schema?: IConfigurationPropertySchema) {\r\n\t\tif (typeof schema !== 'undefined') {\r\n\t\t\tschema.type = 'number';\r\n\t\t\tschema.default = defaultValue;\r\n\t\t}\r\n\t\tsuper(id, name, defaultValue, schema);\r\n\t\tthis.validationFn = validationFn;\r\n\t}\r\n\r\n\tpublic validate(input: any): number {\r\n\t\treturn this.validationFn(EditorFloatOption.float(input, this.defaultValue));\r\n\t}\r\n}\r\n\r\nclass EditorStringOption extends SimpleEditorOption {\r\n\r\n\tpublic static string(value: any, defaultValue: string): string {\r\n\t\tif (typeof value !== 'string') {\r\n\t\t\treturn defaultValue;\r\n\t\t}\r\n\t\treturn value;\r\n\t}\r\n\r\n\tconstructor(id: K1, name: PossibleKeyName, defaultValue: string, schema: IConfigurationPropertySchema | undefined = undefined) {\r\n\t\tif (typeof schema !== 'undefined') {\r\n\t\t\tschema.type = 'string';\r\n\t\t\tschema.default = defaultValue;\r\n\t\t}\r\n\t\tsuper(id, name, defaultValue, schema);\r\n\t}\r\n\r\n\tpublic validate(input: any): string {\r\n\t\treturn EditorStringOption.string(input, this.defaultValue);\r\n\t}\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport function stringSet(value: T | undefined, defaultValue: T, allowedValues: ReadonlyArray): T {\r\n\tif (typeof value !== 'string') {\r\n\t\treturn defaultValue;\r\n\t}\r\n\tif (allowedValues.indexOf(value) === -1) {\r\n\t\treturn defaultValue;\r\n\t}\r\n\treturn value;\r\n}\r\n\r\nclass EditorStringEnumOption extends SimpleEditorOption {\r\n\r\n\tprivate readonly _allowedValues: ReadonlyArray;\r\n\r\n\tconstructor(id: K1, name: PossibleKeyName, defaultValue: V, allowedValues: ReadonlyArray, schema: IConfigurationPropertySchema | undefined = undefined) {\r\n\t\tif (typeof schema !== 'undefined') {\r\n\t\t\tschema.type = 'string';\r\n\t\t\tschema.enum = allowedValues;\r\n\t\t\tschema.default = defaultValue;\r\n\t\t}\r\n\t\tsuper(id, name, defaultValue, schema);\r\n\t\tthis._allowedValues = allowedValues;\r\n\t}\r\n\r\n\tpublic validate(input: any): V {\r\n\t\treturn stringSet(input, this.defaultValue, this._allowedValues);\r\n\t}\r\n}\r\n\r\nclass EditorEnumOption extends BaseEditorOption {\r\n\r\n\tprivate readonly _allowedValues: T[];\r\n\tprivate readonly _convert: (value: T) => V;\r\n\r\n\tconstructor(id: K1, name: PossibleKeyName, defaultValue: V, defaultStringValue: string, allowedValues: T[], convert: (value: T) => V, schema: IConfigurationPropertySchema | undefined = undefined) {\r\n\t\tif (typeof schema !== 'undefined') {\r\n\t\t\tschema.type = 'string';\r\n\t\t\tschema.enum = allowedValues;\r\n\t\t\tschema.default = defaultStringValue;\r\n\t\t}\r\n\t\tsuper(id, name, defaultValue, schema);\r\n\t\tthis._allowedValues = allowedValues;\r\n\t\tthis._convert = convert;\r\n\t}\r\n\r\n\tpublic validate(input: any): V {\r\n\t\tif (typeof input !== 'string') {\r\n\t\t\treturn this.defaultValue;\r\n\t\t}\r\n\t\tif (this._allowedValues.indexOf(input) === -1) {\r\n\t\t\treturn this.defaultValue;\r\n\t\t}\r\n\t\treturn this._convert(input);\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region autoIndent\r\n\r\nfunction _autoIndentFromString(autoIndent: 'none' | 'keep' | 'brackets' | 'advanced' | 'full'): EditorAutoIndentStrategy {\r\n\tswitch (autoIndent) {\r\n\t\tcase 'none': return EditorAutoIndentStrategy.None;\r\n\t\tcase 'keep': return EditorAutoIndentStrategy.Keep;\r\n\t\tcase 'brackets': return EditorAutoIndentStrategy.Brackets;\r\n\t\tcase 'advanced': return EditorAutoIndentStrategy.Advanced;\r\n\t\tcase 'full': return EditorAutoIndentStrategy.Full;\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region accessibilitySupport\r\n\r\nclass EditorAccessibilitySupport extends BaseEditorOption {\r\n\r\n\tconstructor() {\r\n\t\tsuper(\r\n\t\t\tEditorOption.accessibilitySupport, 'accessibilitySupport', AccessibilitySupport.Unknown,\r\n\t\t\t{\r\n\t\t\t\ttype: 'string',\r\n\t\t\t\tenum: ['auto', 'on', 'off'],\r\n\t\t\t\tenumDescriptions: [\r\n\t\t\t\t\tnls.localize('accessibilitySupport.auto', \"The editor will use platform APIs to detect when a Screen Reader is attached.\"),\r\n\t\t\t\t\tnls.localize('accessibilitySupport.on', \"The editor will be permanently optimized for usage with a Screen Reader. Word wrapping will be disabled.\"),\r\n\t\t\t\t\tnls.localize('accessibilitySupport.off', \"The editor will never be optimized for usage with a Screen Reader.\"),\r\n\t\t\t\t],\r\n\t\t\t\tdefault: 'auto',\r\n\t\t\t\tdescription: nls.localize('accessibilitySupport', \"Controls whether the editor should run in a mode where it is optimized for screen readers. Setting to on will disable word wrapping.\")\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n\r\n\tpublic validate(input: any): AccessibilitySupport {\r\n\t\tswitch (input) {\r\n\t\t\tcase 'auto': return AccessibilitySupport.Unknown;\r\n\t\t\tcase 'off': return AccessibilitySupport.Disabled;\r\n\t\t\tcase 'on': return AccessibilitySupport.Enabled;\r\n\t\t}\r\n\t\treturn this.defaultValue;\r\n\t}\r\n\r\n\tpublic compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: AccessibilitySupport): AccessibilitySupport {\r\n\t\tif (value === AccessibilitySupport.Unknown) {\r\n\t\t\t// The editor reads the `accessibilitySupport` from the environment\r\n\t\t\treturn env.accessibilitySupport;\r\n\t\t}\r\n\t\treturn value;\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region comments\r\n\r\n/**\r\n * Configuration options for editor comments\r\n */\r\nexport interface IEditorCommentsOptions {\r\n\t/**\r\n\t * Insert a space after the line comment token and inside the block comments tokens.\r\n\t * Defaults to true.\r\n\t */\r\n\tinsertSpace?: boolean;\r\n\t/**\r\n\t * Ignore empty lines when inserting line comments.\r\n\t * Defaults to true.\r\n\t */\r\n\tignoreEmptyLines?: boolean;\r\n}\r\n\r\nexport type EditorCommentsOptions = Readonly>;\r\n\r\nclass EditorComments extends BaseEditorOption {\r\n\r\n\tconstructor() {\r\n\t\tconst defaults: EditorCommentsOptions = {\r\n\t\t\tinsertSpace: true,\r\n\t\t\tignoreEmptyLines: true,\r\n\t\t};\r\n\t\tsuper(\r\n\t\t\tEditorOption.comments, 'comments', defaults,\r\n\t\t\t{\r\n\t\t\t\t'editor.comments.insertSpace': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: defaults.insertSpace,\r\n\t\t\t\t\tdescription: nls.localize('comments.insertSpace', \"Controls whether a space character is inserted when commenting.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.comments.ignoreEmptyLines': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: defaults.ignoreEmptyLines,\r\n\t\t\t\t\tdescription: nls.localize('comments.ignoreEmptyLines', 'Controls if empty lines should be ignored with toggle, add or remove actions for line comments.')\r\n\t\t\t\t},\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n\r\n\tpublic validate(_input: any): EditorCommentsOptions {\r\n\t\tif (!_input || typeof _input !== 'object') {\r\n\t\t\treturn this.defaultValue;\r\n\t\t}\r\n\t\tconst input = _input as IEditorCommentsOptions;\r\n\t\treturn {\r\n\t\t\tinsertSpace: boolean(input.insertSpace, this.defaultValue.insertSpace),\r\n\t\t\tignoreEmptyLines: boolean(input.ignoreEmptyLines, this.defaultValue.ignoreEmptyLines),\r\n\t\t};\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region cursorBlinking\r\n\r\n/**\r\n * The kind of animation in which the editor's cursor should be rendered.\r\n */\r\nexport const enum TextEditorCursorBlinkingStyle {\r\n\t/**\r\n\t * Hidden\r\n\t */\r\n\tHidden = 0,\r\n\t/**\r\n\t * Blinking\r\n\t */\r\n\tBlink = 1,\r\n\t/**\r\n\t * Blinking with smooth fading\r\n\t */\r\n\tSmooth = 2,\r\n\t/**\r\n\t * Blinking with prolonged filled state and smooth fading\r\n\t */\r\n\tPhase = 3,\r\n\t/**\r\n\t * Expand collapse animation on the y axis\r\n\t */\r\n\tExpand = 4,\r\n\t/**\r\n\t * No-Blinking\r\n\t */\r\n\tSolid = 5\r\n}\r\n\r\nfunction _cursorBlinkingStyleFromString(cursorBlinkingStyle: 'blink' | 'smooth' | 'phase' | 'expand' | 'solid'): TextEditorCursorBlinkingStyle {\r\n\tswitch (cursorBlinkingStyle) {\r\n\t\tcase 'blink': return TextEditorCursorBlinkingStyle.Blink;\r\n\t\tcase 'smooth': return TextEditorCursorBlinkingStyle.Smooth;\r\n\t\tcase 'phase': return TextEditorCursorBlinkingStyle.Phase;\r\n\t\tcase 'expand': return TextEditorCursorBlinkingStyle.Expand;\r\n\t\tcase 'solid': return TextEditorCursorBlinkingStyle.Solid;\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region cursorStyle\r\n\r\n/**\r\n * The style in which the editor's cursor should be rendered.\r\n */\r\nexport enum TextEditorCursorStyle {\r\n\t/**\r\n\t * As a vertical line (sitting between two characters).\r\n\t */\r\n\tLine = 1,\r\n\t/**\r\n\t * As a block (sitting on top of a character).\r\n\t */\r\n\tBlock = 2,\r\n\t/**\r\n\t * As a horizontal line (sitting under a character).\r\n\t */\r\n\tUnderline = 3,\r\n\t/**\r\n\t * As a thin vertical line (sitting between two characters).\r\n\t */\r\n\tLineThin = 4,\r\n\t/**\r\n\t * As an outlined block (sitting on top of a character).\r\n\t */\r\n\tBlockOutline = 5,\r\n\t/**\r\n\t * As a thin horizontal line (sitting under a character).\r\n\t */\r\n\tUnderlineThin = 6\r\n}\r\n\r\nfunction _cursorStyleFromString(cursorStyle: 'line' | 'block' | 'underline' | 'line-thin' | 'block-outline' | 'underline-thin'): TextEditorCursorStyle {\r\n\tswitch (cursorStyle) {\r\n\t\tcase 'line': return TextEditorCursorStyle.Line;\r\n\t\tcase 'block': return TextEditorCursorStyle.Block;\r\n\t\tcase 'underline': return TextEditorCursorStyle.Underline;\r\n\t\tcase 'line-thin': return TextEditorCursorStyle.LineThin;\r\n\t\tcase 'block-outline': return TextEditorCursorStyle.BlockOutline;\r\n\t\tcase 'underline-thin': return TextEditorCursorStyle.UnderlineThin;\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region editorClassName\r\n\r\nclass EditorClassName extends ComputedEditorOption {\r\n\r\n\tconstructor() {\r\n\t\tsuper(EditorOption.editorClassName, [EditorOption.mouseStyle, EditorOption.extraEditorClassName]);\r\n\t}\r\n\r\n\tpublic compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: string): string {\r\n\t\tconst classNames = ['monaco-editor'];\r\n\t\tif (options.get(EditorOption.extraEditorClassName)) {\r\n\t\t\tclassNames.push(options.get(EditorOption.extraEditorClassName));\r\n\t\t}\r\n\t\tif (env.extraEditorClassName) {\r\n\t\t\tclassNames.push(env.extraEditorClassName);\r\n\t\t}\r\n\t\tif (options.get(EditorOption.mouseStyle) === 'default') {\r\n\t\t\tclassNames.push('mouse-default');\r\n\t\t} else if (options.get(EditorOption.mouseStyle) === 'copy') {\r\n\t\t\tclassNames.push('mouse-copy');\r\n\t\t}\r\n\r\n\t\tif (options.get(EditorOption.showUnused)) {\r\n\t\t\tclassNames.push('showUnused');\r\n\t\t}\r\n\r\n\t\tif (options.get(EditorOption.showDeprecated)) {\r\n\t\t\tclassNames.push('showDeprecated');\r\n\t\t}\r\n\r\n\t\treturn classNames.join(' ');\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region emptySelectionClipboard\r\n\r\nclass EditorEmptySelectionClipboard extends EditorBooleanOption {\r\n\r\n\tconstructor() {\r\n\t\tsuper(\r\n\t\t\tEditorOption.emptySelectionClipboard, 'emptySelectionClipboard', true,\r\n\t\t\t{ description: nls.localize('emptySelectionClipboard', \"Controls whether copying without a selection copies the current line.\") }\r\n\t\t);\r\n\t}\r\n\r\n\tpublic compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: boolean): boolean {\r\n\t\treturn value && env.emptySelectionClipboard;\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region find\r\n\r\n/**\r\n * Configuration options for editor find widget\r\n */\r\nexport interface IEditorFindOptions {\r\n\t/**\r\n\t* Controls whether the cursor should move to find matches while typing.\r\n\t*/\r\n\tcursorMoveOnType?: boolean;\r\n\t/**\r\n\t * Controls if we seed search string in the Find Widget with editor selection.\r\n\t */\r\n\tseedSearchStringFromSelection?: boolean;\r\n\t/**\r\n\t * Controls if Find in Selection flag is turned on in the editor.\r\n\t */\r\n\tautoFindInSelection?: 'never' | 'always' | 'multiline';\r\n\t/*\r\n\t * Controls whether the Find Widget should add extra lines on top of the editor.\r\n\t */\r\n\taddExtraSpaceOnTop?: boolean;\r\n\t/**\r\n\t * @internal\r\n\t * Controls if the Find Widget should read or modify the shared find clipboard on macOS\r\n\t */\r\n\tglobalFindClipboard?: boolean;\r\n\t/**\r\n\t * Controls whether the search automatically restarts from the beginning (or the end) when no further matches can be found\r\n\t */\r\n\tloop?: boolean;\r\n}\r\n\r\nexport type EditorFindOptions = Readonly>;\r\n\r\nclass EditorFind extends BaseEditorOption {\r\n\r\n\tconstructor() {\r\n\t\tconst defaults: EditorFindOptions = {\r\n\t\t\tcursorMoveOnType: true,\r\n\t\t\tseedSearchStringFromSelection: true,\r\n\t\t\tautoFindInSelection: 'never',\r\n\t\t\tglobalFindClipboard: false,\r\n\t\t\taddExtraSpaceOnTop: true,\r\n\t\t\tloop: true\r\n\t\t};\r\n\t\tsuper(\r\n\t\t\tEditorOption.find, 'find', defaults,\r\n\t\t\t{\r\n\t\t\t\t'editor.find.cursorMoveOnType': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: defaults.cursorMoveOnType,\r\n\t\t\t\t\tdescription: nls.localize('find.cursorMoveOnType', \"Controls whether the cursor should jump to find matches while typing.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.find.seedSearchStringFromSelection': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: defaults.seedSearchStringFromSelection,\r\n\t\t\t\t\tdescription: nls.localize('find.seedSearchStringFromSelection', \"Controls whether the search string in the Find Widget is seeded from the editor selection.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.find.autoFindInSelection': {\r\n\t\t\t\t\ttype: 'string',\r\n\t\t\t\t\tenum: ['never', 'always', 'multiline'],\r\n\t\t\t\t\tdefault: defaults.autoFindInSelection,\r\n\t\t\t\t\tenumDescriptions: [\r\n\t\t\t\t\t\tnls.localize('editor.find.autoFindInSelection.never', 'Never turn on Find in selection automatically (default)'),\r\n\t\t\t\t\t\tnls.localize('editor.find.autoFindInSelection.always', 'Always turn on Find in selection automatically'),\r\n\t\t\t\t\t\tnls.localize('editor.find.autoFindInSelection.multiline', 'Turn on Find in selection automatically when multiple lines of content are selected.')\r\n\t\t\t\t\t],\r\n\t\t\t\t\tdescription: nls.localize('find.autoFindInSelection', \"Controls the condition for turning on find in selection automatically.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.find.globalFindClipboard': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: defaults.globalFindClipboard,\r\n\t\t\t\t\tdescription: nls.localize('find.globalFindClipboard', \"Controls whether the Find Widget should read or modify the shared find clipboard on macOS.\"),\r\n\t\t\t\t\tincluded: platform.isMacintosh\r\n\t\t\t\t},\r\n\t\t\t\t'editor.find.addExtraSpaceOnTop': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: defaults.addExtraSpaceOnTop,\r\n\t\t\t\t\tdescription: nls.localize('find.addExtraSpaceOnTop', \"Controls whether the Find Widget should add extra lines on top of the editor. When true, you can scroll beyond the first line when the Find Widget is visible.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.find.loop': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: defaults.loop,\r\n\t\t\t\t\tdescription: nls.localize('find.loop', \"Controls whether the search automatically restarts from the beginning (or the end) when no further matches can be found.\")\r\n\t\t\t\t},\r\n\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n\r\n\tpublic validate(_input: any): EditorFindOptions {\r\n\t\tif (!_input || typeof _input !== 'object') {\r\n\t\t\treturn this.defaultValue;\r\n\t\t}\r\n\t\tconst input = _input as IEditorFindOptions;\r\n\t\treturn {\r\n\t\t\tcursorMoveOnType: boolean(input.cursorMoveOnType, this.defaultValue.cursorMoveOnType),\r\n\t\t\tseedSearchStringFromSelection: boolean(input.seedSearchStringFromSelection, this.defaultValue.seedSearchStringFromSelection),\r\n\t\t\tautoFindInSelection: typeof _input.autoFindInSelection === 'boolean'\r\n\t\t\t\t? (_input.autoFindInSelection ? 'always' : 'never')\r\n\t\t\t\t: stringSet<'never' | 'always' | 'multiline'>(input.autoFindInSelection, this.defaultValue.autoFindInSelection, ['never', 'always', 'multiline']),\r\n\t\t\tglobalFindClipboard: boolean(input.globalFindClipboard, this.defaultValue.globalFindClipboard),\r\n\t\t\taddExtraSpaceOnTop: boolean(input.addExtraSpaceOnTop, this.defaultValue.addExtraSpaceOnTop),\r\n\t\t\tloop: boolean(input.loop, this.defaultValue.loop),\r\n\t\t};\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region fontLigatures\r\n\r\n/**\r\n * @internal\r\n */\r\nexport class EditorFontLigatures extends BaseEditorOption {\r\n\r\n\tpublic static OFF = '\"liga\" off, \"calt\" off';\r\n\tpublic static ON = '\"liga\" on, \"calt\" on';\r\n\r\n\tconstructor() {\r\n\t\tsuper(\r\n\t\t\tEditorOption.fontLigatures, 'fontLigatures', EditorFontLigatures.OFF,\r\n\t\t\t{\r\n\t\t\t\tanyOf: [\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\t\tdescription: nls.localize('fontLigatures', \"Enables/Disables font ligatures ('calt' and 'liga' font features). Change this to a string for fine-grained control of the 'font-feature-settings' CSS property.\"),\r\n\t\t\t\t\t},\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\ttype: 'string',\r\n\t\t\t\t\t\tdescription: nls.localize('fontFeatureSettings', \"Explicit 'font-feature-settings' CSS property. A boolean can be passed instead if one only needs to turn on/off ligatures.\")\r\n\t\t\t\t\t}\r\n\t\t\t\t],\r\n\t\t\t\tdescription: nls.localize('fontLigaturesGeneral', \"Configures font ligatures or font features. Can be either a boolean to enable/disable ligatures or a string for the value of the CSS 'font-feature-settings' property.\"),\r\n\t\t\t\tdefault: false\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n\r\n\tpublic validate(input: any): string {\r\n\t\tif (typeof input === 'undefined') {\r\n\t\t\treturn this.defaultValue;\r\n\t\t}\r\n\t\tif (typeof input === 'string') {\r\n\t\t\tif (input === 'false') {\r\n\t\t\t\treturn EditorFontLigatures.OFF;\r\n\t\t\t}\r\n\t\t\tif (input === 'true') {\r\n\t\t\t\treturn EditorFontLigatures.ON;\r\n\t\t\t}\r\n\t\t\treturn input;\r\n\t\t}\r\n\t\tif (Boolean(input)) {\r\n\t\t\treturn EditorFontLigatures.ON;\r\n\t\t}\r\n\t\treturn EditorFontLigatures.OFF;\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region fontInfo\r\n\r\nclass EditorFontInfo extends ComputedEditorOption {\r\n\r\n\tconstructor() {\r\n\t\tsuper(EditorOption.fontInfo);\r\n\t}\r\n\r\n\tpublic compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: FontInfo): FontInfo {\r\n\t\treturn env.fontInfo;\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region fontSize\r\n\r\nclass EditorFontSize extends SimpleEditorOption {\r\n\r\n\tconstructor() {\r\n\t\tsuper(\r\n\t\t\tEditorOption.fontSize, 'fontSize', EDITOR_FONT_DEFAULTS.fontSize,\r\n\t\t\t{\r\n\t\t\t\ttype: 'number',\r\n\t\t\t\tminimum: 6,\r\n\t\t\t\tmaximum: 100,\r\n\t\t\t\tdefault: EDITOR_FONT_DEFAULTS.fontSize,\r\n\t\t\t\tdescription: nls.localize('fontSize', \"Controls the font size in pixels.\")\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n\r\n\tpublic validate(input: any): number {\r\n\t\tlet r = EditorFloatOption.float(input, this.defaultValue);\r\n\t\tif (r === 0) {\r\n\t\t\treturn EDITOR_FONT_DEFAULTS.fontSize;\r\n\t\t}\r\n\t\treturn EditorFloatOption.clamp(r, 6, 100);\r\n\t}\r\n\tpublic compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: number): number {\r\n\t\t// The final fontSize respects the editor zoom level.\r\n\t\t// So take the result from env.fontInfo\r\n\t\treturn env.fontInfo.fontSize;\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region fontWeight\r\n\r\nclass EditorFontWeight extends BaseEditorOption {\r\n\tprivate static SUGGESTION_VALUES = ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'];\r\n\tprivate static MINIMUM_VALUE = 1;\r\n\tprivate static MAXIMUM_VALUE = 1000;\r\n\r\n\tconstructor() {\r\n\t\tsuper(\r\n\t\t\tEditorOption.fontWeight, 'fontWeight', EDITOR_FONT_DEFAULTS.fontWeight,\r\n\t\t\t{\r\n\t\t\t\tanyOf: [\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\ttype: 'number',\r\n\t\t\t\t\t\tminimum: EditorFontWeight.MINIMUM_VALUE,\r\n\t\t\t\t\t\tmaximum: EditorFontWeight.MAXIMUM_VALUE,\r\n\t\t\t\t\t\terrorMessage: nls.localize('fontWeightErrorMessage', \"Only \\\"normal\\\" and \\\"bold\\\" keywords or numbers between 1 and 1000 are allowed.\")\r\n\t\t\t\t\t},\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\ttype: 'string',\r\n\t\t\t\t\t\tpattern: '^(normal|bold|1000|[1-9][0-9]{0,2})$'\r\n\t\t\t\t\t},\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tenum: EditorFontWeight.SUGGESTION_VALUES\r\n\t\t\t\t\t}\r\n\t\t\t\t],\r\n\t\t\t\tdefault: EDITOR_FONT_DEFAULTS.fontWeight,\r\n\t\t\t\tdescription: nls.localize('fontWeight', \"Controls the font weight. Accepts \\\"normal\\\" and \\\"bold\\\" keywords or numbers between 1 and 1000.\")\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n\r\n\tpublic validate(input: any): string {\r\n\t\tif (input === 'normal' || input === 'bold') {\r\n\t\t\treturn input;\r\n\t\t}\r\n\t\treturn String(EditorIntOption.clampedInt(input, EDITOR_FONT_DEFAULTS.fontWeight, EditorFontWeight.MINIMUM_VALUE, EditorFontWeight.MAXIMUM_VALUE));\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region gotoLocation\r\n\r\nexport type GoToLocationValues = 'peek' | 'gotoAndPeek' | 'goto';\r\n\r\n/**\r\n * Configuration options for go to location\r\n */\r\nexport interface IGotoLocationOptions {\r\n\r\n\tmultiple?: GoToLocationValues;\r\n\r\n\tmultipleDefinitions?: GoToLocationValues;\r\n\tmultipleTypeDefinitions?: GoToLocationValues;\r\n\tmultipleDeclarations?: GoToLocationValues;\r\n\tmultipleImplementations?: GoToLocationValues;\r\n\tmultipleReferences?: GoToLocationValues;\r\n\r\n\talternativeDefinitionCommand?: string;\r\n\talternativeTypeDefinitionCommand?: string;\r\n\talternativeDeclarationCommand?: string;\r\n\talternativeImplementationCommand?: string;\r\n\talternativeReferenceCommand?: string;\r\n}\r\n\r\nexport type GoToLocationOptions = Readonly>;\r\n\r\nclass EditorGoToLocation extends BaseEditorOption {\r\n\r\n\tconstructor() {\r\n\t\tconst defaults: GoToLocationOptions = {\r\n\t\t\tmultiple: 'peek',\r\n\t\t\tmultipleDefinitions: 'peek',\r\n\t\t\tmultipleTypeDefinitions: 'peek',\r\n\t\t\tmultipleDeclarations: 'peek',\r\n\t\t\tmultipleImplementations: 'peek',\r\n\t\t\tmultipleReferences: 'peek',\r\n\t\t\talternativeDefinitionCommand: 'editor.action.goToReferences',\r\n\t\t\talternativeTypeDefinitionCommand: 'editor.action.goToReferences',\r\n\t\t\talternativeDeclarationCommand: 'editor.action.goToReferences',\r\n\t\t\talternativeImplementationCommand: '',\r\n\t\t\talternativeReferenceCommand: '',\r\n\t\t};\r\n\t\tconst jsonSubset: IJSONSchema = {\r\n\t\t\ttype: 'string',\r\n\t\t\tenum: ['peek', 'gotoAndPeek', 'goto'],\r\n\t\t\tdefault: defaults.multiple,\r\n\t\t\tenumDescriptions: [\r\n\t\t\t\tnls.localize('editor.gotoLocation.multiple.peek', 'Show peek view of the results (default)'),\r\n\t\t\t\tnls.localize('editor.gotoLocation.multiple.gotoAndPeek', 'Go to the primary result and show a peek view'),\r\n\t\t\t\tnls.localize('editor.gotoLocation.multiple.goto', 'Go to the primary result and enable peek-less navigation to others')\r\n\t\t\t]\r\n\t\t};\r\n\t\tsuper(\r\n\t\t\tEditorOption.gotoLocation, 'gotoLocation', defaults,\r\n\t\t\t{\r\n\t\t\t\t'editor.gotoLocation.multiple': {\r\n\t\t\t\t\tdeprecationMessage: nls.localize('editor.gotoLocation.multiple.deprecated', \"This setting is deprecated, please use separate settings like 'editor.editor.gotoLocation.multipleDefinitions' or 'editor.editor.gotoLocation.multipleImplementations' instead.\"),\r\n\t\t\t\t},\r\n\t\t\t\t'editor.gotoLocation.multipleDefinitions': {\r\n\t\t\t\t\tdescription: nls.localize('editor.editor.gotoLocation.multipleDefinitions', \"Controls the behavior the 'Go to Definition'-command when multiple target locations exist.\"),\r\n\t\t\t\t\t...jsonSubset,\r\n\t\t\t\t},\r\n\t\t\t\t'editor.gotoLocation.multipleTypeDefinitions': {\r\n\t\t\t\t\tdescription: nls.localize('editor.editor.gotoLocation.multipleTypeDefinitions', \"Controls the behavior the 'Go to Type Definition'-command when multiple target locations exist.\"),\r\n\t\t\t\t\t...jsonSubset,\r\n\t\t\t\t},\r\n\t\t\t\t'editor.gotoLocation.multipleDeclarations': {\r\n\t\t\t\t\tdescription: nls.localize('editor.editor.gotoLocation.multipleDeclarations', \"Controls the behavior the 'Go to Declaration'-command when multiple target locations exist.\"),\r\n\t\t\t\t\t...jsonSubset,\r\n\t\t\t\t},\r\n\t\t\t\t'editor.gotoLocation.multipleImplementations': {\r\n\t\t\t\t\tdescription: nls.localize('editor.editor.gotoLocation.multipleImplemenattions', \"Controls the behavior the 'Go to Implementations'-command when multiple target locations exist.\"),\r\n\t\t\t\t\t...jsonSubset,\r\n\t\t\t\t},\r\n\t\t\t\t'editor.gotoLocation.multipleReferences': {\r\n\t\t\t\t\tdescription: nls.localize('editor.editor.gotoLocation.multipleReferences', \"Controls the behavior the 'Go to References'-command when multiple target locations exist.\"),\r\n\t\t\t\t\t...jsonSubset,\r\n\t\t\t\t},\r\n\t\t\t\t'editor.gotoLocation.alternativeDefinitionCommand': {\r\n\t\t\t\t\ttype: 'string',\r\n\t\t\t\t\tdefault: defaults.alternativeDefinitionCommand,\r\n\t\t\t\t\tdescription: nls.localize('alternativeDefinitionCommand', \"Alternative command id that is being executed when the result of 'Go to Definition' is the current location.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.gotoLocation.alternativeTypeDefinitionCommand': {\r\n\t\t\t\t\ttype: 'string',\r\n\t\t\t\t\tdefault: defaults.alternativeTypeDefinitionCommand,\r\n\t\t\t\t\tdescription: nls.localize('alternativeTypeDefinitionCommand', \"Alternative command id that is being executed when the result of 'Go to Type Definition' is the current location.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.gotoLocation.alternativeDeclarationCommand': {\r\n\t\t\t\t\ttype: 'string',\r\n\t\t\t\t\tdefault: defaults.alternativeDeclarationCommand,\r\n\t\t\t\t\tdescription: nls.localize('alternativeDeclarationCommand', \"Alternative command id that is being executed when the result of 'Go to Declaration' is the current location.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.gotoLocation.alternativeImplementationCommand': {\r\n\t\t\t\t\ttype: 'string',\r\n\t\t\t\t\tdefault: defaults.alternativeImplementationCommand,\r\n\t\t\t\t\tdescription: nls.localize('alternativeImplementationCommand', \"Alternative command id that is being executed when the result of 'Go to Implementation' is the current location.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.gotoLocation.alternativeReferenceCommand': {\r\n\t\t\t\t\ttype: 'string',\r\n\t\t\t\t\tdefault: defaults.alternativeReferenceCommand,\r\n\t\t\t\t\tdescription: nls.localize('alternativeReferenceCommand', \"Alternative command id that is being executed when the result of 'Go to Reference' is the current location.\")\r\n\t\t\t\t},\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n\r\n\tpublic validate(_input: any): GoToLocationOptions {\r\n\t\tif (!_input || typeof _input !== 'object') {\r\n\t\t\treturn this.defaultValue;\r\n\t\t}\r\n\t\tconst input = _input as IGotoLocationOptions;\r\n\t\treturn {\r\n\t\t\tmultiple: stringSet(input.multiple, this.defaultValue.multiple!, ['peek', 'gotoAndPeek', 'goto']),\r\n\t\t\tmultipleDefinitions: input.multipleDefinitions ?? stringSet(input.multipleDefinitions, 'peek', ['peek', 'gotoAndPeek', 'goto']),\r\n\t\t\tmultipleTypeDefinitions: input.multipleTypeDefinitions ?? stringSet(input.multipleTypeDefinitions, 'peek', ['peek', 'gotoAndPeek', 'goto']),\r\n\t\t\tmultipleDeclarations: input.multipleDeclarations ?? stringSet(input.multipleDeclarations, 'peek', ['peek', 'gotoAndPeek', 'goto']),\r\n\t\t\tmultipleImplementations: input.multipleImplementations ?? stringSet(input.multipleImplementations, 'peek', ['peek', 'gotoAndPeek', 'goto']),\r\n\t\t\tmultipleReferences: input.multipleReferences ?? stringSet(input.multipleReferences, 'peek', ['peek', 'gotoAndPeek', 'goto']),\r\n\t\t\talternativeDefinitionCommand: EditorStringOption.string(input.alternativeDefinitionCommand, this.defaultValue.alternativeDefinitionCommand),\r\n\t\t\talternativeTypeDefinitionCommand: EditorStringOption.string(input.alternativeTypeDefinitionCommand, this.defaultValue.alternativeTypeDefinitionCommand),\r\n\t\t\talternativeDeclarationCommand: EditorStringOption.string(input.alternativeDeclarationCommand, this.defaultValue.alternativeDeclarationCommand),\r\n\t\t\talternativeImplementationCommand: EditorStringOption.string(input.alternativeImplementationCommand, this.defaultValue.alternativeImplementationCommand),\r\n\t\t\talternativeReferenceCommand: EditorStringOption.string(input.alternativeReferenceCommand, this.defaultValue.alternativeReferenceCommand),\r\n\t\t};\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region hover\r\n\r\n/**\r\n * Configuration options for editor hover\r\n */\r\nexport interface IEditorHoverOptions {\r\n\t/**\r\n\t * Enable the hover.\r\n\t * Defaults to true.\r\n\t */\r\n\tenabled?: boolean;\r\n\t/**\r\n\t * Delay for showing the hover.\r\n\t * Defaults to 300.\r\n\t */\r\n\tdelay?: number;\r\n\t/**\r\n\t * Is the hover sticky such that it can be clicked and its contents selected?\r\n\t * Defaults to true.\r\n\t */\r\n\tsticky?: boolean;\r\n}\r\n\r\nexport type EditorHoverOptions = Readonly>;\r\n\r\nclass EditorHover extends BaseEditorOption {\r\n\r\n\tconstructor() {\r\n\t\tconst defaults: EditorHoverOptions = {\r\n\t\t\tenabled: true,\r\n\t\t\tdelay: 300,\r\n\t\t\tsticky: true\r\n\t\t};\r\n\t\tsuper(\r\n\t\t\tEditorOption.hover, 'hover', defaults,\r\n\t\t\t{\r\n\t\t\t\t'editor.hover.enabled': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: defaults.enabled,\r\n\t\t\t\t\tdescription: nls.localize('hover.enabled', \"Controls whether the hover is shown.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.hover.delay': {\r\n\t\t\t\t\ttype: 'number',\r\n\t\t\t\t\tdefault: defaults.delay,\r\n\t\t\t\t\tdescription: nls.localize('hover.delay', \"Controls the delay in milliseconds after which the hover is shown.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.hover.sticky': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: defaults.sticky,\r\n\t\t\t\t\tdescription: nls.localize('hover.sticky', \"Controls whether the hover should remain visible when mouse is moved over it.\")\r\n\t\t\t\t},\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n\r\n\tpublic validate(_input: any): EditorHoverOptions {\r\n\t\tif (!_input || typeof _input !== 'object') {\r\n\t\t\treturn this.defaultValue;\r\n\t\t}\r\n\t\tconst input = _input as IEditorHoverOptions;\r\n\t\treturn {\r\n\t\t\tenabled: boolean(input.enabled, this.defaultValue.enabled),\r\n\t\t\tdelay: EditorIntOption.clampedInt(input.delay, this.defaultValue.delay, 0, 10000),\r\n\t\t\tsticky: boolean(input.sticky, this.defaultValue.sticky)\r\n\t\t};\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region layoutInfo\r\n\r\n/**\r\n * A description for the overview ruler position.\r\n */\r\nexport interface OverviewRulerPosition {\r\n\t/**\r\n\t * Width of the overview ruler\r\n\t */\r\n\treadonly width: number;\r\n\t/**\r\n\t * Height of the overview ruler\r\n\t */\r\n\treadonly height: number;\r\n\t/**\r\n\t * Top position for the overview ruler\r\n\t */\r\n\treadonly top: number;\r\n\t/**\r\n\t * Right position for the overview ruler\r\n\t */\r\n\treadonly right: number;\r\n}\r\n\r\nexport const enum RenderMinimap {\r\n\tNone = 0,\r\n\tText = 1,\r\n\tBlocks = 2,\r\n}\r\n\r\n/**\r\n * The internal layout details of the editor.\r\n */\r\nexport interface EditorLayoutInfo {\r\n\r\n\t/**\r\n\t * Full editor width.\r\n\t */\r\n\treadonly width: number;\r\n\t/**\r\n\t * Full editor height.\r\n\t */\r\n\treadonly height: number;\r\n\r\n\t/**\r\n\t * Left position for the glyph margin.\r\n\t */\r\n\treadonly glyphMarginLeft: number;\r\n\t/**\r\n\t * The width of the glyph margin.\r\n\t */\r\n\treadonly glyphMarginWidth: number;\r\n\r\n\t/**\r\n\t * Left position for the line numbers.\r\n\t */\r\n\treadonly lineNumbersLeft: number;\r\n\t/**\r\n\t * The width of the line numbers.\r\n\t */\r\n\treadonly lineNumbersWidth: number;\r\n\r\n\t/**\r\n\t * Left position for the line decorations.\r\n\t */\r\n\treadonly decorationsLeft: number;\r\n\t/**\r\n\t * The width of the line decorations.\r\n\t */\r\n\treadonly decorationsWidth: number;\r\n\r\n\t/**\r\n\t * Left position for the content (actual text)\r\n\t */\r\n\treadonly contentLeft: number;\r\n\t/**\r\n\t * The width of the content (actual text)\r\n\t */\r\n\treadonly contentWidth: number;\r\n\r\n\t/**\r\n\t * Layout information for the minimap\r\n\t */\r\n\treadonly minimap: EditorMinimapLayoutInfo;\r\n\r\n\t/**\r\n\t * The number of columns (of typical characters) fitting on a viewport line.\r\n\t */\r\n\treadonly viewportColumn: number;\r\n\r\n\treadonly isWordWrapMinified: boolean;\r\n\treadonly isViewportWrapping: boolean;\r\n\treadonly wrappingColumn: number;\r\n\r\n\t/**\r\n\t * The width of the vertical scrollbar.\r\n\t */\r\n\treadonly verticalScrollbarWidth: number;\r\n\t/**\r\n\t * The height of the horizontal scrollbar.\r\n\t */\r\n\treadonly horizontalScrollbarHeight: number;\r\n\r\n\t/**\r\n\t * The position of the overview ruler.\r\n\t */\r\n\treadonly overviewRuler: OverviewRulerPosition;\r\n}\r\n\r\n/**\r\n * The internal layout details of the editor.\r\n */\r\nexport interface EditorMinimapLayoutInfo {\r\n\treadonly renderMinimap: RenderMinimap;\r\n\treadonly minimapLeft: number;\r\n\treadonly minimapWidth: number;\r\n\treadonly minimapHeightIsEditorHeight: boolean;\r\n\treadonly minimapIsSampling: boolean;\r\n\treadonly minimapScale: number;\r\n\treadonly minimapLineHeight: number;\r\n\treadonly minimapCanvasInnerWidth: number;\r\n\treadonly minimapCanvasInnerHeight: number;\r\n\treadonly minimapCanvasOuterWidth: number;\r\n\treadonly minimapCanvasOuterHeight: number;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface EditorLayoutInfoComputerEnv {\r\n\treadonly memory: ComputeOptionsMemory | null;\r\n\treadonly outerWidth: number;\r\n\treadonly outerHeight: number;\r\n\treadonly isDominatedByLongLines: boolean;\r\n\treadonly lineHeight: number;\r\n\treadonly viewLineCount: number;\r\n\treadonly lineNumbersDigitCount: number;\r\n\treadonly typicalHalfwidthCharacterWidth: number;\r\n\treadonly maxDigitWidth: number;\r\n\treadonly pixelRatio: number;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface IMinimapLayoutInput {\r\n\treadonly outerWidth: number;\r\n\treadonly outerHeight: number;\r\n\treadonly lineHeight: number;\r\n\treadonly typicalHalfwidthCharacterWidth: number;\r\n\treadonly pixelRatio: number;\r\n\treadonly scrollBeyondLastLine: boolean;\r\n\treadonly minimap: Readonly>;\r\n\treadonly verticalScrollbarWidth: number;\r\n\treadonly viewLineCount: number;\r\n\treadonly remainingWidth: number;\r\n\treadonly isViewportWrapping: boolean;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport class EditorLayoutInfoComputer extends ComputedEditorOption {\r\n\r\n\tconstructor() {\r\n\t\tsuper(\r\n\t\t\tEditorOption.layoutInfo,\r\n\t\t\t[\r\n\t\t\t\tEditorOption.glyphMargin, EditorOption.lineDecorationsWidth, EditorOption.folding,\r\n\t\t\t\tEditorOption.minimap, EditorOption.scrollbar, EditorOption.lineNumbers,\r\n\t\t\t\tEditorOption.lineNumbersMinChars, EditorOption.scrollBeyondLastLine,\r\n\t\t\t\tEditorOption.wordWrap, EditorOption.wordWrapColumn, EditorOption.wordWrapOverride1, EditorOption.wordWrapOverride2,\r\n\t\t\t\tEditorOption.accessibilitySupport\r\n\t\t\t]\r\n\t\t);\r\n\t}\r\n\r\n\tpublic compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: EditorLayoutInfo): EditorLayoutInfo {\r\n\t\treturn EditorLayoutInfoComputer.computeLayout(options, {\r\n\t\t\tmemory: env.memory,\r\n\t\t\touterWidth: env.outerWidth,\r\n\t\t\touterHeight: env.outerHeight,\r\n\t\t\tisDominatedByLongLines: env.isDominatedByLongLines,\r\n\t\t\tlineHeight: env.fontInfo.lineHeight,\r\n\t\t\tviewLineCount: env.viewLineCount,\r\n\t\t\tlineNumbersDigitCount: env.lineNumbersDigitCount,\r\n\t\t\ttypicalHalfwidthCharacterWidth: env.fontInfo.typicalHalfwidthCharacterWidth,\r\n\t\t\tmaxDigitWidth: env.fontInfo.maxDigitWidth,\r\n\t\t\tpixelRatio: env.pixelRatio\r\n\t\t});\r\n\t}\r\n\r\n\tpublic static computeContainedMinimapLineCount(input: {\r\n\t\tviewLineCount: number;\r\n\t\tscrollBeyondLastLine: boolean;\r\n\t\theight: number;\r\n\t\tlineHeight: number;\r\n\t\tpixelRatio: number;\r\n\t}): { typicalViewportLineCount: number; extraLinesBeyondLastLine: number; desiredRatio: number; minimapLineCount: number; } {\r\n\t\tconst typicalViewportLineCount = input.height / input.lineHeight;\r\n\t\tconst extraLinesBeyondLastLine = input.scrollBeyondLastLine ? (typicalViewportLineCount - 1) : 0;\r\n\t\tconst desiredRatio = (input.viewLineCount + extraLinesBeyondLastLine) / (input.pixelRatio * input.height);\r\n\t\tconst minimapLineCount = Math.floor(input.viewLineCount / desiredRatio);\r\n\t\treturn { typicalViewportLineCount, extraLinesBeyondLastLine, desiredRatio, minimapLineCount };\r\n\t}\r\n\r\n\tprivate static _computeMinimapLayout(input: IMinimapLayoutInput, memory: ComputeOptionsMemory): EditorMinimapLayoutInfo {\r\n\t\tconst outerWidth = input.outerWidth;\r\n\t\tconst outerHeight = input.outerHeight;\r\n\t\tconst pixelRatio = input.pixelRatio;\r\n\r\n\t\tif (!input.minimap.enabled) {\r\n\t\t\treturn {\r\n\t\t\t\trenderMinimap: RenderMinimap.None,\r\n\t\t\t\tminimapLeft: 0,\r\n\t\t\t\tminimapWidth: 0,\r\n\t\t\t\tminimapHeightIsEditorHeight: false,\r\n\t\t\t\tminimapIsSampling: false,\r\n\t\t\t\tminimapScale: 1,\r\n\t\t\t\tminimapLineHeight: 1,\r\n\t\t\t\tminimapCanvasInnerWidth: 0,\r\n\t\t\t\tminimapCanvasInnerHeight: Math.floor(pixelRatio * outerHeight),\r\n\t\t\t\tminimapCanvasOuterWidth: 0,\r\n\t\t\t\tminimapCanvasOuterHeight: outerHeight,\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\t// Can use memory if only the `viewLineCount` and `remainingWidth` have changed\r\n\t\tconst stableMinimapLayoutInput = memory.stableMinimapLayoutInput;\r\n\t\tconst couldUseMemory = (\r\n\t\t\tstableMinimapLayoutInput\r\n\t\t\t// && input.outerWidth === lastMinimapLayoutInput.outerWidth !!! INTENTIONAL OMITTED\r\n\t\t\t&& input.outerHeight === stableMinimapLayoutInput.outerHeight\r\n\t\t\t&& input.lineHeight === stableMinimapLayoutInput.lineHeight\r\n\t\t\t&& input.typicalHalfwidthCharacterWidth === stableMinimapLayoutInput.typicalHalfwidthCharacterWidth\r\n\t\t\t&& input.pixelRatio === stableMinimapLayoutInput.pixelRatio\r\n\t\t\t&& input.scrollBeyondLastLine === stableMinimapLayoutInput.scrollBeyondLastLine\r\n\t\t\t&& input.minimap.enabled === stableMinimapLayoutInput.minimap.enabled\r\n\t\t\t&& input.minimap.side === stableMinimapLayoutInput.minimap.side\r\n\t\t\t&& input.minimap.size === stableMinimapLayoutInput.minimap.size\r\n\t\t\t&& input.minimap.showSlider === stableMinimapLayoutInput.minimap.showSlider\r\n\t\t\t&& input.minimap.renderCharacters === stableMinimapLayoutInput.minimap.renderCharacters\r\n\t\t\t&& input.minimap.maxColumn === stableMinimapLayoutInput.minimap.maxColumn\r\n\t\t\t&& input.minimap.scale === stableMinimapLayoutInput.minimap.scale\r\n\t\t\t&& input.verticalScrollbarWidth === stableMinimapLayoutInput.verticalScrollbarWidth\r\n\t\t\t// && input.viewLineCount === lastMinimapLayoutInput.viewLineCount !!! INTENTIONAL OMITTED\r\n\t\t\t// && input.remainingWidth === lastMinimapLayoutInput.remainingWidth !!! INTENTIONAL OMITTED\r\n\t\t\t&& input.isViewportWrapping === stableMinimapLayoutInput.isViewportWrapping\r\n\t\t);\r\n\r\n\t\tconst lineHeight = input.lineHeight;\r\n\t\tconst typicalHalfwidthCharacterWidth = input.typicalHalfwidthCharacterWidth;\r\n\t\tconst scrollBeyondLastLine = input.scrollBeyondLastLine;\r\n\t\tconst minimapRenderCharacters = input.minimap.renderCharacters;\r\n\t\tlet minimapScale = (pixelRatio >= 2 ? Math.round(input.minimap.scale * 2) : input.minimap.scale);\r\n\t\tconst minimapMaxColumn = input.minimap.maxColumn;\r\n\t\tconst minimapSize = input.minimap.size;\r\n\t\tconst minimapSide = input.minimap.side;\r\n\t\tconst verticalScrollbarWidth = input.verticalScrollbarWidth;\r\n\t\tconst viewLineCount = input.viewLineCount;\r\n\t\tconst remainingWidth = input.remainingWidth;\r\n\t\tconst isViewportWrapping = input.isViewportWrapping;\r\n\r\n\t\tconst baseCharHeight = minimapRenderCharacters ? 2 : 3;\r\n\t\tlet minimapCanvasInnerHeight = Math.floor(pixelRatio * outerHeight);\r\n\t\tconst minimapCanvasOuterHeight = minimapCanvasInnerHeight / pixelRatio;\r\n\t\tlet minimapHeightIsEditorHeight = false;\r\n\t\tlet minimapIsSampling = false;\r\n\t\tlet minimapLineHeight = baseCharHeight * minimapScale;\r\n\t\tlet minimapCharWidth = minimapScale / pixelRatio;\r\n\t\tlet minimapWidthMultiplier: number = 1;\r\n\r\n\t\tif (minimapSize === 'fill' || minimapSize === 'fit') {\r\n\t\t\tconst { typicalViewportLineCount, extraLinesBeyondLastLine, desiredRatio, minimapLineCount } = EditorLayoutInfoComputer.computeContainedMinimapLineCount({\r\n\t\t\t\tviewLineCount: viewLineCount,\r\n\t\t\t\tscrollBeyondLastLine: scrollBeyondLastLine,\r\n\t\t\t\theight: outerHeight,\r\n\t\t\t\tlineHeight: lineHeight,\r\n\t\t\t\tpixelRatio: pixelRatio\r\n\t\t\t});\r\n\t\t\t// ratio is intentionally not part of the layout to avoid the layout changing all the time\r\n\t\t\t// when doing sampling\r\n\t\t\tconst ratio = viewLineCount / minimapLineCount;\r\n\r\n\t\t\tif (ratio > 1) {\r\n\t\t\t\tminimapHeightIsEditorHeight = true;\r\n\t\t\t\tminimapIsSampling = true;\r\n\t\t\t\tminimapScale = 1;\r\n\t\t\t\tminimapLineHeight = 1;\r\n\t\t\t\tminimapCharWidth = minimapScale / pixelRatio;\r\n\t\t\t} else {\r\n\t\t\t\tlet fitBecomesFill = false;\r\n\t\t\t\tlet maxMinimapScale = minimapScale + 1;\r\n\r\n\t\t\t\tif (minimapSize === 'fit') {\r\n\t\t\t\t\tconst effectiveMinimapHeight = Math.ceil((viewLineCount + extraLinesBeyondLastLine) * minimapLineHeight);\r\n\t\t\t\t\tif (isViewportWrapping && couldUseMemory && remainingWidth <= memory.stableFitRemainingWidth) {\r\n\t\t\t\t\t\t// There is a loop when using `fit` and viewport wrapping:\r\n\t\t\t\t\t\t// - view line count impacts minimap layout\r\n\t\t\t\t\t\t// - minimap layout impacts viewport width\r\n\t\t\t\t\t\t// - viewport width impacts view line count\r\n\t\t\t\t\t\t// To break the loop, once we go to a smaller minimap scale, we try to stick with it.\r\n\t\t\t\t\t\tfitBecomesFill = true;\r\n\t\t\t\t\t\tmaxMinimapScale = memory.stableFitMaxMinimapScale;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tfitBecomesFill = (effectiveMinimapHeight > minimapCanvasInnerHeight);\r\n\t\t\t\t\t\tif (isViewportWrapping && fitBecomesFill) {\r\n\t\t\t\t\t\t\t// remember for next time\r\n\t\t\t\t\t\t\tmemory.stableMinimapLayoutInput = input;\r\n\t\t\t\t\t\t\tmemory.stableFitRemainingWidth = remainingWidth;\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tmemory.stableMinimapLayoutInput = null;\r\n\t\t\t\t\t\t\tmemory.stableFitRemainingWidth = 0;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (minimapSize === 'fill' || fitBecomesFill) {\r\n\t\t\t\t\tminimapHeightIsEditorHeight = true;\r\n\t\t\t\t\tconst configuredMinimapScale = minimapScale;\r\n\t\t\t\t\tminimapLineHeight = Math.min(lineHeight * pixelRatio, Math.max(1, Math.floor(1 / desiredRatio)));\r\n\t\t\t\t\tminimapScale = Math.min(maxMinimapScale, Math.max(1, Math.floor(minimapLineHeight / baseCharHeight)));\r\n\t\t\t\t\tif (minimapScale > configuredMinimapScale) {\r\n\t\t\t\t\t\tminimapWidthMultiplier = Math.min(2, minimapScale / configuredMinimapScale);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tminimapCharWidth = minimapScale / pixelRatio / minimapWidthMultiplier;\r\n\t\t\t\t\tminimapCanvasInnerHeight = Math.ceil((Math.max(typicalViewportLineCount, viewLineCount + extraLinesBeyondLastLine)) * minimapLineHeight);\r\n\t\t\t\t\tif (isViewportWrapping && fitBecomesFill) {\r\n\t\t\t\t\t\tmemory.stableFitMaxMinimapScale = minimapScale;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Given:\r\n\t\t// (leaving 2px for the cursor to have space after the last character)\r\n\t\t// viewportColumn = (contentWidth - verticalScrollbarWidth - 2) / typicalHalfwidthCharacterWidth\r\n\t\t// minimapWidth = viewportColumn * minimapCharWidth\r\n\t\t// contentWidth = remainingWidth - minimapWidth\r\n\t\t// What are good values for contentWidth and minimapWidth ?\r\n\r\n\t\t// minimapWidth = ((contentWidth - verticalScrollbarWidth - 2) / typicalHalfwidthCharacterWidth) * minimapCharWidth\r\n\t\t// typicalHalfwidthCharacterWidth * minimapWidth = (contentWidth - verticalScrollbarWidth - 2) * minimapCharWidth\r\n\t\t// typicalHalfwidthCharacterWidth * minimapWidth = (remainingWidth - minimapWidth - verticalScrollbarWidth - 2) * minimapCharWidth\r\n\t\t// (typicalHalfwidthCharacterWidth + minimapCharWidth) * minimapWidth = (remainingWidth - verticalScrollbarWidth - 2) * minimapCharWidth\r\n\t\t// minimapWidth = ((remainingWidth - verticalScrollbarWidth - 2) * minimapCharWidth) / (typicalHalfwidthCharacterWidth + minimapCharWidth)\r\n\r\n\t\tconst minimapMaxWidth = Math.floor(minimapMaxColumn * minimapCharWidth);\r\n\t\tconst minimapWidth = Math.min(minimapMaxWidth, Math.max(0, Math.floor(((remainingWidth - verticalScrollbarWidth - 2) * minimapCharWidth) / (typicalHalfwidthCharacterWidth + minimapCharWidth))) + MINIMAP_GUTTER_WIDTH);\r\n\r\n\t\tlet minimapCanvasInnerWidth = Math.floor(pixelRatio * minimapWidth);\r\n\t\tconst minimapCanvasOuterWidth = minimapCanvasInnerWidth / pixelRatio;\r\n\t\tminimapCanvasInnerWidth = Math.floor(minimapCanvasInnerWidth * minimapWidthMultiplier);\r\n\r\n\t\tconst renderMinimap = (minimapRenderCharacters ? RenderMinimap.Text : RenderMinimap.Blocks);\r\n\t\tconst minimapLeft = (minimapSide === 'left' ? 0 : (outerWidth - minimapWidth - verticalScrollbarWidth));\r\n\r\n\t\treturn {\r\n\t\t\trenderMinimap,\r\n\t\t\tminimapLeft,\r\n\t\t\tminimapWidth,\r\n\t\t\tminimapHeightIsEditorHeight,\r\n\t\t\tminimapIsSampling,\r\n\t\t\tminimapScale,\r\n\t\t\tminimapLineHeight,\r\n\t\t\tminimapCanvasInnerWidth,\r\n\t\t\tminimapCanvasInnerHeight,\r\n\t\t\tminimapCanvasOuterWidth,\r\n\t\t\tminimapCanvasOuterHeight,\r\n\t\t};\r\n\t}\r\n\r\n\tpublic static computeLayout(options: IComputedEditorOptions, env: EditorLayoutInfoComputerEnv): EditorLayoutInfo {\r\n\t\tconst outerWidth = env.outerWidth | 0;\r\n\t\tconst outerHeight = env.outerHeight | 0;\r\n\t\tconst lineHeight = env.lineHeight | 0;\r\n\t\tconst lineNumbersDigitCount = env.lineNumbersDigitCount | 0;\r\n\t\tconst typicalHalfwidthCharacterWidth = env.typicalHalfwidthCharacterWidth;\r\n\t\tconst maxDigitWidth = env.maxDigitWidth;\r\n\t\tconst pixelRatio = env.pixelRatio;\r\n\t\tconst viewLineCount = env.viewLineCount;\r\n\r\n\t\tconst wordWrapOverride2 = options.get(EditorOption.wordWrapOverride2);\r\n\t\tconst wordWrapOverride1 = (wordWrapOverride2 === 'inherit' ? options.get(EditorOption.wordWrapOverride1) : wordWrapOverride2);\r\n\t\tconst wordWrap = (wordWrapOverride1 === 'inherit' ? options.get(EditorOption.wordWrap) : wordWrapOverride1);\r\n\r\n\t\tconst wordWrapColumn = options.get(EditorOption.wordWrapColumn);\r\n\t\tconst accessibilitySupport = options.get(EditorOption.accessibilitySupport);\r\n\t\tconst isDominatedByLongLines = env.isDominatedByLongLines;\r\n\r\n\t\tconst showGlyphMargin = options.get(EditorOption.glyphMargin);\r\n\t\tconst showLineNumbers = (options.get(EditorOption.lineNumbers).renderType !== RenderLineNumbersType.Off);\r\n\t\tconst lineNumbersMinChars = options.get(EditorOption.lineNumbersMinChars);\r\n\t\tconst scrollBeyondLastLine = options.get(EditorOption.scrollBeyondLastLine);\r\n\t\tconst minimap = options.get(EditorOption.minimap);\r\n\r\n\t\tconst scrollbar = options.get(EditorOption.scrollbar);\r\n\t\tconst verticalScrollbarWidth = scrollbar.verticalScrollbarSize;\r\n\t\tconst verticalScrollbarHasArrows = scrollbar.verticalHasArrows;\r\n\t\tconst scrollbarArrowSize = scrollbar.arrowSize;\r\n\t\tconst horizontalScrollbarHeight = scrollbar.horizontalScrollbarSize;\r\n\r\n\t\tconst rawLineDecorationsWidth = options.get(EditorOption.lineDecorationsWidth);\r\n\t\tconst folding = options.get(EditorOption.folding);\r\n\r\n\t\tlet lineDecorationsWidth: number;\r\n\t\tif (typeof rawLineDecorationsWidth === 'string' && /^\\d+(\\.\\d+)?ch$/.test(rawLineDecorationsWidth)) {\r\n\t\t\tconst multiple = parseFloat(rawLineDecorationsWidth.substr(0, rawLineDecorationsWidth.length - 2));\r\n\t\t\tlineDecorationsWidth = EditorIntOption.clampedInt(multiple * typicalHalfwidthCharacterWidth, 0, 0, 1000);\r\n\t\t} else {\r\n\t\t\tlineDecorationsWidth = EditorIntOption.clampedInt(rawLineDecorationsWidth, 0, 0, 1000);\r\n\t\t}\r\n\t\tif (folding) {\r\n\t\t\tlineDecorationsWidth += 16;\r\n\t\t}\r\n\r\n\t\tlet lineNumbersWidth = 0;\r\n\t\tif (showLineNumbers) {\r\n\t\t\tconst digitCount = Math.max(lineNumbersDigitCount, lineNumbersMinChars);\r\n\t\t\tlineNumbersWidth = Math.round(digitCount * maxDigitWidth);\r\n\t\t}\r\n\r\n\t\tlet glyphMarginWidth = 0;\r\n\t\tif (showGlyphMargin) {\r\n\t\t\tglyphMarginWidth = lineHeight;\r\n\t\t}\r\n\r\n\t\tlet glyphMarginLeft = 0;\r\n\t\tlet lineNumbersLeft = glyphMarginLeft + glyphMarginWidth;\r\n\t\tlet decorationsLeft = lineNumbersLeft + lineNumbersWidth;\r\n\t\tlet contentLeft = decorationsLeft + lineDecorationsWidth;\r\n\r\n\t\tconst remainingWidth = outerWidth - glyphMarginWidth - lineNumbersWidth - lineDecorationsWidth;\r\n\r\n\t\tlet isWordWrapMinified = false;\r\n\t\tlet isViewportWrapping = false;\r\n\t\tlet wrappingColumn = -1;\r\n\r\n\t\tif (accessibilitySupport !== AccessibilitySupport.Enabled) {\r\n\t\t\t// See https://github.com/microsoft/vscode/issues/27766\r\n\t\t\t// Never enable wrapping when a screen reader is attached\r\n\t\t\t// because arrow down etc. will not move the cursor in the way\r\n\t\t\t// a screen reader expects.\r\n\t\t\tif (wordWrapOverride1 === 'inherit' && isDominatedByLongLines) {\r\n\t\t\t\t// Force viewport width wrapping if model is dominated by long lines\r\n\t\t\t\tisWordWrapMinified = true;\r\n\t\t\t\tisViewportWrapping = true;\r\n\t\t\t} else if (wordWrap === 'on' || wordWrap === 'bounded') {\r\n\t\t\t\tisViewportWrapping = true;\r\n\t\t\t} else if (wordWrap === 'wordWrapColumn') {\r\n\t\t\t\twrappingColumn = wordWrapColumn;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst minimapLayout = EditorLayoutInfoComputer._computeMinimapLayout({\r\n\t\t\touterWidth: outerWidth,\r\n\t\t\touterHeight: outerHeight,\r\n\t\t\tlineHeight: lineHeight,\r\n\t\t\ttypicalHalfwidthCharacterWidth: typicalHalfwidthCharacterWidth,\r\n\t\t\tpixelRatio: pixelRatio,\r\n\t\t\tscrollBeyondLastLine: scrollBeyondLastLine,\r\n\t\t\tminimap: minimap,\r\n\t\t\tverticalScrollbarWidth: verticalScrollbarWidth,\r\n\t\t\tviewLineCount: viewLineCount,\r\n\t\t\tremainingWidth: remainingWidth,\r\n\t\t\tisViewportWrapping: isViewportWrapping,\r\n\t\t}, env.memory || new ComputeOptionsMemory());\r\n\r\n\t\tif (minimapLayout.renderMinimap !== RenderMinimap.None && minimapLayout.minimapLeft === 0) {\r\n\t\t\t// the minimap is rendered to the left, so move everything to the right\r\n\t\t\tglyphMarginLeft += minimapLayout.minimapWidth;\r\n\t\t\tlineNumbersLeft += minimapLayout.minimapWidth;\r\n\t\t\tdecorationsLeft += minimapLayout.minimapWidth;\r\n\t\t\tcontentLeft += minimapLayout.minimapWidth;\r\n\t\t}\r\n\t\tconst contentWidth = remainingWidth - minimapLayout.minimapWidth;\r\n\r\n\t\t// (leaving 2px for the cursor to have space after the last character)\r\n\t\tconst viewportColumn = Math.max(1, Math.floor((contentWidth - verticalScrollbarWidth - 2) / typicalHalfwidthCharacterWidth));\r\n\r\n\t\tconst verticalArrowSize = (verticalScrollbarHasArrows ? scrollbarArrowSize : 0);\r\n\r\n\t\tif (isViewportWrapping) {\r\n\t\t\t// compute the actual wrappingColumn\r\n\t\t\twrappingColumn = Math.max(1, viewportColumn);\r\n\t\t\tif (wordWrap === 'bounded') {\r\n\t\t\t\twrappingColumn = Math.min(wrappingColumn, wordWrapColumn);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\twidth: outerWidth,\r\n\t\t\theight: outerHeight,\r\n\r\n\t\t\tglyphMarginLeft: glyphMarginLeft,\r\n\t\t\tglyphMarginWidth: glyphMarginWidth,\r\n\r\n\t\t\tlineNumbersLeft: lineNumbersLeft,\r\n\t\t\tlineNumbersWidth: lineNumbersWidth,\r\n\r\n\t\t\tdecorationsLeft: decorationsLeft,\r\n\t\t\tdecorationsWidth: lineDecorationsWidth,\r\n\r\n\t\t\tcontentLeft: contentLeft,\r\n\t\t\tcontentWidth: contentWidth,\r\n\r\n\t\t\tminimap: minimapLayout,\r\n\r\n\t\t\tviewportColumn: viewportColumn,\r\n\r\n\t\t\tisWordWrapMinified: isWordWrapMinified,\r\n\t\t\tisViewportWrapping: isViewportWrapping,\r\n\t\t\twrappingColumn: wrappingColumn,\r\n\r\n\t\t\tverticalScrollbarWidth: verticalScrollbarWidth,\r\n\t\t\thorizontalScrollbarHeight: horizontalScrollbarHeight,\r\n\r\n\t\t\toverviewRuler: {\r\n\t\t\t\ttop: verticalArrowSize,\r\n\t\t\t\twidth: verticalScrollbarWidth,\r\n\t\t\t\theight: (outerHeight - 2 * verticalArrowSize),\r\n\t\t\t\tright: 0\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region lightbulb\r\n\r\n/**\r\n * Configuration options for editor lightbulb\r\n */\r\nexport interface IEditorLightbulbOptions {\r\n\t/**\r\n\t * Enable the lightbulb code action.\r\n\t * Defaults to true.\r\n\t */\r\n\tenabled?: boolean;\r\n}\r\n\r\nexport type EditorLightbulbOptions = Readonly>;\r\n\r\nclass EditorLightbulb extends BaseEditorOption {\r\n\r\n\tconstructor() {\r\n\t\tconst defaults: EditorLightbulbOptions = { enabled: true };\r\n\t\tsuper(\r\n\t\t\tEditorOption.lightbulb, 'lightbulb', defaults,\r\n\t\t\t{\r\n\t\t\t\t'editor.lightbulb.enabled': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: defaults.enabled,\r\n\t\t\t\t\tdescription: nls.localize('codeActions', \"Enables the code action lightbulb in the editor.\")\r\n\t\t\t\t},\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n\r\n\tpublic validate(_input: any): EditorLightbulbOptions {\r\n\t\tif (!_input || typeof _input !== 'object') {\r\n\t\t\treturn this.defaultValue;\r\n\t\t}\r\n\t\tconst input = _input as IEditorLightbulbOptions;\r\n\t\treturn {\r\n\t\t\tenabled: boolean(input.enabled, this.defaultValue.enabled)\r\n\t\t};\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region inlineHints\r\n\r\n/**\r\n * Configuration options for editor inlineHints\r\n */\r\nexport interface IEditorInlineHintsOptions {\r\n\t/**\r\n\t * Enable the inline hints.\r\n\t * Defaults to true.\r\n\t */\r\n\tenabled?: boolean;\r\n\r\n\t/**\r\n\t * Font size of inline hints.\r\n\t * Default to 90% of the editor font size.\r\n\t */\r\n\tfontSize?: number;\r\n\r\n\t/**\r\n\t * Font family of inline hints.\r\n\t * Defaults to editor font family.\r\n\t */\r\n\tfontFamily?: string;\r\n}\r\n\r\nexport type EditorInlineHintsOptions = Readonly>;\r\n\r\nclass EditorInlineHints extends BaseEditorOption {\r\n\r\n\tconstructor() {\r\n\t\tconst defaults: EditorInlineHintsOptions = { enabled: true, fontSize: 0, fontFamily: EDITOR_FONT_DEFAULTS.fontFamily };\r\n\t\tsuper(\r\n\t\t\tEditorOption.inlineHints, 'inlineHints', defaults,\r\n\t\t\t{\r\n\t\t\t\t'editor.inlineHints.enabled': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: defaults.enabled,\r\n\t\t\t\t\tdescription: nls.localize('inlineHints.enable', \"Enables the inline hints in the editor.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.inlineHints.fontSize': {\r\n\t\t\t\t\ttype: 'number',\r\n\t\t\t\t\tdefault: defaults.fontSize,\r\n\t\t\t\t\tdescription: nls.localize('inlineHints.fontSize', \"Controls font size of inline hints in the editor. When set to `0`, the 90% of `#editor.fontSize#` is used.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.inlineHints.fontFamily': {\r\n\t\t\t\t\ttype: 'string',\r\n\t\t\t\t\tdefault: defaults.fontFamily,\r\n\t\t\t\t\tdescription: nls.localize('inlineHints.fontFamily', \"Controls font family of inline hints in the editor.\")\r\n\t\t\t\t},\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n\r\n\tpublic validate(_input: any): EditorInlineHintsOptions {\r\n\t\tif (!_input || typeof _input !== 'object') {\r\n\t\t\treturn this.defaultValue;\r\n\t\t}\r\n\t\tconst input = _input as IEditorInlineHintsOptions;\r\n\t\treturn {\r\n\t\t\tenabled: boolean(input.enabled, this.defaultValue.enabled),\r\n\t\t\tfontSize: EditorIntOption.clampedInt(input.fontSize, this.defaultValue.fontSize, 0, 100),\r\n\t\t\tfontFamily: EditorStringOption.string(input.fontFamily, this.defaultValue.fontFamily)\r\n\t\t};\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region lineHeight\r\n\r\nclass EditorLineHeight extends EditorIntOption {\r\n\r\n\tconstructor() {\r\n\t\tsuper(\r\n\t\t\tEditorOption.lineHeight, 'lineHeight',\r\n\t\t\tEDITOR_FONT_DEFAULTS.lineHeight, 0, 150,\r\n\t\t\t{ description: nls.localize('lineHeight', \"Controls the line height. Use 0 to compute the line height from the font size.\") }\r\n\t\t);\r\n\t}\r\n\r\n\tpublic compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: number): number {\r\n\t\t// The lineHeight is computed from the fontSize if it is 0.\r\n\t\t// Moreover, the final lineHeight respects the editor zoom level.\r\n\t\t// So take the result from env.fontInfo\r\n\t\treturn env.fontInfo.lineHeight;\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region minimap\r\n\r\n/**\r\n * Configuration options for editor minimap\r\n */\r\nexport interface IEditorMinimapOptions {\r\n\t/**\r\n\t * Enable the rendering of the minimap.\r\n\t * Defaults to true.\r\n\t */\r\n\tenabled?: boolean;\r\n\t/**\r\n\t * Control the side of the minimap in editor.\r\n\t * Defaults to 'right'.\r\n\t */\r\n\tside?: 'right' | 'left';\r\n\t/**\r\n\t * Control the minimap rendering mode.\r\n\t * Defaults to 'actual'.\r\n\t */\r\n\tsize?: 'proportional' | 'fill' | 'fit';\r\n\t/**\r\n\t * Control the rendering of the minimap slider.\r\n\t * Defaults to 'mouseover'.\r\n\t */\r\n\tshowSlider?: 'always' | 'mouseover';\r\n\t/**\r\n\t * Render the actual text on a line (as opposed to color blocks).\r\n\t * Defaults to true.\r\n\t */\r\n\trenderCharacters?: boolean;\r\n\t/**\r\n\t * Limit the width of the minimap to render at most a certain number of columns.\r\n\t * Defaults to 120.\r\n\t */\r\n\tmaxColumn?: number;\r\n\t/**\r\n\t * Relative size of the font in the minimap. Defaults to 1.\r\n\t */\r\n\tscale?: number;\r\n}\r\n\r\nexport type EditorMinimapOptions = Readonly>;\r\n\r\nclass EditorMinimap extends BaseEditorOption {\r\n\r\n\tconstructor() {\r\n\t\tconst defaults: EditorMinimapOptions = {\r\n\t\t\tenabled: true,\r\n\t\t\tsize: 'proportional',\r\n\t\t\tside: 'right',\r\n\t\t\tshowSlider: 'mouseover',\r\n\t\t\trenderCharacters: true,\r\n\t\t\tmaxColumn: 120,\r\n\t\t\tscale: 1,\r\n\t\t};\r\n\t\tsuper(\r\n\t\t\tEditorOption.minimap, 'minimap', defaults,\r\n\t\t\t{\r\n\t\t\t\t'editor.minimap.enabled': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: defaults.enabled,\r\n\t\t\t\t\tdescription: nls.localize('minimap.enabled', \"Controls whether the minimap is shown.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.minimap.size': {\r\n\t\t\t\t\ttype: 'string',\r\n\t\t\t\t\tenum: ['proportional', 'fill', 'fit'],\r\n\t\t\t\t\tenumDescriptions: [\r\n\t\t\t\t\t\tnls.localize('minimap.size.proportional', \"The minimap has the same size as the editor contents (and might scroll).\"),\r\n\t\t\t\t\t\tnls.localize('minimap.size.fill', \"The minimap will stretch or shrink as necessary to fill the height of the editor (no scrolling).\"),\r\n\t\t\t\t\t\tnls.localize('minimap.size.fit', \"The minimap will shrink as necessary to never be larger than the editor (no scrolling).\"),\r\n\t\t\t\t\t],\r\n\t\t\t\t\tdefault: defaults.size,\r\n\t\t\t\t\tdescription: nls.localize('minimap.size', \"Controls the size of the minimap.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.minimap.side': {\r\n\t\t\t\t\ttype: 'string',\r\n\t\t\t\t\tenum: ['left', 'right'],\r\n\t\t\t\t\tdefault: defaults.side,\r\n\t\t\t\t\tdescription: nls.localize('minimap.side', \"Controls the side where to render the minimap.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.minimap.showSlider': {\r\n\t\t\t\t\ttype: 'string',\r\n\t\t\t\t\tenum: ['always', 'mouseover'],\r\n\t\t\t\t\tdefault: defaults.showSlider,\r\n\t\t\t\t\tdescription: nls.localize('minimap.showSlider', \"Controls when the minimap slider is shown.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.minimap.scale': {\r\n\t\t\t\t\ttype: 'number',\r\n\t\t\t\t\tdefault: defaults.scale,\r\n\t\t\t\t\tminimum: 1,\r\n\t\t\t\t\tmaximum: 3,\r\n\t\t\t\t\tenum: [1, 2, 3],\r\n\t\t\t\t\tdescription: nls.localize('minimap.scale', \"Scale of content drawn in the minimap: 1, 2 or 3.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.minimap.renderCharacters': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: defaults.renderCharacters,\r\n\t\t\t\t\tdescription: nls.localize('minimap.renderCharacters', \"Render the actual characters on a line as opposed to color blocks.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.minimap.maxColumn': {\r\n\t\t\t\t\ttype: 'number',\r\n\t\t\t\t\tdefault: defaults.maxColumn,\r\n\t\t\t\t\tdescription: nls.localize('minimap.maxColumn', \"Limit the width of the minimap to render at most a certain number of columns.\")\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n\r\n\tpublic validate(_input: any): EditorMinimapOptions {\r\n\t\tif (!_input || typeof _input !== 'object') {\r\n\t\t\treturn this.defaultValue;\r\n\t\t}\r\n\t\tconst input = _input as IEditorMinimapOptions;\r\n\t\treturn {\r\n\t\t\tenabled: boolean(input.enabled, this.defaultValue.enabled),\r\n\t\t\tsize: stringSet<'proportional' | 'fill' | 'fit'>(input.size, this.defaultValue.size, ['proportional', 'fill', 'fit']),\r\n\t\t\tside: stringSet<'right' | 'left'>(input.side, this.defaultValue.side, ['right', 'left']),\r\n\t\t\tshowSlider: stringSet<'always' | 'mouseover'>(input.showSlider, this.defaultValue.showSlider, ['always', 'mouseover']),\r\n\t\t\trenderCharacters: boolean(input.renderCharacters, this.defaultValue.renderCharacters),\r\n\t\t\tscale: EditorIntOption.clampedInt(input.scale, 1, 1, 3),\r\n\t\t\tmaxColumn: EditorIntOption.clampedInt(input.maxColumn, this.defaultValue.maxColumn, 1, 10000),\r\n\t\t};\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region multiCursorModifier\r\n\r\nfunction _multiCursorModifierFromString(multiCursorModifier: 'ctrlCmd' | 'alt'): 'altKey' | 'metaKey' | 'ctrlKey' {\r\n\tif (multiCursorModifier === 'ctrlCmd') {\r\n\t\treturn (platform.isMacintosh ? 'metaKey' : 'ctrlKey');\r\n\t}\r\n\treturn 'altKey';\r\n}\r\n\r\n//#endregion\r\n\r\n//#region padding\r\n\r\n/**\r\n * Configuration options for editor padding\r\n */\r\nexport interface IEditorPaddingOptions {\r\n\t/**\r\n\t * Spacing between top edge of editor and first line.\r\n\t */\r\n\ttop?: number;\r\n\t/**\r\n\t * Spacing between bottom edge of editor and last line.\r\n\t */\r\n\tbottom?: number;\r\n}\r\n\r\nexport interface InternalEditorPaddingOptions {\r\n\treadonly top: number;\r\n\treadonly bottom: number;\r\n}\r\n\r\nclass EditorPadding extends BaseEditorOption {\r\n\r\n\tconstructor() {\r\n\t\tsuper(\r\n\t\t\tEditorOption.padding, 'padding', { top: 0, bottom: 0 },\r\n\t\t\t{\r\n\t\t\t\t'editor.padding.top': {\r\n\t\t\t\t\ttype: 'number',\r\n\t\t\t\t\tdefault: 0,\r\n\t\t\t\t\tminimum: 0,\r\n\t\t\t\t\tmaximum: 1000,\r\n\t\t\t\t\tdescription: nls.localize('padding.top', \"Controls the amount of space between the top edge of the editor and the first line.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.padding.bottom': {\r\n\t\t\t\t\ttype: 'number',\r\n\t\t\t\t\tdefault: 0,\r\n\t\t\t\t\tminimum: 0,\r\n\t\t\t\t\tmaximum: 1000,\r\n\t\t\t\t\tdescription: nls.localize('padding.bottom', \"Controls the amount of space between the bottom edge of the editor and the last line.\")\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n\r\n\tpublic validate(_input: any): InternalEditorPaddingOptions {\r\n\t\tif (!_input || typeof _input !== 'object') {\r\n\t\t\treturn this.defaultValue;\r\n\t\t}\r\n\t\tconst input = _input as IEditorPaddingOptions;\r\n\r\n\t\treturn {\r\n\t\t\ttop: EditorIntOption.clampedInt(input.top, 0, 0, 1000),\r\n\t\t\tbottom: EditorIntOption.clampedInt(input.bottom, 0, 0, 1000)\r\n\t\t};\r\n\t}\r\n}\r\n//#endregion\r\n\r\n//#region parameterHints\r\n\r\n/**\r\n * Configuration options for parameter hints\r\n */\r\nexport interface IEditorParameterHintOptions {\r\n\t/**\r\n\t * Enable parameter hints.\r\n\t * Defaults to true.\r\n\t */\r\n\tenabled?: boolean;\r\n\t/**\r\n\t * Enable cycling of parameter hints.\r\n\t * Defaults to false.\r\n\t */\r\n\tcycle?: boolean;\r\n}\r\n\r\nexport type InternalParameterHintOptions = Readonly>;\r\n\r\nclass EditorParameterHints extends BaseEditorOption {\r\n\r\n\tconstructor() {\r\n\t\tconst defaults: InternalParameterHintOptions = {\r\n\t\t\tenabled: true,\r\n\t\t\tcycle: false\r\n\t\t};\r\n\t\tsuper(\r\n\t\t\tEditorOption.parameterHints, 'parameterHints', defaults,\r\n\t\t\t{\r\n\t\t\t\t'editor.parameterHints.enabled': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: defaults.enabled,\r\n\t\t\t\t\tdescription: nls.localize('parameterHints.enabled', \"Enables a pop-up that shows parameter documentation and type information as you type.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.parameterHints.cycle': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: defaults.cycle,\r\n\t\t\t\t\tdescription: nls.localize('parameterHints.cycle', \"Controls whether the parameter hints menu cycles or closes when reaching the end of the list.\")\r\n\t\t\t\t},\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n\r\n\tpublic validate(_input: any): InternalParameterHintOptions {\r\n\t\tif (!_input || typeof _input !== 'object') {\r\n\t\t\treturn this.defaultValue;\r\n\t\t}\r\n\t\tconst input = _input as IEditorParameterHintOptions;\r\n\t\treturn {\r\n\t\t\tenabled: boolean(input.enabled, this.defaultValue.enabled),\r\n\t\t\tcycle: boolean(input.cycle, this.defaultValue.cycle)\r\n\t\t};\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region pixelRatio\r\n\r\nclass EditorPixelRatio extends ComputedEditorOption {\r\n\r\n\tconstructor() {\r\n\t\tsuper(EditorOption.pixelRatio);\r\n\t}\r\n\r\n\tpublic compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: number): number {\r\n\t\treturn env.pixelRatio;\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region quickSuggestions\r\n\r\n/**\r\n * Configuration options for quick suggestions\r\n */\r\nexport interface IQuickSuggestionsOptions {\r\n\tother?: boolean;\r\n\tcomments?: boolean;\r\n\tstrings?: boolean;\r\n}\r\n\r\nexport type ValidQuickSuggestionsOptions = boolean | Readonly>;\r\n\r\nclass EditorQuickSuggestions extends BaseEditorOption {\r\n\r\n\tpublic readonly defaultValue: Readonly>;\r\n\r\n\tconstructor() {\r\n\t\tconst defaults: ValidQuickSuggestionsOptions = {\r\n\t\t\tother: true,\r\n\t\t\tcomments: false,\r\n\t\t\tstrings: false\r\n\t\t};\r\n\t\tsuper(\r\n\t\t\tEditorOption.quickSuggestions, 'quickSuggestions', defaults,\r\n\t\t\t{\r\n\t\t\t\tanyOf: [\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\t},\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\ttype: 'object',\r\n\t\t\t\t\t\tproperties: {\r\n\t\t\t\t\t\t\tstrings: {\r\n\t\t\t\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\t\t\t\tdefault: defaults.strings,\r\n\t\t\t\t\t\t\t\tdescription: nls.localize('quickSuggestions.strings', \"Enable quick suggestions inside strings.\")\r\n\t\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\tcomments: {\r\n\t\t\t\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\t\t\t\tdefault: defaults.comments,\r\n\t\t\t\t\t\t\t\tdescription: nls.localize('quickSuggestions.comments', \"Enable quick suggestions inside comments.\")\r\n\t\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\tother: {\r\n\t\t\t\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\t\t\t\tdefault: defaults.other,\r\n\t\t\t\t\t\t\t\tdescription: nls.localize('quickSuggestions.other', \"Enable quick suggestions outside of strings and comments.\")\r\n\t\t\t\t\t\t\t},\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t],\r\n\t\t\t\tdefault: defaults,\r\n\t\t\t\tdescription: nls.localize('quickSuggestions', \"Controls whether suggestions should automatically show up while typing.\")\r\n\t\t\t}\r\n\t\t);\r\n\t\tthis.defaultValue = defaults;\r\n\t}\r\n\r\n\tpublic validate(_input: any): ValidQuickSuggestionsOptions {\r\n\t\tif (typeof _input === 'boolean') {\r\n\t\t\treturn _input;\r\n\t\t}\r\n\t\tif (_input && typeof _input === 'object') {\r\n\t\t\tconst input = _input as IQuickSuggestionsOptions;\r\n\t\t\tconst opts = {\r\n\t\t\t\tother: boolean(input.other, this.defaultValue.other),\r\n\t\t\t\tcomments: boolean(input.comments, this.defaultValue.comments),\r\n\t\t\t\tstrings: boolean(input.strings, this.defaultValue.strings),\r\n\t\t\t};\r\n\t\t\tif (opts.other && opts.comments && opts.strings) {\r\n\t\t\t\treturn true; // all on\r\n\t\t\t} else if (!opts.other && !opts.comments && !opts.strings) {\r\n\t\t\t\treturn false; // all off\r\n\t\t\t} else {\r\n\t\t\t\treturn opts;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this.defaultValue;\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region renderLineNumbers\r\n\r\nexport type LineNumbersType = 'on' | 'off' | 'relative' | 'interval' | ((lineNumber: number) => string);\r\n\r\nexport const enum RenderLineNumbersType {\r\n\tOff = 0,\r\n\tOn = 1,\r\n\tRelative = 2,\r\n\tInterval = 3,\r\n\tCustom = 4\r\n}\r\n\r\nexport interface InternalEditorRenderLineNumbersOptions {\r\n\treadonly renderType: RenderLineNumbersType;\r\n\treadonly renderFn: ((lineNumber: number) => string) | null;\r\n}\r\n\r\nclass EditorRenderLineNumbersOption extends BaseEditorOption {\r\n\r\n\tconstructor() {\r\n\t\tsuper(\r\n\t\t\tEditorOption.lineNumbers, 'lineNumbers', { renderType: RenderLineNumbersType.On, renderFn: null },\r\n\t\t\t{\r\n\t\t\t\ttype: 'string',\r\n\t\t\t\tenum: ['off', 'on', 'relative', 'interval'],\r\n\t\t\t\tenumDescriptions: [\r\n\t\t\t\t\tnls.localize('lineNumbers.off', \"Line numbers are not rendered.\"),\r\n\t\t\t\t\tnls.localize('lineNumbers.on', \"Line numbers are rendered as absolute number.\"),\r\n\t\t\t\t\tnls.localize('lineNumbers.relative', \"Line numbers are rendered as distance in lines to cursor position.\"),\r\n\t\t\t\t\tnls.localize('lineNumbers.interval', \"Line numbers are rendered every 10 lines.\")\r\n\t\t\t\t],\r\n\t\t\t\tdefault: 'on',\r\n\t\t\t\tdescription: nls.localize('lineNumbers', \"Controls the display of line numbers.\")\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n\r\n\tpublic validate(lineNumbers: any): InternalEditorRenderLineNumbersOptions {\r\n\t\tlet renderType: RenderLineNumbersType = this.defaultValue.renderType;\r\n\t\tlet renderFn: ((lineNumber: number) => string) | null = this.defaultValue.renderFn;\r\n\r\n\t\tif (typeof lineNumbers !== 'undefined') {\r\n\t\t\tif (typeof lineNumbers === 'function') {\r\n\t\t\t\trenderType = RenderLineNumbersType.Custom;\r\n\t\t\t\trenderFn = lineNumbers;\r\n\t\t\t} else if (lineNumbers === 'interval') {\r\n\t\t\t\trenderType = RenderLineNumbersType.Interval;\r\n\t\t\t} else if (lineNumbers === 'relative') {\r\n\t\t\t\trenderType = RenderLineNumbersType.Relative;\r\n\t\t\t} else if (lineNumbers === 'on') {\r\n\t\t\t\trenderType = RenderLineNumbersType.On;\r\n\t\t\t} else {\r\n\t\t\t\trenderType = RenderLineNumbersType.Off;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\trenderType,\r\n\t\t\trenderFn\r\n\t\t};\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region renderValidationDecorations\r\n\r\n/**\r\n * @internal\r\n */\r\nexport function filterValidationDecorations(options: IComputedEditorOptions): boolean {\r\n\tconst renderValidationDecorations = options.get(EditorOption.renderValidationDecorations);\r\n\tif (renderValidationDecorations === 'editable') {\r\n\t\treturn options.get(EditorOption.readOnly);\r\n\t}\r\n\treturn renderValidationDecorations === 'on' ? false : true;\r\n}\r\n\r\n//#endregion\r\n\r\n//#region rulers\r\n\r\nexport interface IRulerOption {\r\n\treadonly column: number;\r\n\treadonly color: string | null;\r\n}\r\n\r\nclass EditorRulers extends BaseEditorOption {\r\n\r\n\tconstructor() {\r\n\t\tconst defaults: IRulerOption[] = [];\r\n\t\tconst columnSchema: IJSONSchema = { type: 'number', description: nls.localize('rulers.size', \"Number of monospace characters at which this editor ruler will render.\") };\r\n\t\tsuper(\r\n\t\t\tEditorOption.rulers, 'rulers', defaults,\r\n\t\t\t{\r\n\t\t\t\ttype: 'array',\r\n\t\t\t\titems: {\r\n\t\t\t\t\tanyOf: [\r\n\t\t\t\t\t\tcolumnSchema,\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\ttype: [\r\n\t\t\t\t\t\t\t\t'object'\r\n\t\t\t\t\t\t\t],\r\n\t\t\t\t\t\t\tproperties: {\r\n\t\t\t\t\t\t\t\tcolumn: columnSchema,\r\n\t\t\t\t\t\t\t\tcolor: {\r\n\t\t\t\t\t\t\t\t\ttype: 'string',\r\n\t\t\t\t\t\t\t\t\tdescription: nls.localize('rulers.color', \"Color of this editor ruler.\"),\r\n\t\t\t\t\t\t\t\t\tformat: 'color-hex'\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\tdefault: defaults,\r\n\t\t\t\tdescription: nls.localize('rulers', \"Render vertical rulers after a certain number of monospace characters. Use multiple values for multiple rulers. No rulers are drawn if array is empty.\")\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n\r\n\tpublic validate(input: any): IRulerOption[] {\r\n\t\tif (Array.isArray(input)) {\r\n\t\t\tlet rulers: IRulerOption[] = [];\r\n\t\t\tfor (let _element of input) {\r\n\t\t\t\tif (typeof _element === 'number') {\r\n\t\t\t\t\trulers.push({\r\n\t\t\t\t\t\tcolumn: EditorIntOption.clampedInt(_element, 0, 0, 10000),\r\n\t\t\t\t\t\tcolor: null\r\n\t\t\t\t\t});\r\n\t\t\t\t} else if (_element && typeof _element === 'object') {\r\n\t\t\t\t\tconst element = _element as IRulerOption;\r\n\t\t\t\t\trulers.push({\r\n\t\t\t\t\t\tcolumn: EditorIntOption.clampedInt(element.column, 0, 0, 10000),\r\n\t\t\t\t\t\tcolor: element.color\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\trulers.sort((a, b) => a.column - b.column);\r\n\t\t\treturn rulers;\r\n\t\t}\r\n\t\treturn this.defaultValue;\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region scrollbar\r\n\r\n/**\r\n * Configuration options for editor scrollbars\r\n */\r\nexport interface IEditorScrollbarOptions {\r\n\t/**\r\n\t * The size of arrows (if displayed).\r\n\t * Defaults to 11.\r\n\t */\r\n\tarrowSize?: number;\r\n\t/**\r\n\t * Render vertical scrollbar.\r\n\t * Defaults to 'auto'.\r\n\t */\r\n\tvertical?: 'auto' | 'visible' | 'hidden';\r\n\t/**\r\n\t * Render horizontal scrollbar.\r\n\t * Defaults to 'auto'.\r\n\t */\r\n\thorizontal?: 'auto' | 'visible' | 'hidden';\r\n\t/**\r\n\t * Cast horizontal and vertical shadows when the content is scrolled.\r\n\t * Defaults to true.\r\n\t */\r\n\tuseShadows?: boolean;\r\n\t/**\r\n\t * Render arrows at the top and bottom of the vertical scrollbar.\r\n\t * Defaults to false.\r\n\t */\r\n\tverticalHasArrows?: boolean;\r\n\t/**\r\n\t * Render arrows at the left and right of the horizontal scrollbar.\r\n\t * Defaults to false.\r\n\t */\r\n\thorizontalHasArrows?: boolean;\r\n\t/**\r\n\t * Listen to mouse wheel events and react to them by scrolling.\r\n\t * Defaults to true.\r\n\t */\r\n\thandleMouseWheel?: boolean;\r\n\t/**\r\n\t * Always consume mouse wheel events (always call preventDefault() and stopPropagation() on the browser events).\r\n\t * Defaults to true.\r\n\t */\r\n\talwaysConsumeMouseWheel?: boolean;\r\n\t/**\r\n\t * Height in pixels for the horizontal scrollbar.\r\n\t * Defaults to 10 (px).\r\n\t */\r\n\thorizontalScrollbarSize?: number;\r\n\t/**\r\n\t * Width in pixels for the vertical scrollbar.\r\n\t * Defaults to 10 (px).\r\n\t */\r\n\tverticalScrollbarSize?: number;\r\n\t/**\r\n\t * Width in pixels for the vertical slider.\r\n\t * Defaults to `verticalScrollbarSize`.\r\n\t */\r\n\tverticalSliderSize?: number;\r\n\t/**\r\n\t * Height in pixels for the horizontal slider.\r\n\t * Defaults to `horizontalScrollbarSize`.\r\n\t */\r\n\thorizontalSliderSize?: number;\r\n\t/**\r\n\t * Scroll gutter clicks move by page vs jump to position.\r\n\t * Defaults to false.\r\n\t */\r\n\tscrollByPage?: boolean;\r\n}\r\n\r\nexport interface InternalEditorScrollbarOptions {\r\n\treadonly arrowSize: number;\r\n\treadonly vertical: ScrollbarVisibility;\r\n\treadonly horizontal: ScrollbarVisibility;\r\n\treadonly useShadows: boolean;\r\n\treadonly verticalHasArrows: boolean;\r\n\treadonly horizontalHasArrows: boolean;\r\n\treadonly handleMouseWheel: boolean;\r\n\treadonly alwaysConsumeMouseWheel: boolean;\r\n\treadonly horizontalScrollbarSize: number;\r\n\treadonly horizontalSliderSize: number;\r\n\treadonly verticalScrollbarSize: number;\r\n\treadonly verticalSliderSize: number;\r\n\treadonly scrollByPage: boolean;\r\n}\r\n\r\nfunction _scrollbarVisibilityFromString(visibility: string | undefined, defaultValue: ScrollbarVisibility): ScrollbarVisibility {\r\n\tif (typeof visibility !== 'string') {\r\n\t\treturn defaultValue;\r\n\t}\r\n\tswitch (visibility) {\r\n\t\tcase 'hidden': return ScrollbarVisibility.Hidden;\r\n\t\tcase 'visible': return ScrollbarVisibility.Visible;\r\n\t\tdefault: return ScrollbarVisibility.Auto;\r\n\t}\r\n}\r\n\r\nclass EditorScrollbar extends BaseEditorOption {\r\n\r\n\tconstructor() {\r\n\t\tsuper(\r\n\t\t\tEditorOption.scrollbar, 'scrollbar',\r\n\t\t\t{\r\n\t\t\t\tvertical: ScrollbarVisibility.Auto,\r\n\t\t\t\thorizontal: ScrollbarVisibility.Auto,\r\n\t\t\t\tarrowSize: 11,\r\n\t\t\t\tuseShadows: true,\r\n\t\t\t\tverticalHasArrows: false,\r\n\t\t\t\thorizontalHasArrows: false,\r\n\t\t\t\thorizontalScrollbarSize: 12,\r\n\t\t\t\thorizontalSliderSize: 12,\r\n\t\t\t\tverticalScrollbarSize: 14,\r\n\t\t\t\tverticalSliderSize: 14,\r\n\t\t\t\thandleMouseWheel: true,\r\n\t\t\t\talwaysConsumeMouseWheel: true,\r\n\t\t\t\tscrollByPage: false\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n\r\n\tpublic validate(_input: any): InternalEditorScrollbarOptions {\r\n\t\tif (!_input || typeof _input !== 'object') {\r\n\t\t\treturn this.defaultValue;\r\n\t\t}\r\n\t\tconst input = _input as IEditorScrollbarOptions;\r\n\t\tconst horizontalScrollbarSize = EditorIntOption.clampedInt(input.horizontalScrollbarSize, this.defaultValue.horizontalScrollbarSize, 0, 1000);\r\n\t\tconst verticalScrollbarSize = EditorIntOption.clampedInt(input.verticalScrollbarSize, this.defaultValue.verticalScrollbarSize, 0, 1000);\r\n\t\treturn {\r\n\t\t\tarrowSize: EditorIntOption.clampedInt(input.arrowSize, this.defaultValue.arrowSize, 0, 1000),\r\n\t\t\tvertical: _scrollbarVisibilityFromString(input.vertical, this.defaultValue.vertical),\r\n\t\t\thorizontal: _scrollbarVisibilityFromString(input.horizontal, this.defaultValue.horizontal),\r\n\t\t\tuseShadows: boolean(input.useShadows, this.defaultValue.useShadows),\r\n\t\t\tverticalHasArrows: boolean(input.verticalHasArrows, this.defaultValue.verticalHasArrows),\r\n\t\t\thorizontalHasArrows: boolean(input.horizontalHasArrows, this.defaultValue.horizontalHasArrows),\r\n\t\t\thandleMouseWheel: boolean(input.handleMouseWheel, this.defaultValue.handleMouseWheel),\r\n\t\t\talwaysConsumeMouseWheel: boolean(input.alwaysConsumeMouseWheel, this.defaultValue.alwaysConsumeMouseWheel),\r\n\t\t\thorizontalScrollbarSize: horizontalScrollbarSize,\r\n\t\t\thorizontalSliderSize: EditorIntOption.clampedInt(input.horizontalSliderSize, horizontalScrollbarSize, 0, 1000),\r\n\t\t\tverticalScrollbarSize: verticalScrollbarSize,\r\n\t\t\tverticalSliderSize: EditorIntOption.clampedInt(input.verticalSliderSize, verticalScrollbarSize, 0, 1000),\r\n\t\t\tscrollByPage: boolean(input.scrollByPage, this.defaultValue.scrollByPage),\r\n\t\t};\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region suggest\r\n\r\n/**\r\n * Configuration options for editor suggest widget\r\n */\r\nexport interface ISuggestOptions {\r\n\t/**\r\n\t * Overwrite word ends on accept. Default to false.\r\n\t */\r\n\tinsertMode?: 'insert' | 'replace';\r\n\t/**\r\n\t * Enable graceful matching. Defaults to true.\r\n\t */\r\n\tfilterGraceful?: boolean;\r\n\t/**\r\n\t * Prevent quick suggestions when a snippet is active. Defaults to true.\r\n\t */\r\n\tsnippetsPreventQuickSuggestions?: boolean;\r\n\t/**\r\n\t * Favours words that appear close to the cursor.\r\n\t */\r\n\tlocalityBonus?: boolean;\r\n\t/**\r\n\t * Enable using global storage for remembering suggestions.\r\n\t */\r\n\tshareSuggestSelections?: boolean;\r\n\t/**\r\n\t * Enable or disable icons in suggestions. Defaults to true.\r\n\t */\r\n\tshowIcons?: boolean;\r\n\t/**\r\n\t * Enable or disable the suggest status bar.\r\n\t */\r\n\tshowStatusBar?: boolean;\r\n\t/**\r\n\t * Show details inline with the label. Defaults to true.\r\n\t */\r\n\tshowInlineDetails?: boolean;\r\n\t/**\r\n\t * Show method-suggestions.\r\n\t */\r\n\tshowMethods?: boolean;\r\n\t/**\r\n\t * Show function-suggestions.\r\n\t */\r\n\tshowFunctions?: boolean;\r\n\t/**\r\n\t * Show constructor-suggestions.\r\n\t */\r\n\tshowConstructors?: boolean;\r\n\t/**\r\n\t * Show field-suggestions.\r\n\t */\r\n\tshowFields?: boolean;\r\n\t/**\r\n\t * Show variable-suggestions.\r\n\t */\r\n\tshowVariables?: boolean;\r\n\t/**\r\n\t * Show class-suggestions.\r\n\t */\r\n\tshowClasses?: boolean;\r\n\t/**\r\n\t * Show struct-suggestions.\r\n\t */\r\n\tshowStructs?: boolean;\r\n\t/**\r\n\t * Show interface-suggestions.\r\n\t */\r\n\tshowInterfaces?: boolean;\r\n\t/**\r\n\t * Show module-suggestions.\r\n\t */\r\n\tshowModules?: boolean;\r\n\t/**\r\n\t * Show property-suggestions.\r\n\t */\r\n\tshowProperties?: boolean;\r\n\t/**\r\n\t * Show event-suggestions.\r\n\t */\r\n\tshowEvents?: boolean;\r\n\t/**\r\n\t * Show operator-suggestions.\r\n\t */\r\n\tshowOperators?: boolean;\r\n\t/**\r\n\t * Show unit-suggestions.\r\n\t */\r\n\tshowUnits?: boolean;\r\n\t/**\r\n\t * Show value-suggestions.\r\n\t */\r\n\tshowValues?: boolean;\r\n\t/**\r\n\t * Show constant-suggestions.\r\n\t */\r\n\tshowConstants?: boolean;\r\n\t/**\r\n\t * Show enum-suggestions.\r\n\t */\r\n\tshowEnums?: boolean;\r\n\t/**\r\n\t * Show enumMember-suggestions.\r\n\t */\r\n\tshowEnumMembers?: boolean;\r\n\t/**\r\n\t * Show keyword-suggestions.\r\n\t */\r\n\tshowKeywords?: boolean;\r\n\t/**\r\n\t * Show text-suggestions.\r\n\t */\r\n\tshowWords?: boolean;\r\n\t/**\r\n\t * Show color-suggestions.\r\n\t */\r\n\tshowColors?: boolean;\r\n\t/**\r\n\t * Show file-suggestions.\r\n\t */\r\n\tshowFiles?: boolean;\r\n\t/**\r\n\t * Show reference-suggestions.\r\n\t */\r\n\tshowReferences?: boolean;\r\n\t/**\r\n\t * Show folder-suggestions.\r\n\t */\r\n\tshowFolders?: boolean;\r\n\t/**\r\n\t * Show typeParameter-suggestions.\r\n\t */\r\n\tshowTypeParameters?: boolean;\r\n\t/**\r\n\t * Show issue-suggestions.\r\n\t */\r\n\tshowIssues?: boolean;\r\n\t/**\r\n\t * Show user-suggestions.\r\n\t */\r\n\tshowUsers?: boolean;\r\n\t/**\r\n\t * Show snippet-suggestions.\r\n\t */\r\n\tshowSnippets?: boolean;\r\n}\r\n\r\nexport type InternalSuggestOptions = Readonly>;\r\n\r\nclass EditorSuggest extends BaseEditorOption {\r\n\r\n\tconstructor() {\r\n\t\tconst defaults: InternalSuggestOptions = {\r\n\t\t\tinsertMode: 'insert',\r\n\t\t\tfilterGraceful: true,\r\n\t\t\tsnippetsPreventQuickSuggestions: true,\r\n\t\t\tlocalityBonus: false,\r\n\t\t\tshareSuggestSelections: false,\r\n\t\t\tshowIcons: true,\r\n\t\t\tshowStatusBar: false,\r\n\t\t\tshowInlineDetails: true,\r\n\t\t\tshowMethods: true,\r\n\t\t\tshowFunctions: true,\r\n\t\t\tshowConstructors: true,\r\n\t\t\tshowFields: true,\r\n\t\t\tshowVariables: true,\r\n\t\t\tshowClasses: true,\r\n\t\t\tshowStructs: true,\r\n\t\t\tshowInterfaces: true,\r\n\t\t\tshowModules: true,\r\n\t\t\tshowProperties: true,\r\n\t\t\tshowEvents: true,\r\n\t\t\tshowOperators: true,\r\n\t\t\tshowUnits: true,\r\n\t\t\tshowValues: true,\r\n\t\t\tshowConstants: true,\r\n\t\t\tshowEnums: true,\r\n\t\t\tshowEnumMembers: true,\r\n\t\t\tshowKeywords: true,\r\n\t\t\tshowWords: true,\r\n\t\t\tshowColors: true,\r\n\t\t\tshowFiles: true,\r\n\t\t\tshowReferences: true,\r\n\t\t\tshowFolders: true,\r\n\t\t\tshowTypeParameters: true,\r\n\t\t\tshowSnippets: true,\r\n\t\t\tshowUsers: true,\r\n\t\t\tshowIssues: true,\r\n\t\t};\r\n\t\tsuper(\r\n\t\t\tEditorOption.suggest, 'suggest', defaults,\r\n\t\t\t{\r\n\t\t\t\t'editor.suggest.insertMode': {\r\n\t\t\t\t\ttype: 'string',\r\n\t\t\t\t\tenum: ['insert', 'replace'],\r\n\t\t\t\t\tenumDescriptions: [\r\n\t\t\t\t\t\tnls.localize('suggest.insertMode.insert', \"Insert suggestion without overwriting text right of the cursor.\"),\r\n\t\t\t\t\t\tnls.localize('suggest.insertMode.replace', \"Insert suggestion and overwrite text right of the cursor.\"),\r\n\t\t\t\t\t],\r\n\t\t\t\t\tdefault: defaults.insertMode,\r\n\t\t\t\t\tdescription: nls.localize('suggest.insertMode', \"Controls whether words are overwritten when accepting completions. Note that this depends on extensions opting into this feature.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.filterGraceful': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: defaults.filterGraceful,\r\n\t\t\t\t\tdescription: nls.localize('suggest.filterGraceful', \"Controls whether filtering and sorting suggestions accounts for small typos.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.localityBonus': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: defaults.localityBonus,\r\n\t\t\t\t\tdescription: nls.localize('suggest.localityBonus', \"Controls whether sorting favours words that appear close to the cursor.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.shareSuggestSelections': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: defaults.shareSuggestSelections,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('suggest.shareSuggestSelections', \"Controls whether remembered suggestion selections are shared between multiple workspaces and windows (needs `#editor.suggestSelection#`).\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.snippetsPreventQuickSuggestions': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: defaults.snippetsPreventQuickSuggestions,\r\n\t\t\t\t\tdescription: nls.localize('suggest.snippetsPreventQuickSuggestions', \"Controls whether an active snippet prevents quick suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showIcons': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: defaults.showIcons,\r\n\t\t\t\t\tdescription: nls.localize('suggest.showIcons', \"Controls whether to show or hide icons in suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showStatusBar': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: defaults.showStatusBar,\r\n\t\t\t\t\tdescription: nls.localize('suggest.showStatusBar', \"Controls the visibility of the status bar at the bottom of the suggest widget.\")\r\n\t\t\t\t},\r\n\r\n\t\t\t\t'editor.suggest.showInlineDetails': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: defaults.showInlineDetails,\r\n\t\t\t\t\tdescription: nls.localize('suggest.showInlineDetails', \"Controls whether suggest details show inline with the label or only in the details widget\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.maxVisibleSuggestions': {\r\n\t\t\t\t\ttype: 'number',\r\n\t\t\t\t\tdeprecationMessage: nls.localize('suggest.maxVisibleSuggestions.dep', \"This setting is deprecated. The suggest widget can now be resized.\"),\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.filteredTypes': {\r\n\t\t\t\t\ttype: 'object',\r\n\t\t\t\t\tdeprecationMessage: nls.localize('deprecated', \"This setting is deprecated, please use separate settings like 'editor.suggest.showKeywords' or 'editor.suggest.showSnippets' instead.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showMethods': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showMethods', \"When enabled IntelliSense shows `method`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showFunctions': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showFunctions', \"When enabled IntelliSense shows `function`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showConstructors': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showConstructors', \"When enabled IntelliSense shows `constructor`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showFields': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showFields', \"When enabled IntelliSense shows `field`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showVariables': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showVariables', \"When enabled IntelliSense shows `variable`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showClasses': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showClasss', \"When enabled IntelliSense shows `class`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showStructs': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showStructs', \"When enabled IntelliSense shows `struct`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showInterfaces': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showInterfaces', \"When enabled IntelliSense shows `interface`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showModules': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showModules', \"When enabled IntelliSense shows `module`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showProperties': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showPropertys', \"When enabled IntelliSense shows `property`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showEvents': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showEvents', \"When enabled IntelliSense shows `event`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showOperators': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showOperators', \"When enabled IntelliSense shows `operator`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showUnits': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showUnits', \"When enabled IntelliSense shows `unit`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showValues': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showValues', \"When enabled IntelliSense shows `value`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showConstants': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showConstants', \"When enabled IntelliSense shows `constant`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showEnums': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showEnums', \"When enabled IntelliSense shows `enum`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showEnumMembers': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showEnumMembers', \"When enabled IntelliSense shows `enumMember`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showKeywords': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showKeywords', \"When enabled IntelliSense shows `keyword`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showWords': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showTexts', \"When enabled IntelliSense shows `text`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showColors': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showColors', \"When enabled IntelliSense shows `color`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showFiles': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showFiles', \"When enabled IntelliSense shows `file`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showReferences': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showReferences', \"When enabled IntelliSense shows `reference`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showCustomcolors': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showCustomcolors', \"When enabled IntelliSense shows `customcolor`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showFolders': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showFolders', \"When enabled IntelliSense shows `folder`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showTypeParameters': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showTypeParameters', \"When enabled IntelliSense shows `typeParameter`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showSnippets': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showSnippets', \"When enabled IntelliSense shows `snippet`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showUsers': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showUsers', \"When enabled IntelliSense shows `user`-suggestions.\")\r\n\t\t\t\t},\r\n\t\t\t\t'editor.suggest.showIssues': {\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showIssues', \"When enabled IntelliSense shows `issues`-suggestions.\")\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n\r\n\tpublic validate(_input: any): InternalSuggestOptions {\r\n\t\tif (!_input || typeof _input !== 'object') {\r\n\t\t\treturn this.defaultValue;\r\n\t\t}\r\n\t\tconst input = _input as ISuggestOptions;\r\n\t\treturn {\r\n\t\t\tinsertMode: stringSet(input.insertMode, this.defaultValue.insertMode, ['insert', 'replace']),\r\n\t\t\tfilterGraceful: boolean(input.filterGraceful, this.defaultValue.filterGraceful),\r\n\t\t\tsnippetsPreventQuickSuggestions: boolean(input.snippetsPreventQuickSuggestions, this.defaultValue.filterGraceful),\r\n\t\t\tlocalityBonus: boolean(input.localityBonus, this.defaultValue.localityBonus),\r\n\t\t\tshareSuggestSelections: boolean(input.shareSuggestSelections, this.defaultValue.shareSuggestSelections),\r\n\t\t\tshowIcons: boolean(input.showIcons, this.defaultValue.showIcons),\r\n\t\t\tshowStatusBar: boolean(input.showStatusBar, this.defaultValue.showStatusBar),\r\n\t\t\tshowInlineDetails: boolean(input.showInlineDetails, this.defaultValue.showInlineDetails),\r\n\t\t\tshowMethods: boolean(input.showMethods, this.defaultValue.showMethods),\r\n\t\t\tshowFunctions: boolean(input.showFunctions, this.defaultValue.showFunctions),\r\n\t\t\tshowConstructors: boolean(input.showConstructors, this.defaultValue.showConstructors),\r\n\t\t\tshowFields: boolean(input.showFields, this.defaultValue.showFields),\r\n\t\t\tshowVariables: boolean(input.showVariables, this.defaultValue.showVariables),\r\n\t\t\tshowClasses: boolean(input.showClasses, this.defaultValue.showClasses),\r\n\t\t\tshowStructs: boolean(input.showStructs, this.defaultValue.showStructs),\r\n\t\t\tshowInterfaces: boolean(input.showInterfaces, this.defaultValue.showInterfaces),\r\n\t\t\tshowModules: boolean(input.showModules, this.defaultValue.showModules),\r\n\t\t\tshowProperties: boolean(input.showProperties, this.defaultValue.showProperties),\r\n\t\t\tshowEvents: boolean(input.showEvents, this.defaultValue.showEvents),\r\n\t\t\tshowOperators: boolean(input.showOperators, this.defaultValue.showOperators),\r\n\t\t\tshowUnits: boolean(input.showUnits, this.defaultValue.showUnits),\r\n\t\t\tshowValues: boolean(input.showValues, this.defaultValue.showValues),\r\n\t\t\tshowConstants: boolean(input.showConstants, this.defaultValue.showConstants),\r\n\t\t\tshowEnums: boolean(input.showEnums, this.defaultValue.showEnums),\r\n\t\t\tshowEnumMembers: boolean(input.showEnumMembers, this.defaultValue.showEnumMembers),\r\n\t\t\tshowKeywords: boolean(input.showKeywords, this.defaultValue.showKeywords),\r\n\t\t\tshowWords: boolean(input.showWords, this.defaultValue.showWords),\r\n\t\t\tshowColors: boolean(input.showColors, this.defaultValue.showColors),\r\n\t\t\tshowFiles: boolean(input.showFiles, this.defaultValue.showFiles),\r\n\t\t\tshowReferences: boolean(input.showReferences, this.defaultValue.showReferences),\r\n\t\t\tshowFolders: boolean(input.showFolders, this.defaultValue.showFolders),\r\n\t\t\tshowTypeParameters: boolean(input.showTypeParameters, this.defaultValue.showTypeParameters),\r\n\t\t\tshowSnippets: boolean(input.showSnippets, this.defaultValue.showSnippets),\r\n\t\t\tshowUsers: boolean(input.showUsers, this.defaultValue.showUsers),\r\n\t\t\tshowIssues: boolean(input.showIssues, this.defaultValue.showIssues),\r\n\t\t};\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region smart select\r\n\r\nexport interface ISmartSelectOptions {\r\n\tselectLeadingAndTrailingWhitespace?: boolean\r\n}\r\n\r\nexport type SmartSelectOptions = Readonly>;\r\n\r\nclass SmartSelect extends BaseEditorOption {\r\n\r\n\tconstructor() {\r\n\t\tsuper(\r\n\t\t\tEditorOption.smartSelect, 'smartSelect',\r\n\t\t\t{\r\n\t\t\t\tselectLeadingAndTrailingWhitespace: true\r\n\t\t\t},\r\n\t\t\t{\r\n\t\t\t\t'editor.smartSelect.selectLeadingAndTrailingWhitespace': {\r\n\t\t\t\t\tdescription: nls.localize('selectLeadingAndTrailingWhitespace', \"Whether leading and trailing whitespace should always be selected.\"),\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\ttype: 'boolean'\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n\r\n\tpublic validate(input: any): Readonly> {\r\n\t\tif (!input || typeof input !== 'object') {\r\n\t\t\treturn this.defaultValue;\r\n\t\t}\r\n\t\treturn {\r\n\t\t\tselectLeadingAndTrailingWhitespace: boolean((input as ISmartSelectOptions).selectLeadingAndTrailingWhitespace, this.defaultValue.selectLeadingAndTrailingWhitespace)\r\n\t\t};\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region tabFocusMode\r\n\r\nclass EditorTabFocusMode extends ComputedEditorOption {\r\n\r\n\tconstructor() {\r\n\t\tsuper(EditorOption.tabFocusMode, [EditorOption.readOnly]);\r\n\t}\r\n\r\n\tpublic compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: boolean): boolean {\r\n\t\tconst readOnly = options.get(EditorOption.readOnly);\r\n\t\treturn (readOnly ? true : env.tabFocusMode);\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region wrappingIndent\r\n\r\n/**\r\n * Describes how to indent wrapped lines.\r\n */\r\nexport const enum WrappingIndent {\r\n\t/**\r\n\t * No indentation => wrapped lines begin at column 1.\r\n\t */\r\n\tNone = 0,\r\n\t/**\r\n\t * Same => wrapped lines get the same indentation as the parent.\r\n\t */\r\n\tSame = 1,\r\n\t/**\r\n\t * Indent => wrapped lines get +1 indentation toward the parent.\r\n\t */\r\n\tIndent = 2,\r\n\t/**\r\n\t * DeepIndent => wrapped lines get +2 indentation toward the parent.\r\n\t */\r\n\tDeepIndent = 3\r\n}\r\n\r\nfunction _wrappingIndentFromString(wrappingIndent: 'none' | 'same' | 'indent' | 'deepIndent'): WrappingIndent {\r\n\tswitch (wrappingIndent) {\r\n\t\tcase 'none': return WrappingIndent.None;\r\n\t\tcase 'same': return WrappingIndent.Same;\r\n\t\tcase 'indent': return WrappingIndent.Indent;\r\n\t\tcase 'deepIndent': return WrappingIndent.DeepIndent;\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region wrappingInfo\r\n\r\nexport interface EditorWrappingInfo {\r\n\treadonly isDominatedByLongLines: boolean;\r\n\treadonly isWordWrapMinified: boolean;\r\n\treadonly isViewportWrapping: boolean;\r\n\treadonly wrappingColumn: number;\r\n}\r\n\r\nclass EditorWrappingInfoComputer extends ComputedEditorOption {\r\n\r\n\tconstructor() {\r\n\t\tsuper(EditorOption.wrappingInfo, [EditorOption.layoutInfo]);\r\n\t}\r\n\r\n\tpublic compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: EditorWrappingInfo): EditorWrappingInfo {\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\r\n\t\treturn {\r\n\t\t\tisDominatedByLongLines: env.isDominatedByLongLines,\r\n\t\t\tisWordWrapMinified: layoutInfo.isWordWrapMinified,\r\n\t\t\tisViewportWrapping: layoutInfo.isViewportWrapping,\r\n\t\t\twrappingColumn: layoutInfo.wrappingColumn,\r\n\t\t};\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\nconst DEFAULT_WINDOWS_FONT_FAMILY = 'Consolas, \\'Courier New\\', monospace';\r\nconst DEFAULT_MAC_FONT_FAMILY = 'Menlo, Monaco, \\'Courier New\\', monospace';\r\nconst DEFAULT_LINUX_FONT_FAMILY = '\\'Droid Sans Mono\\', \\'monospace\\', monospace, \\'Droid Sans Fallback\\'';\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const EDITOR_FONT_DEFAULTS = {\r\n\tfontFamily: (\r\n\t\tplatform.isMacintosh ? DEFAULT_MAC_FONT_FAMILY : (platform.isLinux ? DEFAULT_LINUX_FONT_FAMILY : DEFAULT_WINDOWS_FONT_FAMILY)\r\n\t),\r\n\tfontWeight: 'normal',\r\n\tfontSize: (\r\n\t\tplatform.isMacintosh ? 12 : 14\r\n\t),\r\n\tlineHeight: 0,\r\n\tletterSpacing: 0,\r\n};\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const EDITOR_MODEL_DEFAULTS = {\r\n\ttabSize: 4,\r\n\tindentSize: 4,\r\n\tinsertSpaces: true,\r\n\tdetectIndentation: true,\r\n\ttrimAutoWhitespace: true,\r\n\tlargeFileOptimizations: true\r\n};\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const editorOptionsRegistry: IEditorOption[] = [];\r\n\r\nfunction register(option: IEditorOption): IEditorOption {\r\n\teditorOptionsRegistry[option.id] = option;\r\n\treturn option;\r\n}\r\n\r\nexport const enum EditorOption {\r\n\tacceptSuggestionOnCommitCharacter,\r\n\tacceptSuggestionOnEnter,\r\n\taccessibilitySupport,\r\n\taccessibilityPageSize,\r\n\tariaLabel,\r\n\tautoClosingBrackets,\r\n\tautoClosingOvertype,\r\n\tautoClosingQuotes,\r\n\tautoIndent,\r\n\tautomaticLayout,\r\n\tautoSurround,\r\n\tcodeLens,\r\n\tcodeLensFontFamily,\r\n\tcodeLensFontSize,\r\n\tcolorDecorators,\r\n\tcolumnSelection,\r\n\tcomments,\r\n\tcontextmenu,\r\n\tcopyWithSyntaxHighlighting,\r\n\tcursorBlinking,\r\n\tcursorSmoothCaretAnimation,\r\n\tcursorStyle,\r\n\tcursorSurroundingLines,\r\n\tcursorSurroundingLinesStyle,\r\n\tcursorWidth,\r\n\tdisableLayerHinting,\r\n\tdisableMonospaceOptimizations,\r\n\tdragAndDrop,\r\n\temptySelectionClipboard,\r\n\textraEditorClassName,\r\n\tfastScrollSensitivity,\r\n\tfind,\r\n\tfixedOverflowWidgets,\r\n\tfolding,\r\n\tfoldingStrategy,\r\n\tfoldingHighlight,\r\n\tunfoldOnClickAfterEndOfLine,\r\n\tfontFamily,\r\n\tfontInfo,\r\n\tfontLigatures,\r\n\tfontSize,\r\n\tfontWeight,\r\n\tformatOnPaste,\r\n\tformatOnType,\r\n\tglyphMargin,\r\n\tgotoLocation,\r\n\thideCursorInOverviewRuler,\r\n\thighlightActiveIndentGuide,\r\n\thover,\r\n\tinDiffEditor,\r\n\tletterSpacing,\r\n\tlightbulb,\r\n\tlineDecorationsWidth,\r\n\tlineHeight,\r\n\tlineNumbers,\r\n\tlineNumbersMinChars,\r\n\tlinkedEditing,\r\n\tlinks,\r\n\tmatchBrackets,\r\n\tminimap,\r\n\tmouseStyle,\r\n\tmouseWheelScrollSensitivity,\r\n\tmouseWheelZoom,\r\n\tmultiCursorMergeOverlapping,\r\n\tmultiCursorModifier,\r\n\tmultiCursorPaste,\r\n\toccurrencesHighlight,\r\n\toverviewRulerBorder,\r\n\toverviewRulerLanes,\r\n\tpadding,\r\n\tparameterHints,\r\n\tpeekWidgetDefaultFocus,\r\n\tdefinitionLinkOpensInPeek,\r\n\tquickSuggestions,\r\n\tquickSuggestionsDelay,\r\n\treadOnly,\r\n\trenameOnType,\r\n\trenderControlCharacters,\r\n\trenderIndentGuides,\r\n\trenderFinalNewline,\r\n\trenderLineHighlight,\r\n\trenderLineHighlightOnlyWhenFocus,\r\n\trenderValidationDecorations,\r\n\trenderWhitespace,\r\n\trevealHorizontalRightPadding,\r\n\troundedSelection,\r\n\trulers,\r\n\tscrollbar,\r\n\tscrollBeyondLastColumn,\r\n\tscrollBeyondLastLine,\r\n\tscrollPredominantAxis,\r\n\tselectionClipboard,\r\n\tselectionHighlight,\r\n\tselectOnLineNumbers,\r\n\tshowFoldingControls,\r\n\tshowUnused,\r\n\tsnippetSuggestions,\r\n\tsmartSelect,\r\n\tsmoothScrolling,\r\n\tstickyTabStops,\r\n\tstopRenderingLineAfter,\r\n\tsuggest,\r\n\tsuggestFontSize,\r\n\tsuggestLineHeight,\r\n\tsuggestOnTriggerCharacters,\r\n\tsuggestSelection,\r\n\ttabCompletion,\r\n\ttabIndex,\r\n\tunusualLineTerminators,\r\n\tuseTabStops,\r\n\twordSeparators,\r\n\twordWrap,\r\n\twordWrapBreakAfterCharacters,\r\n\twordWrapBreakBeforeCharacters,\r\n\twordWrapColumn,\r\n\twordWrapOverride1,\r\n\twordWrapOverride2,\r\n\twrappingIndent,\r\n\twrappingStrategy,\r\n\tshowDeprecated,\r\n\tinlineHints,\r\n\t// Leave these at the end (because they have dependencies!)\r\n\teditorClassName,\r\n\tpixelRatio,\r\n\ttabFocusMode,\r\n\tlayoutInfo,\r\n\twrappingInfo,\r\n}\r\n\r\n/**\r\n * WORKAROUND: TS emits \"any\" for complex editor options values (anything except string, bool, enum, etc. ends up being \"any\")\r\n * @monacodtsreplace\r\n * /accessibilitySupport, any/accessibilitySupport, AccessibilitySupport/\r\n * /comments, any/comments, EditorCommentsOptions/\r\n * /find, any/find, EditorFindOptions/\r\n * /fontInfo, any/fontInfo, FontInfo/\r\n * /gotoLocation, any/gotoLocation, GoToLocationOptions/\r\n * /hover, any/hover, EditorHoverOptions/\r\n * /lightbulb, any/lightbulb, EditorLightbulbOptions/\r\n * /minimap, any/minimap, EditorMinimapOptions/\r\n * /parameterHints, any/parameterHints, InternalParameterHintOptions/\r\n * /quickSuggestions, any/quickSuggestions, ValidQuickSuggestionsOptions/\r\n * /suggest, any/suggest, InternalSuggestOptions/\r\n */\r\nexport const EditorOptions = {\r\n\tacceptSuggestionOnCommitCharacter: register(new EditorBooleanOption(\r\n\t\tEditorOption.acceptSuggestionOnCommitCharacter, 'acceptSuggestionOnCommitCharacter', true,\r\n\t\t{ markdownDescription: nls.localize('acceptSuggestionOnCommitCharacter', \"Controls whether suggestions should be accepted on commit characters. For example, in JavaScript, the semi-colon (`;`) can be a commit character that accepts a suggestion and types that character.\") }\r\n\t)),\r\n\tacceptSuggestionOnEnter: register(new EditorStringEnumOption(\r\n\t\tEditorOption.acceptSuggestionOnEnter, 'acceptSuggestionOnEnter',\r\n\t\t'on' as 'on' | 'smart' | 'off',\r\n\t\t['on', 'smart', 'off'] as const,\r\n\t\t{\r\n\t\t\tmarkdownEnumDescriptions: [\r\n\t\t\t\t'',\r\n\t\t\t\tnls.localize('acceptSuggestionOnEnterSmart', \"Only accept a suggestion with `Enter` when it makes a textual change.\"),\r\n\t\t\t\t''\r\n\t\t\t],\r\n\t\t\tmarkdownDescription: nls.localize('acceptSuggestionOnEnter', \"Controls whether suggestions should be accepted on `Enter`, in addition to `Tab`. Helps to avoid ambiguity between inserting new lines or accepting suggestions.\")\r\n\t\t}\r\n\t)),\r\n\taccessibilitySupport: register(new EditorAccessibilitySupport()),\r\n\taccessibilityPageSize: register(new EditorIntOption(EditorOption.accessibilityPageSize, 'accessibilityPageSize', 10, 1, Constants.MAX_SAFE_SMALL_INTEGER,\r\n\t\t{ description: nls.localize('accessibilityPageSize', \"Controls the number of lines in the editor that can be read out by a screen reader. Warning: this has a performance implication for numbers larger than the default.\") })),\r\n\tariaLabel: register(new EditorStringOption(\r\n\t\tEditorOption.ariaLabel, 'ariaLabel', nls.localize('editorViewAccessibleLabel', \"Editor content\")\r\n\t)),\r\n\tautoClosingBrackets: register(new EditorStringEnumOption(\r\n\t\tEditorOption.autoClosingBrackets, 'autoClosingBrackets',\r\n\t\t'languageDefined' as 'always' | 'languageDefined' | 'beforeWhitespace' | 'never',\r\n\t\t['always', 'languageDefined', 'beforeWhitespace', 'never'] as const,\r\n\t\t{\r\n\t\t\tenumDescriptions: [\r\n\t\t\t\t'',\r\n\t\t\t\tnls.localize('editor.autoClosingBrackets.languageDefined', \"Use language configurations to determine when to autoclose brackets.\"),\r\n\t\t\t\tnls.localize('editor.autoClosingBrackets.beforeWhitespace', \"Autoclose brackets only when the cursor is to the left of whitespace.\"),\r\n\t\t\t\t'',\r\n\t\t\t],\r\n\t\t\tdescription: nls.localize('autoClosingBrackets', \"Controls whether the editor should automatically close brackets after the user adds an opening bracket.\")\r\n\t\t}\r\n\t)),\r\n\tautoClosingOvertype: register(new EditorStringEnumOption(\r\n\t\tEditorOption.autoClosingOvertype, 'autoClosingOvertype',\r\n\t\t'auto' as 'always' | 'auto' | 'never',\r\n\t\t['always', 'auto', 'never'] as const,\r\n\t\t{\r\n\t\t\tenumDescriptions: [\r\n\t\t\t\t'',\r\n\t\t\t\tnls.localize('editor.autoClosingOvertype.auto', \"Type over closing quotes or brackets only if they were automatically inserted.\"),\r\n\t\t\t\t'',\r\n\t\t\t],\r\n\t\t\tdescription: nls.localize('autoClosingOvertype', \"Controls whether the editor should type over closing quotes or brackets.\")\r\n\t\t}\r\n\t)),\r\n\tautoClosingQuotes: register(new EditorStringEnumOption(\r\n\t\tEditorOption.autoClosingQuotes, 'autoClosingQuotes',\r\n\t\t'languageDefined' as 'always' | 'languageDefined' | 'beforeWhitespace' | 'never',\r\n\t\t['always', 'languageDefined', 'beforeWhitespace', 'never'] as const,\r\n\t\t{\r\n\t\t\tenumDescriptions: [\r\n\t\t\t\t'',\r\n\t\t\t\tnls.localize('editor.autoClosingQuotes.languageDefined', \"Use language configurations to determine when to autoclose quotes.\"),\r\n\t\t\t\tnls.localize('editor.autoClosingQuotes.beforeWhitespace', \"Autoclose quotes only when the cursor is to the left of whitespace.\"),\r\n\t\t\t\t'',\r\n\t\t\t],\r\n\t\t\tdescription: nls.localize('autoClosingQuotes', \"Controls whether the editor should automatically close quotes after the user adds an opening quote.\")\r\n\t\t}\r\n\t)),\r\n\tautoIndent: register(new EditorEnumOption(\r\n\t\tEditorOption.autoIndent, 'autoIndent',\r\n\t\tEditorAutoIndentStrategy.Full, 'full',\r\n\t\t['none', 'keep', 'brackets', 'advanced', 'full'],\r\n\t\t_autoIndentFromString,\r\n\t\t{\r\n\t\t\tenumDescriptions: [\r\n\t\t\t\tnls.localize('editor.autoIndent.none', \"The editor will not insert indentation automatically.\"),\r\n\t\t\t\tnls.localize('editor.autoIndent.keep', \"The editor will keep the current line's indentation.\"),\r\n\t\t\t\tnls.localize('editor.autoIndent.brackets', \"The editor will keep the current line's indentation and honor language defined brackets.\"),\r\n\t\t\t\tnls.localize('editor.autoIndent.advanced', \"The editor will keep the current line's indentation, honor language defined brackets and invoke special onEnterRules defined by languages.\"),\r\n\t\t\t\tnls.localize('editor.autoIndent.full', \"The editor will keep the current line's indentation, honor language defined brackets, invoke special onEnterRules defined by languages, and honor indentationRules defined by languages.\"),\r\n\t\t\t],\r\n\t\t\tdescription: nls.localize('autoIndent', \"Controls whether the editor should automatically adjust the indentation when users type, paste, move or indent lines.\")\r\n\t\t}\r\n\t)),\r\n\tautomaticLayout: register(new EditorBooleanOption(\r\n\t\tEditorOption.automaticLayout, 'automaticLayout', false,\r\n\t)),\r\n\tautoSurround: register(new EditorStringEnumOption(\r\n\t\tEditorOption.autoSurround, 'autoSurround',\r\n\t\t'languageDefined' as 'languageDefined' | 'quotes' | 'brackets' | 'never',\r\n\t\t['languageDefined', 'quotes', 'brackets', 'never'] as const,\r\n\t\t{\r\n\t\t\tenumDescriptions: [\r\n\t\t\t\tnls.localize('editor.autoSurround.languageDefined', \"Use language configurations to determine when to automatically surround selections.\"),\r\n\t\t\t\tnls.localize('editor.autoSurround.quotes', \"Surround with quotes but not brackets.\"),\r\n\t\t\t\tnls.localize('editor.autoSurround.brackets', \"Surround with brackets but not quotes.\"),\r\n\t\t\t\t''\r\n\t\t\t],\r\n\t\t\tdescription: nls.localize('autoSurround', \"Controls whether the editor should automatically surround selections when typing quotes or brackets.\")\r\n\t\t}\r\n\t)),\r\n\tstickyTabStops: register(new EditorBooleanOption(\r\n\t\tEditorOption.stickyTabStops, 'stickyTabStops', false,\r\n\t\t{ description: nls.localize('stickyTabStops', \"Emulate selection behaviour of tab characters when using spaces for indentation. Selection will stick to tab stops.\") }\r\n\t)),\r\n\tcodeLens: register(new EditorBooleanOption(\r\n\t\tEditorOption.codeLens, 'codeLens', true,\r\n\t\t{ description: nls.localize('codeLens', \"Controls whether the editor shows CodeLens.\") }\r\n\t)),\r\n\tcodeLensFontFamily: register(new EditorStringOption(\r\n\t\tEditorOption.codeLensFontFamily, 'codeLensFontFamily', '',\r\n\t\t{ description: nls.localize('codeLensFontFamily', \"Controls the font family for CodeLens.\") }\r\n\t)),\r\n\tcodeLensFontSize: register(new EditorIntOption(EditorOption.codeLensFontSize, 'codeLensFontSize', 0, 0, 100, {\r\n\t\ttype: 'number',\r\n\t\tdefault: 0,\r\n\t\tminimum: 0,\r\n\t\tmaximum: 100,\r\n\t\tdescription: nls.localize('codeLensFontSize', \"Controls the font size in pixels for CodeLens. When set to `0`, the 90% of `#editor.fontSize#` is used.\")\r\n\t})),\r\n\tcolorDecorators: register(new EditorBooleanOption(\r\n\t\tEditorOption.colorDecorators, 'colorDecorators', true,\r\n\t\t{ description: nls.localize('colorDecorators', \"Controls whether the editor should render the inline color decorators and color picker.\") }\r\n\t)),\r\n\tcolumnSelection: register(new EditorBooleanOption(\r\n\t\tEditorOption.columnSelection, 'columnSelection', false,\r\n\t\t{ description: nls.localize('columnSelection', \"Enable that the selection with the mouse and keys is doing column selection.\") }\r\n\t)),\r\n\tcomments: register(new EditorComments()),\r\n\tcontextmenu: register(new EditorBooleanOption(\r\n\t\tEditorOption.contextmenu, 'contextmenu', true,\r\n\t)),\r\n\tcopyWithSyntaxHighlighting: register(new EditorBooleanOption(\r\n\t\tEditorOption.copyWithSyntaxHighlighting, 'copyWithSyntaxHighlighting', true,\r\n\t\t{ description: nls.localize('copyWithSyntaxHighlighting', \"Controls whether syntax highlighting should be copied into the clipboard.\") }\r\n\t)),\r\n\tcursorBlinking: register(new EditorEnumOption(\r\n\t\tEditorOption.cursorBlinking, 'cursorBlinking',\r\n\t\tTextEditorCursorBlinkingStyle.Blink, 'blink',\r\n\t\t['blink', 'smooth', 'phase', 'expand', 'solid'],\r\n\t\t_cursorBlinkingStyleFromString,\r\n\t\t{ description: nls.localize('cursorBlinking', \"Control the cursor animation style.\") }\r\n\t)),\r\n\tcursorSmoothCaretAnimation: register(new EditorBooleanOption(\r\n\t\tEditorOption.cursorSmoothCaretAnimation, 'cursorSmoothCaretAnimation', false,\r\n\t\t{ description: nls.localize('cursorSmoothCaretAnimation', \"Controls whether the smooth caret animation should be enabled.\") }\r\n\t)),\r\n\tcursorStyle: register(new EditorEnumOption(\r\n\t\tEditorOption.cursorStyle, 'cursorStyle',\r\n\t\tTextEditorCursorStyle.Line, 'line',\r\n\t\t['line', 'block', 'underline', 'line-thin', 'block-outline', 'underline-thin'],\r\n\t\t_cursorStyleFromString,\r\n\t\t{ description: nls.localize('cursorStyle', \"Controls the cursor style.\") }\r\n\t)),\r\n\tcursorSurroundingLines: register(new EditorIntOption(\r\n\t\tEditorOption.cursorSurroundingLines, 'cursorSurroundingLines',\r\n\t\t0, 0, Constants.MAX_SAFE_SMALL_INTEGER,\r\n\t\t{ description: nls.localize('cursorSurroundingLines', \"Controls the minimal number of visible leading and trailing lines surrounding the cursor. Known as 'scrollOff' or 'scrollOffset' in some other editors.\") }\r\n\t)),\r\n\tcursorSurroundingLinesStyle: register(new EditorStringEnumOption(\r\n\t\tEditorOption.cursorSurroundingLinesStyle, 'cursorSurroundingLinesStyle',\r\n\t\t'default' as 'default' | 'all',\r\n\t\t['default', 'all'] as const,\r\n\t\t{\r\n\t\t\tenumDescriptions: [\r\n\t\t\t\tnls.localize('cursorSurroundingLinesStyle.default', \"`cursorSurroundingLines` is enforced only when triggered via the keyboard or API.\"),\r\n\t\t\t\tnls.localize('cursorSurroundingLinesStyle.all', \"`cursorSurroundingLines` is enforced always.\")\r\n\t\t\t],\r\n\t\t\tdescription: nls.localize('cursorSurroundingLinesStyle', \"Controls when `cursorSurroundingLines` should be enforced.\")\r\n\t\t}\r\n\t)),\r\n\tcursorWidth: register(new EditorIntOption(\r\n\t\tEditorOption.cursorWidth, 'cursorWidth',\r\n\t\t0, 0, Constants.MAX_SAFE_SMALL_INTEGER,\r\n\t\t{ markdownDescription: nls.localize('cursorWidth', \"Controls the width of the cursor when `#editor.cursorStyle#` is set to `line`.\") }\r\n\t)),\r\n\tdisableLayerHinting: register(new EditorBooleanOption(\r\n\t\tEditorOption.disableLayerHinting, 'disableLayerHinting', false,\r\n\t)),\r\n\tdisableMonospaceOptimizations: register(new EditorBooleanOption(\r\n\t\tEditorOption.disableMonospaceOptimizations, 'disableMonospaceOptimizations', false\r\n\t)),\r\n\tdragAndDrop: register(new EditorBooleanOption(\r\n\t\tEditorOption.dragAndDrop, 'dragAndDrop', true,\r\n\t\t{ description: nls.localize('dragAndDrop', \"Controls whether the editor should allow moving selections via drag and drop.\") }\r\n\t)),\r\n\temptySelectionClipboard: register(new EditorEmptySelectionClipboard()),\r\n\textraEditorClassName: register(new EditorStringOption(\r\n\t\tEditorOption.extraEditorClassName, 'extraEditorClassName', '',\r\n\t)),\r\n\tfastScrollSensitivity: register(new EditorFloatOption(\r\n\t\tEditorOption.fastScrollSensitivity, 'fastScrollSensitivity',\r\n\t\t5, x => (x <= 0 ? 5 : x),\r\n\t\t{ markdownDescription: nls.localize('fastScrollSensitivity', \"Scrolling speed multiplier when pressing `Alt`.\") }\r\n\t)),\r\n\tfind: register(new EditorFind()),\r\n\tfixedOverflowWidgets: register(new EditorBooleanOption(\r\n\t\tEditorOption.fixedOverflowWidgets, 'fixedOverflowWidgets', false,\r\n\t)),\r\n\tfolding: register(new EditorBooleanOption(\r\n\t\tEditorOption.folding, 'folding', true,\r\n\t\t{ description: nls.localize('folding', \"Controls whether the editor has code folding enabled.\") }\r\n\t)),\r\n\tfoldingStrategy: register(new EditorStringEnumOption(\r\n\t\tEditorOption.foldingStrategy, 'foldingStrategy',\r\n\t\t'auto' as 'auto' | 'indentation',\r\n\t\t['auto', 'indentation'] as const,\r\n\t\t{\r\n\t\t\tenumDescriptions: [\r\n\t\t\t\tnls.localize('foldingStrategy.auto', \"Use a language-specific folding strategy if available, else the indentation-based one.\"),\r\n\t\t\t\tnls.localize('foldingStrategy.indentation', \"Use the indentation-based folding strategy.\"),\r\n\t\t\t],\r\n\t\t\tdescription: nls.localize('foldingStrategy', \"Controls the strategy for computing folding ranges.\")\r\n\t\t}\r\n\t)),\r\n\tfoldingHighlight: register(new EditorBooleanOption(\r\n\t\tEditorOption.foldingHighlight, 'foldingHighlight', true,\r\n\t\t{ description: nls.localize('foldingHighlight', \"Controls whether the editor should highlight folded ranges.\") }\r\n\t)),\r\n\tunfoldOnClickAfterEndOfLine: register(new EditorBooleanOption(\r\n\t\tEditorOption.unfoldOnClickAfterEndOfLine, 'unfoldOnClickAfterEndOfLine', false,\r\n\t\t{ description: nls.localize('unfoldOnClickAfterEndOfLine', \"Controls whether clicking on the empty content after a folded line will unfold the line.\") }\r\n\t)),\r\n\tfontFamily: register(new EditorStringOption(\r\n\t\tEditorOption.fontFamily, 'fontFamily', EDITOR_FONT_DEFAULTS.fontFamily,\r\n\t\t{ description: nls.localize('fontFamily', \"Controls the font family.\") }\r\n\t)),\r\n\tfontInfo: register(new EditorFontInfo()),\r\n\tfontLigatures2: register(new EditorFontLigatures()),\r\n\tfontSize: register(new EditorFontSize()),\r\n\tfontWeight: register(new EditorFontWeight()),\r\n\tformatOnPaste: register(new EditorBooleanOption(\r\n\t\tEditorOption.formatOnPaste, 'formatOnPaste', false,\r\n\t\t{ description: nls.localize('formatOnPaste', \"Controls whether the editor should automatically format the pasted content. A formatter must be available and the formatter should be able to format a range in a document.\") }\r\n\t)),\r\n\tformatOnType: register(new EditorBooleanOption(\r\n\t\tEditorOption.formatOnType, 'formatOnType', false,\r\n\t\t{ description: nls.localize('formatOnType', \"Controls whether the editor should automatically format the line after typing.\") }\r\n\t)),\r\n\tglyphMargin: register(new EditorBooleanOption(\r\n\t\tEditorOption.glyphMargin, 'glyphMargin', true,\r\n\t\t{ description: nls.localize('glyphMargin', \"Controls whether the editor should render the vertical glyph margin. Glyph margin is mostly used for debugging.\") }\r\n\t)),\r\n\tgotoLocation: register(new EditorGoToLocation()),\r\n\thideCursorInOverviewRuler: register(new EditorBooleanOption(\r\n\t\tEditorOption.hideCursorInOverviewRuler, 'hideCursorInOverviewRuler', false,\r\n\t\t{ description: nls.localize('hideCursorInOverviewRuler', \"Controls whether the cursor should be hidden in the overview ruler.\") }\r\n\t)),\r\n\thighlightActiveIndentGuide: register(new EditorBooleanOption(\r\n\t\tEditorOption.highlightActiveIndentGuide, 'highlightActiveIndentGuide', true,\r\n\t\t{ description: nls.localize('highlightActiveIndentGuide', \"Controls whether the editor should highlight the active indent guide.\") }\r\n\t)),\r\n\thover: register(new EditorHover()),\r\n\tinDiffEditor: register(new EditorBooleanOption(\r\n\t\tEditorOption.inDiffEditor, 'inDiffEditor', false\r\n\t)),\r\n\tletterSpacing: register(new EditorFloatOption(\r\n\t\tEditorOption.letterSpacing, 'letterSpacing',\r\n\t\tEDITOR_FONT_DEFAULTS.letterSpacing, x => EditorFloatOption.clamp(x, -5, 20),\r\n\t\t{ description: nls.localize('letterSpacing', \"Controls the letter spacing in pixels.\") }\r\n\t)),\r\n\tlightbulb: register(new EditorLightbulb()),\r\n\tlineDecorationsWidth: register(new SimpleEditorOption(EditorOption.lineDecorationsWidth, 'lineDecorationsWidth', 10 as number | string)),\r\n\tlineHeight: register(new EditorLineHeight()),\r\n\tlineNumbers: register(new EditorRenderLineNumbersOption()),\r\n\tlineNumbersMinChars: register(new EditorIntOption(\r\n\t\tEditorOption.lineNumbersMinChars, 'lineNumbersMinChars',\r\n\t\t5, 1, 300\r\n\t)),\r\n\tlinkedEditing: register(new EditorBooleanOption(\r\n\t\tEditorOption.linkedEditing, 'linkedEditing', false,\r\n\t\t{ description: nls.localize('linkedEditing', \"Controls whether the editor has linked editing enabled. Depending on the language, related symbols, e.g. HTML tags, are updated while editing.\") }\r\n\t)),\r\n\tlinks: register(new EditorBooleanOption(\r\n\t\tEditorOption.links, 'links', true,\r\n\t\t{ description: nls.localize('links', \"Controls whether the editor should detect links and make them clickable.\") }\r\n\t)),\r\n\tmatchBrackets: register(new EditorStringEnumOption(\r\n\t\tEditorOption.matchBrackets, 'matchBrackets',\r\n\t\t'always' as 'never' | 'near' | 'always',\r\n\t\t['always', 'near', 'never'] as const,\r\n\t\t{ description: nls.localize('matchBrackets', \"Highlight matching brackets.\") }\r\n\t)),\r\n\tminimap: register(new EditorMinimap()),\r\n\tmouseStyle: register(new EditorStringEnumOption(\r\n\t\tEditorOption.mouseStyle, 'mouseStyle',\r\n\t\t'text' as 'text' | 'default' | 'copy',\r\n\t\t['text', 'default', 'copy'] as const,\r\n\t)),\r\n\tmouseWheelScrollSensitivity: register(new EditorFloatOption(\r\n\t\tEditorOption.mouseWheelScrollSensitivity, 'mouseWheelScrollSensitivity',\r\n\t\t1, x => (x === 0 ? 1 : x),\r\n\t\t{ markdownDescription: nls.localize('mouseWheelScrollSensitivity', \"A multiplier to be used on the `deltaX` and `deltaY` of mouse wheel scroll events.\") }\r\n\t)),\r\n\tmouseWheelZoom: register(new EditorBooleanOption(\r\n\t\tEditorOption.mouseWheelZoom, 'mouseWheelZoom', false,\r\n\t\t{ markdownDescription: nls.localize('mouseWheelZoom', \"Zoom the font of the editor when using mouse wheel and holding `Ctrl`.\") }\r\n\t)),\r\n\tmultiCursorMergeOverlapping: register(new EditorBooleanOption(\r\n\t\tEditorOption.multiCursorMergeOverlapping, 'multiCursorMergeOverlapping', true,\r\n\t\t{ description: nls.localize('multiCursorMergeOverlapping', \"Merge multiple cursors when they are overlapping.\") }\r\n\t)),\r\n\tmultiCursorModifier: register(new EditorEnumOption(\r\n\t\tEditorOption.multiCursorModifier, 'multiCursorModifier',\r\n\t\t'altKey', 'alt',\r\n\t\t['ctrlCmd', 'alt'],\r\n\t\t_multiCursorModifierFromString,\r\n\t\t{\r\n\t\t\tmarkdownEnumDescriptions: [\r\n\t\t\t\tnls.localize('multiCursorModifier.ctrlCmd', \"Maps to `Control` on Windows and Linux and to `Command` on macOS.\"),\r\n\t\t\t\tnls.localize('multiCursorModifier.alt', \"Maps to `Alt` on Windows and Linux and to `Option` on macOS.\")\r\n\t\t\t],\r\n\t\t\tmarkdownDescription: nls.localize({\r\n\t\t\t\tkey: 'multiCursorModifier',\r\n\t\t\t\tcomment: [\r\n\t\t\t\t\t'- `ctrlCmd` refers to a value the setting can take and should not be localized.',\r\n\t\t\t\t\t'- `Control` and `Command` refer to the modifier keys Ctrl or Cmd on the keyboard and can be localized.'\r\n\t\t\t\t]\r\n\t\t\t}, \"The modifier to be used to add multiple cursors with the mouse. The Go To Definition and Open Link mouse gestures will adapt such that they do not conflict with the multicursor modifier. [Read more](https://code.visualstudio.com/docs/editor/codebasics#_multicursor-modifier).\")\r\n\t\t}\r\n\t)),\r\n\tmultiCursorPaste: register(new EditorStringEnumOption(\r\n\t\tEditorOption.multiCursorPaste, 'multiCursorPaste',\r\n\t\t'spread' as 'spread' | 'full',\r\n\t\t['spread', 'full'] as const,\r\n\t\t{\r\n\t\t\tmarkdownEnumDescriptions: [\r\n\t\t\t\tnls.localize('multiCursorPaste.spread', \"Each cursor pastes a single line of the text.\"),\r\n\t\t\t\tnls.localize('multiCursorPaste.full', \"Each cursor pastes the full text.\")\r\n\t\t\t],\r\n\t\t\tmarkdownDescription: nls.localize('multiCursorPaste', \"Controls pasting when the line count of the pasted text matches the cursor count.\")\r\n\t\t}\r\n\t)),\r\n\toccurrencesHighlight: register(new EditorBooleanOption(\r\n\t\tEditorOption.occurrencesHighlight, 'occurrencesHighlight', true,\r\n\t\t{ description: nls.localize('occurrencesHighlight', \"Controls whether the editor should highlight semantic symbol occurrences.\") }\r\n\t)),\r\n\toverviewRulerBorder: register(new EditorBooleanOption(\r\n\t\tEditorOption.overviewRulerBorder, 'overviewRulerBorder', true,\r\n\t\t{ description: nls.localize('overviewRulerBorder', \"Controls whether a border should be drawn around the overview ruler.\") }\r\n\t)),\r\n\toverviewRulerLanes: register(new EditorIntOption(\r\n\t\tEditorOption.overviewRulerLanes, 'overviewRulerLanes',\r\n\t\t3, 0, 3\r\n\t)),\r\n\tpadding: register(new EditorPadding()),\r\n\tparameterHints: register(new EditorParameterHints()),\r\n\tpeekWidgetDefaultFocus: register(new EditorStringEnumOption(\r\n\t\tEditorOption.peekWidgetDefaultFocus, 'peekWidgetDefaultFocus',\r\n\t\t'tree' as 'tree' | 'editor',\r\n\t\t['tree', 'editor'] as const,\r\n\t\t{\r\n\t\t\tenumDescriptions: [\r\n\t\t\t\tnls.localize('peekWidgetDefaultFocus.tree', \"Focus the tree when opening peek\"),\r\n\t\t\t\tnls.localize('peekWidgetDefaultFocus.editor', \"Focus the editor when opening peek\")\r\n\t\t\t],\r\n\t\t\tdescription: nls.localize('peekWidgetDefaultFocus', \"Controls whether to focus the inline editor or the tree in the peek widget.\")\r\n\t\t}\r\n\t)),\r\n\tdefinitionLinkOpensInPeek: register(new EditorBooleanOption(\r\n\t\tEditorOption.definitionLinkOpensInPeek, 'definitionLinkOpensInPeek', false,\r\n\t\t{ description: nls.localize('definitionLinkOpensInPeek', \"Controls whether the Go to Definition mouse gesture always opens the peek widget.\") }\r\n\t)),\r\n\tquickSuggestions: register(new EditorQuickSuggestions()),\r\n\tquickSuggestionsDelay: register(new EditorIntOption(\r\n\t\tEditorOption.quickSuggestionsDelay, 'quickSuggestionsDelay',\r\n\t\t10, 0, Constants.MAX_SAFE_SMALL_INTEGER,\r\n\t\t{ description: nls.localize('quickSuggestionsDelay', \"Controls the delay in milliseconds after which quick suggestions will show up.\") }\r\n\t)),\r\n\treadOnly: register(new EditorBooleanOption(\r\n\t\tEditorOption.readOnly, 'readOnly', false,\r\n\t)),\r\n\trenameOnType: register(new EditorBooleanOption(\r\n\t\tEditorOption.renameOnType, 'renameOnType', false,\r\n\t\t{ description: nls.localize('renameOnType', \"Controls whether the editor auto renames on type.\"), markdownDeprecationMessage: nls.localize('renameOnTypeDeprecate', \"Deprecated, use `editor.linkedEditing` instead.\") }\r\n\t)),\r\n\trenderControlCharacters: register(new EditorBooleanOption(\r\n\t\tEditorOption.renderControlCharacters, 'renderControlCharacters', false,\r\n\t\t{ description: nls.localize('renderControlCharacters', \"Controls whether the editor should render control characters.\") }\r\n\t)),\r\n\trenderIndentGuides: register(new EditorBooleanOption(\r\n\t\tEditorOption.renderIndentGuides, 'renderIndentGuides', true,\r\n\t\t{ description: nls.localize('renderIndentGuides', \"Controls whether the editor should render indent guides.\") }\r\n\t)),\r\n\trenderFinalNewline: register(new EditorBooleanOption(\r\n\t\tEditorOption.renderFinalNewline, 'renderFinalNewline', true,\r\n\t\t{ description: nls.localize('renderFinalNewline', \"Render last line number when the file ends with a newline.\") }\r\n\t)),\r\n\trenderLineHighlight: register(new EditorStringEnumOption(\r\n\t\tEditorOption.renderLineHighlight, 'renderLineHighlight',\r\n\t\t'line' as 'none' | 'gutter' | 'line' | 'all',\r\n\t\t['none', 'gutter', 'line', 'all'] as const,\r\n\t\t{\r\n\t\t\tenumDescriptions: [\r\n\t\t\t\t'',\r\n\t\t\t\t'',\r\n\t\t\t\t'',\r\n\t\t\t\tnls.localize('renderLineHighlight.all', \"Highlights both the gutter and the current line.\"),\r\n\t\t\t],\r\n\t\t\tdescription: nls.localize('renderLineHighlight', \"Controls how the editor should render the current line highlight.\")\r\n\t\t}\r\n\t)),\r\n\trenderLineHighlightOnlyWhenFocus: register(new EditorBooleanOption(\r\n\t\tEditorOption.renderLineHighlightOnlyWhenFocus, 'renderLineHighlightOnlyWhenFocus', false,\r\n\t\t{ description: nls.localize('renderLineHighlightOnlyWhenFocus', \"Controls if the editor should render the current line highlight only when the editor is focused\") }\r\n\t)),\r\n\trenderValidationDecorations: register(new EditorStringEnumOption(\r\n\t\tEditorOption.renderValidationDecorations, 'renderValidationDecorations',\r\n\t\t'editable' as 'editable' | 'on' | 'off',\r\n\t\t['editable', 'on', 'off'] as const\r\n\t)),\r\n\trenderWhitespace: register(new EditorStringEnumOption(\r\n\t\tEditorOption.renderWhitespace, 'renderWhitespace',\r\n\t\t'selection' as 'selection' | 'none' | 'boundary' | 'trailing' | 'all',\r\n\t\t['none', 'boundary', 'selection', 'trailing', 'all'] as const,\r\n\t\t{\r\n\t\t\tenumDescriptions: [\r\n\t\t\t\t'',\r\n\t\t\t\tnls.localize('renderWhitespace.boundary', \"Render whitespace characters except for single spaces between words.\"),\r\n\t\t\t\tnls.localize('renderWhitespace.selection', \"Render whitespace characters only on selected text.\"),\r\n\t\t\t\tnls.localize('renderWhitespace.trailing', \"Render only trailing whitespace characters\"),\r\n\t\t\t\t''\r\n\t\t\t],\r\n\t\t\tdescription: nls.localize('renderWhitespace', \"Controls how the editor should render whitespace characters.\")\r\n\t\t}\r\n\t)),\r\n\trevealHorizontalRightPadding: register(new EditorIntOption(\r\n\t\tEditorOption.revealHorizontalRightPadding, 'revealHorizontalRightPadding',\r\n\t\t30, 0, 1000,\r\n\t)),\r\n\troundedSelection: register(new EditorBooleanOption(\r\n\t\tEditorOption.roundedSelection, 'roundedSelection', true,\r\n\t\t{ description: nls.localize('roundedSelection', \"Controls whether selections should have rounded corners.\") }\r\n\t)),\r\n\trulers: register(new EditorRulers()),\r\n\tscrollbar: register(new EditorScrollbar()),\r\n\tscrollBeyondLastColumn: register(new EditorIntOption(\r\n\t\tEditorOption.scrollBeyondLastColumn, 'scrollBeyondLastColumn',\r\n\t\t5, 0, Constants.MAX_SAFE_SMALL_INTEGER,\r\n\t\t{ description: nls.localize('scrollBeyondLastColumn', \"Controls the number of extra characters beyond which the editor will scroll horizontally.\") }\r\n\t)),\r\n\tscrollBeyondLastLine: register(new EditorBooleanOption(\r\n\t\tEditorOption.scrollBeyondLastLine, 'scrollBeyondLastLine', true,\r\n\t\t{ description: nls.localize('scrollBeyondLastLine', \"Controls whether the editor will scroll beyond the last line.\") }\r\n\t)),\r\n\tscrollPredominantAxis: register(new EditorBooleanOption(\r\n\t\tEditorOption.scrollPredominantAxis, 'scrollPredominantAxis', true,\r\n\t\t{ description: nls.localize('scrollPredominantAxis', \"Scroll only along the predominant axis when scrolling both vertically and horizontally at the same time. Prevents horizontal drift when scrolling vertically on a trackpad.\") }\r\n\t)),\r\n\tselectionClipboard: register(new EditorBooleanOption(\r\n\t\tEditorOption.selectionClipboard, 'selectionClipboard', true,\r\n\t\t{\r\n\t\t\tdescription: nls.localize('selectionClipboard', \"Controls whether the Linux primary clipboard should be supported.\"),\r\n\t\t\tincluded: platform.isLinux\r\n\t\t}\r\n\t)),\r\n\tselectionHighlight: register(new EditorBooleanOption(\r\n\t\tEditorOption.selectionHighlight, 'selectionHighlight', true,\r\n\t\t{ description: nls.localize('selectionHighlight', \"Controls whether the editor should highlight matches similar to the selection.\") }\r\n\t)),\r\n\tselectOnLineNumbers: register(new EditorBooleanOption(\r\n\t\tEditorOption.selectOnLineNumbers, 'selectOnLineNumbers', true,\r\n\t)),\r\n\tshowFoldingControls: register(new EditorStringEnumOption(\r\n\t\tEditorOption.showFoldingControls, 'showFoldingControls',\r\n\t\t'mouseover' as 'always' | 'mouseover',\r\n\t\t['always', 'mouseover'] as const,\r\n\t\t{\r\n\t\t\tenumDescriptions: [\r\n\t\t\t\tnls.localize('showFoldingControls.always', \"Always show the folding controls.\"),\r\n\t\t\t\tnls.localize('showFoldingControls.mouseover', \"Only show the folding controls when the mouse is over the gutter.\"),\r\n\t\t\t],\r\n\t\t\tdescription: nls.localize('showFoldingControls', \"Controls when the folding controls on the gutter are shown.\")\r\n\t\t}\r\n\t)),\r\n\tshowUnused: register(new EditorBooleanOption(\r\n\t\tEditorOption.showUnused, 'showUnused', true,\r\n\t\t{ description: nls.localize('showUnused', \"Controls fading out of unused code.\") }\r\n\t)),\r\n\tshowDeprecated: register(new EditorBooleanOption(\r\n\t\tEditorOption.showDeprecated, 'showDeprecated', true,\r\n\t\t{ description: nls.localize('showDeprecated', \"Controls strikethrough deprecated variables.\") }\r\n\t)),\r\n\tinlineHints: register(new EditorInlineHints()),\r\n\tsnippetSuggestions: register(new EditorStringEnumOption(\r\n\t\tEditorOption.snippetSuggestions, 'snippetSuggestions',\r\n\t\t'inline' as 'top' | 'bottom' | 'inline' | 'none',\r\n\t\t['top', 'bottom', 'inline', 'none'] as const,\r\n\t\t{\r\n\t\t\tenumDescriptions: [\r\n\t\t\t\tnls.localize('snippetSuggestions.top', \"Show snippet suggestions on top of other suggestions.\"),\r\n\t\t\t\tnls.localize('snippetSuggestions.bottom', \"Show snippet suggestions below other suggestions.\"),\r\n\t\t\t\tnls.localize('snippetSuggestions.inline', \"Show snippets suggestions with other suggestions.\"),\r\n\t\t\t\tnls.localize('snippetSuggestions.none', \"Do not show snippet suggestions.\"),\r\n\t\t\t],\r\n\t\t\tdescription: nls.localize('snippetSuggestions', \"Controls whether snippets are shown with other suggestions and how they are sorted.\")\r\n\t\t}\r\n\t)),\r\n\tsmartSelect: register(new SmartSelect()),\r\n\tsmoothScrolling: register(new EditorBooleanOption(\r\n\t\tEditorOption.smoothScrolling, 'smoothScrolling', false,\r\n\t\t{ description: nls.localize('smoothScrolling', \"Controls whether the editor will scroll using an animation.\") }\r\n\t)),\r\n\tstopRenderingLineAfter: register(new EditorIntOption(\r\n\t\tEditorOption.stopRenderingLineAfter, 'stopRenderingLineAfter',\r\n\t\t10000, -1, Constants.MAX_SAFE_SMALL_INTEGER,\r\n\t)),\r\n\tsuggest: register(new EditorSuggest()),\r\n\tsuggestFontSize: register(new EditorIntOption(\r\n\t\tEditorOption.suggestFontSize, 'suggestFontSize',\r\n\t\t0, 0, 1000,\r\n\t\t{ markdownDescription: nls.localize('suggestFontSize', \"Font size for the suggest widget. When set to `0`, the value of `#editor.fontSize#` is used.\") }\r\n\t)),\r\n\tsuggestLineHeight: register(new EditorIntOption(\r\n\t\tEditorOption.suggestLineHeight, 'suggestLineHeight',\r\n\t\t0, 0, 1000,\r\n\t\t{ markdownDescription: nls.localize('suggestLineHeight', \"Line height for the suggest widget. When set to `0`, the value of `#editor.lineHeight#` is used. The minimum value is 8.\") }\r\n\t)),\r\n\tsuggestOnTriggerCharacters: register(new EditorBooleanOption(\r\n\t\tEditorOption.suggestOnTriggerCharacters, 'suggestOnTriggerCharacters', true,\r\n\t\t{ description: nls.localize('suggestOnTriggerCharacters', \"Controls whether suggestions should automatically show up when typing trigger characters.\") }\r\n\t)),\r\n\tsuggestSelection: register(new EditorStringEnumOption(\r\n\t\tEditorOption.suggestSelection, 'suggestSelection',\r\n\t\t'recentlyUsed' as 'first' | 'recentlyUsed' | 'recentlyUsedByPrefix',\r\n\t\t['first', 'recentlyUsed', 'recentlyUsedByPrefix'] as const,\r\n\t\t{\r\n\t\t\tmarkdownEnumDescriptions: [\r\n\t\t\t\tnls.localize('suggestSelection.first', \"Always select the first suggestion.\"),\r\n\t\t\t\tnls.localize('suggestSelection.recentlyUsed', \"Select recent suggestions unless further typing selects one, e.g. `console.| -> console.log` because `log` has been completed recently.\"),\r\n\t\t\t\tnls.localize('suggestSelection.recentlyUsedByPrefix', \"Select suggestions based on previous prefixes that have completed those suggestions, e.g. `co -> console` and `con -> const`.\"),\r\n\t\t\t],\r\n\t\t\tdescription: nls.localize('suggestSelection', \"Controls how suggestions are pre-selected when showing the suggest list.\")\r\n\t\t}\r\n\t)),\r\n\ttabCompletion: register(new EditorStringEnumOption(\r\n\t\tEditorOption.tabCompletion, 'tabCompletion',\r\n\t\t'off' as 'on' | 'off' | 'onlySnippets',\r\n\t\t['on', 'off', 'onlySnippets'] as const,\r\n\t\t{\r\n\t\t\tenumDescriptions: [\r\n\t\t\t\tnls.localize('tabCompletion.on', \"Tab complete will insert the best matching suggestion when pressing tab.\"),\r\n\t\t\t\tnls.localize('tabCompletion.off', \"Disable tab completions.\"),\r\n\t\t\t\tnls.localize('tabCompletion.onlySnippets', \"Tab complete snippets when their prefix match. Works best when 'quickSuggestions' aren't enabled.\"),\r\n\t\t\t],\r\n\t\t\tdescription: nls.localize('tabCompletion', \"Enables tab completions.\")\r\n\t\t}\r\n\t)),\r\n\ttabIndex: register(new EditorIntOption(\r\n\t\tEditorOption.tabIndex, 'tabIndex',\r\n\t\t0, -1, Constants.MAX_SAFE_SMALL_INTEGER\r\n\t)),\r\n\tunusualLineTerminators: register(new EditorStringEnumOption(\r\n\t\tEditorOption.unusualLineTerminators, 'unusualLineTerminators',\r\n\t\t'prompt' as 'auto' | 'off' | 'prompt',\r\n\t\t['auto', 'off', 'prompt'] as const,\r\n\t\t{\r\n\t\t\tenumDescriptions: [\r\n\t\t\t\tnls.localize('unusualLineTerminators.auto', \"Unusual line terminators are automatically removed.\"),\r\n\t\t\t\tnls.localize('unusualLineTerminators.off', \"Unusual line terminators are ignored.\"),\r\n\t\t\t\tnls.localize('unusualLineTerminators.prompt', \"Unusual line terminators prompt to be removed.\"),\r\n\t\t\t],\r\n\t\t\tdescription: nls.localize('unusualLineTerminators', \"Remove unusual line terminators that might cause problems.\")\r\n\t\t}\r\n\t)),\r\n\tuseTabStops: register(new EditorBooleanOption(\r\n\t\tEditorOption.useTabStops, 'useTabStops', true,\r\n\t\t{ description: nls.localize('useTabStops', \"Inserting and deleting whitespace follows tab stops.\") }\r\n\t)),\r\n\twordSeparators: register(new EditorStringOption(\r\n\t\tEditorOption.wordSeparators, 'wordSeparators', USUAL_WORD_SEPARATORS,\r\n\t\t{ description: nls.localize('wordSeparators', \"Characters that will be used as word separators when doing word related navigations or operations.\") }\r\n\t)),\r\n\twordWrap: register(new EditorStringEnumOption(\r\n\t\tEditorOption.wordWrap, 'wordWrap',\r\n\t\t'off' as 'off' | 'on' | 'wordWrapColumn' | 'bounded',\r\n\t\t['off', 'on', 'wordWrapColumn', 'bounded'] as const,\r\n\t\t{\r\n\t\t\tmarkdownEnumDescriptions: [\r\n\t\t\t\tnls.localize('wordWrap.off', \"Lines will never wrap.\"),\r\n\t\t\t\tnls.localize('wordWrap.on', \"Lines will wrap at the viewport width.\"),\r\n\t\t\t\tnls.localize({\r\n\t\t\t\t\tkey: 'wordWrap.wordWrapColumn',\r\n\t\t\t\t\tcomment: [\r\n\t\t\t\t\t\t'- `editor.wordWrapColumn` refers to a different setting and should not be localized.'\r\n\t\t\t\t\t]\r\n\t\t\t\t}, \"Lines will wrap at `#editor.wordWrapColumn#`.\"),\r\n\t\t\t\tnls.localize({\r\n\t\t\t\t\tkey: 'wordWrap.bounded',\r\n\t\t\t\t\tcomment: [\r\n\t\t\t\t\t\t'- viewport means the edge of the visible window size.',\r\n\t\t\t\t\t\t'- `editor.wordWrapColumn` refers to a different setting and should not be localized.'\r\n\t\t\t\t\t]\r\n\t\t\t\t}, \"Lines will wrap at the minimum of viewport and `#editor.wordWrapColumn#`.\"),\r\n\t\t\t],\r\n\t\t\tdescription: nls.localize({\r\n\t\t\t\tkey: 'wordWrap',\r\n\t\t\t\tcomment: [\r\n\t\t\t\t\t'- \\'off\\', \\'on\\', \\'wordWrapColumn\\' and \\'bounded\\' refer to values the setting can take and should not be localized.',\r\n\t\t\t\t\t'- `editor.wordWrapColumn` refers to a different setting and should not be localized.'\r\n\t\t\t\t]\r\n\t\t\t}, \"Controls how lines should wrap.\")\r\n\t\t}\r\n\t)),\r\n\twordWrapBreakAfterCharacters: register(new EditorStringOption(\r\n\t\tEditorOption.wordWrapBreakAfterCharacters, 'wordWrapBreakAfterCharacters',\r\n\t\t' \\t})]?|/&.,;¢°′″‰℃、。。、¢,.:;?!%・・ゝゞヽヾーァィゥェォッャュョヮヵヶぁぃぅぇぉっゃゅょゎゕゖㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ々〻ァィゥェォャュョッー”〉》」』】〕)]}」',\r\n\t)),\r\n\twordWrapBreakBeforeCharacters: register(new EditorStringOption(\r\n\t\tEditorOption.wordWrapBreakBeforeCharacters, 'wordWrapBreakBeforeCharacters',\r\n\t\t'([{‘“〈《「『【〔([{「£¥$£¥++'\r\n\t)),\r\n\twordWrapColumn: register(new EditorIntOption(\r\n\t\tEditorOption.wordWrapColumn, 'wordWrapColumn',\r\n\t\t80, 1, Constants.MAX_SAFE_SMALL_INTEGER,\r\n\t\t{\r\n\t\t\tmarkdownDescription: nls.localize({\r\n\t\t\t\tkey: 'wordWrapColumn',\r\n\t\t\t\tcomment: [\r\n\t\t\t\t\t'- `editor.wordWrap` refers to a different setting and should not be localized.',\r\n\t\t\t\t\t'- \\'wordWrapColumn\\' and \\'bounded\\' refer to values the different setting can take and should not be localized.'\r\n\t\t\t\t]\r\n\t\t\t}, \"Controls the wrapping column of the editor when `#editor.wordWrap#` is `wordWrapColumn` or `bounded`.\")\r\n\t\t}\r\n\t)),\r\n\twordWrapOverride1: register(new EditorStringEnumOption(\r\n\t\tEditorOption.wordWrapOverride1, 'wordWrapOverride1',\r\n\t\t'inherit' as 'off' | 'on' | 'inherit',\r\n\t\t['off', 'on', 'inherit'] as const\r\n\t)),\r\n\twordWrapOverride2: register(new EditorStringEnumOption(\r\n\t\tEditorOption.wordWrapOverride2, 'wordWrapOverride2',\r\n\t\t'inherit' as 'off' | 'on' | 'inherit',\r\n\t\t['off', 'on', 'inherit'] as const\r\n\t)),\r\n\twrappingIndent: register(new EditorEnumOption(\r\n\t\tEditorOption.wrappingIndent, 'wrappingIndent',\r\n\t\tWrappingIndent.Same, 'same',\r\n\t\t['none', 'same', 'indent', 'deepIndent'],\r\n\t\t_wrappingIndentFromString,\r\n\t\t{\r\n\t\t\tenumDescriptions: [\r\n\t\t\t\tnls.localize('wrappingIndent.none', \"No indentation. Wrapped lines begin at column 1.\"),\r\n\t\t\t\tnls.localize('wrappingIndent.same', \"Wrapped lines get the same indentation as the parent.\"),\r\n\t\t\t\tnls.localize('wrappingIndent.indent', \"Wrapped lines get +1 indentation toward the parent.\"),\r\n\t\t\t\tnls.localize('wrappingIndent.deepIndent', \"Wrapped lines get +2 indentation toward the parent.\"),\r\n\t\t\t],\r\n\t\t\tdescription: nls.localize('wrappingIndent', \"Controls the indentation of wrapped lines.\"),\r\n\t\t}\r\n\t)),\r\n\twrappingStrategy: register(new EditorStringEnumOption(\r\n\t\tEditorOption.wrappingStrategy, 'wrappingStrategy',\r\n\t\t'simple' as 'simple' | 'advanced',\r\n\t\t['simple', 'advanced'] as const,\r\n\t\t{\r\n\t\t\tenumDescriptions: [\r\n\t\t\t\tnls.localize('wrappingStrategy.simple', \"Assumes that all characters are of the same width. This is a fast algorithm that works correctly for monospace fonts and certain scripts (like Latin characters) where glyphs are of equal width.\"),\r\n\t\t\t\tnls.localize('wrappingStrategy.advanced', \"Delegates wrapping points computation to the browser. This is a slow algorithm, that might cause freezes for large files, but it works correctly in all cases.\")\r\n\t\t\t],\r\n\t\t\tdescription: nls.localize('wrappingStrategy', \"Controls the algorithm that computes wrapping points.\")\r\n\t\t}\r\n\t)),\r\n\r\n\t// Leave these at the end (because they have dependencies!)\r\n\teditorClassName: register(new EditorClassName()),\r\n\tpixelRatio: register(new EditorPixelRatio()),\r\n\ttabFocusMode: register(new EditorTabFocusMode()),\r\n\tlayoutInfo: register(new EditorLayoutInfoComputer()),\r\n\twrappingInfo: register(new EditorWrappingInfoComputer())\r\n};\r\n\r\ntype EditorOptionsType = typeof EditorOptions;\r\ntype FindEditorOptionsKeyById = { [K in keyof EditorOptionsType]: EditorOptionsType[K]['id'] extends T ? K : never }[keyof EditorOptionsType];\r\ntype ComputedEditorOptionValue> = T extends IEditorOption ? R : never;\r\nexport type FindComputedEditorOptionValueById = NonNullable]>>;\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport * as editorCommon from 'vs/editor/common/editorCommon';\r\nimport { IModelDecoration, ITextModel } from 'vs/editor/common/model';\r\nimport { IViewModelLinesCollection } from 'vs/editor/common/viewModel/splitLinesCollection';\r\nimport { ICoordinatesConverter, InlineDecoration, InlineDecorationType, ViewModelDecoration } from 'vs/editor/common/viewModel/viewModel';\r\nimport { filterValidationDecorations } from 'vs/editor/common/config/editorOptions';\r\n\r\nexport interface IDecorationsViewportData {\r\n\t/**\r\n\t * decorations in the viewport.\r\n\t */\r\n\treadonly decorations: ViewModelDecoration[];\r\n\t/**\r\n\t * inline decorations grouped by each line in the viewport.\r\n\t */\r\n\treadonly inlineDecorations: InlineDecoration[][];\r\n}\r\n\r\nexport class ViewModelDecorations implements IDisposable {\r\n\r\n\tprivate readonly editorId: number;\r\n\tprivate readonly model: ITextModel;\r\n\tprivate readonly configuration: editorCommon.IConfiguration;\r\n\tprivate readonly _linesCollection: IViewModelLinesCollection;\r\n\tprivate readonly _coordinatesConverter: ICoordinatesConverter;\r\n\r\n\tprivate _decorationsCache: { [decorationId: string]: ViewModelDecoration; };\r\n\r\n\tprivate _cachedModelDecorationsResolver: IDecorationsViewportData | null;\r\n\tprivate _cachedModelDecorationsResolverViewRange: Range | null;\r\n\r\n\tconstructor(editorId: number, model: ITextModel, configuration: editorCommon.IConfiguration, linesCollection: IViewModelLinesCollection, coordinatesConverter: ICoordinatesConverter) {\r\n\t\tthis.editorId = editorId;\r\n\t\tthis.model = model;\r\n\t\tthis.configuration = configuration;\r\n\t\tthis._linesCollection = linesCollection;\r\n\t\tthis._coordinatesConverter = coordinatesConverter;\r\n\t\tthis._decorationsCache = Object.create(null);\r\n\t\tthis._cachedModelDecorationsResolver = null;\r\n\t\tthis._cachedModelDecorationsResolverViewRange = null;\r\n\t}\r\n\r\n\tprivate _clearCachedModelDecorationsResolver(): void {\r\n\t\tthis._cachedModelDecorationsResolver = null;\r\n\t\tthis._cachedModelDecorationsResolverViewRange = null;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._decorationsCache = Object.create(null);\r\n\t\tthis._clearCachedModelDecorationsResolver();\r\n\t}\r\n\r\n\tpublic reset(): void {\r\n\t\tthis._decorationsCache = Object.create(null);\r\n\t\tthis._clearCachedModelDecorationsResolver();\r\n\t}\r\n\r\n\tpublic onModelDecorationsChanged(): void {\r\n\t\tthis._decorationsCache = Object.create(null);\r\n\t\tthis._clearCachedModelDecorationsResolver();\r\n\t}\r\n\r\n\tpublic onLineMappingChanged(): void {\r\n\t\tthis._decorationsCache = Object.create(null);\r\n\r\n\t\tthis._clearCachedModelDecorationsResolver();\r\n\t}\r\n\r\n\tprivate _getOrCreateViewModelDecoration(modelDecoration: IModelDecoration): ViewModelDecoration {\r\n\t\tconst id = modelDecoration.id;\r\n\t\tlet r = this._decorationsCache[id];\r\n\t\tif (!r) {\r\n\t\t\tconst modelRange = modelDecoration.range;\r\n\t\t\tconst options = modelDecoration.options;\r\n\t\t\tlet viewRange: Range;\r\n\t\t\tif (options.isWholeLine) {\r\n\t\t\t\tconst start = this._coordinatesConverter.convertModelPositionToViewPosition(new Position(modelRange.startLineNumber, 1));\r\n\t\t\t\tconst end = this._coordinatesConverter.convertModelPositionToViewPosition(new Position(modelRange.endLineNumber, this.model.getLineMaxColumn(modelRange.endLineNumber)));\r\n\t\t\t\tviewRange = new Range(start.lineNumber, start.column, end.lineNumber, end.column);\r\n\t\t\t} else {\r\n\t\t\t\tviewRange = this._coordinatesConverter.convertModelRangeToViewRange(modelRange);\r\n\t\t\t}\r\n\t\t\tr = new ViewModelDecoration(viewRange, options);\r\n\t\t\tthis._decorationsCache[id] = r;\r\n\t\t}\r\n\t\treturn r;\r\n\t}\r\n\r\n\tpublic getDecorationsViewportData(viewRange: Range): IDecorationsViewportData {\r\n\t\tlet cacheIsValid = (this._cachedModelDecorationsResolver !== null);\r\n\t\tcacheIsValid = cacheIsValid && (viewRange.equalsRange(this._cachedModelDecorationsResolverViewRange));\r\n\t\tif (!cacheIsValid) {\r\n\t\t\tthis._cachedModelDecorationsResolver = this._getDecorationsViewportData(viewRange);\r\n\t\t\tthis._cachedModelDecorationsResolverViewRange = viewRange;\r\n\t\t}\r\n\t\treturn this._cachedModelDecorationsResolver!;\r\n\t}\r\n\r\n\tprivate _getDecorationsViewportData(viewportRange: Range): IDecorationsViewportData {\r\n\t\tconst modelDecorations = this._linesCollection.getDecorationsInRange(viewportRange, this.editorId, filterValidationDecorations(this.configuration.options));\r\n\t\tconst startLineNumber = viewportRange.startLineNumber;\r\n\t\tconst endLineNumber = viewportRange.endLineNumber;\r\n\r\n\t\tlet decorationsInViewport: ViewModelDecoration[] = [], decorationsInViewportLen = 0;\r\n\t\tlet inlineDecorations: InlineDecoration[][] = [];\r\n\t\tfor (let j = startLineNumber; j <= endLineNumber; j++) {\r\n\t\t\tinlineDecorations[j - startLineNumber] = [];\r\n\t\t}\r\n\r\n\t\tfor (let i = 0, len = modelDecorations.length; i < len; i++) {\r\n\t\t\tlet modelDecoration = modelDecorations[i];\r\n\t\t\tlet decorationOptions = modelDecoration.options;\r\n\r\n\t\t\tlet viewModelDecoration = this._getOrCreateViewModelDecoration(modelDecoration);\r\n\t\t\tlet viewRange = viewModelDecoration.range;\r\n\r\n\t\t\tdecorationsInViewport[decorationsInViewportLen++] = viewModelDecoration;\r\n\r\n\t\t\tif (decorationOptions.inlineClassName) {\r\n\t\t\t\tlet inlineDecoration = new InlineDecoration(viewRange, decorationOptions.inlineClassName, decorationOptions.inlineClassNameAffectsLetterSpacing ? InlineDecorationType.RegularAffectingLetterSpacing : InlineDecorationType.Regular);\r\n\t\t\t\tlet intersectedStartLineNumber = Math.max(startLineNumber, viewRange.startLineNumber);\r\n\t\t\t\tlet intersectedEndLineNumber = Math.min(endLineNumber, viewRange.endLineNumber);\r\n\t\t\t\tfor (let j = intersectedStartLineNumber; j <= intersectedEndLineNumber; j++) {\r\n\t\t\t\t\tinlineDecorations[j - startLineNumber].push(inlineDecoration);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (decorationOptions.beforeContentClassName) {\r\n\t\t\t\tif (startLineNumber <= viewRange.startLineNumber && viewRange.startLineNumber <= endLineNumber) {\r\n\t\t\t\t\tlet inlineDecoration = new InlineDecoration(\r\n\t\t\t\t\t\tnew Range(viewRange.startLineNumber, viewRange.startColumn, viewRange.startLineNumber, viewRange.startColumn),\r\n\t\t\t\t\t\tdecorationOptions.beforeContentClassName,\r\n\t\t\t\t\t\tInlineDecorationType.Before\r\n\t\t\t\t\t);\r\n\t\t\t\t\tinlineDecorations[viewRange.startLineNumber - startLineNumber].push(inlineDecoration);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (decorationOptions.afterContentClassName) {\r\n\t\t\t\tif (startLineNumber <= viewRange.endLineNumber && viewRange.endLineNumber <= endLineNumber) {\r\n\t\t\t\t\tlet inlineDecoration = new InlineDecoration(\r\n\t\t\t\t\t\tnew Range(viewRange.endLineNumber, viewRange.endColumn, viewRange.endLineNumber, viewRange.endColumn),\r\n\t\t\t\t\t\tdecorationOptions.afterContentClassName,\r\n\t\t\t\t\t\tInlineDecorationType.After\r\n\t\t\t\t\t);\r\n\t\t\t\t\tinlineDecorations[viewRange.endLineNumber - startLineNumber].push(inlineDecoration);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tdecorations: decorationsInViewport,\r\n\t\t\tinlineDecorations: inlineDecorations\r\n\t\t};\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { EndOfLineSequence, ICursorStateComputer, IIdentifiedSingleEditOperation, IValidEditOperation, ITextModel } from 'vs/editor/common/model';\r\nimport { TextModel } from 'vs/editor/common/model/textModel';\r\nimport { IUndoRedoService, IResourceUndoRedoElement, UndoRedoElementType, IWorkspaceUndoRedoElement } from 'vs/platform/undoRedo/common/undoRedo';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { TextChange, compressConsecutiveTextChanges } from 'vs/editor/common/model/textChange';\r\nimport * as buffer from 'vs/base/common/buffer';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { basename } from 'vs/base/common/resources';\r\n\r\nfunction uriGetComparisonKey(resource: URI): string {\r\n\treturn resource.toString();\r\n}\r\n\r\nclass SingleModelEditStackData {\r\n\r\n\tpublic static create(model: ITextModel, beforeCursorState: Selection[] | null): SingleModelEditStackData {\r\n\t\tconst alternativeVersionId = model.getAlternativeVersionId();\r\n\t\tconst eol = getModelEOL(model);\r\n\t\treturn new SingleModelEditStackData(\r\n\t\t\talternativeVersionId,\r\n\t\t\talternativeVersionId,\r\n\t\t\teol,\r\n\t\t\teol,\r\n\t\t\tbeforeCursorState,\r\n\t\t\tbeforeCursorState,\r\n\t\t\t[]\r\n\t\t);\r\n\t}\r\n\r\n\tconstructor(\r\n\t\tpublic readonly beforeVersionId: number,\r\n\t\tpublic afterVersionId: number,\r\n\t\tpublic readonly beforeEOL: EndOfLineSequence,\r\n\t\tpublic afterEOL: EndOfLineSequence,\r\n\t\tpublic readonly beforeCursorState: Selection[] | null,\r\n\t\tpublic afterCursorState: Selection[] | null,\r\n\t\tpublic changes: TextChange[]\r\n\t) { }\r\n\r\n\tpublic append(model: ITextModel, textChanges: TextChange[], afterEOL: EndOfLineSequence, afterVersionId: number, afterCursorState: Selection[] | null): void {\r\n\t\tif (textChanges.length > 0) {\r\n\t\t\tthis.changes = compressConsecutiveTextChanges(this.changes, textChanges);\r\n\t\t}\r\n\t\tthis.afterEOL = afterEOL;\r\n\t\tthis.afterVersionId = afterVersionId;\r\n\t\tthis.afterCursorState = afterCursorState;\r\n\t}\r\n\r\n\tprivate static _writeSelectionsSize(selections: Selection[] | null): number {\r\n\t\treturn 4 + 4 * 4 * (selections ? selections.length : 0);\r\n\t}\r\n\r\n\tprivate static _writeSelections(b: Uint8Array, selections: Selection[] | null, offset: number): number {\r\n\t\tbuffer.writeUInt32BE(b, (selections ? selections.length : 0), offset); offset += 4;\r\n\t\tif (selections) {\r\n\t\t\tfor (const selection of selections) {\r\n\t\t\t\tbuffer.writeUInt32BE(b, selection.selectionStartLineNumber, offset); offset += 4;\r\n\t\t\t\tbuffer.writeUInt32BE(b, selection.selectionStartColumn, offset); offset += 4;\r\n\t\t\t\tbuffer.writeUInt32BE(b, selection.positionLineNumber, offset); offset += 4;\r\n\t\t\t\tbuffer.writeUInt32BE(b, selection.positionColumn, offset); offset += 4;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn offset;\r\n\t}\r\n\r\n\tprivate static _readSelections(b: Uint8Array, offset: number, dest: Selection[]): number {\r\n\t\tconst count = buffer.readUInt32BE(b, offset); offset += 4;\r\n\t\tfor (let i = 0; i < count; i++) {\r\n\t\t\tconst selectionStartLineNumber = buffer.readUInt32BE(b, offset); offset += 4;\r\n\t\t\tconst selectionStartColumn = buffer.readUInt32BE(b, offset); offset += 4;\r\n\t\t\tconst positionLineNumber = buffer.readUInt32BE(b, offset); offset += 4;\r\n\t\t\tconst positionColumn = buffer.readUInt32BE(b, offset); offset += 4;\r\n\t\t\tdest.push(new Selection(selectionStartLineNumber, selectionStartColumn, positionLineNumber, positionColumn));\r\n\t\t}\r\n\t\treturn offset;\r\n\t}\r\n\r\n\tpublic serialize(): ArrayBuffer {\r\n\t\tlet necessarySize = (\r\n\t\t\t+ 4 // beforeVersionId\r\n\t\t\t+ 4 // afterVersionId\r\n\t\t\t+ 1 // beforeEOL\r\n\t\t\t+ 1 // afterEOL\r\n\t\t\t+ SingleModelEditStackData._writeSelectionsSize(this.beforeCursorState)\r\n\t\t\t+ SingleModelEditStackData._writeSelectionsSize(this.afterCursorState)\r\n\t\t\t+ 4 // change count\r\n\t\t);\r\n\t\tfor (const change of this.changes) {\r\n\t\t\tnecessarySize += change.writeSize();\r\n\t\t}\r\n\r\n\t\tconst b = new Uint8Array(necessarySize);\r\n\t\tlet offset = 0;\r\n\t\tbuffer.writeUInt32BE(b, this.beforeVersionId, offset); offset += 4;\r\n\t\tbuffer.writeUInt32BE(b, this.afterVersionId, offset); offset += 4;\r\n\t\tbuffer.writeUInt8(b, this.beforeEOL, offset); offset += 1;\r\n\t\tbuffer.writeUInt8(b, this.afterEOL, offset); offset += 1;\r\n\t\toffset = SingleModelEditStackData._writeSelections(b, this.beforeCursorState, offset);\r\n\t\toffset = SingleModelEditStackData._writeSelections(b, this.afterCursorState, offset);\r\n\t\tbuffer.writeUInt32BE(b, this.changes.length, offset); offset += 4;\r\n\t\tfor (const change of this.changes) {\r\n\t\t\toffset = change.write(b, offset);\r\n\t\t}\r\n\t\treturn b.buffer;\r\n\t}\r\n\r\n\tpublic static deserialize(source: ArrayBuffer): SingleModelEditStackData {\r\n\t\tconst b = new Uint8Array(source);\r\n\t\tlet offset = 0;\r\n\t\tconst beforeVersionId = buffer.readUInt32BE(b, offset); offset += 4;\r\n\t\tconst afterVersionId = buffer.readUInt32BE(b, offset); offset += 4;\r\n\t\tconst beforeEOL = buffer.readUInt8(b, offset); offset += 1;\r\n\t\tconst afterEOL = buffer.readUInt8(b, offset); offset += 1;\r\n\t\tconst beforeCursorState: Selection[] = [];\r\n\t\toffset = SingleModelEditStackData._readSelections(b, offset, beforeCursorState);\r\n\t\tconst afterCursorState: Selection[] = [];\r\n\t\toffset = SingleModelEditStackData._readSelections(b, offset, afterCursorState);\r\n\t\tconst changeCount = buffer.readUInt32BE(b, offset); offset += 4;\r\n\t\tconst changes: TextChange[] = [];\r\n\t\tfor (let i = 0; i < changeCount; i++) {\r\n\t\t\toffset = TextChange.read(b, offset, changes);\r\n\t\t}\r\n\t\treturn new SingleModelEditStackData(\r\n\t\t\tbeforeVersionId,\r\n\t\t\tafterVersionId,\r\n\t\t\tbeforeEOL,\r\n\t\t\tafterEOL,\r\n\t\t\tbeforeCursorState,\r\n\t\t\tafterCursorState,\r\n\t\t\tchanges\r\n\t\t);\r\n\t}\r\n}\r\n\r\nexport interface IUndoRedoDelegate {\r\n\tprepareUndoRedo(element: MultiModelEditStackElement): Promise | IDisposable | void;\r\n}\r\n\r\nexport class SingleModelEditStackElement implements IResourceUndoRedoElement {\r\n\r\n\tpublic model: ITextModel | URI;\r\n\tprivate _data: SingleModelEditStackData | ArrayBuffer;\r\n\r\n\tpublic get type(): UndoRedoElementType.Resource {\r\n\t\treturn UndoRedoElementType.Resource;\r\n\t}\r\n\r\n\tpublic get resource(): URI {\r\n\t\tif (URI.isUri(this.model)) {\r\n\t\t\treturn this.model;\r\n\t\t}\r\n\t\treturn this.model.uri;\r\n\t}\r\n\r\n\tpublic get label(): string {\r\n\t\treturn nls.localize('edit', \"Typing\");\r\n\t}\r\n\r\n\tconstructor(model: ITextModel, beforeCursorState: Selection[] | null) {\r\n\t\tthis.model = model;\r\n\t\tthis._data = SingleModelEditStackData.create(model, beforeCursorState);\r\n\t}\r\n\r\n\tpublic toString(): string {\r\n\t\tconst data = (this._data instanceof SingleModelEditStackData ? this._data : SingleModelEditStackData.deserialize(this._data));\r\n\t\treturn data.changes.map(change => change.toString()).join(', ');\r\n\t}\r\n\r\n\tpublic matchesResource(resource: URI): boolean {\r\n\t\tconst uri = (URI.isUri(this.model) ? this.model : this.model.uri);\r\n\t\treturn (uri.toString() === resource.toString());\r\n\t}\r\n\r\n\tpublic setModel(model: ITextModel | URI): void {\r\n\t\tthis.model = model;\r\n\t}\r\n\r\n\tpublic canAppend(model: ITextModel): boolean {\r\n\t\treturn (this.model === model && this._data instanceof SingleModelEditStackData);\r\n\t}\r\n\r\n\tpublic append(model: ITextModel, textChanges: TextChange[], afterEOL: EndOfLineSequence, afterVersionId: number, afterCursorState: Selection[] | null): void {\r\n\t\tif (this._data instanceof SingleModelEditStackData) {\r\n\t\t\tthis._data.append(model, textChanges, afterEOL, afterVersionId, afterCursorState);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic close(): void {\r\n\t\tif (this._data instanceof SingleModelEditStackData) {\r\n\t\t\tthis._data = this._data.serialize();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic open(): void {\r\n\t\tif (!(this._data instanceof SingleModelEditStackData)) {\r\n\t\t\tthis._data = SingleModelEditStackData.deserialize(this._data);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic undo(): void {\r\n\t\tif (URI.isUri(this.model)) {\r\n\t\t\t// don't have a model\r\n\t\t\tthrow new Error(`Invalid SingleModelEditStackElement`);\r\n\t\t}\r\n\t\tif (this._data instanceof SingleModelEditStackData) {\r\n\t\t\tthis._data = this._data.serialize();\r\n\t\t}\r\n\t\tconst data = SingleModelEditStackData.deserialize(this._data);\r\n\t\tthis.model._applyUndo(data.changes, data.beforeEOL, data.beforeVersionId, data.beforeCursorState);\r\n\t}\r\n\r\n\tpublic redo(): void {\r\n\t\tif (URI.isUri(this.model)) {\r\n\t\t\t// don't have a model\r\n\t\t\tthrow new Error(`Invalid SingleModelEditStackElement`);\r\n\t\t}\r\n\t\tif (this._data instanceof SingleModelEditStackData) {\r\n\t\t\tthis._data = this._data.serialize();\r\n\t\t}\r\n\t\tconst data = SingleModelEditStackData.deserialize(this._data);\r\n\t\tthis.model._applyRedo(data.changes, data.afterEOL, data.afterVersionId, data.afterCursorState);\r\n\t}\r\n\r\n\tpublic heapSize(): number {\r\n\t\tif (this._data instanceof SingleModelEditStackData) {\r\n\t\t\tthis._data = this._data.serialize();\r\n\t\t}\r\n\t\treturn this._data.byteLength + 168/*heap overhead*/;\r\n\t}\r\n}\r\n\r\nexport class MultiModelEditStackElement implements IWorkspaceUndoRedoElement {\r\n\r\n\tpublic readonly type = UndoRedoElementType.Workspace;\r\n\tpublic readonly label: string;\r\n\tprivate _isOpen: boolean;\r\n\r\n\tprivate readonly _editStackElementsArr: SingleModelEditStackElement[];\r\n\tprivate readonly _editStackElementsMap: Map;\r\n\r\n\tprivate _delegate: IUndoRedoDelegate | null;\r\n\r\n\tpublic get resources(): readonly URI[] {\r\n\t\treturn this._editStackElementsArr.map(editStackElement => editStackElement.resource);\r\n\t}\r\n\r\n\tconstructor(\r\n\t\tlabel: string,\r\n\t\teditStackElements: SingleModelEditStackElement[]\r\n\t) {\r\n\t\tthis.label = label;\r\n\t\tthis._isOpen = true;\r\n\t\tthis._editStackElementsArr = editStackElements.slice(0);\r\n\t\tthis._editStackElementsMap = new Map();\r\n\t\tfor (const editStackElement of this._editStackElementsArr) {\r\n\t\t\tconst key = uriGetComparisonKey(editStackElement.resource);\r\n\t\t\tthis._editStackElementsMap.set(key, editStackElement);\r\n\t\t}\r\n\t\tthis._delegate = null;\r\n\t}\r\n\r\n\tpublic prepareUndoRedo(): Promise | IDisposable | void {\r\n\t\tif (this._delegate) {\r\n\t\t\treturn this._delegate.prepareUndoRedo(this);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic matchesResource(resource: URI): boolean {\r\n\t\tconst key = uriGetComparisonKey(resource);\r\n\t\treturn (this._editStackElementsMap.has(key));\r\n\t}\r\n\r\n\tpublic setModel(model: ITextModel | URI): void {\r\n\t\tconst key = uriGetComparisonKey(URI.isUri(model) ? model : model.uri);\r\n\t\tif (this._editStackElementsMap.has(key)) {\r\n\t\t\tthis._editStackElementsMap.get(key)!.setModel(model);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic canAppend(model: ITextModel): boolean {\r\n\t\tif (!this._isOpen) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tconst key = uriGetComparisonKey(model.uri);\r\n\t\tif (this._editStackElementsMap.has(key)) {\r\n\t\t\tconst editStackElement = this._editStackElementsMap.get(key)!;\r\n\t\t\treturn editStackElement.canAppend(model);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic append(model: ITextModel, textChanges: TextChange[], afterEOL: EndOfLineSequence, afterVersionId: number, afterCursorState: Selection[] | null): void {\r\n\t\tconst key = uriGetComparisonKey(model.uri);\r\n\t\tconst editStackElement = this._editStackElementsMap.get(key)!;\r\n\t\teditStackElement.append(model, textChanges, afterEOL, afterVersionId, afterCursorState);\r\n\t}\r\n\r\n\tpublic close(): void {\r\n\t\tthis._isOpen = false;\r\n\t}\r\n\r\n\tpublic open(): void {\r\n\t\t// cannot reopen\r\n\t}\r\n\r\n\tpublic undo(): void {\r\n\t\tthis._isOpen = false;\r\n\r\n\t\tfor (const editStackElement of this._editStackElementsArr) {\r\n\t\t\teditStackElement.undo();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic redo(): void {\r\n\t\tfor (const editStackElement of this._editStackElementsArr) {\r\n\t\t\teditStackElement.redo();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic heapSize(resource: URI): number {\r\n\t\tconst key = uriGetComparisonKey(resource);\r\n\t\tif (this._editStackElementsMap.has(key)) {\r\n\t\t\tconst editStackElement = this._editStackElementsMap.get(key)!;\r\n\t\t\treturn editStackElement.heapSize();\r\n\t\t}\r\n\t\treturn 0;\r\n\t}\r\n\r\n\tpublic split(): IResourceUndoRedoElement[] {\r\n\t\treturn this._editStackElementsArr;\r\n\t}\r\n\r\n\tpublic toString(): string {\r\n\t\tlet result: string[] = [];\r\n\t\tfor (const editStackElement of this._editStackElementsArr) {\r\n\t\t\tresult.push(`${basename(editStackElement.resource)}: ${editStackElement}`);\r\n\t\t}\r\n\t\treturn `{${result.join(', ')}}`;\r\n\t}\r\n}\r\n\r\nexport type EditStackElement = SingleModelEditStackElement | MultiModelEditStackElement;\r\n\r\nfunction getModelEOL(model: ITextModel): EndOfLineSequence {\r\n\tconst eol = model.getEOL();\r\n\tif (eol === '\\n') {\r\n\t\treturn EndOfLineSequence.LF;\r\n\t} else {\r\n\t\treturn EndOfLineSequence.CRLF;\r\n\t}\r\n}\r\n\r\nexport function isEditStackElement(element: IResourceUndoRedoElement | IWorkspaceUndoRedoElement | null): element is EditStackElement {\r\n\tif (!element) {\r\n\t\treturn false;\r\n\t}\r\n\treturn ((element instanceof SingleModelEditStackElement) || (element instanceof MultiModelEditStackElement));\r\n}\r\n\r\nexport class EditStack {\r\n\r\n\tprivate readonly _model: TextModel;\r\n\tprivate readonly _undoRedoService: IUndoRedoService;\r\n\r\n\tconstructor(model: TextModel, undoRedoService: IUndoRedoService) {\r\n\t\tthis._model = model;\r\n\t\tthis._undoRedoService = undoRedoService;\r\n\t}\r\n\r\n\tpublic pushStackElement(): void {\r\n\t\tconst lastElement = this._undoRedoService.getLastElement(this._model.uri);\r\n\t\tif (isEditStackElement(lastElement)) {\r\n\t\t\tlastElement.close();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic popStackElement(): void {\r\n\t\tconst lastElement = this._undoRedoService.getLastElement(this._model.uri);\r\n\t\tif (isEditStackElement(lastElement)) {\r\n\t\t\tlastElement.open();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic clear(): void {\r\n\t\tthis._undoRedoService.removeElements(this._model.uri);\r\n\t}\r\n\r\n\tprivate _getOrCreateEditStackElement(beforeCursorState: Selection[] | null): EditStackElement {\r\n\t\tconst lastElement = this._undoRedoService.getLastElement(this._model.uri);\r\n\t\tif (isEditStackElement(lastElement) && lastElement.canAppend(this._model)) {\r\n\t\t\treturn lastElement;\r\n\t\t}\r\n\t\tconst newElement = new SingleModelEditStackElement(this._model, beforeCursorState);\r\n\t\tthis._undoRedoService.pushElement(newElement);\r\n\t\treturn newElement;\r\n\t}\r\n\r\n\tpublic pushEOL(eol: EndOfLineSequence): void {\r\n\t\tconst editStackElement = this._getOrCreateEditStackElement(null);\r\n\t\tthis._model.setEOL(eol);\r\n\t\teditStackElement.append(this._model, [], getModelEOL(this._model), this._model.getAlternativeVersionId(), null);\r\n\t}\r\n\r\n\tpublic pushEditOperation(beforeCursorState: Selection[] | null, editOperations: IIdentifiedSingleEditOperation[], cursorStateComputer: ICursorStateComputer | null): Selection[] | null {\r\n\t\tconst editStackElement = this._getOrCreateEditStackElement(beforeCursorState);\r\n\t\tconst inverseEditOperations = this._model.applyEdits(editOperations, true);\r\n\t\tconst afterCursorState = EditStack._computeCursorState(cursorStateComputer, inverseEditOperations);\r\n\t\tconst textChanges = inverseEditOperations.map((op, index) => ({ index: index, textChange: op.textChange }));\r\n\t\ttextChanges.sort((a, b) => {\r\n\t\t\tif (a.textChange.oldPosition === b.textChange.oldPosition) {\r\n\t\t\t\treturn a.index - b.index;\r\n\t\t\t}\r\n\t\t\treturn a.textChange.oldPosition - b.textChange.oldPosition;\r\n\t\t});\r\n\t\teditStackElement.append(this._model, textChanges.map(op => op.textChange), getModelEOL(this._model), this._model.getAlternativeVersionId(), afterCursorState);\r\n\t\treturn afterCursorState;\r\n\t}\r\n\r\n\tprivate static _computeCursorState(cursorStateComputer: ICursorStateComputer | null, inverseEditOperations: IValidEditOperation[]): Selection[] | null {\r\n\t\ttry {\r\n\t\t\treturn cursorStateComputer ? cursorStateComputer(inverseEditOperations) : null;\r\n\t\t} catch (e) {\r\n\t\t\tonUnexpectedError(e);\r\n\t\t\treturn null;\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\n\r\nexport namespace AccessibilityHelpNLS {\r\n\texport const noSelection = nls.localize(\"noSelection\", \"No selection\");\r\n\texport const singleSelectionRange = nls.localize(\"singleSelectionRange\", \"Line {0}, Column {1} ({2} selected)\");\r\n\texport const singleSelection = nls.localize(\"singleSelection\", \"Line {0}, Column {1}\");\r\n\texport const multiSelectionRange = nls.localize(\"multiSelectionRange\", \"{0} selections ({1} characters selected)\");\r\n\texport const multiSelection = nls.localize(\"multiSelection\", \"{0} selections\");\r\n\texport const emergencyConfOn = nls.localize(\"emergencyConfOn\", \"Now changing the setting `accessibilitySupport` to 'on'.\");\r\n\texport const openingDocs = nls.localize(\"openingDocs\", \"Now opening the Editor Accessibility documentation page.\");\r\n\texport const readonlyDiffEditor = nls.localize(\"readonlyDiffEditor\", \" in a read-only pane of a diff editor.\");\r\n\texport const editableDiffEditor = nls.localize(\"editableDiffEditor\", \" in a pane of a diff editor.\");\r\n\texport const readonlyEditor = nls.localize(\"readonlyEditor\", \" in a read-only code editor\");\r\n\texport const editableEditor = nls.localize(\"editableEditor\", \" in a code editor\");\r\n\texport const changeConfigToOnMac = nls.localize(\"changeConfigToOnMac\", \"To configure the editor to be optimized for usage with a Screen Reader press Command+E now.\");\r\n\texport const changeConfigToOnWinLinux = nls.localize(\"changeConfigToOnWinLinux\", \"To configure the editor to be optimized for usage with a Screen Reader press Control+E now.\");\r\n\texport const auto_on = nls.localize(\"auto_on\", \"The editor is configured to be optimized for usage with a Screen Reader.\");\r\n\texport const auto_off = nls.localize(\"auto_off\", \"The editor is configured to never be optimized for usage with a Screen Reader, which is not the case at this time.\");\r\n\texport const tabFocusModeOnMsg = nls.localize(\"tabFocusModeOnMsg\", \"Pressing Tab in the current editor will move focus to the next focusable element. Toggle this behavior by pressing {0}.\");\r\n\texport const tabFocusModeOnMsgNoKb = nls.localize(\"tabFocusModeOnMsgNoKb\", \"Pressing Tab in the current editor will move focus to the next focusable element. The command {0} is currently not triggerable by a keybinding.\");\r\n\texport const tabFocusModeOffMsg = nls.localize(\"tabFocusModeOffMsg\", \"Pressing Tab in the current editor will insert the tab character. Toggle this behavior by pressing {0}.\");\r\n\texport const tabFocusModeOffMsgNoKb = nls.localize(\"tabFocusModeOffMsgNoKb\", \"Pressing Tab in the current editor will insert the tab character. The command {0} is currently not triggerable by a keybinding.\");\r\n\texport const openDocMac = nls.localize(\"openDocMac\", \"Press Command+H now to open a browser window with more information related to editor accessibility.\");\r\n\texport const openDocWinLinux = nls.localize(\"openDocWinLinux\", \"Press Control+H now to open a browser window with more information related to editor accessibility.\");\r\n\texport const outroMsg = nls.localize(\"outroMsg\", \"You can dismiss this tooltip and return to the editor by pressing Escape or Shift+Escape.\");\r\n\texport const showAccessibilityHelpAction = nls.localize(\"showAccessibilityHelpAction\", \"Show Accessibility Help\");\r\n}\r\n\r\nexport namespace InspectTokensNLS {\r\n\texport const inspectTokensAction = nls.localize('inspectTokens', \"Developer: Inspect Tokens\");\r\n}\r\n\r\nexport namespace GoToLineNLS {\r\n\texport const gotoLineActionLabel = nls.localize('gotoLineActionLabel', \"Go to Line/Column...\");\r\n}\r\n\r\nexport namespace QuickHelpNLS {\r\n\texport const helpQuickAccessActionLabel = nls.localize('helpQuickAccess', \"Show all Quick Access Providers\");\r\n}\r\n\r\nexport namespace QuickCommandNLS {\r\n\texport const quickCommandActionLabel = nls.localize('quickCommandActionLabel', \"Command Palette\");\r\n\texport const quickCommandHelp = nls.localize('quickCommandActionHelp', \"Show And Run Commands\");\r\n}\r\n\r\nexport namespace QuickOutlineNLS {\r\n\texport const quickOutlineActionLabel = nls.localize('quickOutlineActionLabel', \"Go to Symbol...\");\r\n\texport const quickOutlineByCategoryActionLabel = nls.localize('quickOutlineByCategoryActionLabel', \"Go to Symbol by Category...\");\r\n}\r\n\r\nexport namespace StandaloneCodeEditorNLS {\r\n\texport const editorViewAccessibleLabel = nls.localize('editorViewAccessibleLabel', \"Editor content\");\r\n\texport const accessibilityHelpMessage = nls.localize('accessibilityHelpMessage', \"Press Alt+F1 for Accessibility Options.\");\r\n}\r\n\r\nexport namespace ToggleHighContrastNLS {\r\n\texport const toggleHighContrast = nls.localize('toggleHighContrast', \"Toggle High Contrast Theme\");\r\n}\r\n\r\nexport namespace SimpleServicesNLS {\r\n\texport const bulkEditServiceSummary = nls.localize('bulkEditServiceSummary', \"Made {0} edits in {1} files\");\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { localize } from 'vs/nls';\r\nimport { Event, Emitter } from 'vs/base/common/event';\r\nimport { basename, extUri } from 'vs/base/common/resources';\r\nimport { IDisposable, dispose, IReference, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { defaultGenerator } from 'vs/base/common/idGenerator';\r\nimport { Range, IRange } from 'vs/editor/common/core/range';\r\nimport { Location, LocationLink } from 'vs/editor/common/modes';\r\nimport { ITextModelService, ITextEditorModel } from 'vs/editor/common/services/resolverService';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { IMatch } from 'vs/base/common/filters';\r\nimport { Constants } from 'vs/base/common/uint';\r\nimport { ResourceMap } from 'vs/base/common/map';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\n\r\nexport class OneReference {\r\n\r\n\treadonly id: string = defaultGenerator.nextId();\r\n\r\n\tconstructor(\r\n\t\treadonly isProviderFirst: boolean,\r\n\t\treadonly parent: FileReferences,\r\n\t\treadonly uri: URI,\r\n\t\tprivate _range: IRange,\r\n\t\tprivate _rangeCallback: (ref: OneReference) => void\r\n\t) { }\r\n\r\n\tget range(): IRange {\r\n\t\treturn this._range;\r\n\t}\r\n\r\n\tset range(value: IRange) {\r\n\t\tthis._range = value;\r\n\t\tthis._rangeCallback(this);\r\n\t}\r\n\r\n\tget ariaMessage(): string {\r\n\r\n\t\tconst preview = this.parent.getPreview(this)?.preview(this.range);\r\n\r\n\t\tif (!preview) {\r\n\t\t\treturn localize(\r\n\t\t\t\t'aria.oneReference', \"symbol in {0} on line {1} at column {2}\",\r\n\t\t\t\tbasename(this.uri), this.range.startLineNumber, this.range.startColumn\r\n\t\t\t);\r\n\t\t} else {\r\n\t\t\treturn localize(\r\n\t\t\t\t{ key: 'aria.oneReference.preview', comment: ['Placeholders are: 0: filename, 1:line number, 2: column number, 3: preview snippet of source code'] }, \"symbol in {0} on line {1} at column {2}, {3}\",\r\n\t\t\t\tbasename(this.uri), this.range.startLineNumber, this.range.startColumn, preview.value\r\n\t\t\t);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class FilePreview implements IDisposable {\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _modelReference: IReference\r\n\t) { }\r\n\r\n\tdispose(): void {\r\n\t\tthis._modelReference.dispose();\r\n\t}\r\n\r\n\tpreview(range: IRange, n: number = 8): { value: string; highlight: IMatch } | undefined {\r\n\t\tconst model = this._modelReference.object.textEditorModel;\r\n\r\n\t\tif (!model) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\r\n\t\tconst { startLineNumber, startColumn, endLineNumber, endColumn } = range;\r\n\t\tconst word = model.getWordUntilPosition({ lineNumber: startLineNumber, column: startColumn - n });\r\n\t\tconst beforeRange = new Range(startLineNumber, word.startColumn, startLineNumber, startColumn);\r\n\t\tconst afterRange = new Range(endLineNumber, endColumn, endLineNumber, Constants.MAX_SAFE_SMALL_INTEGER);\r\n\r\n\t\tconst before = model.getValueInRange(beforeRange).replace(/^\\s+/, '');\r\n\t\tconst inside = model.getValueInRange(range);\r\n\t\tconst after = model.getValueInRange(afterRange).replace(/\\s+$/, '');\r\n\r\n\t\treturn {\r\n\t\t\tvalue: before + inside + after,\r\n\t\t\thighlight: { start: before.length, end: before.length + inside.length }\r\n\t\t};\r\n\t}\r\n}\r\n\r\nexport class FileReferences implements IDisposable {\r\n\r\n\treadonly children: OneReference[] = [];\r\n\r\n\tprivate _previews = new ResourceMap();\r\n\r\n\tconstructor(\r\n\t\treadonly parent: ReferencesModel,\r\n\t\treadonly uri: URI\r\n\t) { }\r\n\r\n\tdispose(): void {\r\n\t\tdispose(this._previews.values());\r\n\t\tthis._previews.clear();\r\n\t}\r\n\r\n\tgetPreview(child: OneReference): FilePreview | undefined {\r\n\t\treturn this._previews.get(child.uri);\r\n\t}\r\n\r\n\tget ariaMessage(): string {\r\n\t\tconst len = this.children.length;\r\n\t\tif (len === 1) {\r\n\t\t\treturn localize('aria.fileReferences.1', \"1 symbol in {0}, full path {1}\", basename(this.uri), this.uri.fsPath);\r\n\t\t} else {\r\n\t\t\treturn localize('aria.fileReferences.N', \"{0} symbols in {1}, full path {2}\", len, basename(this.uri), this.uri.fsPath);\r\n\t\t}\r\n\t}\r\n\r\n\tasync resolve(textModelResolverService: ITextModelService): Promise {\r\n\t\tif (this._previews.size !== 0) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\tfor (let child of this.children) {\r\n\t\t\tif (this._previews.has(child.uri)) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\ttry {\r\n\t\t\t\tconst ref = await textModelResolverService.createModelReference(child.uri);\r\n\t\t\t\tthis._previews.set(child.uri, new FilePreview(ref));\r\n\t\t\t} catch (err) {\r\n\t\t\t\tonUnexpectedError(err);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this;\r\n\t}\r\n}\r\n\r\nexport class ReferencesModel implements IDisposable {\r\n\r\n\tprivate readonly _disposables = new DisposableStore();\r\n\tprivate readonly _links: LocationLink[];\r\n\tprivate readonly _title: string;\r\n\r\n\treadonly groups: FileReferences[] = [];\r\n\treadonly references: OneReference[] = [];\r\n\r\n\treadonly _onDidChangeReferenceRange = new Emitter();\r\n\treadonly onDidChangeReferenceRange: Event = this._onDidChangeReferenceRange.event;\r\n\r\n\tconstructor(links: LocationLink[], title: string) {\r\n\t\tthis._links = links;\r\n\t\tthis._title = title;\r\n\r\n\t\t// grouping and sorting\r\n\t\tconst [providersFirst] = links;\r\n\t\tlinks.sort(ReferencesModel._compareReferences);\r\n\r\n\t\tlet current: FileReferences | undefined;\r\n\t\tfor (let link of links) {\r\n\t\t\tif (!current || !extUri.isEqual(current.uri, link.uri, true)) {\r\n\t\t\t\t// new group\r\n\t\t\t\tcurrent = new FileReferences(this, link.uri);\r\n\t\t\t\tthis.groups.push(current);\r\n\t\t\t}\r\n\r\n\t\t\t// append, check for equality first!\r\n\t\t\tif (current.children.length === 0 || ReferencesModel._compareReferences(link, current.children[current.children.length - 1]) !== 0) {\r\n\r\n\t\t\t\tconst oneRef = new OneReference(\r\n\t\t\t\t\tprovidersFirst === link,\r\n\t\t\t\t\tcurrent,\r\n\t\t\t\t\tlink.uri,\r\n\t\t\t\t\tlink.targetSelectionRange || link.range,\r\n\t\t\t\t\tref => this._onDidChangeReferenceRange.fire(ref)\r\n\t\t\t\t);\r\n\t\t\t\tthis.references.push(oneRef);\r\n\t\t\t\tcurrent.children.push(oneRef);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tdispose(this.groups);\r\n\t\tthis._disposables.dispose();\r\n\t\tthis._onDidChangeReferenceRange.dispose();\r\n\t\tthis.groups.length = 0;\r\n\t}\r\n\r\n\tclone(): ReferencesModel {\r\n\t\treturn new ReferencesModel(this._links, this._title);\r\n\t}\r\n\r\n\tget title(): string {\r\n\t\treturn this._title;\r\n\t}\r\n\r\n\tget isEmpty(): boolean {\r\n\t\treturn this.groups.length === 0;\r\n\t}\r\n\r\n\tget ariaMessage(): string {\r\n\t\tif (this.isEmpty) {\r\n\t\t\treturn localize('aria.result.0', \"No results found\");\r\n\t\t} else if (this.references.length === 1) {\r\n\t\t\treturn localize('aria.result.1', \"Found 1 symbol in {0}\", this.references[0].uri.fsPath);\r\n\t\t} else if (this.groups.length === 1) {\r\n\t\t\treturn localize('aria.result.n1', \"Found {0} symbols in {1}\", this.references.length, this.groups[0].uri.fsPath);\r\n\t\t} else {\r\n\t\t\treturn localize('aria.result.nm', \"Found {0} symbols in {1} files\", this.references.length, this.groups.length);\r\n\t\t}\r\n\t}\r\n\r\n\tnextOrPreviousReference(reference: OneReference, next: boolean): OneReference {\r\n\r\n\t\tlet { parent } = reference;\r\n\r\n\t\tlet idx = parent.children.indexOf(reference);\r\n\t\tlet childCount = parent.children.length;\r\n\t\tlet groupCount = parent.parent.groups.length;\r\n\r\n\t\tif (groupCount === 1 || next && idx + 1 < childCount || !next && idx > 0) {\r\n\t\t\t// cycling within one file\r\n\t\t\tif (next) {\r\n\t\t\t\tidx = (idx + 1) % childCount;\r\n\t\t\t} else {\r\n\t\t\t\tidx = (idx + childCount - 1) % childCount;\r\n\t\t\t}\r\n\t\t\treturn parent.children[idx];\r\n\t\t}\r\n\r\n\t\tidx = parent.parent.groups.indexOf(parent);\r\n\t\tif (next) {\r\n\t\t\tidx = (idx + 1) % groupCount;\r\n\t\t\treturn parent.parent.groups[idx].children[0];\r\n\t\t} else {\r\n\t\t\tidx = (idx + groupCount - 1) % groupCount;\r\n\t\t\treturn parent.parent.groups[idx].children[parent.parent.groups[idx].children.length - 1];\r\n\t\t}\r\n\t}\r\n\r\n\tnearestReference(resource: URI, position: Position): OneReference | undefined {\r\n\r\n\t\tconst nearest = this.references.map((ref, idx) => {\r\n\t\t\treturn {\r\n\t\t\t\tidx,\r\n\t\t\t\tprefixLen: strings.commonPrefixLength(ref.uri.toString(), resource.toString()),\r\n\t\t\t\toffsetDist: Math.abs(ref.range.startLineNumber - position.lineNumber) * 100 + Math.abs(ref.range.startColumn - position.column)\r\n\t\t\t};\r\n\t\t}).sort((a, b) => {\r\n\t\t\tif (a.prefixLen > b.prefixLen) {\r\n\t\t\t\treturn -1;\r\n\t\t\t} else if (a.prefixLen < b.prefixLen) {\r\n\t\t\t\treturn 1;\r\n\t\t\t} else if (a.offsetDist < b.offsetDist) {\r\n\t\t\t\treturn -1;\r\n\t\t\t} else if (a.offsetDist > b.offsetDist) {\r\n\t\t\t\treturn 1;\r\n\t\t\t} else {\r\n\t\t\t\treturn 0;\r\n\t\t\t}\r\n\t\t})[0];\r\n\r\n\t\tif (nearest) {\r\n\t\t\treturn this.references[nearest.idx];\r\n\t\t}\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\treferenceAt(resource: URI, position: Position): OneReference | undefined {\r\n\t\tfor (const ref of this.references) {\r\n\t\t\tif (ref.uri.toString() === resource.toString()) {\r\n\t\t\t\tif (Range.containsPosition(ref.range, position)) {\r\n\t\t\t\t\treturn ref;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tfirstReference(): OneReference | undefined {\r\n\t\tfor (const ref of this.references) {\r\n\t\t\tif (ref.isProviderFirst) {\r\n\t\t\t\treturn ref;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this.references[0];\r\n\t}\r\n\r\n\tprivate static _compareReferences(a: Location, b: Location): number {\r\n\t\treturn extUri.compare(a.uri, b.uri) || Range.compareRangesUsingStarts(a.range, b.range);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';\r\nimport { $ } from 'vs/base/browser/dom';\r\n\r\nexport class BrowserClipboardService implements IClipboardService {\r\n\r\n\tdeclare readonly _serviceBrand: undefined;\r\n\r\n\tprivate readonly mapTextToType = new Map(); // unsupported in web (only in-memory)\r\n\r\n\tasync writeText(text: string, type?: string): Promise {\r\n\r\n\t\t// With type: only in-memory is supported\r\n\t\tif (type) {\r\n\t\t\tthis.mapTextToType.set(type, text);\r\n\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// Guard access to navigator.clipboard with try/catch\r\n\t\t// as we have seen DOMExceptions in certain browsers\r\n\t\t// due to security policies.\r\n\t\ttry {\r\n\t\t\treturn await navigator.clipboard.writeText(text);\r\n\t\t} catch (error) {\r\n\t\t\tconsole.error(error);\r\n\t\t}\r\n\r\n\t\t// Fallback to textarea and execCommand solution\r\n\r\n\t\tconst activeElement = document.activeElement;\r\n\r\n\t\tconst textArea: HTMLTextAreaElement = document.body.appendChild($('textarea', { 'aria-hidden': true }));\r\n\t\ttextArea.style.height = '1px';\r\n\t\ttextArea.style.width = '1px';\r\n\t\ttextArea.style.position = 'absolute';\r\n\r\n\t\ttextArea.value = text;\r\n\t\ttextArea.focus();\r\n\t\ttextArea.select();\r\n\r\n\t\tdocument.execCommand('copy');\r\n\r\n\t\tif (activeElement instanceof HTMLElement) {\r\n\t\t\tactiveElement.focus();\r\n\t\t}\r\n\r\n\t\tdocument.body.removeChild(textArea);\r\n\r\n\t\treturn;\r\n\t}\r\n\r\n\tasync readText(type?: string): Promise {\r\n\r\n\t\t// With type: only in-memory is supported\r\n\t\tif (type) {\r\n\t\t\treturn this.mapTextToType.get(type) || '';\r\n\t\t}\r\n\r\n\t\t// Guard access to navigator.clipboard with try/catch\r\n\t\t// as we have seen DOMExceptions in certain browsers\r\n\t\t// due to security policies.\r\n\t\ttry {\r\n\t\t\treturn await navigator.clipboard.readText();\r\n\t\t} catch (error) {\r\n\t\t\tconsole.error(error);\r\n\r\n\t\t\treturn '';\r\n\t\t}\r\n\t}\r\n\r\n\tprivate findText = ''; // unsupported in web (only in-memory)\r\n\r\n\tasync readFindText(): Promise {\r\n\t\treturn this.findText;\r\n\t}\r\n\r\n\tasync writeFindText(text: string): Promise {\r\n\t\tthis.findText = text;\r\n\t}\r\n}\r\n","\r\n\r\nexport const InputFocusedContextKey = 'inputFocus';\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { URI } from 'vs/base/common/uri';\r\n\r\nexport interface IEditorModel {\r\n\r\n\t/**\r\n\t * Dispose associated resources\r\n\t */\r\n\tdispose(): void;\r\n}\r\n\r\nexport interface IBaseResourceEditorInput {\r\n\r\n\t/**\r\n\t * Optional options to use when opening the text input.\r\n\t */\r\n\toptions?: ITextEditorOptions;\r\n}\r\n\r\nexport interface IResourceEditorInput extends IBaseResourceEditorInput {\r\n\r\n\t/**\r\n\t * The resource URI of the resource to open.\r\n\t */\r\n\treadonly resource: URI;\r\n}\r\n\r\nexport enum EditorOpenContext {\r\n\r\n\t/**\r\n\t * Default: the editor is opening via a programmatic call\r\n\t * to the editor service API.\r\n\t */\r\n\tAPI,\r\n\r\n\t/**\r\n\t * Indicates that a user action triggered the opening, e.g.\r\n\t * via mouse or keyboard use.\r\n\t */\r\n\tUSER\r\n}\r\n\r\nexport interface IEditorOptions {\r\n\r\n\t/**\r\n\t * Tells the editor to not receive keyboard focus when the editor is being opened.\r\n\t *\r\n\t * Will also not activate the group the editor opens in unless the group is already\r\n\t * the active one. This behaviour can be overridden via the `activation` option.\r\n\t */\r\n\treadonly preserveFocus?: boolean;\r\n\r\n\t/**\r\n\t * Will reveal the editor if it is already opened and visible in any of the opened editor groups.\r\n\t *\r\n\t * Note that this option is just a hint that might be ignored if the user wants to open an editor explicitly\r\n\t * to the side of another one or into a specific editor group.\r\n\t */\r\n\treadonly revealIfVisible?: boolean;\r\n\r\n\t/**\r\n\t * Will reveal the editor if it is already opened (even when not visible) in any of the opened editor groups.\r\n\t *\r\n\t * Note that this option is just a hint that might be ignored if the user wants to open an editor explicitly\r\n\t * to the side of another one or into a specific editor group.\r\n\t */\r\n\treadonly revealIfOpened?: boolean;\r\n\r\n\t/**\r\n\t * An editor that is pinned remains in the editor stack even when another editor is being opened.\r\n\t * An editor that is not pinned will always get replaced by another editor that is not pinned.\r\n\t */\r\n\treadonly pinned?: boolean;\r\n\r\n\t/**\r\n\t * A optional hint to signal in which context the editor opens.\r\n\t *\r\n\t * If configured to be `EditorOpenContext.USER`, this hint can be\r\n\t * used in various places to control the experience. For example,\r\n\t * if the editor to open fails with an error, a notification could\r\n\t * inform about this in a modal dialog. If the editor opened through\r\n\t * some background task, the notification would show in the background,\r\n\t * not as a modal dialog.\r\n\t */\r\n\treadonly context?: EditorOpenContext;\r\n}\r\n\r\nexport interface ITextEditorSelection {\r\n\treadonly startLineNumber: number;\r\n\treadonly startColumn: number;\r\n}\r\n\r\nexport const enum TextEditorSelectionRevealType {\r\n\t/**\r\n\t * Option to scroll vertically or horizontally as necessary and reveal a range centered vertically.\r\n\t */\r\n\tCenter = 0,\r\n\t/**\r\n\t * Option to scroll vertically or horizontally as necessary and reveal a range centered vertically only if it lies outside the viewport.\r\n\t */\r\n\tCenterIfOutsideViewport = 1,\r\n\t/**\r\n\t * Option to scroll vertically or horizontally as necessary and reveal a range close to the top of the viewport, but not quite at the top.\r\n\t */\r\n\tNearTop = 2,\r\n\t/**\r\n\t * Option to scroll vertically or horizontally as necessary and reveal a range close to the top of the viewport, but not quite at the top.\r\n\t * Only if it lies outside the viewport\r\n\t */\r\n\tNearTopIfOutsideViewport = 3,\r\n}\r\n\r\nexport interface ITextEditorOptions extends IEditorOptions {\r\n\r\n\t/**\r\n\t * Text editor selection.\r\n\t */\r\n\treadonly selection?: ITextEditorSelection;\r\n\r\n\t/**\r\n\t * Option to control the text editor selection reveal type.\r\n\t * Defaults to TextEditorSelectionRevealType.Center\r\n\t */\r\n\treadonly selectionRevealType?: TextEditorSelectionRevealType;\r\n}\r\n","\r\n\r\n/**\r\n * **!Do not construct directly!**\r\n *\r\n * **!Only static methods because it gets serialized!**\r\n *\r\n * This represents the \"canonical\" version for an extension identifier. Extension ids\r\n * have to be case-insensitive (due to the marketplace), but we must ensure case\r\n * preservation because the extension API is already public at this time.\r\n *\r\n * For example, given an extension with the publisher `\"Hello\"` and the name `\"World\"`,\r\n * its canonical extension identifier is `\"Hello.World\"`. This extension could be\r\n * referenced in some other extension's dependencies using the string `\"hello.world\"`.\r\n *\r\n * To make matters more complicated, an extension can optionally have an UUID. When two\r\n * extensions have the same UUID, they are considered equal even if their identifier is different.\r\n */\r\nexport class ExtensionIdentifier {\r\n\tpublic readonly value: string;\r\n\tprivate readonly _lower: string;\r\n\r\n\tconstructor(value: string) {\r\n\t\tthis.value = value;\r\n\t\tthis._lower = value.toLowerCase();\r\n\t}\r\n\r\n\t/**\r\n\t * Gives the value by which to index (for equality).\r\n\t */\r\n\tpublic static toKey(id: ExtensionIdentifier | string): string {\r\n\t\tif (typeof id === 'string') {\r\n\t\t\treturn id.toLowerCase();\r\n\t\t}\r\n\t\treturn id._lower;\r\n\t}\r\n}\r\n","\r\n\r\nexport enum FileKind {\r\n\tFILE,\r\n\tFOLDER,\r\n\tROOT_FOLDER\r\n}\r\n","\r\n\r\nexport class SyncDescriptor {\r\n\r\n\treadonly ctor: any;\r\n\treadonly staticArguments: any[];\r\n\treadonly supportsDelayedInstantiation: boolean;\r\n\r\n\tconstructor(ctor: new (...args: any[]) => T, staticArguments: any[] = [], supportsDelayedInstantiation: boolean = false) {\r\n\t\tthis.ctor = ctor;\r\n\t\tthis.staticArguments = staticArguments;\r\n\t\tthis.supportsDelayedInstantiation = supportsDelayedInstantiation;\r\n\t}\r\n}\r\n\r\nexport interface SyncDescriptor0 {\r\n\tctor: any;\r\n\tbind(): SyncDescriptor0;\r\n}\r\nexport interface SyncDescriptor1 {\r\n\tctor: any;\r\n\tbind(a1: A1): SyncDescriptor0;\r\n}\r\nexport interface SyncDescriptor2 {\r\n\tctor: any;\r\n\tbind(a1: A1): SyncDescriptor1;\r\n\tbind(a1: A1, a2: A2): SyncDescriptor0;\r\n}\r\nexport interface SyncDescriptor3 {\r\n\tctor: any;\r\n\tbind(a1: A1): SyncDescriptor2;\r\n\tbind(a1: A1, a2: A2): SyncDescriptor1;\r\n\tbind(a1: A1, a2: A2, a3: A3): SyncDescriptor0;\r\n}\r\nexport interface SyncDescriptor4 {\r\n\tctor: any;\r\n\tbind(a1: A1): SyncDescriptor3;\r\n\tbind(a1: A1, a2: A2): SyncDescriptor2;\r\n\tbind(a1: A1, a2: A2, a3: A3): SyncDescriptor1;\r\n\tbind(a1: A1, a2: A2, a3: A3, a4: A4): SyncDescriptor0;\r\n}\r\nexport interface SyncDescriptor5 {\r\n\tctor: any;\r\n\tbind(a1: A1): SyncDescriptor4;\r\n\tbind(a1: A1, a2: A2): SyncDescriptor3;\r\n\tbind(a1: A1, a2: A2, a3: A3): SyncDescriptor2;\r\n\tbind(a1: A1, a2: A2, a3: A3, a4: A4): SyncDescriptor1;\r\n\tbind(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5): SyncDescriptor0;\r\n}\r\nexport interface SyncDescriptor6 {\r\n\tctor: any;\r\n\tbind(a1: A1): SyncDescriptor5;\r\n\tbind(a1: A1, a2: A2): SyncDescriptor4;\r\n\tbind(a1: A1, a2: A2, a3: A3): SyncDescriptor3;\r\n\tbind(a1: A1, a2: A2, a3: A3, a4: A4): SyncDescriptor2;\r\n\tbind(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5): SyncDescriptor1;\r\n\tbind(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6): SyncDescriptor0;\r\n}\r\nexport interface SyncDescriptor7 {\r\n\tctor: any;\r\n\tbind(a1: A1): SyncDescriptor6;\r\n\tbind(a1: A1, a2: A2): SyncDescriptor5;\r\n\tbind(a1: A1, a2: A2, a3: A3): SyncDescriptor4;\r\n\tbind(a1: A1, a2: A2, a3: A3, a4: A4): SyncDescriptor3;\r\n\tbind(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5): SyncDescriptor2;\r\n\tbind(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6): SyncDescriptor1;\r\n\tbind(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7): SyncDescriptor0;\r\n}\r\nexport interface SyncDescriptor8 {\r\n\tctor: any;\r\n\tbind(a1: A1): SyncDescriptor7;\r\n\tbind(a1: A1, a2: A2): SyncDescriptor6;\r\n\tbind(a1: A1, a2: A2, a3: A3): SyncDescriptor5;\r\n\tbind(a1: A1, a2: A2, a3: A3, a4: A4): SyncDescriptor4;\r\n\tbind(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5): SyncDescriptor3;\r\n\tbind(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6): SyncDescriptor2;\r\n\tbind(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7): SyncDescriptor1;\r\n\tbind(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8): SyncDescriptor0;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { SyncDescriptor } from './descriptors';\r\nimport { ServiceIdentifier, BrandedService } from './instantiation';\r\n\r\nconst _registry: [ServiceIdentifier, SyncDescriptor][] = [];\r\n\r\nexport function registerSingleton(id: ServiceIdentifier, ctor: new (...services: Services) => T, supportsDelayedInstantiation?: boolean): void {\r\n\t_registry.push([id, new SyncDescriptor(ctor as new (...args: any[]) => T, [], supportsDelayedInstantiation)]);\r\n}\r\n\r\nexport function getSingletonServiceDescriptors(): [ServiceIdentifier, SyncDescriptor][] {\r\n\treturn _registry;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nexport class Node {\r\n\r\n\treadonly data: T;\r\n\treadonly incoming = new Map>();\r\n\treadonly outgoing = new Map>();\r\n\r\n\tconstructor(data: T) {\r\n\t\tthis.data = data;\r\n\t}\r\n}\r\n\r\nexport class Graph {\r\n\r\n\tprivate readonly _nodes = new Map>();\r\n\r\n\tconstructor(private readonly _hashFn: (element: T) => string) {\r\n\t\t// empty\r\n\t}\r\n\r\n\troots(): Node[] {\r\n\t\tconst ret: Node[] = [];\r\n\t\tfor (let node of this._nodes.values()) {\r\n\t\t\tif (node.outgoing.size === 0) {\r\n\t\t\t\tret.push(node);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn ret;\r\n\t}\r\n\r\n\tinsertEdge(from: T, to: T): void {\r\n\t\tconst fromNode = this.lookupOrInsertNode(from);\r\n\t\tconst toNode = this.lookupOrInsertNode(to);\r\n\r\n\t\tfromNode.outgoing.set(this._hashFn(to), toNode);\r\n\t\ttoNode.incoming.set(this._hashFn(from), fromNode);\r\n\t}\r\n\r\n\tremoveNode(data: T): void {\r\n\t\tconst key = this._hashFn(data);\r\n\t\tthis._nodes.delete(key);\r\n\t\tfor (let node of this._nodes.values()) {\r\n\t\t\tnode.outgoing.delete(key);\r\n\t\t\tnode.incoming.delete(key);\r\n\t\t}\r\n\t}\r\n\r\n\tlookupOrInsertNode(data: T): Node {\r\n\t\tconst key = this._hashFn(data);\r\n\t\tlet node = this._nodes.get(key);\r\n\r\n\t\tif (!node) {\r\n\t\t\tnode = new Node(data);\r\n\t\t\tthis._nodes.set(key, node);\r\n\t\t}\r\n\r\n\t\treturn node;\r\n\t}\r\n\r\n\tisEmpty(): boolean {\r\n\t\treturn this._nodes.size === 0;\r\n\t}\r\n\r\n\ttoString(): string {\r\n\t\tlet data: string[] = [];\r\n\t\tfor (let [key, value] of this._nodes) {\r\n\t\t\tdata.push(`${key}, (incoming)[${[...value.incoming.keys()].join(', ')}], (outgoing)[${[...value.outgoing.keys()].join(',')}]`);\r\n\r\n\t\t}\r\n\t\treturn data.join('\\n');\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { ServiceCollection } from './serviceCollection';\r\nimport * as descriptors from './descriptors';\r\n\r\n// ------ internal util\r\n\r\nexport namespace _util {\r\n\r\n\texport const serviceIds = new Map>();\r\n\r\n\texport const DI_TARGET = '$di$target';\r\n\texport const DI_DEPENDENCIES = '$di$dependencies';\r\n\r\n\texport function getServiceDependencies(ctor: any): { id: ServiceIdentifier, index: number, optional: boolean }[] {\r\n\t\treturn ctor[DI_DEPENDENCIES] || [];\r\n\t}\r\n}\r\n\r\n// --- interfaces ------\r\n\r\nexport type BrandedService = { _serviceBrand: undefined };\r\n\r\nexport interface IConstructorSignature1 {\r\n\tnew (first: A1, ...services: Services): T;\r\n}\r\n\r\nexport interface ServicesAccessor {\r\n\tget(id: ServiceIdentifier): T;\r\n\tget(id: ServiceIdentifier, isOptional: typeof optional): T | undefined;\r\n}\r\n\r\nexport const IInstantiationService = createDecorator('instantiationService');\r\n\r\n/**\r\n * Given a list of arguments as a tuple, attempt to extract the leading, non-service arguments\r\n * to their own tuple.\r\n */\r\ntype GetLeadingNonServiceArgs =\r\n\tArgs extends [...BrandedService[]] ? []\r\n\t: Args extends [infer A1, ...BrandedService[]] ? [A1]\r\n\t: Args extends [infer A1, infer A2, ...BrandedService[]] ? [A1, A2]\r\n\t: Args extends [infer A1, infer A2, infer A3, ...BrandedService[]] ? [A1, A2, A3]\r\n\t: Args extends [infer A1, infer A2, infer A3, infer A4, ...BrandedService[]] ? [A1, A2, A3, A4]\r\n\t: Args extends [infer A1, infer A2, infer A3, infer A4, infer A5, ...BrandedService[]] ? [A1, A2, A3, A4, A5]\r\n\t: Args extends [infer A1, infer A2, infer A3, infer A4, infer A5, infer A6, ...BrandedService[]] ? [A1, A2, A3, A4, A5, A6]\r\n\t: Args extends [infer A1, infer A2, infer A3, infer A4, infer A5, infer A6, infer A7, ...BrandedService[]] ? [A1, A2, A3, A4, A5, A6, A7]\r\n\t: Args extends [infer A1, infer A2, infer A3, infer A4, infer A5, infer A6, infer A7, infer A8, ...BrandedService[]] ? [A1, A2, A3, A4, A5, A6, A7, A8]\r\n\t: never;\r\n\r\nexport interface IInstantiationService {\r\n\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\t/**\r\n\t * Synchronously creates an instance that is denoted by\r\n\t * the descriptor\r\n\t */\r\n\tcreateInstance(descriptor: descriptors.SyncDescriptor0): T;\r\n\tcreateInstance(descriptor: descriptors.SyncDescriptor1, a1: A1): T;\r\n\tcreateInstance(descriptor: descriptors.SyncDescriptor2, a1: A1, a2: A2): T;\r\n\tcreateInstance(descriptor: descriptors.SyncDescriptor3, a1: A1, a2: A2, a3: A3): T;\r\n\tcreateInstance(descriptor: descriptors.SyncDescriptor4, a1: A1, a2: A2, a3: A3, a4: A4): T;\r\n\tcreateInstance(descriptor: descriptors.SyncDescriptor5, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5): T;\r\n\tcreateInstance(descriptor: descriptors.SyncDescriptor6, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6): T;\r\n\tcreateInstance(descriptor: descriptors.SyncDescriptor7, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7): T;\r\n\tcreateInstance(descriptor: descriptors.SyncDescriptor8, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8): T;\r\n\r\n\tcreateInstance any, R extends InstanceType>(t: Ctor, ...args: GetLeadingNonServiceArgs>): R;\r\n\r\n\t/**\r\n\t *\r\n\t */\r\n\tinvokeFunction(fn: (accessor: ServicesAccessor, ...args: TS) => R, ...args: TS): R;\r\n\r\n\t/**\r\n\t * Creates a child of this service which inherts all current services\r\n\t * and adds/overwrites the given services\r\n\t */\r\n\tcreateChild(services: ServiceCollection): IInstantiationService;\r\n}\r\n\r\n\r\n/**\r\n * Identifies a service of type T\r\n */\r\nexport interface ServiceIdentifier {\r\n\t(...args: any[]): void;\r\n\ttype: T;\r\n}\r\n\r\nfunction storeServiceDependency(id: Function, target: Function, index: number, optional: boolean): void {\r\n\tif ((target as any)[_util.DI_TARGET] === target) {\r\n\t\t(target as any)[_util.DI_DEPENDENCIES].push({ id, index, optional });\r\n\t} else {\r\n\t\t(target as any)[_util.DI_DEPENDENCIES] = [{ id, index, optional }];\r\n\t\t(target as any)[_util.DI_TARGET] = target;\r\n\t}\r\n}\r\n\r\n/**\r\n * The *only* valid way to create a {{ServiceIdentifier}}.\r\n */\r\nexport function createDecorator(serviceId: string): ServiceIdentifier {\r\n\r\n\tif (_util.serviceIds.has(serviceId)) {\r\n\t\treturn _util.serviceIds.get(serviceId)!;\r\n\t}\r\n\r\n\tconst id = function (target: Function, key: string, index: number): any {\r\n\t\tif (arguments.length !== 3) {\r\n\t\t\tthrow new Error('@IServiceName-decorator can only be used to decorate a parameter');\r\n\t\t}\r\n\t\tstoreServiceDependency(id, target, index, false);\r\n\t};\r\n\r\n\tid.toString = () => serviceId;\r\n\r\n\t_util.serviceIds.set(serviceId, id);\r\n\treturn id;\r\n}\r\n\r\n/**\r\n * Mark a service dependency as optional.\r\n */\r\nexport function optional(serviceIdentifier: ServiceIdentifier) {\r\n\r\n\treturn function (target: Function, key: string, index: number) {\r\n\t\tif (arguments.length !== 3) {\r\n\t\t\tthrow new Error('@optional-decorator can only be used to decorate a parameter');\r\n\t\t}\r\n\t\tstoreServiceDependency(serviceIdentifier, target, index, true);\r\n\t};\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { TextEdit, WorkspaceEdit, WorkspaceEditMetadata, WorkspaceFileEdit, WorkspaceFileEditOptions, WorkspaceTextEdit } from 'vs/editor/common/modes';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { isObject } from 'vs/base/common/types';\r\n\r\nexport const IBulkEditService = createDecorator('IWorkspaceEditService');\r\n\r\nfunction isWorkspaceFileEdit(thing: any): thing is WorkspaceFileEdit {\r\n\treturn isObject(thing) && (Boolean((thing).newUri) || Boolean((thing).oldUri));\r\n}\r\n\r\nfunction isWorkspaceTextEdit(thing: any): thing is WorkspaceTextEdit {\r\n\treturn isObject(thing) && URI.isUri((thing).resource) && isObject((thing).edit);\r\n}\r\n\r\nexport class ResourceEdit {\r\n\r\n\tprotected constructor(readonly metadata?: WorkspaceEditMetadata) { }\r\n\r\n\tstatic convert(edit: WorkspaceEdit): ResourceEdit[] {\r\n\r\n\r\n\t\treturn edit.edits.map(edit => {\r\n\t\t\tif (isWorkspaceTextEdit(edit)) {\r\n\t\t\t\treturn new ResourceTextEdit(edit.resource, edit.edit, edit.modelVersionId, edit.metadata);\r\n\t\t\t}\r\n\t\t\tif (isWorkspaceFileEdit(edit)) {\r\n\t\t\t\treturn new ResourceFileEdit(edit.oldUri, edit.newUri, edit.options, edit.metadata);\r\n\t\t\t}\r\n\t\t\tthrow new Error('Unsupported edit');\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class ResourceTextEdit extends ResourceEdit {\r\n\tconstructor(\r\n\t\treadonly resource: URI,\r\n\t\treadonly textEdit: TextEdit,\r\n\t\treadonly versionId?: number,\r\n\t\treadonly metadata?: WorkspaceEditMetadata\r\n\t) {\r\n\t\tsuper(metadata);\r\n\t}\r\n}\r\n\r\nexport class ResourceFileEdit extends ResourceEdit {\r\n\tconstructor(\r\n\t\treadonly oldResource: URI | undefined,\r\n\t\treadonly newResource: URI | undefined,\r\n\t\treadonly options?: WorkspaceFileEditOptions,\r\n\t\treadonly metadata?: WorkspaceEditMetadata\r\n\t) {\r\n\t\tsuper(metadata);\r\n\t}\r\n}\r\n\r\nexport interface IBulkEditOptions {\r\n\teditor?: ICodeEditor;\r\n\tshowPreview?: boolean;\r\n\tlabel?: string;\r\n\tquotableLabel?: string;\r\n}\r\n\r\nexport interface IBulkEditResult {\r\n\tariaSummary: string;\r\n}\r\n\r\nexport interface IBulkEditService {\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\thasPreviewHandler(): boolean;\r\n\r\n\tapply(edit: ResourceEdit[], options?: IBulkEditOptions): Promise;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Event } from 'vs/base/common/event';\r\nimport { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { IDecorationRenderOptions } from 'vs/editor/common/editorCommon';\r\nimport { IModelDecorationOptions } from 'vs/editor/common/model';\r\nimport { IResourceEditorInput } from 'vs/platform/editor/common/editor';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { URI } from 'vs/base/common/uri';\r\n\r\nexport const ICodeEditorService = createDecorator('codeEditorService');\r\n\r\nexport interface ICodeEditorService {\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\treadonly onCodeEditorAdd: Event;\r\n\treadonly onCodeEditorRemove: Event;\r\n\r\n\r\n\taddCodeEditor(editor: ICodeEditor): void;\r\n\tremoveCodeEditor(editor: ICodeEditor): void;\r\n\tlistCodeEditors(): readonly ICodeEditor[];\r\n\r\n\taddDiffEditor(editor: IDiffEditor): void;\r\n\tremoveDiffEditor(editor: IDiffEditor): void;\r\n\tlistDiffEditors(): readonly IDiffEditor[];\r\n\r\n\t/**\r\n\t * Returns the current focused code editor (if the focus is in the editor or in an editor widget) or null.\r\n\t */\r\n\tgetFocusedCodeEditor(): ICodeEditor | null;\r\n\r\n\tregisterDecorationType(key: string, options: IDecorationRenderOptions, parentTypeKey?: string, editor?: ICodeEditor): void;\r\n\tremoveDecorationType(key: string): void;\r\n\tresolveDecorationOptions(typeKey: string, writable: boolean): IModelDecorationOptions;\r\n\r\n\tsetModelProperty(resource: URI, key: string, value: any): void;\r\n\tgetModelProperty(resource: URI, key: string): any;\r\n\r\n\tgetActiveCodeEditor(): ICodeEditor | null;\r\n\topenCodeEditor(input: IResourceEditorInput, source: ICodeEditor | null, sideBySide?: boolean): Promise;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { IRange } from 'vs/editor/common/core/range';\r\nimport { ILineChange } from 'vs/editor/common/editorCommon';\r\nimport { IInplaceReplaceSupportResult, TextEdit } from 'vs/editor/common/modes';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\n\r\nexport const ID_EDITOR_WORKER_SERVICE = 'editorWorkerService';\r\nexport const IEditorWorkerService = createDecorator(ID_EDITOR_WORKER_SERVICE);\r\n\r\nexport interface IDiffComputationResult {\r\n\tquitEarly: boolean;\r\n\tidentical: boolean;\r\n\tchanges: ILineChange[];\r\n}\r\n\r\nexport interface IEditorWorkerService {\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\tcanComputeDiff(original: URI, modified: URI): boolean;\r\n\tcomputeDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean, maxComputationTime: number): Promise;\r\n\r\n\tcomputeMoreMinimalEdits(resource: URI, edits: TextEdit[] | null | undefined): Promise;\r\n\r\n\tcanComputeWordRanges(resource: URI): boolean;\r\n\tcomputeWordRanges(resource: URI, range: IRange): Promise<{ [word: string]: IRange[] } | null>;\r\n\r\n\tcanNavigateValueSet(resource: URI): boolean;\r\n\tnavigateValueSet(resource: URI, range: IRange, up: boolean): Promise;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IModelDecoration } from 'vs/editor/common/model';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IMarker } from 'vs/platform/markers/common/markers';\r\nimport { URI } from 'vs/base/common/uri';\r\n\r\nexport const IMarkerDecorationsService = createDecorator('markerDecorationsService');\r\n\r\nexport interface IMarkerDecorationsService {\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\tgetMarker(uri: URI, decoration: IModelDecoration): IMarker | null;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Event } from 'vs/base/common/event';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { IMode, LanguageId, LanguageIdentifier } from 'vs/editor/common/modes';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\n\r\nexport const IModeService = createDecorator('modeService');\r\n\r\nexport interface ILanguageExtensionPoint {\r\n\tid: string;\r\n\textensions?: string[];\r\n\tfilenames?: string[];\r\n\tfilenamePatterns?: string[];\r\n\tfirstLine?: string;\r\n\taliases?: string[];\r\n\tmimetypes?: string[];\r\n\tconfiguration?: URI;\r\n}\r\n\r\nexport interface ILanguageSelection extends IDisposable {\r\n\treadonly languageIdentifier: LanguageIdentifier;\r\n\treadonly onDidChange: Event;\r\n}\r\n\r\nexport interface IModeService {\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\tonDidCreateMode: Event;\r\n\r\n\t// --- reading\r\n\tisRegisteredMode(mimetypeOrModeId: string): boolean;\r\n\tgetModeIdForLanguageName(alias: string): string | null;\r\n\tgetModeIdByFilepathOrFirstLine(resource: URI, firstLine?: string): string | null;\r\n\tgetModeId(commaSeparatedMimetypesOrCommaSeparatedIds: string): string | null;\r\n\tgetLanguageIdentifier(modeId: string | LanguageId): LanguageIdentifier | null;\r\n\r\n\t// --- instantiation\r\n\tcreate(commaSeparatedMimetypesOrCommaSeparatedIds: string | undefined): ILanguageSelection;\r\n\tcreateByFilepathOrFirstLine(resource: URI | null, firstLine?: string): ILanguageSelection;\r\n\r\n\ttriggerMode(commaSeparatedMimetypesOrCommaSeparatedIds: string): void;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Event } from 'vs/base/common/event';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { ITextBufferFactory, ITextModel, ITextModelCreationOptions } from 'vs/editor/common/model';\r\nimport { ILanguageSelection } from 'vs/editor/common/services/modeService';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { DocumentSemanticTokensProvider, DocumentRangeSemanticTokensProvider } from 'vs/editor/common/modes';\r\nimport { SemanticTokensProviderStyling } from 'vs/editor/common/services/semanticTokensProviderStyling';\r\n\r\nexport const IModelService = createDecorator('modelService');\r\n\r\nexport type DocumentTokensProvider = DocumentSemanticTokensProvider | DocumentRangeSemanticTokensProvider;\r\n\r\nexport interface IModelService {\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\tcreateModel(value: string | ITextBufferFactory, languageSelection: ILanguageSelection | null, resource?: URI, isForSimpleWidget?: boolean): ITextModel;\r\n\r\n\tsetMode(model: ITextModel, languageSelection: ILanguageSelection): void;\r\n\r\n\tgetModels(): ITextModel[];\r\n\r\n\tgetCreationOptions(language: string, resource: URI, isForSimpleWidget: boolean): ITextModelCreationOptions;\r\n\r\n\tgetModel(resource: URI): ITextModel | null;\r\n\r\n\tgetSemanticTokensProviderStyling(provider: DocumentTokensProvider): SemanticTokensProviderStyling;\r\n\r\n\tonModelAdded: Event;\r\n\r\n\tonModelRemoved: Event;\r\n\r\n\tonModelModeChanged: Event<{ model: ITextModel; oldModeId: string; }>;\r\n}\r\n\r\nexport function shouldSynchronizeModel(model: ITextModel): boolean {\r\n\treturn (\r\n\t\t!model.isTooLargeForSyncing() && !model.isForSimpleWidget\r\n\t);\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { hash } from 'vs/base/common/hash';\r\nimport { IDisposable, toDisposable } from 'vs/base/common/lifecycle';\r\nimport { LRUCache } from 'vs/base/common/map';\r\nimport { MovingAverage } from 'vs/base/common/numbers';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { LanguageSelector, score } from 'vs/editor/common/modes/languageSelector';\r\nimport { shouldSynchronizeModel } from 'vs/editor/common/services/modelService';\r\n\r\ninterface Entry {\r\n\tselector: LanguageSelector;\r\n\tprovider: T;\r\n\t_score: number;\r\n\t_time: number;\r\n}\r\n\r\nfunction isExclusive(selector: LanguageSelector): boolean {\r\n\tif (typeof selector === 'string') {\r\n\t\treturn false;\r\n\t} else if (Array.isArray(selector)) {\r\n\t\treturn selector.every(isExclusive);\r\n\t} else {\r\n\t\treturn !!selector.exclusive;\r\n\t}\r\n}\r\n\r\nexport class LanguageFeatureRegistry {\r\n\r\n\tprivate _clock: number = 0;\r\n\tprivate readonly _entries: Entry[] = [];\r\n\tprivate readonly _onDidChange = new Emitter();\r\n\r\n\tget onDidChange(): Event {\r\n\t\treturn this._onDidChange.event;\r\n\t}\r\n\r\n\tregister(selector: LanguageSelector, provider: T): IDisposable {\r\n\r\n\t\tlet entry: Entry | undefined = {\r\n\t\t\tselector,\r\n\t\t\tprovider,\r\n\t\t\t_score: -1,\r\n\t\t\t_time: this._clock++\r\n\t\t};\r\n\r\n\t\tthis._entries.push(entry);\r\n\t\tthis._lastCandidate = undefined;\r\n\t\tthis._onDidChange.fire(this._entries.length);\r\n\r\n\t\treturn toDisposable(() => {\r\n\t\t\tif (entry) {\r\n\t\t\t\tlet idx = this._entries.indexOf(entry);\r\n\t\t\t\tif (idx >= 0) {\r\n\t\t\t\t\tthis._entries.splice(idx, 1);\r\n\t\t\t\t\tthis._lastCandidate = undefined;\r\n\t\t\t\t\tthis._onDidChange.fire(this._entries.length);\r\n\t\t\t\t\tentry = undefined;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\thas(model: ITextModel): boolean {\r\n\t\treturn this.all(model).length > 0;\r\n\t}\r\n\r\n\tall(model: ITextModel): T[] {\r\n\t\tif (!model) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tthis._updateScores(model);\r\n\t\tconst result: T[] = [];\r\n\r\n\t\t// from registry\r\n\t\tfor (let entry of this._entries) {\r\n\t\t\tif (entry._score > 0) {\r\n\t\t\t\tresult.push(entry.provider);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tordered(model: ITextModel): T[] {\r\n\t\tconst result: T[] = [];\r\n\t\tthis._orderedForEach(model, entry => result.push(entry.provider));\r\n\t\treturn result;\r\n\t}\r\n\r\n\torderedGroups(model: ITextModel): T[][] {\r\n\t\tconst result: T[][] = [];\r\n\t\tlet lastBucket: T[];\r\n\t\tlet lastBucketScore: number;\r\n\r\n\t\tthis._orderedForEach(model, entry => {\r\n\t\t\tif (lastBucket && lastBucketScore === entry._score) {\r\n\t\t\t\tlastBucket.push(entry.provider);\r\n\t\t\t} else {\r\n\t\t\t\tlastBucketScore = entry._score;\r\n\t\t\t\tlastBucket = [entry.provider];\r\n\t\t\t\tresult.push(lastBucket);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate _orderedForEach(model: ITextModel, callback: (provider: Entry) => any): void {\r\n\r\n\t\tif (!model) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._updateScores(model);\r\n\r\n\t\tfor (const entry of this._entries) {\r\n\t\t\tif (entry._score > 0) {\r\n\t\t\t\tcallback(entry);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _lastCandidate: { uri: string; language: string; } | undefined;\r\n\r\n\tprivate _updateScores(model: ITextModel): void {\r\n\r\n\t\tlet candidate = {\r\n\t\t\turi: model.uri.toString(),\r\n\t\t\tlanguage: model.getLanguageIdentifier().language\r\n\t\t};\r\n\r\n\t\tif (this._lastCandidate\r\n\t\t\t&& this._lastCandidate.language === candidate.language\r\n\t\t\t&& this._lastCandidate.uri === candidate.uri) {\r\n\r\n\t\t\t// nothing has changed\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._lastCandidate = candidate;\r\n\r\n\t\tfor (let entry of this._entries) {\r\n\t\t\tentry._score = score(entry.selector, model.uri, model.getLanguageIdentifier().language, shouldSynchronizeModel(model));\r\n\r\n\t\t\tif (isExclusive(entry.selector) && entry._score > 0) {\r\n\t\t\t\t// support for one exclusive selector that overwrites\r\n\t\t\t\t// any other selector\r\n\t\t\t\tfor (let entry of this._entries) {\r\n\t\t\t\t\tentry._score = 0;\r\n\t\t\t\t}\r\n\t\t\t\tentry._score = 1000;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// needs sorting\r\n\t\tthis._entries.sort(LanguageFeatureRegistry._compareByScoreAndTime);\r\n\t}\r\n\r\n\tprivate static _compareByScoreAndTime(a: Entry, b: Entry): number {\r\n\t\tif (a._score < b._score) {\r\n\t\t\treturn 1;\r\n\t\t} else if (a._score > b._score) {\r\n\t\t\treturn -1;\r\n\t\t} else if (a._time < b._time) {\r\n\t\t\treturn 1;\r\n\t\t} else if (a._time > b._time) {\r\n\t\t\treturn -1;\r\n\t\t} else {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t}\r\n}\r\n\r\n\r\n/**\r\n * Keeps moving average per model and set of providers so that requests\r\n * can be debounce according to the provider performance\r\n */\r\nexport class LanguageFeatureRequestDelays {\r\n\r\n\tprivate readonly _cache = new LRUCache(50, 0.7);\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _registry: LanguageFeatureRegistry,\r\n\t\treadonly min: number,\r\n\t\treadonly max: number = Number.MAX_SAFE_INTEGER,\r\n\t) { }\r\n\r\n\tprivate _key(model: ITextModel): string {\r\n\t\treturn model.id + hash(this._registry.all(model));\r\n\t}\r\n\r\n\tprivate _clamp(value: number | undefined): number {\r\n\t\tif (value === undefined) {\r\n\t\t\treturn this.min;\r\n\t\t} else {\r\n\t\t\treturn Math.min(this.max, Math.max(this.min, Math.floor(value * 1.3)));\r\n\t\t}\r\n\t}\r\n\r\n\tget(model: ITextModel): number {\r\n\t\tconst key = this._key(model);\r\n\t\tconst avg = this._cache.get(key);\r\n\t\treturn this._clamp(avg?.value);\r\n\t}\r\n\r\n\tupdate(model: ITextModel, value: number): number {\r\n\t\tconst key = this._key(model);\r\n\t\tlet avg = this._cache.get(key);\r\n\t\tif (!avg) {\r\n\t\t\tavg = new MovingAverage();\r\n\t\t\tthis._cache.set(key, avg);\r\n\t\t}\r\n\t\tavg.update(value);\r\n\t\treturn this.get(model);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { Event } from 'vs/base/common/event';\r\nimport { IMarkdownString } from 'vs/base/common/htmlContent';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { IRange, Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { TokenizationResult, TokenizationResult2 } from 'vs/editor/common/core/token';\r\nimport * as model from 'vs/editor/common/model';\r\nimport { LanguageFeatureRegistry } from 'vs/editor/common/modes/languageFeatureRegistry';\r\nimport { TokenizationRegistryImpl } from 'vs/editor/common/modes/tokenizationRegistry';\r\nimport { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';\r\nimport { IMarkerData } from 'vs/platform/markers/common/markers';\r\nimport { iconRegistry, Codicon } from 'vs/base/common/codicons';\r\n/**\r\n * Open ended enum at runtime\r\n * @internal\r\n */\r\nexport const enum LanguageId {\r\n\tNull = 0,\r\n\tPlainText = 1\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport class LanguageIdentifier {\r\n\r\n\t/**\r\n\t * A string identifier. Unique across languages. e.g. 'javascript'.\r\n\t */\r\n\tpublic readonly language: string;\r\n\r\n\t/**\r\n\t * A numeric identifier. Unique across languages. e.g. 5\r\n\t * Will vary at runtime based on registration order, etc.\r\n\t */\r\n\tpublic readonly id: LanguageId;\r\n\r\n\tconstructor(language: string, id: LanguageId) {\r\n\t\tthis.language = language;\r\n\t\tthis.id = id;\r\n\t}\r\n}\r\n\r\n/**\r\n * A mode. Will soon be obsolete.\r\n * @internal\r\n */\r\nexport interface IMode {\r\n\r\n\tgetId(): string;\r\n\r\n}\r\n\r\n/**\r\n * A font style. Values are 2^x such that a bit mask can be used.\r\n * @internal\r\n */\r\nexport const enum FontStyle {\r\n\tNotSet = -1,\r\n\tNone = 0,\r\n\tItalic = 1,\r\n\tBold = 2,\r\n\tUnderline = 4\r\n}\r\n\r\n/**\r\n * Open ended enum at runtime\r\n * @internal\r\n */\r\nexport const enum ColorId {\r\n\tNone = 0,\r\n\tDefaultForeground = 1,\r\n\tDefaultBackground = 2\r\n}\r\n\r\n/**\r\n * A standard token type. Values are 2^x such that a bit mask can be used.\r\n * @internal\r\n */\r\nexport const enum StandardTokenType {\r\n\tOther = 0,\r\n\tComment = 1,\r\n\tString = 2,\r\n\tRegEx = 4\r\n}\r\n\r\n/**\r\n * Helpers to manage the \"collapsed\" metadata of an entire StackElement stack.\r\n * The following assumptions have been made:\r\n * - languageId < 256 => needs 8 bits\r\n * - unique color count < 512 => needs 9 bits\r\n *\r\n * The binary format is:\r\n * - -------------------------------------------\r\n * 3322 2222 2222 1111 1111 1100 0000 0000\r\n * 1098 7654 3210 9876 5432 1098 7654 3210\r\n * - -------------------------------------------\r\n * xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx\r\n * bbbb bbbb bfff ffff ffFF FTTT LLLL LLLL\r\n * - -------------------------------------------\r\n * - L = LanguageId (8 bits)\r\n * - T = StandardTokenType (3 bits)\r\n * - F = FontStyle (3 bits)\r\n * - f = foreground color (9 bits)\r\n * - b = background color (9 bits)\r\n *\r\n * @internal\r\n */\r\nexport const enum MetadataConsts {\r\n\tLANGUAGEID_MASK = 0b00000000000000000000000011111111,\r\n\tTOKEN_TYPE_MASK = 0b00000000000000000000011100000000,\r\n\tFONT_STYLE_MASK = 0b00000000000000000011100000000000,\r\n\tFOREGROUND_MASK = 0b00000000011111111100000000000000,\r\n\tBACKGROUND_MASK = 0b11111111100000000000000000000000,\r\n\r\n\tITALIC_MASK = 0b00000000000000000000100000000000,\r\n\tBOLD_MASK = 0b00000000000000000001000000000000,\r\n\tUNDERLINE_MASK = 0b00000000000000000010000000000000,\r\n\r\n\tSEMANTIC_USE_ITALIC = 0b00000000000000000000000000000001,\r\n\tSEMANTIC_USE_BOLD = 0b00000000000000000000000000000010,\r\n\tSEMANTIC_USE_UNDERLINE = 0b00000000000000000000000000000100,\r\n\tSEMANTIC_USE_FOREGROUND = 0b00000000000000000000000000001000,\r\n\tSEMANTIC_USE_BACKGROUND = 0b00000000000000000000000000010000,\r\n\r\n\tLANGUAGEID_OFFSET = 0,\r\n\tTOKEN_TYPE_OFFSET = 8,\r\n\tFONT_STYLE_OFFSET = 11,\r\n\tFOREGROUND_OFFSET = 14,\r\n\tBACKGROUND_OFFSET = 23\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport class TokenMetadata {\r\n\r\n\tpublic static getLanguageId(metadata: number): LanguageId {\r\n\t\treturn (metadata & MetadataConsts.LANGUAGEID_MASK) >>> MetadataConsts.LANGUAGEID_OFFSET;\r\n\t}\r\n\r\n\tpublic static getTokenType(metadata: number): StandardTokenType {\r\n\t\treturn (metadata & MetadataConsts.TOKEN_TYPE_MASK) >>> MetadataConsts.TOKEN_TYPE_OFFSET;\r\n\t}\r\n\r\n\tpublic static getFontStyle(metadata: number): FontStyle {\r\n\t\treturn (metadata & MetadataConsts.FONT_STYLE_MASK) >>> MetadataConsts.FONT_STYLE_OFFSET;\r\n\t}\r\n\r\n\tpublic static getForeground(metadata: number): ColorId {\r\n\t\treturn (metadata & MetadataConsts.FOREGROUND_MASK) >>> MetadataConsts.FOREGROUND_OFFSET;\r\n\t}\r\n\r\n\tpublic static getBackground(metadata: number): ColorId {\r\n\t\treturn (metadata & MetadataConsts.BACKGROUND_MASK) >>> MetadataConsts.BACKGROUND_OFFSET;\r\n\t}\r\n\r\n\tpublic static getClassNameFromMetadata(metadata: number): string {\r\n\t\tlet foreground = this.getForeground(metadata);\r\n\t\tlet className = 'mtk' + foreground;\r\n\r\n\t\tlet fontStyle = this.getFontStyle(metadata);\r\n\t\tif (fontStyle & FontStyle.Italic) {\r\n\t\t\tclassName += ' mtki';\r\n\t\t}\r\n\t\tif (fontStyle & FontStyle.Bold) {\r\n\t\t\tclassName += ' mtkb';\r\n\t\t}\r\n\t\tif (fontStyle & FontStyle.Underline) {\r\n\t\t\tclassName += ' mtku';\r\n\t\t}\r\n\r\n\t\treturn className;\r\n\t}\r\n\r\n\tpublic static getInlineStyleFromMetadata(metadata: number, colorMap: string[]): string {\r\n\t\tconst foreground = this.getForeground(metadata);\r\n\t\tconst fontStyle = this.getFontStyle(metadata);\r\n\r\n\t\tlet result = `color: ${colorMap[foreground]};`;\r\n\t\tif (fontStyle & FontStyle.Italic) {\r\n\t\t\tresult += 'font-style: italic;';\r\n\t\t}\r\n\t\tif (fontStyle & FontStyle.Bold) {\r\n\t\t\tresult += 'font-weight: bold;';\r\n\t\t}\r\n\t\tif (fontStyle & FontStyle.Underline) {\r\n\t\t\tresult += 'text-decoration: underline;';\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface ITokenizationSupport {\r\n\r\n\tgetInitialState(): IState;\r\n\r\n\t// add offsetDelta to each of the returned indices\r\n\ttokenize(line: string, hasEOL: boolean, state: IState, offsetDelta: number): TokenizationResult;\r\n\r\n\ttokenize2(line: string, hasEOL: boolean, state: IState, offsetDelta: number): TokenizationResult2;\r\n}\r\n\r\n/**\r\n * The state of the tokenizer between two lines.\r\n * It is useful to store flags such as in multiline comment, etc.\r\n * The model will clone the previous line's state and pass it in to tokenize the next line.\r\n */\r\nexport interface IState {\r\n\tclone(): IState;\r\n\tequals(other: IState): boolean;\r\n}\r\n\r\n/**\r\n * A provider result represents the values a provider, like the [`HoverProvider`](#HoverProvider),\r\n * may return. For once this is the actual result type `T`, like `Hover`, or a thenable that resolves\r\n * to that type `T`. In addition, `null` and `undefined` can be returned - either directly or from a\r\n * thenable.\r\n */\r\nexport type ProviderResult = T | undefined | null | Thenable;\r\n\r\n/**\r\n * A hover represents additional information for a symbol or word. Hovers are\r\n * rendered in a tooltip-like widget.\r\n */\r\nexport interface Hover {\r\n\t/**\r\n\t * The contents of this hover.\r\n\t */\r\n\tcontents: IMarkdownString[];\r\n\r\n\t/**\r\n\t * The range to which this hover applies. When missing, the\r\n\t * editor will use the range at the current position or the\r\n\t * current position itself.\r\n\t */\r\n\trange?: IRange;\r\n}\r\n\r\n/**\r\n * The hover provider interface defines the contract between extensions and\r\n * the [hover](https://code.visualstudio.com/docs/editor/intellisense)-feature.\r\n */\r\nexport interface HoverProvider {\r\n\t/**\r\n\t * Provide a hover for the given position and document. Multiple hovers at the same\r\n\t * position will be merged by the editor. A hover can have a range which defaults\r\n\t * to the word range at the position when omitted.\r\n\t */\r\n\tprovideHover(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult;\r\n}\r\n\r\nexport const enum CompletionItemKind {\r\n\tMethod,\r\n\tFunction,\r\n\tConstructor,\r\n\tField,\r\n\tVariable,\r\n\tClass,\r\n\tStruct,\r\n\tInterface,\r\n\tModule,\r\n\tProperty,\r\n\tEvent,\r\n\tOperator,\r\n\tUnit,\r\n\tValue,\r\n\tConstant,\r\n\tEnum,\r\n\tEnumMember,\r\n\tKeyword,\r\n\tText,\r\n\tColor,\r\n\tFile,\r\n\tReference,\r\n\tCustomcolor,\r\n\tFolder,\r\n\tTypeParameter,\r\n\tUser,\r\n\tIssue,\r\n\tSnippet, // <- highest value (used for compare!)\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const completionKindToCssClass = (function () {\r\n\tlet data = Object.create(null);\r\n\tdata[CompletionItemKind.Method] = 'symbol-method';\r\n\tdata[CompletionItemKind.Function] = 'symbol-function';\r\n\tdata[CompletionItemKind.Constructor] = 'symbol-constructor';\r\n\tdata[CompletionItemKind.Field] = 'symbol-field';\r\n\tdata[CompletionItemKind.Variable] = 'symbol-variable';\r\n\tdata[CompletionItemKind.Class] = 'symbol-class';\r\n\tdata[CompletionItemKind.Struct] = 'symbol-struct';\r\n\tdata[CompletionItemKind.Interface] = 'symbol-interface';\r\n\tdata[CompletionItemKind.Module] = 'symbol-module';\r\n\tdata[CompletionItemKind.Property] = 'symbol-property';\r\n\tdata[CompletionItemKind.Event] = 'symbol-event';\r\n\tdata[CompletionItemKind.Operator] = 'symbol-operator';\r\n\tdata[CompletionItemKind.Unit] = 'symbol-unit';\r\n\tdata[CompletionItemKind.Value] = 'symbol-value';\r\n\tdata[CompletionItemKind.Constant] = 'symbol-constant';\r\n\tdata[CompletionItemKind.Enum] = 'symbol-enum';\r\n\tdata[CompletionItemKind.EnumMember] = 'symbol-enum-member';\r\n\tdata[CompletionItemKind.Keyword] = 'symbol-keyword';\r\n\tdata[CompletionItemKind.Snippet] = 'symbol-snippet';\r\n\tdata[CompletionItemKind.Text] = 'symbol-text';\r\n\tdata[CompletionItemKind.Color] = 'symbol-color';\r\n\tdata[CompletionItemKind.File] = 'symbol-file';\r\n\tdata[CompletionItemKind.Reference] = 'symbol-reference';\r\n\tdata[CompletionItemKind.Customcolor] = 'symbol-customcolor';\r\n\tdata[CompletionItemKind.Folder] = 'symbol-folder';\r\n\tdata[CompletionItemKind.TypeParameter] = 'symbol-type-parameter';\r\n\tdata[CompletionItemKind.User] = 'account';\r\n\tdata[CompletionItemKind.Issue] = 'issues';\r\n\r\n\treturn function (kind: CompletionItemKind): string {\r\n\t\tconst name = data[kind];\r\n\t\tlet codicon = name && iconRegistry.get(name);\r\n\t\tif (!codicon) {\r\n\t\t\tconsole.info('No codicon found for CompletionItemKind ' + kind);\r\n\t\t\tcodicon = Codicon.symbolProperty;\r\n\t\t}\r\n\t\treturn codicon.classNames;\r\n\t};\r\n})();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport let completionKindFromString: {\r\n\t(value: string): CompletionItemKind;\r\n\t(value: string, strict: true): CompletionItemKind | undefined;\r\n} = (function () {\r\n\tlet data: Record = Object.create(null);\r\n\tdata['method'] = CompletionItemKind.Method;\r\n\tdata['function'] = CompletionItemKind.Function;\r\n\tdata['constructor'] = CompletionItemKind.Constructor;\r\n\tdata['field'] = CompletionItemKind.Field;\r\n\tdata['variable'] = CompletionItemKind.Variable;\r\n\tdata['class'] = CompletionItemKind.Class;\r\n\tdata['struct'] = CompletionItemKind.Struct;\r\n\tdata['interface'] = CompletionItemKind.Interface;\r\n\tdata['module'] = CompletionItemKind.Module;\r\n\tdata['property'] = CompletionItemKind.Property;\r\n\tdata['event'] = CompletionItemKind.Event;\r\n\tdata['operator'] = CompletionItemKind.Operator;\r\n\tdata['unit'] = CompletionItemKind.Unit;\r\n\tdata['value'] = CompletionItemKind.Value;\r\n\tdata['constant'] = CompletionItemKind.Constant;\r\n\tdata['enum'] = CompletionItemKind.Enum;\r\n\tdata['enum-member'] = CompletionItemKind.EnumMember;\r\n\tdata['enumMember'] = CompletionItemKind.EnumMember;\r\n\tdata['keyword'] = CompletionItemKind.Keyword;\r\n\tdata['snippet'] = CompletionItemKind.Snippet;\r\n\tdata['text'] = CompletionItemKind.Text;\r\n\tdata['color'] = CompletionItemKind.Color;\r\n\tdata['file'] = CompletionItemKind.File;\r\n\tdata['reference'] = CompletionItemKind.Reference;\r\n\tdata['customcolor'] = CompletionItemKind.Customcolor;\r\n\tdata['folder'] = CompletionItemKind.Folder;\r\n\tdata['type-parameter'] = CompletionItemKind.TypeParameter;\r\n\tdata['typeParameter'] = CompletionItemKind.TypeParameter;\r\n\tdata['account'] = CompletionItemKind.User;\r\n\tdata['issue'] = CompletionItemKind.Issue;\r\n\treturn function (value: string, strict?: true) {\r\n\t\tlet res = data[value];\r\n\t\tif (typeof res === 'undefined' && !strict) {\r\n\t\t\tres = CompletionItemKind.Property;\r\n\t\t}\r\n\t\treturn res;\r\n\t};\r\n})();\r\n\r\nexport interface CompletionItemLabel {\r\n\t/**\r\n\t * The function or variable. Rendered leftmost.\r\n\t */\r\n\tname: string;\r\n\r\n\t/**\r\n\t * The parameters without the return type. Render after `name`.\r\n\t */\r\n\tparameters?: string;\r\n\r\n\t/**\r\n\t * The fully qualified name, like package name or file path. Rendered after `signature`.\r\n\t */\r\n\tqualifier?: string;\r\n\r\n\t/**\r\n\t * The return-type of a function or type of a property/variable. Rendered rightmost.\r\n\t */\r\n\ttype?: string;\r\n}\r\n\r\nexport const enum CompletionItemTag {\r\n\tDeprecated = 1\r\n}\r\n\r\nexport const enum CompletionItemInsertTextRule {\r\n\t/**\r\n\t * Adjust whitespace/indentation of multiline insert texts to\r\n\t * match the current line indentation.\r\n\t */\r\n\tKeepWhitespace = 0b001,\r\n\r\n\t/**\r\n\t * `insertText` is a snippet.\r\n\t */\r\n\tInsertAsSnippet = 0b100,\r\n}\r\n\r\n/**\r\n * A completion item represents a text snippet that is\r\n * proposed to complete text that is being typed.\r\n */\r\nexport interface CompletionItem {\r\n\t/**\r\n\t * The label of this completion item. By default\r\n\t * this is also the text that is inserted when selecting\r\n\t * this completion.\r\n\t */\r\n\tlabel: string | CompletionItemLabel;\r\n\t/**\r\n\t * The kind of this completion item. Based on the kind\r\n\t * an icon is chosen by the editor.\r\n\t */\r\n\tkind: CompletionItemKind;\r\n\t/**\r\n\t * A modifier to the `kind` which affect how the item\r\n\t * is rendered, e.g. Deprecated is rendered with a strikeout\r\n\t */\r\n\ttags?: ReadonlyArray;\r\n\t/**\r\n\t * A human-readable string with additional information\r\n\t * about this item, like type or symbol information.\r\n\t */\r\n\tdetail?: string;\r\n\t/**\r\n\t * A human-readable string that represents a doc-comment.\r\n\t */\r\n\tdocumentation?: string | IMarkdownString;\r\n\t/**\r\n\t * A string that should be used when comparing this item\r\n\t * with other items. When `falsy` the [label](#CompletionItem.label)\r\n\t * is used.\r\n\t */\r\n\tsortText?: string;\r\n\t/**\r\n\t * A string that should be used when filtering a set of\r\n\t * completion items. When `falsy` the [label](#CompletionItem.label)\r\n\t * is used.\r\n\t */\r\n\tfilterText?: string;\r\n\t/**\r\n\t * Select this item when showing. *Note* that only one completion item can be selected and\r\n\t * that the editor decides which item that is. The rule is that the *first* item of those\r\n\t * that match best is selected.\r\n\t */\r\n\tpreselect?: boolean;\r\n\t/**\r\n\t * A string or snippet that should be inserted in a document when selecting\r\n\t * this completion.\r\n\t * is used.\r\n\t */\r\n\tinsertText: string;\r\n\t/**\r\n\t * Addition rules (as bitmask) that should be applied when inserting\r\n\t * this completion.\r\n\t */\r\n\tinsertTextRules?: CompletionItemInsertTextRule;\r\n\t/**\r\n\t * A range of text that should be replaced by this completion item.\r\n\t *\r\n\t * Defaults to a range from the start of the [current word](#TextDocument.getWordRangeAtPosition) to the\r\n\t * current position.\r\n\t *\r\n\t * *Note:* The range must be a [single line](#Range.isSingleLine) and it must\r\n\t * [contain](#Range.contains) the position at which completion has been [requested](#CompletionItemProvider.provideCompletionItems).\r\n\t */\r\n\trange: IRange | { insert: IRange, replace: IRange };\r\n\t/**\r\n\t * An optional set of characters that when pressed while this completion is active will accept it first and\r\n\t * then type that character. *Note* that all commit characters should have `length=1` and that superfluous\r\n\t * characters will be ignored.\r\n\t */\r\n\tcommitCharacters?: string[];\r\n\t/**\r\n\t * An optional array of additional text edits that are applied when\r\n\t * selecting this completion. Edits must not overlap with the main edit\r\n\t * nor with themselves.\r\n\t */\r\n\tadditionalTextEdits?: model.ISingleEditOperation[];\r\n\t/**\r\n\t * A command that should be run upon acceptance of this item.\r\n\t */\r\n\tcommand?: Command;\r\n}\r\n\r\nexport interface CompletionList {\r\n\tsuggestions: CompletionItem[];\r\n\tincomplete?: boolean;\r\n\tdispose?(): void;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\tduration?: number;\r\n}\r\n\r\n/**\r\n * How a suggest provider was triggered.\r\n */\r\nexport const enum CompletionTriggerKind {\r\n\tInvoke = 0,\r\n\tTriggerCharacter = 1,\r\n\tTriggerForIncompleteCompletions = 2\r\n}\r\n/**\r\n * Contains additional information about the context in which\r\n * [completion provider](#CompletionItemProvider.provideCompletionItems) is triggered.\r\n */\r\nexport interface CompletionContext {\r\n\t/**\r\n\t * How the completion was triggered.\r\n\t */\r\n\ttriggerKind: CompletionTriggerKind;\r\n\t/**\r\n\t * Character that triggered the completion item provider.\r\n\t *\r\n\t * `undefined` if provider was not triggered by a character.\r\n\t */\r\n\ttriggerCharacter?: string;\r\n}\r\n/**\r\n * The completion item provider interface defines the contract between extensions and\r\n * the [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense).\r\n *\r\n * When computing *complete* completion items is expensive, providers can optionally implement\r\n * the `resolveCompletionItem`-function. In that case it is enough to return completion\r\n * items with a [label](#CompletionItem.label) from the\r\n * [provideCompletionItems](#CompletionItemProvider.provideCompletionItems)-function. Subsequently,\r\n * when a completion item is shown in the UI and gains focus this provider is asked to resolve\r\n * the item, like adding [doc-comment](#CompletionItem.documentation) or [details](#CompletionItem.detail).\r\n */\r\nexport interface CompletionItemProvider {\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\t_debugDisplayName?: string;\r\n\r\n\ttriggerCharacters?: string[];\r\n\t/**\r\n\t * Provide completion items for the given position and document.\r\n\t */\r\n\tprovideCompletionItems(model: model.ITextModel, position: Position, context: CompletionContext, token: CancellationToken): ProviderResult;\r\n\r\n\t/**\r\n\t * Given a completion item fill in more data, like [doc-comment](#CompletionItem.documentation)\r\n\t * or [details](#CompletionItem.detail).\r\n\t *\r\n\t * The editor will only resolve a completion item once.\r\n\t */\r\n\tresolveCompletionItem?(item: CompletionItem, token: CancellationToken): ProviderResult;\r\n}\r\n\r\nexport interface CodeAction {\r\n\ttitle: string;\r\n\tcommand?: Command;\r\n\tedit?: WorkspaceEdit;\r\n\tdiagnostics?: IMarkerData[];\r\n\tkind?: string;\r\n\tisPreferred?: boolean;\r\n\tdisabled?: string;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const enum CodeActionTriggerType {\r\n\tAuto = 1,\r\n\tManual = 2,\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface CodeActionContext {\r\n\tonly?: string;\r\n\ttrigger: CodeActionTriggerType;\r\n}\r\n\r\nexport interface CodeActionList extends IDisposable {\r\n\treadonly actions: ReadonlyArray;\r\n}\r\n\r\n/**\r\n * The code action interface defines the contract between extensions and\r\n * the [light bulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) feature.\r\n * @internal\r\n */\r\nexport interface CodeActionProvider {\r\n\r\n\t/**\r\n\t * Provide commands for the given document and range.\r\n\t */\r\n\tprovideCodeActions(model: model.ITextModel, range: Range | Selection, context: CodeActionContext, token: CancellationToken): ProviderResult;\r\n\r\n\t/**\r\n\t * Given a code action fill in the edit. Will only invoked when missing.\r\n\t */\r\n\tresolveCodeAction?(codeAction: CodeAction, token: CancellationToken): ProviderResult;\r\n\r\n\t/**\r\n\t * Optional list of CodeActionKinds that this provider returns.\r\n\t */\r\n\treadonly providedCodeActionKinds?: ReadonlyArray;\r\n\r\n\treadonly documentation?: ReadonlyArray<{ readonly kind: string, readonly command: Command }>;\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\t_getAdditionalMenuItems?(context: CodeActionContext, actions: readonly CodeAction[]): Command[];\r\n}\r\n\r\n/**\r\n * Represents a parameter of a callable-signature. A parameter can\r\n * have a label and a doc-comment.\r\n */\r\nexport interface ParameterInformation {\r\n\t/**\r\n\t * The label of this signature. Will be shown in\r\n\t * the UI.\r\n\t */\r\n\tlabel: string | [number, number];\r\n\t/**\r\n\t * The human-readable doc-comment of this signature. Will be shown\r\n\t * in the UI but can be omitted.\r\n\t */\r\n\tdocumentation?: string | IMarkdownString;\r\n}\r\n/**\r\n * Represents the signature of something callable. A signature\r\n * can have a label, like a function-name, a doc-comment, and\r\n * a set of parameters.\r\n */\r\nexport interface SignatureInformation {\r\n\t/**\r\n\t * The label of this signature. Will be shown in\r\n\t * the UI.\r\n\t */\r\n\tlabel: string;\r\n\t/**\r\n\t * The human-readable doc-comment of this signature. Will be shown\r\n\t * in the UI but can be omitted.\r\n\t */\r\n\tdocumentation?: string | IMarkdownString;\r\n\t/**\r\n\t * The parameters of this signature.\r\n\t */\r\n\tparameters: ParameterInformation[];\r\n\t/**\r\n\t * Index of the active parameter.\r\n\t *\r\n\t * If provided, this is used in place of `SignatureHelp.activeSignature`.\r\n\t */\r\n\tactiveParameter?: number;\r\n}\r\n/**\r\n * Signature help represents the signature of something\r\n * callable. There can be multiple signatures but only one\r\n * active and only one active parameter.\r\n */\r\nexport interface SignatureHelp {\r\n\t/**\r\n\t * One or more signatures.\r\n\t */\r\n\tsignatures: SignatureInformation[];\r\n\t/**\r\n\t * The active signature.\r\n\t */\r\n\tactiveSignature: number;\r\n\t/**\r\n\t * The active parameter of the active signature.\r\n\t */\r\n\tactiveParameter: number;\r\n}\r\n\r\nexport interface SignatureHelpResult extends IDisposable {\r\n\tvalue: SignatureHelp;\r\n}\r\n\r\nexport enum SignatureHelpTriggerKind {\r\n\tInvoke = 1,\r\n\tTriggerCharacter = 2,\r\n\tContentChange = 3,\r\n}\r\n\r\nexport interface SignatureHelpContext {\r\n\treadonly triggerKind: SignatureHelpTriggerKind;\r\n\treadonly triggerCharacter?: string;\r\n\treadonly isRetrigger: boolean;\r\n\treadonly activeSignatureHelp?: SignatureHelp;\r\n}\r\n\r\n/**\r\n * The signature help provider interface defines the contract between extensions and\r\n * the [parameter hints](https://code.visualstudio.com/docs/editor/intellisense)-feature.\r\n */\r\nexport interface SignatureHelpProvider {\r\n\r\n\treadonly signatureHelpTriggerCharacters?: ReadonlyArray;\r\n\treadonly signatureHelpRetriggerCharacters?: ReadonlyArray;\r\n\r\n\t/**\r\n\t * Provide help for the signature at the given position and document.\r\n\t */\r\n\tprovideSignatureHelp(model: model.ITextModel, position: Position, token: CancellationToken, context: SignatureHelpContext): ProviderResult;\r\n}\r\n\r\n/**\r\n * A document highlight kind.\r\n */\r\nexport enum DocumentHighlightKind {\r\n\t/**\r\n\t * A textual occurrence.\r\n\t */\r\n\tText,\r\n\t/**\r\n\t * Read-access of a symbol, like reading a variable.\r\n\t */\r\n\tRead,\r\n\t/**\r\n\t * Write-access of a symbol, like writing to a variable.\r\n\t */\r\n\tWrite\r\n}\r\n/**\r\n * A document highlight is a range inside a text document which deserves\r\n * special attention. Usually a document highlight is visualized by changing\r\n * the background color of its range.\r\n */\r\nexport interface DocumentHighlight {\r\n\t/**\r\n\t * The range this highlight applies to.\r\n\t */\r\n\trange: IRange;\r\n\t/**\r\n\t * The highlight kind, default is [text](#DocumentHighlightKind.Text).\r\n\t */\r\n\tkind?: DocumentHighlightKind;\r\n}\r\n/**\r\n * The document highlight provider interface defines the contract between extensions and\r\n * the word-highlight-feature.\r\n */\r\nexport interface DocumentHighlightProvider {\r\n\t/**\r\n\t * Provide a set of document highlights, like all occurrences of a variable or\r\n\t * all exit-points of a function.\r\n\t */\r\n\tprovideDocumentHighlights(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult;\r\n}\r\n\r\n/**\r\n * The linked editing range provider interface defines the contract between extensions and\r\n * the linked editing feature.\r\n */\r\nexport interface LinkedEditingRangeProvider {\r\n\r\n\t/**\r\n\t * Provide a list of ranges that can be edited together.\r\n\t */\r\n\tprovideLinkedEditingRanges(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult;\r\n}\r\n\r\n/**\r\n * Represents a list of ranges that can be edited together along with a word pattern to describe valid contents.\r\n */\r\nexport interface LinkedEditingRanges {\r\n\t/**\r\n\t * A list of ranges that can be edited together. The ranges must have\r\n\t * identical length and text content. The ranges cannot overlap\r\n\t */\r\n\tranges: IRange[];\r\n\r\n\t/**\r\n\t * An optional word pattern that describes valid contents for the given ranges.\r\n\t * If no pattern is provided, the language configuration's word pattern will be used.\r\n\t */\r\n\twordPattern?: RegExp;\r\n}\r\n\r\n/**\r\n * Value-object that contains additional information when\r\n * requesting references.\r\n */\r\nexport interface ReferenceContext {\r\n\t/**\r\n\t * Include the declaration of the current symbol.\r\n\t */\r\n\tincludeDeclaration: boolean;\r\n}\r\n/**\r\n * The reference provider interface defines the contract between extensions and\r\n * the [find references](https://code.visualstudio.com/docs/editor/editingevolved#_peek)-feature.\r\n */\r\nexport interface ReferenceProvider {\r\n\t/**\r\n\t * Provide a set of project-wide references for the given position and document.\r\n\t */\r\n\tprovideReferences(model: model.ITextModel, position: Position, context: ReferenceContext, token: CancellationToken): ProviderResult;\r\n}\r\n\r\n/**\r\n * Represents a location inside a resource, such as a line\r\n * inside a text file.\r\n */\r\nexport interface Location {\r\n\t/**\r\n\t * The resource identifier of this location.\r\n\t */\r\n\turi: URI;\r\n\t/**\r\n\t * The document range of this locations.\r\n\t */\r\n\trange: IRange;\r\n}\r\n\r\nexport interface LocationLink {\r\n\t/**\r\n\t * A range to select where this link originates from.\r\n\t */\r\n\toriginSelectionRange?: IRange;\r\n\r\n\t/**\r\n\t * The target uri this link points to.\r\n\t */\r\n\turi: URI;\r\n\r\n\t/**\r\n\t * The full range this link points to.\r\n\t */\r\n\trange: IRange;\r\n\r\n\t/**\r\n\t * A range to select this link points to. Must be contained\r\n\t * in `LocationLink.range`.\r\n\t */\r\n\ttargetSelectionRange?: IRange;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport function isLocationLink(thing: any): thing is LocationLink {\r\n\treturn thing\r\n\t\t&& URI.isUri((thing as LocationLink).uri)\r\n\t\t&& Range.isIRange((thing as LocationLink).range)\r\n\t\t&& (Range.isIRange((thing as LocationLink).originSelectionRange) || Range.isIRange((thing as LocationLink).targetSelectionRange));\r\n}\r\n\r\nexport type Definition = Location | Location[] | LocationLink[];\r\n\r\n/**\r\n * The definition provider interface defines the contract between extensions and\r\n * the [go to definition](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-definition)\r\n * and peek definition features.\r\n */\r\nexport interface DefinitionProvider {\r\n\t/**\r\n\t * Provide the definition of the symbol at the given position and document.\r\n\t */\r\n\tprovideDefinition(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult;\r\n}\r\n\r\n/**\r\n * The definition provider interface defines the contract between extensions and\r\n * the [go to definition](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-definition)\r\n * and peek definition features.\r\n */\r\nexport interface DeclarationProvider {\r\n\t/**\r\n\t * Provide the declaration of the symbol at the given position and document.\r\n\t */\r\n\tprovideDeclaration(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult;\r\n}\r\n\r\n/**\r\n * The implementation provider interface defines the contract between extensions and\r\n * the go to implementation feature.\r\n */\r\nexport interface ImplementationProvider {\r\n\t/**\r\n\t * Provide the implementation of the symbol at the given position and document.\r\n\t */\r\n\tprovideImplementation(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult;\r\n}\r\n\r\n/**\r\n * The type definition provider interface defines the contract between extensions and\r\n * the go to type definition feature.\r\n */\r\nexport interface TypeDefinitionProvider {\r\n\t/**\r\n\t * Provide the type definition of the symbol at the given position and document.\r\n\t */\r\n\tprovideTypeDefinition(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult;\r\n}\r\n\r\n/**\r\n * A symbol kind.\r\n */\r\nexport const enum SymbolKind {\r\n\tFile = 0,\r\n\tModule = 1,\r\n\tNamespace = 2,\r\n\tPackage = 3,\r\n\tClass = 4,\r\n\tMethod = 5,\r\n\tProperty = 6,\r\n\tField = 7,\r\n\tConstructor = 8,\r\n\tEnum = 9,\r\n\tInterface = 10,\r\n\tFunction = 11,\r\n\tVariable = 12,\r\n\tConstant = 13,\r\n\tString = 14,\r\n\tNumber = 15,\r\n\tBoolean = 16,\r\n\tArray = 17,\r\n\tObject = 18,\r\n\tKey = 19,\r\n\tNull = 20,\r\n\tEnumMember = 21,\r\n\tStruct = 22,\r\n\tEvent = 23,\r\n\tOperator = 24,\r\n\tTypeParameter = 25\r\n}\r\n\r\nexport const enum SymbolTag {\r\n\tDeprecated = 1,\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport namespace SymbolKinds {\r\n\r\n\tconst byName = new Map();\r\n\tbyName.set('file', SymbolKind.File);\r\n\tbyName.set('module', SymbolKind.Module);\r\n\tbyName.set('namespace', SymbolKind.Namespace);\r\n\tbyName.set('package', SymbolKind.Package);\r\n\tbyName.set('class', SymbolKind.Class);\r\n\tbyName.set('method', SymbolKind.Method);\r\n\tbyName.set('property', SymbolKind.Property);\r\n\tbyName.set('field', SymbolKind.Field);\r\n\tbyName.set('constructor', SymbolKind.Constructor);\r\n\tbyName.set('enum', SymbolKind.Enum);\r\n\tbyName.set('interface', SymbolKind.Interface);\r\n\tbyName.set('function', SymbolKind.Function);\r\n\tbyName.set('variable', SymbolKind.Variable);\r\n\tbyName.set('constant', SymbolKind.Constant);\r\n\tbyName.set('string', SymbolKind.String);\r\n\tbyName.set('number', SymbolKind.Number);\r\n\tbyName.set('boolean', SymbolKind.Boolean);\r\n\tbyName.set('array', SymbolKind.Array);\r\n\tbyName.set('object', SymbolKind.Object);\r\n\tbyName.set('key', SymbolKind.Key);\r\n\tbyName.set('null', SymbolKind.Null);\r\n\tbyName.set('enum-member', SymbolKind.EnumMember);\r\n\tbyName.set('struct', SymbolKind.Struct);\r\n\tbyName.set('event', SymbolKind.Event);\r\n\tbyName.set('operator', SymbolKind.Operator);\r\n\tbyName.set('type-parameter', SymbolKind.TypeParameter);\r\n\r\n\tconst byKind = new Map();\r\n\tbyKind.set(SymbolKind.File, 'file');\r\n\tbyKind.set(SymbolKind.Module, 'module');\r\n\tbyKind.set(SymbolKind.Namespace, 'namespace');\r\n\tbyKind.set(SymbolKind.Package, 'package');\r\n\tbyKind.set(SymbolKind.Class, 'class');\r\n\tbyKind.set(SymbolKind.Method, 'method');\r\n\tbyKind.set(SymbolKind.Property, 'property');\r\n\tbyKind.set(SymbolKind.Field, 'field');\r\n\tbyKind.set(SymbolKind.Constructor, 'constructor');\r\n\tbyKind.set(SymbolKind.Enum, 'enum');\r\n\tbyKind.set(SymbolKind.Interface, 'interface');\r\n\tbyKind.set(SymbolKind.Function, 'function');\r\n\tbyKind.set(SymbolKind.Variable, 'variable');\r\n\tbyKind.set(SymbolKind.Constant, 'constant');\r\n\tbyKind.set(SymbolKind.String, 'string');\r\n\tbyKind.set(SymbolKind.Number, 'number');\r\n\tbyKind.set(SymbolKind.Boolean, 'boolean');\r\n\tbyKind.set(SymbolKind.Array, 'array');\r\n\tbyKind.set(SymbolKind.Object, 'object');\r\n\tbyKind.set(SymbolKind.Key, 'key');\r\n\tbyKind.set(SymbolKind.Null, 'null');\r\n\tbyKind.set(SymbolKind.EnumMember, 'enum-member');\r\n\tbyKind.set(SymbolKind.Struct, 'struct');\r\n\tbyKind.set(SymbolKind.Event, 'event');\r\n\tbyKind.set(SymbolKind.Operator, 'operator');\r\n\tbyKind.set(SymbolKind.TypeParameter, 'type-parameter');\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\texport function fromString(value: string): SymbolKind | undefined {\r\n\t\treturn byName.get(value);\r\n\t}\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\texport function toString(kind: SymbolKind): string | undefined {\r\n\t\treturn byKind.get(kind);\r\n\t}\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\texport function toCssClassName(kind: SymbolKind, inline?: boolean): string {\r\n\t\tconst symbolName = byKind.get(kind);\r\n\t\tlet codicon = symbolName && iconRegistry.get('symbol-' + symbolName);\r\n\t\tif (!codicon) {\r\n\t\t\tconsole.info('No codicon found for SymbolKind ' + kind);\r\n\t\t\tcodicon = Codicon.symbolProperty;\r\n\t\t}\r\n\t\treturn `${inline ? 'inline' : 'block'} ${codicon.classNames}`;\r\n\t}\r\n}\r\n\r\nexport interface DocumentSymbol {\r\n\tname: string;\r\n\tdetail: string;\r\n\tkind: SymbolKind;\r\n\ttags: ReadonlyArray;\r\n\tcontainerName?: string;\r\n\trange: IRange;\r\n\tselectionRange: IRange;\r\n\tchildren?: DocumentSymbol[];\r\n}\r\n\r\n/**\r\n * The document symbol provider interface defines the contract between extensions and\r\n * the [go to symbol](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-symbol)-feature.\r\n */\r\nexport interface DocumentSymbolProvider {\r\n\r\n\tdisplayName?: string;\r\n\r\n\t/**\r\n\t * Provide symbol information for the given document.\r\n\t */\r\n\tprovideDocumentSymbols(model: model.ITextModel, token: CancellationToken): ProviderResult;\r\n}\r\n\r\nexport type TextEdit = { range: IRange; text: string; eol?: model.EndOfLineSequence; };\r\n\r\n/**\r\n * Interface used to format a model\r\n */\r\nexport interface FormattingOptions {\r\n\t/**\r\n\t * Size of a tab in spaces.\r\n\t */\r\n\ttabSize: number;\r\n\t/**\r\n\t * Prefer spaces over tabs.\r\n\t */\r\n\tinsertSpaces: boolean;\r\n}\r\n/**\r\n * The document formatting provider interface defines the contract between extensions and\r\n * the formatting-feature.\r\n */\r\nexport interface DocumentFormattingEditProvider {\r\n\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\treadonly extensionId?: ExtensionIdentifier;\r\n\r\n\treadonly displayName?: string;\r\n\r\n\t/**\r\n\t * Provide formatting edits for a whole document.\r\n\t */\r\n\tprovideDocumentFormattingEdits(model: model.ITextModel, options: FormattingOptions, token: CancellationToken): ProviderResult;\r\n}\r\n/**\r\n * The document formatting provider interface defines the contract between extensions and\r\n * the formatting-feature.\r\n */\r\nexport interface DocumentRangeFormattingEditProvider {\r\n\t/**\r\n\t * @internal\r\n\t */\r\n\treadonly extensionId?: ExtensionIdentifier;\r\n\r\n\treadonly displayName?: string;\r\n\r\n\t/**\r\n\t * Provide formatting edits for a range in a document.\r\n\t *\r\n\t * The given range is a hint and providers can decide to format a smaller\r\n\t * or larger range. Often this is done by adjusting the start and end\r\n\t * of the range to full syntax nodes.\r\n\t */\r\n\tprovideDocumentRangeFormattingEdits(model: model.ITextModel, range: Range, options: FormattingOptions, token: CancellationToken): ProviderResult;\r\n}\r\n/**\r\n * The document formatting provider interface defines the contract between extensions and\r\n * the formatting-feature.\r\n */\r\nexport interface OnTypeFormattingEditProvider {\r\n\r\n\tautoFormatTriggerCharacters: string[];\r\n\r\n\t/**\r\n\t * Provide formatting edits after a character has been typed.\r\n\t *\r\n\t * The given position and character should hint to the provider\r\n\t * what range the position to expand to, like find the matching `{`\r\n\t * when `}` has been entered.\r\n\t */\r\n\tprovideOnTypeFormattingEdits(model: model.ITextModel, position: Position, ch: string, options: FormattingOptions, token: CancellationToken): ProviderResult;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface IInplaceReplaceSupportResult {\r\n\tvalue: string;\r\n\trange: IRange;\r\n}\r\n\r\n/**\r\n * A link inside the editor.\r\n */\r\nexport interface ILink {\r\n\trange: IRange;\r\n\turl?: URI | string;\r\n\ttooltip?: string;\r\n}\r\n\r\nexport interface ILinksList {\r\n\tlinks: ILink[];\r\n\tdispose?(): void;\r\n}\r\n/**\r\n * A provider of links.\r\n */\r\nexport interface LinkProvider {\r\n\tprovideLinks(model: model.ITextModel, token: CancellationToken): ProviderResult;\r\n\tresolveLink?: (link: ILink, token: CancellationToken) => ProviderResult;\r\n}\r\n\r\n/**\r\n * A color in RGBA format.\r\n */\r\nexport interface IColor {\r\n\r\n\t/**\r\n\t * The red component in the range [0-1].\r\n\t */\r\n\treadonly red: number;\r\n\r\n\t/**\r\n\t * The green component in the range [0-1].\r\n\t */\r\n\treadonly green: number;\r\n\r\n\t/**\r\n\t * The blue component in the range [0-1].\r\n\t */\r\n\treadonly blue: number;\r\n\r\n\t/**\r\n\t * The alpha component in the range [0-1].\r\n\t */\r\n\treadonly alpha: number;\r\n}\r\n\r\n/**\r\n * String representations for a color\r\n */\r\nexport interface IColorPresentation {\r\n\t/**\r\n\t * The label of this color presentation. It will be shown on the color\r\n\t * picker header. By default this is also the text that is inserted when selecting\r\n\t * this color presentation.\r\n\t */\r\n\tlabel: string;\r\n\t/**\r\n\t * An [edit](#TextEdit) which is applied to a document when selecting\r\n\t * this presentation for the color.\r\n\t */\r\n\ttextEdit?: TextEdit;\r\n\t/**\r\n\t * An optional array of additional [text edits](#TextEdit) that are applied when\r\n\t * selecting this color presentation.\r\n\t */\r\n\tadditionalTextEdits?: TextEdit[];\r\n}\r\n\r\n/**\r\n * A color range is a range in a text model which represents a color.\r\n */\r\nexport interface IColorInformation {\r\n\r\n\t/**\r\n\t * The range within the model.\r\n\t */\r\n\trange: IRange;\r\n\r\n\t/**\r\n\t * The color represented in this range.\r\n\t */\r\n\tcolor: IColor;\r\n}\r\n\r\n/**\r\n * A provider of colors for editor models.\r\n */\r\nexport interface DocumentColorProvider {\r\n\t/**\r\n\t * Provides the color ranges for a specific model.\r\n\t */\r\n\tprovideDocumentColors(model: model.ITextModel, token: CancellationToken): ProviderResult;\r\n\t/**\r\n\t * Provide the string representations for a color.\r\n\t */\r\n\tprovideColorPresentations(model: model.ITextModel, colorInfo: IColorInformation, token: CancellationToken): ProviderResult;\r\n}\r\n\r\nexport interface SelectionRange {\r\n\trange: IRange;\r\n}\r\n\r\nexport interface SelectionRangeProvider {\r\n\t/**\r\n\t * Provide ranges that should be selected from the given position.\r\n\t */\r\n\tprovideSelectionRanges(model: model.ITextModel, positions: Position[], token: CancellationToken): ProviderResult;\r\n}\r\n\r\nexport interface FoldingContext {\r\n}\r\n/**\r\n * A provider of folding ranges for editor models.\r\n */\r\nexport interface FoldingRangeProvider {\r\n\r\n\t/**\r\n\t * An optional event to signal that the folding ranges from this provider have changed.\r\n\t */\r\n\tonDidChange?: Event;\r\n\r\n\t/**\r\n\t * Provides the folding ranges for a specific model.\r\n\t */\r\n\tprovideFoldingRanges(model: model.ITextModel, context: FoldingContext, token: CancellationToken): ProviderResult;\r\n}\r\n\r\nexport interface FoldingRange {\r\n\r\n\t/**\r\n\t * The one-based start line of the range to fold. The folded area starts after the line's last character.\r\n\t */\r\n\tstart: number;\r\n\r\n\t/**\r\n\t * The one-based end line of the range to fold. The folded area ends with the line's last character.\r\n\t */\r\n\tend: number;\r\n\r\n\t/**\r\n\t * Describes the [Kind](#FoldingRangeKind) of the folding range such as [Comment](#FoldingRangeKind.Comment) or\r\n\t * [Region](#FoldingRangeKind.Region). The kind is used to categorize folding ranges and used by commands\r\n\t * like 'Fold all comments'. See\r\n\t * [FoldingRangeKind](#FoldingRangeKind) for an enumeration of standardized kinds.\r\n\t */\r\n\tkind?: FoldingRangeKind;\r\n}\r\nexport class FoldingRangeKind {\r\n\t/**\r\n\t * Kind for folding range representing a comment. The value of the kind is 'comment'.\r\n\t */\r\n\tstatic readonly Comment = new FoldingRangeKind('comment');\r\n\t/**\r\n\t * Kind for folding range representing a import. The value of the kind is 'imports'.\r\n\t */\r\n\tstatic readonly Imports = new FoldingRangeKind('imports');\r\n\t/**\r\n\t * Kind for folding range representing regions (for example marked by `#region`, `#endregion`).\r\n\t * The value of the kind is 'region'.\r\n\t */\r\n\tstatic readonly Region = new FoldingRangeKind('region');\r\n\r\n\t/**\r\n\t * Creates a new [FoldingRangeKind](#FoldingRangeKind).\r\n\t *\r\n\t * @param value of the kind.\r\n\t */\r\n\tpublic constructor(public value: string) {\r\n\t}\r\n}\r\n\r\n\r\nexport interface WorkspaceEditMetadata {\r\n\tneedsConfirmation: boolean;\r\n\tlabel: string;\r\n\tdescription?: string;\r\n}\r\n\r\nexport interface WorkspaceFileEditOptions {\r\n\toverwrite?: boolean;\r\n\tignoreIfNotExists?: boolean;\r\n\tignoreIfExists?: boolean;\r\n\trecursive?: boolean;\r\n\tcopy?: boolean;\r\n\tfolder?: boolean;\r\n\tskipTrashBin?: boolean;\r\n\tmaxSize?: number;\r\n}\r\n\r\nexport interface WorkspaceFileEdit {\r\n\toldUri?: URI;\r\n\tnewUri?: URI;\r\n\toptions?: WorkspaceFileEditOptions;\r\n\tmetadata?: WorkspaceEditMetadata;\r\n}\r\n\r\nexport interface WorkspaceTextEdit {\r\n\tresource: URI;\r\n\tedit: TextEdit;\r\n\tmodelVersionId?: number;\r\n\tmetadata?: WorkspaceEditMetadata;\r\n}\r\n\r\nexport interface WorkspaceEdit {\r\n\tedits: Array;\r\n}\r\n\r\nexport interface Rejection {\r\n\trejectReason?: string;\r\n}\r\nexport interface RenameLocation {\r\n\trange: IRange;\r\n\ttext: string;\r\n}\r\n\r\nexport interface RenameProvider {\r\n\tprovideRenameEdits(model: model.ITextModel, position: Position, newName: string, token: CancellationToken): ProviderResult;\r\n\tresolveRenameLocation?(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult;\r\n}\r\n\r\nexport interface Command {\r\n\tid: string;\r\n\ttitle: string;\r\n\ttooltip?: string;\r\n\targuments?: any[];\r\n}\r\n\r\n\r\nexport interface CodeLens {\r\n\trange: IRange;\r\n\tid?: string;\r\n\tcommand?: Command;\r\n}\r\n\r\nexport interface CodeLensList {\r\n\tlenses: CodeLens[];\r\n\tdispose(): void;\r\n}\r\n\r\nexport interface CodeLensProvider {\r\n\tonDidChange?: Event;\r\n\tprovideCodeLenses(model: model.ITextModel, token: CancellationToken): ProviderResult;\r\n\tresolveCodeLens?(model: model.ITextModel, codeLens: CodeLens, token: CancellationToken): ProviderResult;\r\n}\r\n\r\nexport interface InlineHint {\r\n\ttext: string;\r\n\trange: IRange;\r\n\tdescription?: string | IMarkdownString;\r\n\twhitespaceBefore?: boolean;\r\n\twhitespaceAfter?: boolean;\r\n}\r\n\r\nexport interface InlineHintsProvider {\r\n\tonDidChangeInlineHints?: Event | undefined;\r\n\tprovideInlineHints(model: model.ITextModel, range: Range, token: CancellationToken): ProviderResult;\r\n}\r\n\r\nexport interface SemanticTokensLegend {\r\n\treadonly tokenTypes: string[];\r\n\treadonly tokenModifiers: string[];\r\n}\r\n\r\nexport interface SemanticTokens {\r\n\treadonly resultId?: string;\r\n\treadonly data: Uint32Array;\r\n}\r\n\r\nexport interface SemanticTokensEdit {\r\n\treadonly start: number;\r\n\treadonly deleteCount: number;\r\n\treadonly data?: Uint32Array;\r\n}\r\n\r\nexport interface SemanticTokensEdits {\r\n\treadonly resultId?: string;\r\n\treadonly edits: SemanticTokensEdit[];\r\n}\r\n\r\nexport interface DocumentSemanticTokensProvider {\r\n\tonDidChange?: Event;\r\n\tgetLegend(): SemanticTokensLegend;\r\n\tprovideDocumentSemanticTokens(model: model.ITextModel, lastResultId: string | null, token: CancellationToken): ProviderResult;\r\n\treleaseDocumentSemanticTokens(resultId: string | undefined): void;\r\n}\r\n\r\nexport interface DocumentRangeSemanticTokensProvider {\r\n\tgetLegend(): SemanticTokensLegend;\r\n\tprovideDocumentRangeSemanticTokens(model: model.ITextModel, range: Range, token: CancellationToken): ProviderResult;\r\n}\r\n\r\n// --- feature registries ------\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const ReferenceProviderRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const RenameProviderRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const CompletionProviderRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const SignatureHelpProviderRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const HoverProviderRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const DocumentSymbolProviderRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const DocumentHighlightProviderRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const LinkedEditingRangeProviderRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const DefinitionProviderRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const DeclarationProviderRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const ImplementationProviderRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const TypeDefinitionProviderRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const CodeLensProviderRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const InlineHintsProviderRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const CodeActionProviderRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const DocumentFormattingEditProviderRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const DocumentRangeFormattingEditProviderRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const OnTypeFormattingEditProviderRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const LinkProviderRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const ColorProviderRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const SelectionRangeRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const FoldingRangeProviderRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const DocumentSemanticTokensProviderRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const DocumentRangeSemanticTokensProviderRegistry = new LanguageFeatureRegistry();\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface ITokenizationSupportChangedEvent {\r\n\tchangedLanguages: string[];\r\n\tchangedColorMap: boolean;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface ITokenizationRegistry {\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport const TokenizationRegistry = new TokenizationRegistryImpl();\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { ColorId, LanguageId, StandardTokenType, TokenMetadata } from 'vs/editor/common/modes';\r\n\r\nexport interface IViewLineTokens {\r\n\tequals(other: IViewLineTokens): boolean;\r\n\tgetCount(): number;\r\n\tgetForeground(tokenIndex: number): ColorId;\r\n\tgetEndOffset(tokenIndex: number): number;\r\n\tgetClassName(tokenIndex: number): string;\r\n\tgetInlineStyle(tokenIndex: number, colorMap: string[]): string;\r\n\tfindTokenIndexAtOffset(offset: number): number;\r\n}\r\n\r\nexport class LineTokens implements IViewLineTokens {\r\n\t_lineTokensBrand: void;\r\n\r\n\tprivate readonly _tokens: Uint32Array;\r\n\tprivate readonly _tokensCount: number;\r\n\tprivate readonly _text: string;\r\n\r\n\tconstructor(tokens: Uint32Array, text: string) {\r\n\t\tthis._tokens = tokens;\r\n\t\tthis._tokensCount = (this._tokens.length >>> 1);\r\n\t\tthis._text = text;\r\n\t}\r\n\r\n\tpublic equals(other: IViewLineTokens): boolean {\r\n\t\tif (other instanceof LineTokens) {\r\n\t\t\treturn this.slicedEquals(other, 0, this._tokensCount);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic slicedEquals(other: LineTokens, sliceFromTokenIndex: number, sliceTokenCount: number): boolean {\r\n\t\tif (this._text !== other._text) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (this._tokensCount !== other._tokensCount) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tconst from = (sliceFromTokenIndex << 1);\r\n\t\tconst to = from + (sliceTokenCount << 1);\r\n\t\tfor (let i = from; i < to; i++) {\r\n\t\t\tif (this._tokens[i] !== other._tokens[i]) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic getLineContent(): string {\r\n\t\treturn this._text;\r\n\t}\r\n\r\n\tpublic getCount(): number {\r\n\t\treturn this._tokensCount;\r\n\t}\r\n\r\n\tpublic getStartOffset(tokenIndex: number): number {\r\n\t\tif (tokenIndex > 0) {\r\n\t\t\treturn this._tokens[(tokenIndex - 1) << 1];\r\n\t\t}\r\n\t\treturn 0;\r\n\t}\r\n\r\n\tpublic getMetadata(tokenIndex: number): number {\r\n\t\tconst metadata = this._tokens[(tokenIndex << 1) + 1];\r\n\t\treturn metadata;\r\n\t}\r\n\r\n\tpublic getLanguageId(tokenIndex: number): LanguageId {\r\n\t\tconst metadata = this._tokens[(tokenIndex << 1) + 1];\r\n\t\treturn TokenMetadata.getLanguageId(metadata);\r\n\t}\r\n\r\n\tpublic getStandardTokenType(tokenIndex: number): StandardTokenType {\r\n\t\tconst metadata = this._tokens[(tokenIndex << 1) + 1];\r\n\t\treturn TokenMetadata.getTokenType(metadata);\r\n\t}\r\n\r\n\tpublic getForeground(tokenIndex: number): ColorId {\r\n\t\tconst metadata = this._tokens[(tokenIndex << 1) + 1];\r\n\t\treturn TokenMetadata.getForeground(metadata);\r\n\t}\r\n\r\n\tpublic getClassName(tokenIndex: number): string {\r\n\t\tconst metadata = this._tokens[(tokenIndex << 1) + 1];\r\n\t\treturn TokenMetadata.getClassNameFromMetadata(metadata);\r\n\t}\r\n\r\n\tpublic getInlineStyle(tokenIndex: number, colorMap: string[]): string {\r\n\t\tconst metadata = this._tokens[(tokenIndex << 1) + 1];\r\n\t\treturn TokenMetadata.getInlineStyleFromMetadata(metadata, colorMap);\r\n\t}\r\n\r\n\tpublic getEndOffset(tokenIndex: number): number {\r\n\t\treturn this._tokens[tokenIndex << 1];\r\n\t}\r\n\r\n\t/**\r\n\t * Find the token containing offset `offset`.\r\n\t * @param offset The search offset\r\n\t * @return The index of the token containing the offset.\r\n\t */\r\n\tpublic findTokenIndexAtOffset(offset: number): number {\r\n\t\treturn LineTokens.findIndexInTokensArray(this._tokens, offset);\r\n\t}\r\n\r\n\tpublic inflate(): IViewLineTokens {\r\n\t\treturn this;\r\n\t}\r\n\r\n\tpublic sliceAndInflate(startOffset: number, endOffset: number, deltaOffset: number): IViewLineTokens {\r\n\t\treturn new SlicedLineTokens(this, startOffset, endOffset, deltaOffset);\r\n\t}\r\n\r\n\tpublic static convertToEndOffset(tokens: Uint32Array, lineTextLength: number): void {\r\n\t\tconst tokenCount = (tokens.length >>> 1);\r\n\t\tconst lastTokenIndex = tokenCount - 1;\r\n\t\tfor (let tokenIndex = 0; tokenIndex < lastTokenIndex; tokenIndex++) {\r\n\t\t\ttokens[tokenIndex << 1] = tokens[(tokenIndex + 1) << 1];\r\n\t\t}\r\n\t\ttokens[lastTokenIndex << 1] = lineTextLength;\r\n\t}\r\n\r\n\tpublic static findIndexInTokensArray(tokens: Uint32Array, desiredIndex: number): number {\r\n\t\tif (tokens.length <= 2) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tlet low = 0;\r\n\t\tlet high = (tokens.length >>> 1) - 1;\r\n\r\n\t\twhile (low < high) {\r\n\r\n\t\t\tconst mid = low + Math.floor((high - low) / 2);\r\n\t\t\tconst endOffset = tokens[(mid << 1)];\r\n\r\n\t\t\tif (endOffset === desiredIndex) {\r\n\t\t\t\treturn mid + 1;\r\n\t\t\t} else if (endOffset < desiredIndex) {\r\n\t\t\t\tlow = mid + 1;\r\n\t\t\t} else if (endOffset > desiredIndex) {\r\n\t\t\t\thigh = mid;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn low;\r\n\t}\r\n}\r\n\r\nexport class SlicedLineTokens implements IViewLineTokens {\r\n\r\n\tprivate readonly _source: LineTokens;\r\n\tprivate readonly _startOffset: number;\r\n\tprivate readonly _endOffset: number;\r\n\tprivate readonly _deltaOffset: number;\r\n\r\n\tprivate readonly _firstTokenIndex: number;\r\n\tprivate readonly _tokensCount: number;\r\n\r\n\tconstructor(source: LineTokens, startOffset: number, endOffset: number, deltaOffset: number) {\r\n\t\tthis._source = source;\r\n\t\tthis._startOffset = startOffset;\r\n\t\tthis._endOffset = endOffset;\r\n\t\tthis._deltaOffset = deltaOffset;\r\n\t\tthis._firstTokenIndex = source.findTokenIndexAtOffset(startOffset);\r\n\r\n\t\tthis._tokensCount = 0;\r\n\t\tfor (let i = this._firstTokenIndex, len = source.getCount(); i < len; i++) {\r\n\t\t\tconst tokenStartOffset = source.getStartOffset(i);\r\n\t\t\tif (tokenStartOffset >= endOffset) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tthis._tokensCount++;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic equals(other: IViewLineTokens): boolean {\r\n\t\tif (other instanceof SlicedLineTokens) {\r\n\t\t\treturn (\r\n\t\t\t\tthis._startOffset === other._startOffset\r\n\t\t\t\t&& this._endOffset === other._endOffset\r\n\t\t\t\t&& this._deltaOffset === other._deltaOffset\r\n\t\t\t\t&& this._source.slicedEquals(other._source, this._firstTokenIndex, this._tokensCount)\r\n\t\t\t);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic getCount(): number {\r\n\t\treturn this._tokensCount;\r\n\t}\r\n\r\n\tpublic getForeground(tokenIndex: number): ColorId {\r\n\t\treturn this._source.getForeground(this._firstTokenIndex + tokenIndex);\r\n\t}\r\n\r\n\tpublic getEndOffset(tokenIndex: number): number {\r\n\t\tconst tokenEndOffset = this._source.getEndOffset(this._firstTokenIndex + tokenIndex);\r\n\t\treturn Math.min(this._endOffset, tokenEndOffset) - this._startOffset + this._deltaOffset;\r\n\t}\r\n\r\n\tpublic getClassName(tokenIndex: number): string {\r\n\t\treturn this._source.getClassName(this._firstTokenIndex + tokenIndex);\r\n\t}\r\n\r\n\tpublic getInlineStyle(tokenIndex: number, colorMap: string[]): string {\r\n\t\treturn this._source.getInlineStyle(this._firstTokenIndex + tokenIndex, colorMap);\r\n\t}\r\n\r\n\tpublic findTokenIndexAtOffset(offset: number): number {\r\n\t\treturn this._source.findTokenIndexAtOffset(offset + this._startOffset - this._deltaOffset) - this._firstTokenIndex;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as arrays from 'vs/base/common/arrays';\r\nimport { LineTokens } from 'vs/editor/common/core/lineTokens';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { IRange, Range } from 'vs/editor/common/core/range';\r\nimport { ColorId, FontStyle, LanguageId, MetadataConsts, StandardTokenType, TokenMetadata } from 'vs/editor/common/modes';\r\nimport { CharCode } from 'vs/base/common/charCode';\r\n\r\nexport const enum StringEOL {\r\n\tUnknown = 0,\r\n\tInvalid = 3,\r\n\tLF = 1,\r\n\tCRLF = 2\r\n}\r\n\r\nexport function countEOL(text: string): [number, number, number, StringEOL] {\r\n\tlet eolCount = 0;\r\n\tlet firstLineLength = 0;\r\n\tlet lastLineStart = 0;\r\n\tlet eol: StringEOL = StringEOL.Unknown;\r\n\tfor (let i = 0, len = text.length; i < len; i++) {\r\n\t\tconst chr = text.charCodeAt(i);\r\n\r\n\t\tif (chr === CharCode.CarriageReturn) {\r\n\t\t\tif (eolCount === 0) {\r\n\t\t\t\tfirstLineLength = i;\r\n\t\t\t}\r\n\t\t\teolCount++;\r\n\t\t\tif (i + 1 < len && text.charCodeAt(i + 1) === CharCode.LineFeed) {\r\n\t\t\t\t// \\r\\n... case\r\n\t\t\t\teol |= StringEOL.CRLF;\r\n\t\t\t\ti++; // skip \\n\r\n\t\t\t} else {\r\n\t\t\t\t// \\r... case\r\n\t\t\t\teol |= StringEOL.Invalid;\r\n\t\t\t}\r\n\t\t\tlastLineStart = i + 1;\r\n\t\t} else if (chr === CharCode.LineFeed) {\r\n\t\t\t// \\n... case\r\n\t\t\teol |= StringEOL.LF;\r\n\t\t\tif (eolCount === 0) {\r\n\t\t\t\tfirstLineLength = i;\r\n\t\t\t}\r\n\t\t\teolCount++;\r\n\t\t\tlastLineStart = i + 1;\r\n\t\t}\r\n\t}\r\n\tif (eolCount === 0) {\r\n\t\tfirstLineLength = text.length;\r\n\t}\r\n\treturn [eolCount, firstLineLength, text.length - lastLineStart, eol];\r\n}\r\n\r\nfunction getDefaultMetadata(topLevelLanguageId: LanguageId): number {\r\n\treturn (\r\n\t\t(topLevelLanguageId << MetadataConsts.LANGUAGEID_OFFSET)\r\n\t\t| (StandardTokenType.Other << MetadataConsts.TOKEN_TYPE_OFFSET)\r\n\t\t| (FontStyle.None << MetadataConsts.FONT_STYLE_OFFSET)\r\n\t\t| (ColorId.DefaultForeground << MetadataConsts.FOREGROUND_OFFSET)\r\n\t\t| (ColorId.DefaultBackground << MetadataConsts.BACKGROUND_OFFSET)\r\n\t) >>> 0;\r\n}\r\n\r\nconst EMPTY_LINE_TOKENS = (new Uint32Array(0)).buffer;\r\n\r\nexport class MultilineTokensBuilder {\r\n\r\n\tpublic readonly tokens: MultilineTokens[];\r\n\r\n\tconstructor() {\r\n\t\tthis.tokens = [];\r\n\t}\r\n\r\n\tpublic add(lineNumber: number, lineTokens: Uint32Array): void {\r\n\t\tif (this.tokens.length > 0) {\r\n\t\t\tconst last = this.tokens[this.tokens.length - 1];\r\n\t\t\tconst lastLineNumber = last.startLineNumber + last.tokens.length - 1;\r\n\t\t\tif (lastLineNumber + 1 === lineNumber) {\r\n\t\t\t\t// append\r\n\t\t\t\tlast.tokens.push(lineTokens);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis.tokens.push(new MultilineTokens(lineNumber, [lineTokens]));\r\n\t}\r\n}\r\n\r\nexport class SparseEncodedTokens {\r\n\t/**\r\n\t * The encoding of tokens is:\r\n\t * 4*i deltaLine (from `startLineNumber`)\r\n\t * 4*i+1 startCharacter (from the line start)\r\n\t * 4*i+2 endCharacter (from the line start)\r\n\t * 4*i+3 metadata\r\n\t */\r\n\tprivate readonly _tokens: Uint32Array;\r\n\tprivate _tokenCount: number;\r\n\r\n\tconstructor(tokens: Uint32Array) {\r\n\t\tthis._tokens = tokens;\r\n\t\tthis._tokenCount = tokens.length / 4;\r\n\t}\r\n\r\n\tpublic toString(startLineNumber: number): string {\r\n\t\tlet pieces: string[] = [];\r\n\t\tfor (let i = 0; i < this._tokenCount; i++) {\r\n\t\t\tpieces.push(`(${this._getDeltaLine(i) + startLineNumber},${this._getStartCharacter(i)}-${this._getEndCharacter(i)})`);\r\n\t\t}\r\n\t\treturn `[${pieces.join(',')}]`;\r\n\t}\r\n\r\n\tpublic getMaxDeltaLine(): number {\r\n\t\tconst tokenCount = this._getTokenCount();\r\n\t\tif (tokenCount === 0) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\treturn this._getDeltaLine(tokenCount - 1);\r\n\t}\r\n\r\n\tpublic getRange(): Range | null {\r\n\t\tconst tokenCount = this._getTokenCount();\r\n\t\tif (tokenCount === 0) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tconst startChar = this._getStartCharacter(0);\r\n\t\tconst maxDeltaLine = this._getDeltaLine(tokenCount - 1);\r\n\t\tconst endChar = this._getEndCharacter(tokenCount - 1);\r\n\t\treturn new Range(0, startChar + 1, maxDeltaLine, endChar + 1);\r\n\t}\r\n\r\n\tprivate _getTokenCount(): number {\r\n\t\treturn this._tokenCount;\r\n\t}\r\n\r\n\tprivate _getDeltaLine(tokenIndex: number): number {\r\n\t\treturn this._tokens[4 * tokenIndex];\r\n\t}\r\n\r\n\tprivate _getStartCharacter(tokenIndex: number): number {\r\n\t\treturn this._tokens[4 * tokenIndex + 1];\r\n\t}\r\n\r\n\tprivate _getEndCharacter(tokenIndex: number): number {\r\n\t\treturn this._tokens[4 * tokenIndex + 2];\r\n\t}\r\n\r\n\tpublic isEmpty(): boolean {\r\n\t\treturn (this._getTokenCount() === 0);\r\n\t}\r\n\r\n\tpublic getLineTokens(deltaLine: number): LineTokens2 | null {\r\n\t\tlet low = 0;\r\n\t\tlet high = this._getTokenCount() - 1;\r\n\r\n\t\twhile (low < high) {\r\n\t\t\tconst mid = low + Math.floor((high - low) / 2);\r\n\t\t\tconst midDeltaLine = this._getDeltaLine(mid);\r\n\r\n\t\t\tif (midDeltaLine < deltaLine) {\r\n\t\t\t\tlow = mid + 1;\r\n\t\t\t} else if (midDeltaLine > deltaLine) {\r\n\t\t\t\thigh = mid - 1;\r\n\t\t\t} else {\r\n\t\t\t\tlet min = mid;\r\n\t\t\t\twhile (min > low && this._getDeltaLine(min - 1) === deltaLine) {\r\n\t\t\t\t\tmin--;\r\n\t\t\t\t}\r\n\t\t\t\tlet max = mid;\r\n\t\t\t\twhile (max < high && this._getDeltaLine(max + 1) === deltaLine) {\r\n\t\t\t\t\tmax++;\r\n\t\t\t\t}\r\n\t\t\t\treturn new LineTokens2(this._tokens.subarray(4 * min, 4 * max + 4));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (this._getDeltaLine(low) === deltaLine) {\r\n\t\t\treturn new LineTokens2(this._tokens.subarray(4 * low, 4 * low + 4));\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic clear(): void {\r\n\t\tthis._tokenCount = 0;\r\n\t}\r\n\r\n\tpublic removeTokens(startDeltaLine: number, startChar: number, endDeltaLine: number, endChar: number): number {\r\n\t\tconst tokens = this._tokens;\r\n\t\tconst tokenCount = this._tokenCount;\r\n\t\tlet newTokenCount = 0;\r\n\t\tlet hasDeletedTokens = false;\r\n\t\tlet firstDeltaLine = 0;\r\n\t\tfor (let i = 0; i < tokenCount; i++) {\r\n\t\t\tconst srcOffset = 4 * i;\r\n\t\t\tconst tokenDeltaLine = tokens[srcOffset];\r\n\t\t\tconst tokenStartCharacter = tokens[srcOffset + 1];\r\n\t\t\tconst tokenEndCharacter = tokens[srcOffset + 2];\r\n\t\t\tconst tokenMetadata = tokens[srcOffset + 3];\r\n\r\n\t\t\tif (\r\n\t\t\t\t(tokenDeltaLine > startDeltaLine || (tokenDeltaLine === startDeltaLine && tokenEndCharacter >= startChar))\r\n\t\t\t\t&& (tokenDeltaLine < endDeltaLine || (tokenDeltaLine === endDeltaLine && tokenStartCharacter <= endChar))\r\n\t\t\t) {\r\n\t\t\t\thasDeletedTokens = true;\r\n\t\t\t} else {\r\n\t\t\t\tif (newTokenCount === 0) {\r\n\t\t\t\t\tfirstDeltaLine = tokenDeltaLine;\r\n\t\t\t\t}\r\n\t\t\t\tif (hasDeletedTokens) {\r\n\t\t\t\t\t// must move the token to the left\r\n\t\t\t\t\tconst destOffset = 4 * newTokenCount;\r\n\t\t\t\t\ttokens[destOffset] = tokenDeltaLine - firstDeltaLine;\r\n\t\t\t\t\ttokens[destOffset + 1] = tokenStartCharacter;\r\n\t\t\t\t\ttokens[destOffset + 2] = tokenEndCharacter;\r\n\t\t\t\t\ttokens[destOffset + 3] = tokenMetadata;\r\n\t\t\t\t}\r\n\t\t\t\tnewTokenCount++;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._tokenCount = newTokenCount;\r\n\r\n\t\treturn firstDeltaLine;\r\n\t}\r\n\r\n\tpublic split(startDeltaLine: number, startChar: number, endDeltaLine: number, endChar: number): [SparseEncodedTokens, SparseEncodedTokens, number] {\r\n\t\tconst tokens = this._tokens;\r\n\t\tconst tokenCount = this._tokenCount;\r\n\t\tlet aTokens: number[] = [];\r\n\t\tlet bTokens: number[] = [];\r\n\t\tlet destTokens: number[] = aTokens;\r\n\t\tlet destOffset = 0;\r\n\t\tlet destFirstDeltaLine: number = 0;\r\n\t\tfor (let i = 0; i < tokenCount; i++) {\r\n\t\t\tconst srcOffset = 4 * i;\r\n\t\t\tconst tokenDeltaLine = tokens[srcOffset];\r\n\t\t\tconst tokenStartCharacter = tokens[srcOffset + 1];\r\n\t\t\tconst tokenEndCharacter = tokens[srcOffset + 2];\r\n\t\t\tconst tokenMetadata = tokens[srcOffset + 3];\r\n\r\n\t\t\tif ((tokenDeltaLine > startDeltaLine || (tokenDeltaLine === startDeltaLine && tokenEndCharacter >= startChar))) {\r\n\t\t\t\tif ((tokenDeltaLine < endDeltaLine || (tokenDeltaLine === endDeltaLine && tokenStartCharacter <= endChar))) {\r\n\t\t\t\t\t// this token is touching the range\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// this token is after the range\r\n\t\t\t\t\tif (destTokens !== bTokens) {\r\n\t\t\t\t\t\t// this token is the first token after the range\r\n\t\t\t\t\t\tdestTokens = bTokens;\r\n\t\t\t\t\t\tdestOffset = 0;\r\n\t\t\t\t\t\tdestFirstDeltaLine = tokenDeltaLine;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tdestTokens[destOffset++] = tokenDeltaLine - destFirstDeltaLine;\r\n\t\t\tdestTokens[destOffset++] = tokenStartCharacter;\r\n\t\t\tdestTokens[destOffset++] = tokenEndCharacter;\r\n\t\t\tdestTokens[destOffset++] = tokenMetadata;\r\n\t\t}\r\n\r\n\t\treturn [new SparseEncodedTokens(new Uint32Array(aTokens)), new SparseEncodedTokens(new Uint32Array(bTokens)), destFirstDeltaLine];\r\n\t}\r\n\r\n\tpublic acceptDeleteRange(horizontalShiftForFirstLineTokens: number, startDeltaLine: number, startCharacter: number, endDeltaLine: number, endCharacter: number): void {\r\n\t\t// This is a bit complex, here are the cases I used to think about this:\r\n\t\t//\r\n\t\t// 1. The token starts before the deletion range\r\n\t\t// 1a. The token is completely before the deletion range\r\n\t\t// -----------\r\n\t\t// xxxxxxxxxxx\r\n\t\t// 1b. The token starts before, the deletion range ends after the token\r\n\t\t// -----------\r\n\t\t// xxxxxxxxxxx\r\n\t\t// 1c. The token starts before, the deletion range ends precisely with the token\r\n\t\t// ---------------\r\n\t\t// xxxxxxxx\r\n\t\t// 1d. The token starts before, the deletion range is inside the token\r\n\t\t// ---------------\r\n\t\t// xxxxx\r\n\t\t//\r\n\t\t// 2. The token starts at the same position with the deletion range\r\n\t\t// 2a. The token starts at the same position, and ends inside the deletion range\r\n\t\t// -------\r\n\t\t// xxxxxxxxxxx\r\n\t\t// 2b. The token starts at the same position, and ends at the same position as the deletion range\r\n\t\t// ----------\r\n\t\t// xxxxxxxxxx\r\n\t\t// 2c. The token starts at the same position, and ends after the deletion range\r\n\t\t// -------------\r\n\t\t// xxxxxxx\r\n\t\t//\r\n\t\t// 3. The token starts inside the deletion range\r\n\t\t// 3a. The token is inside the deletion range\r\n\t\t// -------\r\n\t\t// xxxxxxxxxxxxx\r\n\t\t// 3b. The token starts inside the deletion range, and ends at the same position as the deletion range\r\n\t\t// ----------\r\n\t\t// xxxxxxxxxxxxx\r\n\t\t// 3c. The token starts inside the deletion range, and ends after the deletion range\r\n\t\t// ------------\r\n\t\t// xxxxxxxxxxx\r\n\t\t//\r\n\t\t// 4. The token starts after the deletion range\r\n\t\t// -----------\r\n\t\t// xxxxxxxx\r\n\t\t//\r\n\t\tconst tokens = this._tokens;\r\n\t\tconst tokenCount = this._tokenCount;\r\n\t\tconst deletedLineCount = (endDeltaLine - startDeltaLine);\r\n\t\tlet newTokenCount = 0;\r\n\t\tlet hasDeletedTokens = false;\r\n\t\tfor (let i = 0; i < tokenCount; i++) {\r\n\t\t\tconst srcOffset = 4 * i;\r\n\t\t\tlet tokenDeltaLine = tokens[srcOffset];\r\n\t\t\tlet tokenStartCharacter = tokens[srcOffset + 1];\r\n\t\t\tlet tokenEndCharacter = tokens[srcOffset + 2];\r\n\t\t\tconst tokenMetadata = tokens[srcOffset + 3];\r\n\r\n\t\t\tif (tokenDeltaLine < startDeltaLine || (tokenDeltaLine === startDeltaLine && tokenEndCharacter <= startCharacter)) {\r\n\t\t\t\t// 1a. The token is completely before the deletion range\r\n\t\t\t\t// => nothing to do\r\n\t\t\t\tnewTokenCount++;\r\n\t\t\t\tcontinue;\r\n\t\t\t} else if (tokenDeltaLine === startDeltaLine && tokenStartCharacter < startCharacter) {\r\n\t\t\t\t// 1b, 1c, 1d\r\n\t\t\t\t// => the token survives, but it needs to shrink\r\n\t\t\t\tif (tokenDeltaLine === endDeltaLine && tokenEndCharacter > endCharacter) {\r\n\t\t\t\t\t// 1d. The token starts before, the deletion range is inside the token\r\n\t\t\t\t\t// => the token shrinks by the deletion character count\r\n\t\t\t\t\ttokenEndCharacter -= (endCharacter - startCharacter);\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// 1b. The token starts before, the deletion range ends after the token\r\n\t\t\t\t\t// 1c. The token starts before, the deletion range ends precisely with the token\r\n\t\t\t\t\t// => the token shrinks its ending to the deletion start\r\n\t\t\t\t\ttokenEndCharacter = startCharacter;\r\n\t\t\t\t}\r\n\t\t\t} else if (tokenDeltaLine === startDeltaLine && tokenStartCharacter === startCharacter) {\r\n\t\t\t\t// 2a, 2b, 2c\r\n\t\t\t\tif (tokenDeltaLine === endDeltaLine && tokenEndCharacter > endCharacter) {\r\n\t\t\t\t\t// 2c. The token starts at the same position, and ends after the deletion range\r\n\t\t\t\t\t// => the token shrinks by the deletion character count\r\n\t\t\t\t\ttokenEndCharacter -= (endCharacter - startCharacter);\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// 2a. The token starts at the same position, and ends inside the deletion range\r\n\t\t\t\t\t// 2b. The token starts at the same position, and ends at the same position as the deletion range\r\n\t\t\t\t\t// => the token is deleted\r\n\t\t\t\t\thasDeletedTokens = true;\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t} else if (tokenDeltaLine < endDeltaLine || (tokenDeltaLine === endDeltaLine && tokenStartCharacter < endCharacter)) {\r\n\t\t\t\t// 3a, 3b, 3c\r\n\t\t\t\tif (tokenDeltaLine === endDeltaLine && tokenEndCharacter > endCharacter) {\r\n\t\t\t\t\t// 3c. The token starts inside the deletion range, and ends after the deletion range\r\n\t\t\t\t\t// => the token moves left and shrinks\r\n\t\t\t\t\tif (tokenDeltaLine === startDeltaLine) {\r\n\t\t\t\t\t\t// the deletion started on the same line as the token\r\n\t\t\t\t\t\t// => the token moves left and shrinks\r\n\t\t\t\t\t\ttokenStartCharacter = startCharacter;\r\n\t\t\t\t\t\ttokenEndCharacter = tokenStartCharacter + (tokenEndCharacter - endCharacter);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t// the deletion started on a line above the token\r\n\t\t\t\t\t\t// => the token moves to the beginning of the line\r\n\t\t\t\t\t\ttokenStartCharacter = 0;\r\n\t\t\t\t\t\ttokenEndCharacter = tokenStartCharacter + (tokenEndCharacter - endCharacter);\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// 3a. The token is inside the deletion range\r\n\t\t\t\t\t// 3b. The token starts inside the deletion range, and ends at the same position as the deletion range\r\n\t\t\t\t\t// => the token is deleted\r\n\t\t\t\t\thasDeletedTokens = true;\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t} else if (tokenDeltaLine > endDeltaLine) {\r\n\t\t\t\t// 4. (partial) The token starts after the deletion range, on a line below...\r\n\t\t\t\tif (deletedLineCount === 0 && !hasDeletedTokens) {\r\n\t\t\t\t\t// early stop, there is no need to walk all the tokens and do nothing...\r\n\t\t\t\t\tnewTokenCount = tokenCount;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\ttokenDeltaLine -= deletedLineCount;\r\n\t\t\t} else if (tokenDeltaLine === endDeltaLine && tokenStartCharacter >= endCharacter) {\r\n\t\t\t\t// 4. (continued) The token starts after the deletion range, on the last line where a deletion occurs\r\n\t\t\t\tif (horizontalShiftForFirstLineTokens && tokenDeltaLine === 0) {\r\n\t\t\t\t\ttokenStartCharacter += horizontalShiftForFirstLineTokens;\r\n\t\t\t\t\ttokenEndCharacter += horizontalShiftForFirstLineTokens;\r\n\t\t\t\t}\r\n\t\t\t\ttokenDeltaLine -= deletedLineCount;\r\n\t\t\t\ttokenStartCharacter -= (endCharacter - startCharacter);\r\n\t\t\t\ttokenEndCharacter -= (endCharacter - startCharacter);\r\n\t\t\t} else {\r\n\t\t\t\tthrow new Error(`Not possible!`);\r\n\t\t\t}\r\n\r\n\t\t\tconst destOffset = 4 * newTokenCount;\r\n\t\t\ttokens[destOffset] = tokenDeltaLine;\r\n\t\t\ttokens[destOffset + 1] = tokenStartCharacter;\r\n\t\t\ttokens[destOffset + 2] = tokenEndCharacter;\r\n\t\t\ttokens[destOffset + 3] = tokenMetadata;\r\n\t\t\tnewTokenCount++;\r\n\t\t}\r\n\r\n\t\tthis._tokenCount = newTokenCount;\r\n\t}\r\n\r\n\tpublic acceptInsertText(deltaLine: number, character: number, eolCount: number, firstLineLength: number, lastLineLength: number, firstCharCode: number): void {\r\n\t\t// Here are the cases I used to think about this:\r\n\t\t//\r\n\t\t// 1. The token is completely before the insertion point\r\n\t\t// ----------- |\r\n\t\t// 2. The token ends precisely at the insertion point\r\n\t\t// -----------|\r\n\t\t// 3. The token contains the insertion point\r\n\t\t// -----|------\r\n\t\t// 4. The token starts precisely at the insertion point\r\n\t\t// |-----------\r\n\t\t// 5. The token is completely after the insertion point\r\n\t\t// | -----------\r\n\t\t//\r\n\t\tconst isInsertingPreciselyOneWordCharacter = (\r\n\t\t\teolCount === 0\r\n\t\t\t&& firstLineLength === 1\r\n\t\t\t&& (\r\n\t\t\t\t(firstCharCode >= CharCode.Digit0 && firstCharCode <= CharCode.Digit9)\r\n\t\t\t\t|| (firstCharCode >= CharCode.A && firstCharCode <= CharCode.Z)\r\n\t\t\t\t|| (firstCharCode >= CharCode.a && firstCharCode <= CharCode.z)\r\n\t\t\t)\r\n\t\t);\r\n\t\tconst tokens = this._tokens;\r\n\t\tconst tokenCount = this._tokenCount;\r\n\t\tfor (let i = 0; i < tokenCount; i++) {\r\n\t\t\tconst offset = 4 * i;\r\n\t\t\tlet tokenDeltaLine = tokens[offset];\r\n\t\t\tlet tokenStartCharacter = tokens[offset + 1];\r\n\t\t\tlet tokenEndCharacter = tokens[offset + 2];\r\n\r\n\t\t\tif (tokenDeltaLine < deltaLine || (tokenDeltaLine === deltaLine && tokenEndCharacter < character)) {\r\n\t\t\t\t// 1. The token is completely before the insertion point\r\n\t\t\t\t// => nothing to do\r\n\t\t\t\tcontinue;\r\n\t\t\t} else if (tokenDeltaLine === deltaLine && tokenEndCharacter === character) {\r\n\t\t\t\t// 2. The token ends precisely at the insertion point\r\n\t\t\t\t// => expand the end character only if inserting precisely one character that is a word character\r\n\t\t\t\tif (isInsertingPreciselyOneWordCharacter) {\r\n\t\t\t\t\ttokenEndCharacter += 1;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t} else if (tokenDeltaLine === deltaLine && tokenStartCharacter < character && character < tokenEndCharacter) {\r\n\t\t\t\t// 3. The token contains the insertion point\r\n\t\t\t\tif (eolCount === 0) {\r\n\t\t\t\t\t// => just expand the end character\r\n\t\t\t\t\ttokenEndCharacter += firstLineLength;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// => cut off the token\r\n\t\t\t\t\ttokenEndCharacter = character;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\t// 4. or 5.\r\n\t\t\t\tif (tokenDeltaLine === deltaLine && tokenStartCharacter === character) {\r\n\t\t\t\t\t// 4. The token starts precisely at the insertion point\r\n\t\t\t\t\t// => grow the token (by keeping its start constant) only if inserting precisely one character that is a word character\r\n\t\t\t\t\t// => otherwise behave as in case 5.\r\n\t\t\t\t\tif (isInsertingPreciselyOneWordCharacter) {\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\t// => the token must move and keep its size constant\r\n\t\t\t\tif (tokenDeltaLine === deltaLine) {\r\n\t\t\t\t\ttokenDeltaLine += eolCount;\r\n\t\t\t\t\t// this token is on the line where the insertion is taking place\r\n\t\t\t\t\tif (eolCount === 0) {\r\n\t\t\t\t\t\ttokenStartCharacter += firstLineLength;\r\n\t\t\t\t\t\ttokenEndCharacter += firstLineLength;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tconst tokenLength = tokenEndCharacter - tokenStartCharacter;\r\n\t\t\t\t\t\ttokenStartCharacter = lastLineLength + (tokenStartCharacter - character);\r\n\t\t\t\t\t\ttokenEndCharacter = tokenStartCharacter + tokenLength;\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\ttokenDeltaLine += eolCount;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\ttokens[offset] = tokenDeltaLine;\r\n\t\t\ttokens[offset + 1] = tokenStartCharacter;\r\n\t\t\ttokens[offset + 2] = tokenEndCharacter;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class LineTokens2 {\r\n\r\n\tprivate readonly _tokens: Uint32Array;\r\n\r\n\tconstructor(tokens: Uint32Array) {\r\n\t\tthis._tokens = tokens;\r\n\t}\r\n\r\n\tpublic getCount(): number {\r\n\t\treturn this._tokens.length / 4;\r\n\t}\r\n\r\n\tpublic getStartCharacter(tokenIndex: number): number {\r\n\t\treturn this._tokens[4 * tokenIndex + 1];\r\n\t}\r\n\r\n\tpublic getEndCharacter(tokenIndex: number): number {\r\n\t\treturn this._tokens[4 * tokenIndex + 2];\r\n\t}\r\n\r\n\tpublic getMetadata(tokenIndex: number): number {\r\n\t\treturn this._tokens[4 * tokenIndex + 3];\r\n\t}\r\n}\r\n\r\nexport class MultilineTokens2 {\r\n\r\n\tpublic startLineNumber: number;\r\n\tpublic endLineNumber: number;\r\n\tpublic tokens: SparseEncodedTokens;\r\n\r\n\tconstructor(startLineNumber: number, tokens: SparseEncodedTokens) {\r\n\t\tthis.startLineNumber = startLineNumber;\r\n\t\tthis.tokens = tokens;\r\n\t\tthis.endLineNumber = this.startLineNumber + this.tokens.getMaxDeltaLine();\r\n\t}\r\n\r\n\tpublic toString(): string {\r\n\t\treturn this.tokens.toString(this.startLineNumber);\r\n\t}\r\n\r\n\tprivate _updateEndLineNumber(): void {\r\n\t\tthis.endLineNumber = this.startLineNumber + this.tokens.getMaxDeltaLine();\r\n\t}\r\n\r\n\tpublic isEmpty(): boolean {\r\n\t\treturn this.tokens.isEmpty();\r\n\t}\r\n\r\n\tpublic getLineTokens(lineNumber: number): LineTokens2 | null {\r\n\t\tif (this.startLineNumber <= lineNumber && lineNumber <= this.endLineNumber) {\r\n\t\t\treturn this.tokens.getLineTokens(lineNumber - this.startLineNumber);\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic getRange(): Range | null {\r\n\t\tconst deltaRange = this.tokens.getRange();\r\n\t\tif (!deltaRange) {\r\n\t\t\treturn deltaRange;\r\n\t\t}\r\n\t\treturn new Range(this.startLineNumber + deltaRange.startLineNumber, deltaRange.startColumn, this.startLineNumber + deltaRange.endLineNumber, deltaRange.endColumn);\r\n\t}\r\n\r\n\tpublic removeTokens(range: Range): void {\r\n\t\tconst startLineIndex = range.startLineNumber - this.startLineNumber;\r\n\t\tconst endLineIndex = range.endLineNumber - this.startLineNumber;\r\n\r\n\t\tthis.startLineNumber += this.tokens.removeTokens(startLineIndex, range.startColumn - 1, endLineIndex, range.endColumn - 1);\r\n\t\tthis._updateEndLineNumber();\r\n\t}\r\n\r\n\tpublic split(range: Range): [MultilineTokens2, MultilineTokens2] {\r\n\t\t// split tokens to two:\r\n\t\t// a) all the tokens before `range`\r\n\t\t// b) all the tokens after `range`\r\n\t\tconst startLineIndex = range.startLineNumber - this.startLineNumber;\r\n\t\tconst endLineIndex = range.endLineNumber - this.startLineNumber;\r\n\r\n\t\tconst [a, b, bDeltaLine] = this.tokens.split(startLineIndex, range.startColumn - 1, endLineIndex, range.endColumn - 1);\r\n\t\treturn [new MultilineTokens2(this.startLineNumber, a), new MultilineTokens2(this.startLineNumber + bDeltaLine, b)];\r\n\t}\r\n\r\n\tpublic applyEdit(range: IRange, text: string): void {\r\n\t\tconst [eolCount, firstLineLength, lastLineLength] = countEOL(text);\r\n\t\tthis.acceptEdit(range, eolCount, firstLineLength, lastLineLength, text.length > 0 ? text.charCodeAt(0) : CharCode.Null);\r\n\t}\r\n\r\n\tpublic acceptEdit(range: IRange, eolCount: number, firstLineLength: number, lastLineLength: number, firstCharCode: number): void {\r\n\t\tthis._acceptDeleteRange(range);\r\n\t\tthis._acceptInsertText(new Position(range.startLineNumber, range.startColumn), eolCount, firstLineLength, lastLineLength, firstCharCode);\r\n\t\tthis._updateEndLineNumber();\r\n\t}\r\n\r\n\tprivate _acceptDeleteRange(range: IRange): void {\r\n\t\tif (range.startLineNumber === range.endLineNumber && range.startColumn === range.endColumn) {\r\n\t\t\t// Nothing to delete\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst firstLineIndex = range.startLineNumber - this.startLineNumber;\r\n\t\tconst lastLineIndex = range.endLineNumber - this.startLineNumber;\r\n\r\n\t\tif (lastLineIndex < 0) {\r\n\t\t\t// this deletion occurs entirely before this block, so we only need to adjust line numbers\r\n\t\t\tconst deletedLinesCount = lastLineIndex - firstLineIndex;\r\n\t\t\tthis.startLineNumber -= deletedLinesCount;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst tokenMaxDeltaLine = this.tokens.getMaxDeltaLine();\r\n\r\n\t\tif (firstLineIndex >= tokenMaxDeltaLine + 1) {\r\n\t\t\t// this deletion occurs entirely after this block, so there is nothing to do\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (firstLineIndex < 0 && lastLineIndex >= tokenMaxDeltaLine + 1) {\r\n\t\t\t// this deletion completely encompasses this block\r\n\t\t\tthis.startLineNumber = 0;\r\n\t\t\tthis.tokens.clear();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (firstLineIndex < 0) {\r\n\t\t\tconst deletedBefore = -firstLineIndex;\r\n\t\t\tthis.startLineNumber -= deletedBefore;\r\n\r\n\t\t\tthis.tokens.acceptDeleteRange(range.startColumn - 1, 0, 0, lastLineIndex, range.endColumn - 1);\r\n\t\t} else {\r\n\t\t\tthis.tokens.acceptDeleteRange(0, firstLineIndex, range.startColumn - 1, lastLineIndex, range.endColumn - 1);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _acceptInsertText(position: Position, eolCount: number, firstLineLength: number, lastLineLength: number, firstCharCode: number): void {\r\n\r\n\t\tif (eolCount === 0 && firstLineLength === 0) {\r\n\t\t\t// Nothing to insert\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst lineIndex = position.lineNumber - this.startLineNumber;\r\n\r\n\t\tif (lineIndex < 0) {\r\n\t\t\t// this insertion occurs before this block, so we only need to adjust line numbers\r\n\t\t\tthis.startLineNumber += eolCount;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst tokenMaxDeltaLine = this.tokens.getMaxDeltaLine();\r\n\r\n\t\tif (lineIndex >= tokenMaxDeltaLine + 1) {\r\n\t\t\t// this insertion occurs after this block, so there is nothing to do\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.tokens.acceptInsertText(lineIndex, position.column - 1, eolCount, firstLineLength, lastLineLength, firstCharCode);\r\n\t}\r\n}\r\n\r\nexport class MultilineTokens {\r\n\r\n\tpublic startLineNumber: number;\r\n\tpublic tokens: (Uint32Array | ArrayBuffer | null)[];\r\n\r\n\tconstructor(startLineNumber: number, tokens: Uint32Array[]) {\r\n\t\tthis.startLineNumber = startLineNumber;\r\n\t\tthis.tokens = tokens;\r\n\t}\r\n}\r\n\r\nfunction toUint32Array(arr: Uint32Array | ArrayBuffer): Uint32Array {\r\n\tif (arr instanceof Uint32Array) {\r\n\t\treturn arr;\r\n\t} else {\r\n\t\treturn new Uint32Array(arr);\r\n\t}\r\n}\r\n\r\nexport class TokensStore2 {\r\n\r\n\tprivate _pieces: MultilineTokens2[];\r\n\tprivate _isComplete: boolean;\r\n\r\n\tconstructor() {\r\n\t\tthis._pieces = [];\r\n\t\tthis._isComplete = false;\r\n\t}\r\n\r\n\tpublic flush(): void {\r\n\t\tthis._pieces = [];\r\n\t\tthis._isComplete = false;\r\n\t}\r\n\r\n\tpublic isEmpty(): boolean {\r\n\t\treturn (this._pieces.length === 0);\r\n\t}\r\n\r\n\tpublic set(pieces: MultilineTokens2[] | null, isComplete: boolean): void {\r\n\t\tthis._pieces = pieces || [];\r\n\t\tthis._isComplete = isComplete;\r\n\t}\r\n\r\n\tpublic setPartial(_range: Range, pieces: MultilineTokens2[]): Range {\r\n\t\t// console.log(`setPartial ${_range} ${pieces.map(p => p.toString()).join(', ')}`);\r\n\r\n\t\tlet range = _range;\r\n\t\tif (pieces.length > 0) {\r\n\t\t\tconst _firstRange = pieces[0].getRange();\r\n\t\t\tconst _lastRange = pieces[pieces.length - 1].getRange();\r\n\t\t\tif (!_firstRange || !_lastRange) {\r\n\t\t\t\treturn _range;\r\n\t\t\t}\r\n\t\t\trange = _range.plusRange(_firstRange).plusRange(_lastRange);\r\n\t\t}\r\n\r\n\t\tlet insertPosition: { index: number; } | null = null;\r\n\t\tfor (let i = 0, len = this._pieces.length; i < len; i++) {\r\n\t\t\tconst piece = this._pieces[i];\r\n\t\t\tif (piece.endLineNumber < range.startLineNumber) {\r\n\t\t\t\t// this piece is before the range\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (piece.startLineNumber > range.endLineNumber) {\r\n\t\t\t\t// this piece is after the range, so mark the spot before this piece\r\n\t\t\t\t// as a good insertion position and stop looping\r\n\t\t\t\tinsertPosition = insertPosition || { index: i };\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\t// this piece might intersect with the range\r\n\t\t\tpiece.removeTokens(range);\r\n\r\n\t\t\tif (piece.isEmpty()) {\r\n\t\t\t\t// remove the piece if it became empty\r\n\t\t\t\tthis._pieces.splice(i, 1);\r\n\t\t\t\ti--;\r\n\t\t\t\tlen--;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (piece.endLineNumber < range.startLineNumber) {\r\n\t\t\t\t// after removal, this piece is before the range\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (piece.startLineNumber > range.endLineNumber) {\r\n\t\t\t\t// after removal, this piece is after the range\r\n\t\t\t\tinsertPosition = insertPosition || { index: i };\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\t// after removal, this piece contains the range\r\n\t\t\tconst [a, b] = piece.split(range);\r\n\t\t\tif (a.isEmpty()) {\r\n\t\t\t\t// this piece is actually after the range\r\n\t\t\t\tinsertPosition = insertPosition || { index: i };\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (b.isEmpty()) {\r\n\t\t\t\t// this piece is actually before the range\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tthis._pieces.splice(i, 1, a, b);\r\n\t\t\ti++;\r\n\t\t\tlen++;\r\n\r\n\t\t\tinsertPosition = insertPosition || { index: i };\r\n\t\t}\r\n\r\n\t\tinsertPosition = insertPosition || { index: this._pieces.length };\r\n\r\n\t\tif (pieces.length > 0) {\r\n\t\t\tthis._pieces = arrays.arrayInsert(this._pieces, insertPosition.index, pieces);\r\n\t\t}\r\n\r\n\t\t// console.log(`I HAVE ${this._pieces.length} pieces`);\r\n\t\t// console.log(`${this._pieces.map(p => p.toString()).join('\\n')}`);\r\n\r\n\t\treturn range;\r\n\t}\r\n\r\n\tpublic isComplete(): boolean {\r\n\t\treturn this._isComplete;\r\n\t}\r\n\r\n\tpublic addSemanticTokens(lineNumber: number, aTokens: LineTokens): LineTokens {\r\n\t\tconst pieces = this._pieces;\r\n\r\n\t\tif (pieces.length === 0) {\r\n\t\t\treturn aTokens;\r\n\t\t}\r\n\r\n\t\tconst pieceIndex = TokensStore2._findFirstPieceWithLine(pieces, lineNumber);\r\n\t\tconst bTokens = pieces[pieceIndex].getLineTokens(lineNumber);\r\n\r\n\t\tif (!bTokens) {\r\n\t\t\treturn aTokens;\r\n\t\t}\r\n\r\n\t\tconst aLen = aTokens.getCount();\r\n\t\tconst bLen = bTokens.getCount();\r\n\r\n\t\tlet aIndex = 0;\r\n\t\tlet result: number[] = [], resultLen = 0;\r\n\t\tlet lastEndOffset = 0;\r\n\r\n\t\tconst emitToken = (endOffset: number, metadata: number) => {\r\n\t\t\tif (endOffset === lastEndOffset) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tlastEndOffset = endOffset;\r\n\t\t\tresult[resultLen++] = endOffset;\r\n\t\t\tresult[resultLen++] = metadata;\r\n\t\t};\r\n\r\n\t\tfor (let bIndex = 0; bIndex < bLen; bIndex++) {\r\n\t\t\tconst bStartCharacter = bTokens.getStartCharacter(bIndex);\r\n\t\t\tconst bEndCharacter = bTokens.getEndCharacter(bIndex);\r\n\t\t\tconst bMetadata = bTokens.getMetadata(bIndex);\r\n\r\n\t\t\tconst bMask = (\r\n\t\t\t\t((bMetadata & MetadataConsts.SEMANTIC_USE_ITALIC) ? MetadataConsts.ITALIC_MASK : 0)\r\n\t\t\t\t| ((bMetadata & MetadataConsts.SEMANTIC_USE_BOLD) ? MetadataConsts.BOLD_MASK : 0)\r\n\t\t\t\t| ((bMetadata & MetadataConsts.SEMANTIC_USE_UNDERLINE) ? MetadataConsts.UNDERLINE_MASK : 0)\r\n\t\t\t\t| ((bMetadata & MetadataConsts.SEMANTIC_USE_FOREGROUND) ? MetadataConsts.FOREGROUND_MASK : 0)\r\n\t\t\t\t| ((bMetadata & MetadataConsts.SEMANTIC_USE_BACKGROUND) ? MetadataConsts.BACKGROUND_MASK : 0)\r\n\t\t\t) >>> 0;\r\n\t\t\tconst aMask = (~bMask) >>> 0;\r\n\r\n\t\t\t// push any token from `a` that is before `b`\r\n\t\t\twhile (aIndex < aLen && aTokens.getEndOffset(aIndex) <= bStartCharacter) {\r\n\t\t\t\temitToken(aTokens.getEndOffset(aIndex), aTokens.getMetadata(aIndex));\r\n\t\t\t\taIndex++;\r\n\t\t\t}\r\n\r\n\t\t\t// push the token from `a` if it intersects the token from `b`\r\n\t\t\tif (aIndex < aLen && aTokens.getStartOffset(aIndex) < bStartCharacter) {\r\n\t\t\t\temitToken(bStartCharacter, aTokens.getMetadata(aIndex));\r\n\t\t\t}\r\n\r\n\t\t\t// skip any tokens from `a` that are contained inside `b`\r\n\t\t\twhile (aIndex < aLen && aTokens.getEndOffset(aIndex) < bEndCharacter) {\r\n\t\t\t\temitToken(aTokens.getEndOffset(aIndex), (aTokens.getMetadata(aIndex) & aMask) | (bMetadata & bMask));\r\n\t\t\t\taIndex++;\r\n\t\t\t}\r\n\r\n\t\t\tif (aIndex < aLen) {\r\n\t\t\t\temitToken(bEndCharacter, (aTokens.getMetadata(aIndex) & aMask) | (bMetadata & bMask));\r\n\t\t\t\tif (aTokens.getEndOffset(aIndex) === bEndCharacter) {\r\n\t\t\t\t\t// `a` ends exactly at the same spot as `b`!\r\n\t\t\t\t\taIndex++;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tconst aMergeIndex = Math.min(Math.max(0, aIndex - 1), aLen - 1);\r\n\r\n\t\t\t\t// push the token from `b`\r\n\t\t\t\temitToken(bEndCharacter, (aTokens.getMetadata(aMergeIndex) & aMask) | (bMetadata & bMask));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// push the remaining tokens from `a`\r\n\t\twhile (aIndex < aLen) {\r\n\t\t\temitToken(aTokens.getEndOffset(aIndex), aTokens.getMetadata(aIndex));\r\n\t\t\taIndex++;\r\n\t\t}\r\n\r\n\t\treturn new LineTokens(new Uint32Array(result), aTokens.getLineContent());\r\n\t}\r\n\r\n\tprivate static _findFirstPieceWithLine(pieces: MultilineTokens2[], lineNumber: number): number {\r\n\t\tlet low = 0;\r\n\t\tlet high = pieces.length - 1;\r\n\r\n\t\twhile (low < high) {\r\n\t\t\tlet mid = low + Math.floor((high - low) / 2);\r\n\r\n\t\t\tif (pieces[mid].endLineNumber < lineNumber) {\r\n\t\t\t\tlow = mid + 1;\r\n\t\t\t} else if (pieces[mid].startLineNumber > lineNumber) {\r\n\t\t\t\thigh = mid - 1;\r\n\t\t\t} else {\r\n\t\t\t\twhile (mid > low && pieces[mid - 1].startLineNumber <= lineNumber && lineNumber <= pieces[mid - 1].endLineNumber) {\r\n\t\t\t\t\tmid--;\r\n\t\t\t\t}\r\n\t\t\t\treturn mid;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn low;\r\n\t}\r\n\r\n\t//#region Editing\r\n\r\n\tpublic acceptEdit(range: IRange, eolCount: number, firstLineLength: number, lastLineLength: number, firstCharCode: number): void {\r\n\t\tfor (const piece of this._pieces) {\r\n\t\t\tpiece.acceptEdit(range, eolCount, firstLineLength, lastLineLength, firstCharCode);\r\n\t\t}\r\n\t}\r\n\r\n\t//#endregion\r\n}\r\n\r\nexport class TokensStore {\r\n\tprivate _lineTokens: (Uint32Array | ArrayBuffer | null)[];\r\n\tprivate _len: number;\r\n\r\n\tconstructor() {\r\n\t\tthis._lineTokens = [];\r\n\t\tthis._len = 0;\r\n\t}\r\n\r\n\tpublic flush(): void {\r\n\t\tthis._lineTokens = [];\r\n\t\tthis._len = 0;\r\n\t}\r\n\r\n\tpublic getTokens(topLevelLanguageId: LanguageId, lineIndex: number, lineText: string): LineTokens {\r\n\t\tlet rawLineTokens: Uint32Array | ArrayBuffer | null = null;\r\n\t\tif (lineIndex < this._len) {\r\n\t\t\trawLineTokens = this._lineTokens[lineIndex];\r\n\t\t}\r\n\r\n\t\tif (rawLineTokens !== null && rawLineTokens !== EMPTY_LINE_TOKENS) {\r\n\t\t\treturn new LineTokens(toUint32Array(rawLineTokens), lineText);\r\n\t\t}\r\n\r\n\t\tlet lineTokens = new Uint32Array(2);\r\n\t\tlineTokens[0] = lineText.length;\r\n\t\tlineTokens[1] = getDefaultMetadata(topLevelLanguageId);\r\n\t\treturn new LineTokens(lineTokens, lineText);\r\n\t}\r\n\r\n\tprivate static _massageTokens(topLevelLanguageId: LanguageId, lineTextLength: number, _tokens: Uint32Array | ArrayBuffer | null): Uint32Array | ArrayBuffer {\r\n\r\n\t\tconst tokens = _tokens ? toUint32Array(_tokens) : null;\r\n\r\n\t\tif (lineTextLength === 0) {\r\n\t\t\tlet hasDifferentLanguageId = false;\r\n\t\t\tif (tokens && tokens.length > 1) {\r\n\t\t\t\thasDifferentLanguageId = (TokenMetadata.getLanguageId(tokens[1]) !== topLevelLanguageId);\r\n\t\t\t}\r\n\r\n\t\t\tif (!hasDifferentLanguageId) {\r\n\t\t\t\treturn EMPTY_LINE_TOKENS;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!tokens || tokens.length === 0) {\r\n\t\t\tconst tokens = new Uint32Array(2);\r\n\t\t\ttokens[0] = lineTextLength;\r\n\t\t\ttokens[1] = getDefaultMetadata(topLevelLanguageId);\r\n\t\t\treturn tokens.buffer;\r\n\t\t}\r\n\r\n\t\t// Ensure the last token covers the end of the text\r\n\t\ttokens[tokens.length - 2] = lineTextLength;\r\n\r\n\t\tif (tokens.byteOffset === 0 && tokens.byteLength === tokens.buffer.byteLength) {\r\n\t\t\t// Store directly the ArrayBuffer pointer to save an object\r\n\t\t\treturn tokens.buffer;\r\n\t\t}\r\n\t\treturn tokens;\r\n\t}\r\n\r\n\tprivate _ensureLine(lineIndex: number): void {\r\n\t\twhile (lineIndex >= this._len) {\r\n\t\t\tthis._lineTokens[this._len] = null;\r\n\t\t\tthis._len++;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _deleteLines(start: number, deleteCount: number): void {\r\n\t\tif (deleteCount === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (start + deleteCount > this._len) {\r\n\t\t\tdeleteCount = this._len - start;\r\n\t\t}\r\n\t\tthis._lineTokens.splice(start, deleteCount);\r\n\t\tthis._len -= deleteCount;\r\n\t}\r\n\r\n\tprivate _insertLines(insertIndex: number, insertCount: number): void {\r\n\t\tif (insertCount === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tlet lineTokens: (Uint32Array | ArrayBuffer | null)[] = [];\r\n\t\tfor (let i = 0; i < insertCount; i++) {\r\n\t\t\tlineTokens[i] = null;\r\n\t\t}\r\n\t\tthis._lineTokens = arrays.arrayInsert(this._lineTokens, insertIndex, lineTokens);\r\n\t\tthis._len += insertCount;\r\n\t}\r\n\r\n\tpublic setTokens(topLevelLanguageId: LanguageId, lineIndex: number, lineTextLength: number, _tokens: Uint32Array | ArrayBuffer | null, checkEquality: boolean): boolean {\r\n\t\tconst tokens = TokensStore._massageTokens(topLevelLanguageId, lineTextLength, _tokens);\r\n\t\tthis._ensureLine(lineIndex);\r\n\t\tconst oldTokens = this._lineTokens[lineIndex];\r\n\t\tthis._lineTokens[lineIndex] = tokens;\r\n\r\n\t\tif (checkEquality) {\r\n\t\t\treturn !TokensStore._equals(oldTokens, tokens);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tprivate static _equals(_a: Uint32Array | ArrayBuffer | null, _b: Uint32Array | ArrayBuffer | null) {\r\n\t\tif (!_a || !_b) {\r\n\t\t\treturn !_a && !_b;\r\n\t\t}\r\n\r\n\t\tconst a = toUint32Array(_a);\r\n\t\tconst b = toUint32Array(_b);\r\n\r\n\t\tif (a.length !== b.length) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tfor (let i = 0, len = a.length; i < len; i++) {\r\n\t\t\tif (a[i] !== b[i]) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\t//#region Editing\r\n\r\n\tpublic acceptEdit(range: IRange, eolCount: number, firstLineLength: number): void {\r\n\t\tthis._acceptDeleteRange(range);\r\n\t\tthis._acceptInsertText(new Position(range.startLineNumber, range.startColumn), eolCount, firstLineLength);\r\n\t}\r\n\r\n\tprivate _acceptDeleteRange(range: IRange): void {\r\n\r\n\t\tconst firstLineIndex = range.startLineNumber - 1;\r\n\t\tif (firstLineIndex >= this._len) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (range.startLineNumber === range.endLineNumber) {\r\n\t\t\tif (range.startColumn === range.endColumn) {\r\n\t\t\t\t// Nothing to delete\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tthis._lineTokens[firstLineIndex] = TokensStore._delete(this._lineTokens[firstLineIndex], range.startColumn - 1, range.endColumn - 1);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._lineTokens[firstLineIndex] = TokensStore._deleteEnding(this._lineTokens[firstLineIndex], range.startColumn - 1);\r\n\r\n\t\tconst lastLineIndex = range.endLineNumber - 1;\r\n\t\tlet lastLineTokens: Uint32Array | ArrayBuffer | null = null;\r\n\t\tif (lastLineIndex < this._len) {\r\n\t\t\tlastLineTokens = TokensStore._deleteBeginning(this._lineTokens[lastLineIndex], range.endColumn - 1);\r\n\t\t}\r\n\r\n\t\t// Take remaining text on last line and append it to remaining text on first line\r\n\t\tthis._lineTokens[firstLineIndex] = TokensStore._append(this._lineTokens[firstLineIndex], lastLineTokens);\r\n\r\n\t\t// Delete middle lines\r\n\t\tthis._deleteLines(range.startLineNumber, range.endLineNumber - range.startLineNumber);\r\n\t}\r\n\r\n\tprivate _acceptInsertText(position: Position, eolCount: number, firstLineLength: number): void {\r\n\r\n\t\tif (eolCount === 0 && firstLineLength === 0) {\r\n\t\t\t// Nothing to insert\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst lineIndex = position.lineNumber - 1;\r\n\t\tif (lineIndex >= this._len) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (eolCount === 0) {\r\n\t\t\t// Inserting text on one line\r\n\t\t\tthis._lineTokens[lineIndex] = TokensStore._insert(this._lineTokens[lineIndex], position.column - 1, firstLineLength);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._lineTokens[lineIndex] = TokensStore._deleteEnding(this._lineTokens[lineIndex], position.column - 1);\r\n\t\tthis._lineTokens[lineIndex] = TokensStore._insert(this._lineTokens[lineIndex], position.column - 1, firstLineLength);\r\n\r\n\t\tthis._insertLines(position.lineNumber, eolCount);\r\n\t}\r\n\r\n\tpublic static _deleteBeginning(lineTokens: Uint32Array | ArrayBuffer | null, toChIndex: number): Uint32Array | ArrayBuffer | null {\r\n\t\tif (lineTokens === null || lineTokens === EMPTY_LINE_TOKENS) {\r\n\t\t\treturn lineTokens;\r\n\t\t}\r\n\t\treturn TokensStore._delete(lineTokens, 0, toChIndex);\r\n\t}\r\n\r\n\tpublic static _deleteEnding(lineTokens: Uint32Array | ArrayBuffer | null, fromChIndex: number): Uint32Array | ArrayBuffer | null {\r\n\t\tif (lineTokens === null || lineTokens === EMPTY_LINE_TOKENS) {\r\n\t\t\treturn lineTokens;\r\n\t\t}\r\n\r\n\t\tconst tokens = toUint32Array(lineTokens);\r\n\t\tconst lineTextLength = tokens[tokens.length - 2];\r\n\t\treturn TokensStore._delete(lineTokens, fromChIndex, lineTextLength);\r\n\t}\r\n\r\n\tpublic static _delete(lineTokens: Uint32Array | ArrayBuffer | null, fromChIndex: number, toChIndex: number): Uint32Array | ArrayBuffer | null {\r\n\t\tif (lineTokens === null || lineTokens === EMPTY_LINE_TOKENS || fromChIndex === toChIndex) {\r\n\t\t\treturn lineTokens;\r\n\t\t}\r\n\r\n\t\tconst tokens = toUint32Array(lineTokens);\r\n\t\tconst tokensCount = (tokens.length >>> 1);\r\n\r\n\t\t// special case: deleting everything\r\n\t\tif (fromChIndex === 0 && tokens[tokens.length - 2] === toChIndex) {\r\n\t\t\treturn EMPTY_LINE_TOKENS;\r\n\t\t}\r\n\r\n\t\tconst fromTokenIndex = LineTokens.findIndexInTokensArray(tokens, fromChIndex);\r\n\t\tconst fromTokenStartOffset = (fromTokenIndex > 0 ? tokens[(fromTokenIndex - 1) << 1] : 0);\r\n\t\tconst fromTokenEndOffset = tokens[fromTokenIndex << 1];\r\n\r\n\t\tif (toChIndex < fromTokenEndOffset) {\r\n\t\t\t// the delete range is inside a single token\r\n\t\t\tconst delta = (toChIndex - fromChIndex);\r\n\t\t\tfor (let i = fromTokenIndex; i < tokensCount; i++) {\r\n\t\t\t\ttokens[i << 1] -= delta;\r\n\t\t\t}\r\n\t\t\treturn lineTokens;\r\n\t\t}\r\n\r\n\t\tlet dest: number;\r\n\t\tlet lastEnd: number;\r\n\t\tif (fromTokenStartOffset !== fromChIndex) {\r\n\t\t\ttokens[fromTokenIndex << 1] = fromChIndex;\r\n\t\t\tdest = ((fromTokenIndex + 1) << 1);\r\n\t\t\tlastEnd = fromChIndex;\r\n\t\t} else {\r\n\t\t\tdest = (fromTokenIndex << 1);\r\n\t\t\tlastEnd = fromTokenStartOffset;\r\n\t\t}\r\n\r\n\t\tconst delta = (toChIndex - fromChIndex);\r\n\t\tfor (let tokenIndex = fromTokenIndex + 1; tokenIndex < tokensCount; tokenIndex++) {\r\n\t\t\tconst tokenEndOffset = tokens[tokenIndex << 1] - delta;\r\n\t\t\tif (tokenEndOffset > lastEnd) {\r\n\t\t\t\ttokens[dest++] = tokenEndOffset;\r\n\t\t\t\ttokens[dest++] = tokens[(tokenIndex << 1) + 1];\r\n\t\t\t\tlastEnd = tokenEndOffset;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (dest === tokens.length) {\r\n\t\t\t// nothing to trim\r\n\t\t\treturn lineTokens;\r\n\t\t}\r\n\r\n\t\tlet tmp = new Uint32Array(dest);\r\n\t\ttmp.set(tokens.subarray(0, dest), 0);\r\n\t\treturn tmp.buffer;\r\n\t}\r\n\r\n\tpublic static _append(lineTokens: Uint32Array | ArrayBuffer | null, _otherTokens: Uint32Array | ArrayBuffer | null): Uint32Array | ArrayBuffer | null {\r\n\t\tif (_otherTokens === EMPTY_LINE_TOKENS) {\r\n\t\t\treturn lineTokens;\r\n\t\t}\r\n\t\tif (lineTokens === EMPTY_LINE_TOKENS) {\r\n\t\t\treturn _otherTokens;\r\n\t\t}\r\n\t\tif (lineTokens === null) {\r\n\t\t\treturn lineTokens;\r\n\t\t}\r\n\t\tif (_otherTokens === null) {\r\n\t\t\t// cannot determine combined line length...\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tconst myTokens = toUint32Array(lineTokens);\r\n\t\tconst otherTokens = toUint32Array(_otherTokens);\r\n\t\tconst otherTokensCount = (otherTokens.length >>> 1);\r\n\r\n\t\tlet result = new Uint32Array(myTokens.length + otherTokens.length);\r\n\t\tresult.set(myTokens, 0);\r\n\t\tlet dest = myTokens.length;\r\n\t\tconst delta = myTokens[myTokens.length - 2];\r\n\t\tfor (let i = 0; i < otherTokensCount; i++) {\r\n\t\t\tresult[dest++] = otherTokens[(i << 1)] + delta;\r\n\t\t\tresult[dest++] = otherTokens[(i << 1) + 1];\r\n\t\t}\r\n\t\treturn result.buffer;\r\n\t}\r\n\r\n\tpublic static _insert(lineTokens: Uint32Array | ArrayBuffer | null, chIndex: number, textLength: number): Uint32Array | ArrayBuffer | null {\r\n\t\tif (lineTokens === null || lineTokens === EMPTY_LINE_TOKENS) {\r\n\t\t\t// nothing to do\r\n\t\t\treturn lineTokens;\r\n\t\t}\r\n\r\n\t\tconst tokens = toUint32Array(lineTokens);\r\n\t\tconst tokensCount = (tokens.length >>> 1);\r\n\r\n\t\tlet fromTokenIndex = LineTokens.findIndexInTokensArray(tokens, chIndex);\r\n\t\tif (fromTokenIndex > 0) {\r\n\t\t\tconst fromTokenStartOffset = tokens[(fromTokenIndex - 1) << 1];\r\n\t\t\tif (fromTokenStartOffset === chIndex) {\r\n\t\t\t\tfromTokenIndex--;\r\n\t\t\t}\r\n\t\t}\r\n\t\tfor (let tokenIndex = fromTokenIndex; tokenIndex < tokensCount; tokenIndex++) {\r\n\t\t\ttokens[tokenIndex << 1] += textLength;\r\n\t\t}\r\n\t\treturn lineTokens;\r\n\t}\r\n\r\n\t//#endregion\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Emitter } from 'vs/base/common/event';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { ApplyEditsResult, EndOfLinePreference, FindMatch, IInternalModelContentChange, ISingleEditOperationIdentifier, ITextBuffer, ITextSnapshot, ValidAnnotatedEditOperation, IValidEditOperation } from 'vs/editor/common/model';\r\nimport { PieceTreeBase, StringBuffer } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase';\r\nimport { SearchData } from 'vs/editor/common/model/textModelSearch';\r\nimport { countEOL, StringEOL } from 'vs/editor/common/model/tokensStore';\r\nimport { TextChange } from 'vs/editor/common/model/textChange';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\n\r\nexport interface IValidatedEditOperation {\r\n\tsortIndex: number;\r\n\tidentifier: ISingleEditOperationIdentifier | null;\r\n\trange: Range;\r\n\trangeOffset: number;\r\n\trangeLength: number;\r\n\ttext: string;\r\n\teolCount: number;\r\n\tfirstLineLength: number;\r\n\tlastLineLength: number;\r\n\tforceMoveMarkers: boolean;\r\n\tisAutoWhitespaceEdit: boolean;\r\n}\r\n\r\nexport interface IReverseSingleEditOperation extends IValidEditOperation {\r\n\tsortIndex: number;\r\n}\r\n\r\nexport class PieceTreeTextBuffer extends Disposable implements ITextBuffer {\r\n\tprivate _pieceTree: PieceTreeBase;\r\n\tprivate readonly _BOM: string;\r\n\tprivate _mightContainRTL: boolean;\r\n\tprivate _mightContainUnusualLineTerminators: boolean;\r\n\tprivate _mightContainNonBasicASCII: boolean;\r\n\r\n\tprivate readonly _onDidChangeContent: Emitter = this._register(new Emitter());\r\n\r\n\tconstructor(chunks: StringBuffer[], BOM: string, eol: '\\r\\n' | '\\n', containsRTL: boolean, containsUnusualLineTerminators: boolean, isBasicASCII: boolean, eolNormalized: boolean) {\r\n\t\tsuper();\r\n\t\tthis._BOM = BOM;\r\n\t\tthis._mightContainNonBasicASCII = !isBasicASCII;\r\n\t\tthis._mightContainRTL = containsRTL;\r\n\t\tthis._mightContainUnusualLineTerminators = containsUnusualLineTerminators;\r\n\t\tthis._pieceTree = new PieceTreeBase(chunks, eol, eolNormalized);\r\n\t}\r\n\tpublic mightContainRTL(): boolean {\r\n\t\treturn this._mightContainRTL;\r\n\t}\r\n\tpublic mightContainUnusualLineTerminators(): boolean {\r\n\t\treturn this._mightContainUnusualLineTerminators;\r\n\t}\r\n\tpublic resetMightContainUnusualLineTerminators(): void {\r\n\t\tthis._mightContainUnusualLineTerminators = false;\r\n\t}\r\n\tpublic mightContainNonBasicASCII(): boolean {\r\n\t\treturn this._mightContainNonBasicASCII;\r\n\t}\r\n\tpublic getBOM(): string {\r\n\t\treturn this._BOM;\r\n\t}\r\n\tpublic getEOL(): '\\r\\n' | '\\n' {\r\n\t\treturn this._pieceTree.getEOL();\r\n\t}\r\n\r\n\tpublic createSnapshot(preserveBOM: boolean): ITextSnapshot {\r\n\t\treturn this._pieceTree.createSnapshot(preserveBOM ? this._BOM : '');\r\n\t}\r\n\r\n\tpublic getOffsetAt(lineNumber: number, column: number): number {\r\n\t\treturn this._pieceTree.getOffsetAt(lineNumber, column);\r\n\t}\r\n\r\n\tpublic getPositionAt(offset: number): Position {\r\n\t\treturn this._pieceTree.getPositionAt(offset);\r\n\t}\r\n\r\n\tpublic getRangeAt(start: number, length: number): Range {\r\n\t\tlet end = start + length;\r\n\t\tconst startPosition = this.getPositionAt(start);\r\n\t\tconst endPosition = this.getPositionAt(end);\r\n\t\treturn new Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column);\r\n\t}\r\n\r\n\tpublic getValueInRange(range: Range, eol: EndOfLinePreference = EndOfLinePreference.TextDefined): string {\r\n\t\tif (range.isEmpty()) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\r\n\t\tconst lineEnding = this._getEndOfLine(eol);\r\n\t\treturn this._pieceTree.getValueInRange(range, lineEnding);\r\n\t}\r\n\r\n\tpublic getValueLengthInRange(range: Range, eol: EndOfLinePreference = EndOfLinePreference.TextDefined): number {\r\n\t\tif (range.isEmpty()) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tif (range.startLineNumber === range.endLineNumber) {\r\n\t\t\treturn (range.endColumn - range.startColumn);\r\n\t\t}\r\n\r\n\t\tlet startOffset = this.getOffsetAt(range.startLineNumber, range.startColumn);\r\n\t\tlet endOffset = this.getOffsetAt(range.endLineNumber, range.endColumn);\r\n\t\treturn endOffset - startOffset;\r\n\t}\r\n\r\n\tpublic getCharacterCountInRange(range: Range, eol: EndOfLinePreference = EndOfLinePreference.TextDefined): number {\r\n\t\tif (this._mightContainNonBasicASCII) {\r\n\t\t\t// we must count by iterating\r\n\r\n\t\t\tlet result = 0;\r\n\r\n\t\t\tconst fromLineNumber = range.startLineNumber;\r\n\t\t\tconst toLineNumber = range.endLineNumber;\r\n\t\t\tfor (let lineNumber = fromLineNumber; lineNumber <= toLineNumber; lineNumber++) {\r\n\t\t\t\tconst lineContent = this.getLineContent(lineNumber);\r\n\t\t\t\tconst fromOffset = (lineNumber === fromLineNumber ? range.startColumn - 1 : 0);\r\n\t\t\t\tconst toOffset = (lineNumber === toLineNumber ? range.endColumn - 1 : lineContent.length);\r\n\r\n\t\t\t\tfor (let offset = fromOffset; offset < toOffset; offset++) {\r\n\t\t\t\t\tif (strings.isHighSurrogate(lineContent.charCodeAt(offset))) {\r\n\t\t\t\t\t\tresult = result + 1;\r\n\t\t\t\t\t\toffset = offset + 1;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tresult = result + 1;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tresult += this._getEndOfLine(eol).length * (toLineNumber - fromLineNumber);\r\n\r\n\t\t\treturn result;\r\n\t\t}\r\n\r\n\t\treturn this.getValueLengthInRange(range, eol);\r\n\t}\r\n\r\n\tpublic getLength(): number {\r\n\t\treturn this._pieceTree.getLength();\r\n\t}\r\n\r\n\tpublic getLineCount(): number {\r\n\t\treturn this._pieceTree.getLineCount();\r\n\t}\r\n\r\n\tpublic getLinesContent(): string[] {\r\n\t\treturn this._pieceTree.getLinesContent();\r\n\t}\r\n\r\n\tpublic getLineContent(lineNumber: number): string {\r\n\t\treturn this._pieceTree.getLineContent(lineNumber);\r\n\t}\r\n\r\n\tpublic getLineCharCode(lineNumber: number, index: number): number {\r\n\t\treturn this._pieceTree.getLineCharCode(lineNumber, index);\r\n\t}\r\n\r\n\tpublic getLineLength(lineNumber: number): number {\r\n\t\treturn this._pieceTree.getLineLength(lineNumber);\r\n\t}\r\n\r\n\tpublic getLineFirstNonWhitespaceColumn(lineNumber: number): number {\r\n\t\tconst result = strings.firstNonWhitespaceIndex(this.getLineContent(lineNumber));\r\n\t\tif (result === -1) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t\treturn result + 1;\r\n\t}\r\n\r\n\tpublic getLineLastNonWhitespaceColumn(lineNumber: number): number {\r\n\t\tconst result = strings.lastNonWhitespaceIndex(this.getLineContent(lineNumber));\r\n\t\tif (result === -1) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t\treturn result + 2;\r\n\t}\r\n\r\n\tprivate _getEndOfLine(eol: EndOfLinePreference): string {\r\n\t\tswitch (eol) {\r\n\t\t\tcase EndOfLinePreference.LF:\r\n\t\t\t\treturn '\\n';\r\n\t\t\tcase EndOfLinePreference.CRLF:\r\n\t\t\t\treturn '\\r\\n';\r\n\t\t\tcase EndOfLinePreference.TextDefined:\r\n\t\t\t\treturn this.getEOL();\r\n\t\t\tdefault:\r\n\t\t\t\tthrow new Error('Unknown EOL preference');\r\n\t\t}\r\n\t}\r\n\r\n\tpublic setEOL(newEOL: '\\r\\n' | '\\n'): void {\r\n\t\tthis._pieceTree.setEOL(newEOL);\r\n\t}\r\n\r\n\tpublic applyEdits(rawOperations: ValidAnnotatedEditOperation[], recordTrimAutoWhitespace: boolean, computeUndoEdits: boolean): ApplyEditsResult {\r\n\t\tlet mightContainRTL = this._mightContainRTL;\r\n\t\tlet mightContainUnusualLineTerminators = this._mightContainUnusualLineTerminators;\r\n\t\tlet mightContainNonBasicASCII = this._mightContainNonBasicASCII;\r\n\t\tlet canReduceOperations = true;\r\n\r\n\t\tlet operations: IValidatedEditOperation[] = [];\r\n\t\tfor (let i = 0; i < rawOperations.length; i++) {\r\n\t\t\tlet op = rawOperations[i];\r\n\t\t\tif (canReduceOperations && op._isTracked) {\r\n\t\t\t\tcanReduceOperations = false;\r\n\t\t\t}\r\n\t\t\tlet validatedRange = op.range;\r\n\t\t\tif (op.text) {\r\n\t\t\t\tlet textMightContainNonBasicASCII = true;\r\n\t\t\t\tif (!mightContainNonBasicASCII) {\r\n\t\t\t\t\ttextMightContainNonBasicASCII = !strings.isBasicASCII(op.text);\r\n\t\t\t\t\tmightContainNonBasicASCII = textMightContainNonBasicASCII;\r\n\t\t\t\t}\r\n\t\t\t\tif (!mightContainRTL && textMightContainNonBasicASCII) {\r\n\t\t\t\t\t// check if the new inserted text contains RTL\r\n\t\t\t\t\tmightContainRTL = strings.containsRTL(op.text);\r\n\t\t\t\t}\r\n\t\t\t\tif (!mightContainUnusualLineTerminators && textMightContainNonBasicASCII) {\r\n\t\t\t\t\t// check if the new inserted text contains unusual line terminators\r\n\t\t\t\t\tmightContainUnusualLineTerminators = strings.containsUnusualLineTerminators(op.text);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tlet validText = '';\r\n\t\t\tlet eolCount = 0;\r\n\t\t\tlet firstLineLength = 0;\r\n\t\t\tlet lastLineLength = 0;\r\n\t\t\tif (op.text) {\r\n\t\t\t\tlet strEOL: StringEOL;\r\n\t\t\t\t[eolCount, firstLineLength, lastLineLength, strEOL] = countEOL(op.text);\r\n\r\n\t\t\t\tconst bufferEOL = this.getEOL();\r\n\t\t\t\tconst expectedStrEOL = (bufferEOL === '\\r\\n' ? StringEOL.CRLF : StringEOL.LF);\r\n\t\t\t\tif (strEOL === StringEOL.Unknown || strEOL === expectedStrEOL) {\r\n\t\t\t\t\tvalidText = op.text;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tvalidText = op.text.replace(/\\r\\n|\\r|\\n/g, bufferEOL);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\toperations[i] = {\r\n\t\t\t\tsortIndex: i,\r\n\t\t\t\tidentifier: op.identifier || null,\r\n\t\t\t\trange: validatedRange,\r\n\t\t\t\trangeOffset: this.getOffsetAt(validatedRange.startLineNumber, validatedRange.startColumn),\r\n\t\t\t\trangeLength: this.getValueLengthInRange(validatedRange),\r\n\t\t\t\ttext: validText,\r\n\t\t\t\teolCount: eolCount,\r\n\t\t\t\tfirstLineLength: firstLineLength,\r\n\t\t\t\tlastLineLength: lastLineLength,\r\n\t\t\t\tforceMoveMarkers: Boolean(op.forceMoveMarkers),\r\n\t\t\t\tisAutoWhitespaceEdit: op.isAutoWhitespaceEdit || false\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\t// Sort operations ascending\r\n\t\toperations.sort(PieceTreeTextBuffer._sortOpsAscending);\r\n\r\n\t\tlet hasTouchingRanges = false;\r\n\t\tfor (let i = 0, count = operations.length - 1; i < count; i++) {\r\n\t\t\tlet rangeEnd = operations[i].range.getEndPosition();\r\n\t\t\tlet nextRangeStart = operations[i + 1].range.getStartPosition();\r\n\r\n\t\t\tif (nextRangeStart.isBeforeOrEqual(rangeEnd)) {\r\n\t\t\t\tif (nextRangeStart.isBefore(rangeEnd)) {\r\n\t\t\t\t\t// overlapping ranges\r\n\t\t\t\t\tthrow new Error('Overlapping ranges are not allowed!');\r\n\t\t\t\t}\r\n\t\t\t\thasTouchingRanges = true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (canReduceOperations) {\r\n\t\t\toperations = this._reduceOperations(operations);\r\n\t\t}\r\n\r\n\t\t// Delta encode operations\r\n\t\tlet reverseRanges = (computeUndoEdits || recordTrimAutoWhitespace ? PieceTreeTextBuffer._getInverseEditRanges(operations) : []);\r\n\t\tlet newTrimAutoWhitespaceCandidates: { lineNumber: number, oldContent: string }[] = [];\r\n\t\tif (recordTrimAutoWhitespace) {\r\n\t\t\tfor (let i = 0; i < operations.length; i++) {\r\n\t\t\t\tlet op = operations[i];\r\n\t\t\t\tlet reverseRange = reverseRanges[i];\r\n\r\n\t\t\t\tif (op.isAutoWhitespaceEdit && op.range.isEmpty()) {\r\n\t\t\t\t\t// Record already the future line numbers that might be auto whitespace removal candidates on next edit\r\n\t\t\t\t\tfor (let lineNumber = reverseRange.startLineNumber; lineNumber <= reverseRange.endLineNumber; lineNumber++) {\r\n\t\t\t\t\t\tlet currentLineContent = '';\r\n\t\t\t\t\t\tif (lineNumber === reverseRange.startLineNumber) {\r\n\t\t\t\t\t\t\tcurrentLineContent = this.getLineContent(op.range.startLineNumber);\r\n\t\t\t\t\t\t\tif (strings.firstNonWhitespaceIndex(currentLineContent) !== -1) {\r\n\t\t\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tnewTrimAutoWhitespaceCandidates.push({ lineNumber: lineNumber, oldContent: currentLineContent });\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet reverseOperations: IReverseSingleEditOperation[] | null = null;\r\n\t\tif (computeUndoEdits) {\r\n\r\n\t\t\tlet reverseRangeDeltaOffset = 0;\r\n\t\t\treverseOperations = [];\r\n\t\t\tfor (let i = 0; i < operations.length; i++) {\r\n\t\t\t\tconst op = operations[i];\r\n\t\t\t\tconst reverseRange = reverseRanges[i];\r\n\t\t\t\tconst bufferText = this.getValueInRange(op.range);\r\n\t\t\t\tconst reverseRangeOffset = op.rangeOffset + reverseRangeDeltaOffset;\r\n\t\t\t\treverseRangeDeltaOffset += (op.text.length - bufferText.length);\r\n\r\n\t\t\t\treverseOperations[i] = {\r\n\t\t\t\t\tsortIndex: op.sortIndex,\r\n\t\t\t\t\tidentifier: op.identifier,\r\n\t\t\t\t\trange: reverseRange,\r\n\t\t\t\t\ttext: bufferText,\r\n\t\t\t\t\ttextChange: new TextChange(op.rangeOffset, bufferText, reverseRangeOffset, op.text)\r\n\t\t\t\t};\r\n\t\t\t}\r\n\r\n\t\t\t// Can only sort reverse operations when the order is not significant\r\n\t\t\tif (!hasTouchingRanges) {\r\n\t\t\t\treverseOperations.sort((a, b) => a.sortIndex - b.sortIndex);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\r\n\t\tthis._mightContainRTL = mightContainRTL;\r\n\t\tthis._mightContainUnusualLineTerminators = mightContainUnusualLineTerminators;\r\n\t\tthis._mightContainNonBasicASCII = mightContainNonBasicASCII;\r\n\r\n\t\tconst contentChanges = this._doApplyEdits(operations);\r\n\r\n\t\tlet trimAutoWhitespaceLineNumbers: number[] | null = null;\r\n\t\tif (recordTrimAutoWhitespace && newTrimAutoWhitespaceCandidates.length > 0) {\r\n\t\t\t// sort line numbers auto whitespace removal candidates for next edit descending\r\n\t\t\tnewTrimAutoWhitespaceCandidates.sort((a, b) => b.lineNumber - a.lineNumber);\r\n\r\n\t\t\ttrimAutoWhitespaceLineNumbers = [];\r\n\t\t\tfor (let i = 0, len = newTrimAutoWhitespaceCandidates.length; i < len; i++) {\r\n\t\t\t\tlet lineNumber = newTrimAutoWhitespaceCandidates[i].lineNumber;\r\n\t\t\t\tif (i > 0 && newTrimAutoWhitespaceCandidates[i - 1].lineNumber === lineNumber) {\r\n\t\t\t\t\t// Do not have the same line number twice\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tlet prevContent = newTrimAutoWhitespaceCandidates[i].oldContent;\r\n\t\t\t\tlet lineContent = this.getLineContent(lineNumber);\r\n\r\n\t\t\t\tif (lineContent.length === 0 || lineContent === prevContent || strings.firstNonWhitespaceIndex(lineContent) !== -1) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\ttrimAutoWhitespaceLineNumbers.push(lineNumber);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._onDidChangeContent.fire();\r\n\r\n\t\treturn new ApplyEditsResult(\r\n\t\t\treverseOperations,\r\n\t\t\tcontentChanges,\r\n\t\t\ttrimAutoWhitespaceLineNumbers\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * Transform operations such that they represent the same logic edit,\r\n\t * but that they also do not cause OOM crashes.\r\n\t */\r\n\tprivate _reduceOperations(operations: IValidatedEditOperation[]): IValidatedEditOperation[] {\r\n\t\tif (operations.length < 1000) {\r\n\t\t\t// We know from empirical testing that a thousand edits work fine regardless of their shape.\r\n\t\t\treturn operations;\r\n\t\t}\r\n\r\n\t\t// At one point, due to how events are emitted and how each operation is handled,\r\n\t\t// some operations can trigger a high amount of temporary string allocations,\r\n\t\t// that will immediately get edited again.\r\n\t\t// e.g. a formatter inserting ridiculous ammounts of \\n on a model with a single line\r\n\t\t// Therefore, the strategy is to collapse all the operations into a huge single edit operation\r\n\t\treturn [this._toSingleEditOperation(operations)];\r\n\t}\r\n\r\n\t_toSingleEditOperation(operations: IValidatedEditOperation[]): IValidatedEditOperation {\r\n\t\tlet forceMoveMarkers = false;\r\n\t\tconst firstEditRange = operations[0].range;\r\n\t\tconst lastEditRange = operations[operations.length - 1].range;\r\n\t\tconst entireEditRange = new Range(firstEditRange.startLineNumber, firstEditRange.startColumn, lastEditRange.endLineNumber, lastEditRange.endColumn);\r\n\t\tlet lastEndLineNumber = firstEditRange.startLineNumber;\r\n\t\tlet lastEndColumn = firstEditRange.startColumn;\r\n\t\tconst result: string[] = [];\r\n\r\n\t\tfor (let i = 0, len = operations.length; i < len; i++) {\r\n\t\t\tconst operation = operations[i];\r\n\t\t\tconst range = operation.range;\r\n\r\n\t\t\tforceMoveMarkers = forceMoveMarkers || operation.forceMoveMarkers;\r\n\r\n\t\t\t// (1) -- Push old text\r\n\t\t\tresult.push(this.getValueInRange(new Range(lastEndLineNumber, lastEndColumn, range.startLineNumber, range.startColumn)));\r\n\r\n\t\t\t// (2) -- Push new text\r\n\t\t\tif (operation.text.length > 0) {\r\n\t\t\t\tresult.push(operation.text);\r\n\t\t\t}\r\n\r\n\t\t\tlastEndLineNumber = range.endLineNumber;\r\n\t\t\tlastEndColumn = range.endColumn;\r\n\t\t}\r\n\r\n\t\tconst text = result.join('');\r\n\t\tconst [eolCount, firstLineLength, lastLineLength] = countEOL(text);\r\n\r\n\t\treturn {\r\n\t\t\tsortIndex: 0,\r\n\t\t\tidentifier: operations[0].identifier,\r\n\t\t\trange: entireEditRange,\r\n\t\t\trangeOffset: this.getOffsetAt(entireEditRange.startLineNumber, entireEditRange.startColumn),\r\n\t\t\trangeLength: this.getValueLengthInRange(entireEditRange, EndOfLinePreference.TextDefined),\r\n\t\t\ttext: text,\r\n\t\t\teolCount: eolCount,\r\n\t\t\tfirstLineLength: firstLineLength,\r\n\t\t\tlastLineLength: lastLineLength,\r\n\t\t\tforceMoveMarkers: forceMoveMarkers,\r\n\t\t\tisAutoWhitespaceEdit: false\r\n\t\t};\r\n\t}\r\n\r\n\tprivate _doApplyEdits(operations: IValidatedEditOperation[]): IInternalModelContentChange[] {\r\n\t\toperations.sort(PieceTreeTextBuffer._sortOpsDescending);\r\n\r\n\t\tlet contentChanges: IInternalModelContentChange[] = [];\r\n\r\n\t\t// operations are from bottom to top\r\n\t\tfor (let i = 0; i < operations.length; i++) {\r\n\t\t\tlet op = operations[i];\r\n\r\n\t\t\tconst startLineNumber = op.range.startLineNumber;\r\n\t\t\tconst startColumn = op.range.startColumn;\r\n\t\t\tconst endLineNumber = op.range.endLineNumber;\r\n\t\t\tconst endColumn = op.range.endColumn;\r\n\r\n\t\t\tif (startLineNumber === endLineNumber && startColumn === endColumn && op.text.length === 0) {\r\n\t\t\t\t// no-op\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (op.text) {\r\n\t\t\t\t// replacement\r\n\t\t\t\tthis._pieceTree.delete(op.rangeOffset, op.rangeLength);\r\n\t\t\t\tthis._pieceTree.insert(op.rangeOffset, op.text, true);\r\n\r\n\t\t\t} else {\r\n\t\t\t\t// deletion\r\n\t\t\t\tthis._pieceTree.delete(op.rangeOffset, op.rangeLength);\r\n\t\t\t}\r\n\r\n\t\t\tconst contentChangeRange = new Range(startLineNumber, startColumn, endLineNumber, endColumn);\r\n\t\t\tcontentChanges.push({\r\n\t\t\t\trange: contentChangeRange,\r\n\t\t\t\trangeLength: op.rangeLength,\r\n\t\t\t\ttext: op.text,\r\n\t\t\t\trangeOffset: op.rangeOffset,\r\n\t\t\t\tforceMoveMarkers: op.forceMoveMarkers\r\n\t\t\t});\r\n\t\t}\r\n\t\treturn contentChanges;\r\n\t}\r\n\r\n\tfindMatchesLineByLine(searchRange: Range, searchData: SearchData, captureMatches: boolean, limitResultCount: number): FindMatch[] {\r\n\t\treturn this._pieceTree.findMatchesLineByLine(searchRange, searchData, captureMatches, limitResultCount);\r\n\t}\r\n\r\n\t/**\r\n\t * Assumes `operations` are validated and sorted ascending\r\n\t */\r\n\tpublic static _getInverseEditRanges(operations: IValidatedEditOperation[]): Range[] {\r\n\t\tlet result: Range[] = [];\r\n\r\n\t\tlet prevOpEndLineNumber: number = 0;\r\n\t\tlet prevOpEndColumn: number = 0;\r\n\t\tlet prevOp: IValidatedEditOperation | null = null;\r\n\t\tfor (let i = 0, len = operations.length; i < len; i++) {\r\n\t\t\tlet op = operations[i];\r\n\r\n\t\t\tlet startLineNumber: number;\r\n\t\t\tlet startColumn: number;\r\n\r\n\t\t\tif (prevOp) {\r\n\t\t\t\tif (prevOp.range.endLineNumber === op.range.startLineNumber) {\r\n\t\t\t\t\tstartLineNumber = prevOpEndLineNumber;\r\n\t\t\t\t\tstartColumn = prevOpEndColumn + (op.range.startColumn - prevOp.range.endColumn);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tstartLineNumber = prevOpEndLineNumber + (op.range.startLineNumber - prevOp.range.endLineNumber);\r\n\t\t\t\t\tstartColumn = op.range.startColumn;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tstartLineNumber = op.range.startLineNumber;\r\n\t\t\t\tstartColumn = op.range.startColumn;\r\n\t\t\t}\r\n\r\n\t\t\tlet resultRange: Range;\r\n\r\n\t\t\tif (op.text.length > 0) {\r\n\t\t\t\t// the operation inserts something\r\n\t\t\t\tconst lineCount = op.eolCount + 1;\r\n\r\n\t\t\t\tif (lineCount === 1) {\r\n\t\t\t\t\t// single line insert\r\n\t\t\t\t\tresultRange = new Range(startLineNumber, startColumn, startLineNumber, startColumn + op.firstLineLength);\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// multi line insert\r\n\t\t\t\t\tresultRange = new Range(startLineNumber, startColumn, startLineNumber + lineCount - 1, op.lastLineLength + 1);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\t// There is nothing to insert\r\n\t\t\t\tresultRange = new Range(startLineNumber, startColumn, startLineNumber, startColumn);\r\n\t\t\t}\r\n\r\n\t\t\tprevOpEndLineNumber = resultRange.endLineNumber;\r\n\t\t\tprevOpEndColumn = resultRange.endColumn;\r\n\r\n\t\t\tresult.push(resultRange);\r\n\t\t\tprevOp = op;\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _sortOpsAscending(a: IValidatedEditOperation, b: IValidatedEditOperation): number {\r\n\t\tlet r = Range.compareRangesUsingEnds(a.range, b.range);\r\n\t\tif (r === 0) {\r\n\t\t\treturn a.sortIndex - b.sortIndex;\r\n\t\t}\r\n\t\treturn r;\r\n\t}\r\n\r\n\tprivate static _sortOpsDescending(a: IValidatedEditOperation, b: IValidatedEditOperation): number {\r\n\t\tlet r = Range.compareRangesUsingEnds(a.range, b.range);\r\n\t\tif (r === 0) {\r\n\t\t\treturn b.sortIndex - a.sortIndex;\r\n\t\t}\r\n\t\treturn -r;\r\n\t}\r\n\t// #endregion\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { DefaultEndOfLine, ITextBuffer, ITextBufferBuilder, ITextBufferFactory } from 'vs/editor/common/model';\r\nimport { StringBuffer, createLineStarts, createLineStartsFast } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase';\r\nimport { PieceTreeTextBuffer } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer';\r\n\r\nexport class PieceTreeTextBufferFactory implements ITextBufferFactory {\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _chunks: StringBuffer[],\r\n\t\tprivate readonly _bom: string,\r\n\t\tprivate readonly _cr: number,\r\n\t\tprivate readonly _lf: number,\r\n\t\tprivate readonly _crlf: number,\r\n\t\tprivate readonly _containsRTL: boolean,\r\n\t\tprivate readonly _containsUnusualLineTerminators: boolean,\r\n\t\tprivate readonly _isBasicASCII: boolean,\r\n\t\tprivate readonly _normalizeEOL: boolean\r\n\t) { }\r\n\r\n\tprivate _getEOL(defaultEOL: DefaultEndOfLine): '\\r\\n' | '\\n' {\r\n\t\tconst totalEOLCount = this._cr + this._lf + this._crlf;\r\n\t\tconst totalCRCount = this._cr + this._crlf;\r\n\t\tif (totalEOLCount === 0) {\r\n\t\t\t// This is an empty file or a file with precisely one line\r\n\t\t\treturn (defaultEOL === DefaultEndOfLine.LF ? '\\n' : '\\r\\n');\r\n\t\t}\r\n\t\tif (totalCRCount > totalEOLCount / 2) {\r\n\t\t\t// More than half of the file contains \\r\\n ending lines\r\n\t\t\treturn '\\r\\n';\r\n\t\t}\r\n\t\t// At least one line more ends in \\n\r\n\t\treturn '\\n';\r\n\t}\r\n\r\n\tpublic create(defaultEOL: DefaultEndOfLine): { textBuffer: ITextBuffer; disposable: IDisposable; } {\r\n\t\tconst eol = this._getEOL(defaultEOL);\r\n\t\tlet chunks = this._chunks;\r\n\r\n\t\tif (this._normalizeEOL &&\r\n\t\t\t((eol === '\\r\\n' && (this._cr > 0 || this._lf > 0))\r\n\t\t\t\t|| (eol === '\\n' && (this._cr > 0 || this._crlf > 0)))\r\n\t\t) {\r\n\t\t\t// Normalize pieces\r\n\t\t\tfor (let i = 0, len = chunks.length; i < len; i++) {\r\n\t\t\t\tlet str = chunks[i].buffer.replace(/\\r\\n|\\r|\\n/g, eol);\r\n\t\t\t\tlet newLineStart = createLineStartsFast(str);\r\n\t\t\t\tchunks[i] = new StringBuffer(str, newLineStart);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst textBuffer = new PieceTreeTextBuffer(chunks, this._bom, eol, this._containsRTL, this._containsUnusualLineTerminators, this._isBasicASCII, this._normalizeEOL);\r\n\t\treturn { textBuffer: textBuffer, disposable: textBuffer };\r\n\t}\r\n}\r\n\r\nexport class PieceTreeTextBufferBuilder implements ITextBufferBuilder {\r\n\tprivate readonly chunks: StringBuffer[];\r\n\tprivate BOM: string;\r\n\r\n\tprivate _hasPreviousChar: boolean;\r\n\tprivate _previousChar: number;\r\n\tprivate readonly _tmpLineStarts: number[];\r\n\r\n\tprivate cr: number;\r\n\tprivate lf: number;\r\n\tprivate crlf: number;\r\n\tprivate containsRTL: boolean;\r\n\tprivate containsUnusualLineTerminators: boolean;\r\n\tprivate isBasicASCII: boolean;\r\n\r\n\tconstructor() {\r\n\t\tthis.chunks = [];\r\n\t\tthis.BOM = '';\r\n\r\n\t\tthis._hasPreviousChar = false;\r\n\t\tthis._previousChar = 0;\r\n\t\tthis._tmpLineStarts = [];\r\n\r\n\t\tthis.cr = 0;\r\n\t\tthis.lf = 0;\r\n\t\tthis.crlf = 0;\r\n\t\tthis.containsRTL = false;\r\n\t\tthis.containsUnusualLineTerminators = false;\r\n\t\tthis.isBasicASCII = true;\r\n\t}\r\n\r\n\tpublic acceptChunk(chunk: string): void {\r\n\t\tif (chunk.length === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this.chunks.length === 0) {\r\n\t\t\tif (strings.startsWithUTF8BOM(chunk)) {\r\n\t\t\t\tthis.BOM = strings.UTF8_BOM_CHARACTER;\r\n\t\t\t\tchunk = chunk.substr(1);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst lastChar = chunk.charCodeAt(chunk.length - 1);\r\n\t\tif (lastChar === CharCode.CarriageReturn || (lastChar >= 0xD800 && lastChar <= 0xDBFF)) {\r\n\t\t\t// last character is \\r or a high surrogate => keep it back\r\n\t\t\tthis._acceptChunk1(chunk.substr(0, chunk.length - 1), false);\r\n\t\t\tthis._hasPreviousChar = true;\r\n\t\t\tthis._previousChar = lastChar;\r\n\t\t} else {\r\n\t\t\tthis._acceptChunk1(chunk, false);\r\n\t\t\tthis._hasPreviousChar = false;\r\n\t\t\tthis._previousChar = lastChar;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _acceptChunk1(chunk: string, allowEmptyStrings: boolean): void {\r\n\t\tif (!allowEmptyStrings && chunk.length === 0) {\r\n\t\t\t// Nothing to do\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this._hasPreviousChar) {\r\n\t\t\tthis._acceptChunk2(String.fromCharCode(this._previousChar) + chunk);\r\n\t\t} else {\r\n\t\t\tthis._acceptChunk2(chunk);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _acceptChunk2(chunk: string): void {\r\n\t\tconst lineStarts = createLineStarts(this._tmpLineStarts, chunk);\r\n\r\n\t\tthis.chunks.push(new StringBuffer(chunk, lineStarts.lineStarts));\r\n\t\tthis.cr += lineStarts.cr;\r\n\t\tthis.lf += lineStarts.lf;\r\n\t\tthis.crlf += lineStarts.crlf;\r\n\r\n\t\tif (this.isBasicASCII) {\r\n\t\t\tthis.isBasicASCII = lineStarts.isBasicASCII;\r\n\t\t}\r\n\t\tif (!this.isBasicASCII && !this.containsRTL) {\r\n\t\t\t// No need to check if it is basic ASCII\r\n\t\t\tthis.containsRTL = strings.containsRTL(chunk);\r\n\t\t}\r\n\t\tif (!this.isBasicASCII && !this.containsUnusualLineTerminators) {\r\n\t\t\t// No need to check if it is basic ASCII\r\n\t\t\tthis.containsUnusualLineTerminators = strings.containsUnusualLineTerminators(chunk);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic finish(normalizeEOL: boolean = true): PieceTreeTextBufferFactory {\r\n\t\tthis._finish();\r\n\t\treturn new PieceTreeTextBufferFactory(\r\n\t\t\tthis.chunks,\r\n\t\t\tthis.BOM,\r\n\t\t\tthis.cr,\r\n\t\t\tthis.lf,\r\n\t\t\tthis.crlf,\r\n\t\t\tthis.containsRTL,\r\n\t\t\tthis.containsUnusualLineTerminators,\r\n\t\t\tthis.isBasicASCII,\r\n\t\t\tnormalizeEOL\r\n\t\t);\r\n\t}\r\n\r\n\tprivate _finish(): void {\r\n\t\tif (this.chunks.length === 0) {\r\n\t\t\tthis._acceptChunk1('', true);\r\n\t\t}\r\n\r\n\t\tif (this._hasPreviousChar) {\r\n\t\t\tthis._hasPreviousChar = false;\r\n\t\t\t// recreate last chunk\r\n\t\t\tlet lastChunk = this.chunks[this.chunks.length - 1];\r\n\t\t\tlastChunk.buffer += String.fromCharCode(this._previousChar);\r\n\t\t\tlet newLineStarts = createLineStartsFast(lastChunk.buffer);\r\n\t\t\tlastChunk.lineStarts = newLineStarts;\r\n\t\t\tif (this._previousChar === CharCode.CarriageReturn) {\r\n\t\t\t\tthis.cr++;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Token, TokenizationResult, TokenizationResult2 } from 'vs/editor/common/core/token';\r\nimport { ColorId, FontStyle, IState, LanguageId, LanguageIdentifier, MetadataConsts, StandardTokenType } from 'vs/editor/common/modes';\r\n\r\nclass NullStateImpl implements IState {\r\n\r\n\tpublic clone(): IState {\r\n\t\treturn this;\r\n\t}\r\n\r\n\tpublic equals(other: IState): boolean {\r\n\t\treturn (this === other);\r\n\t}\r\n}\r\n\r\nexport const NULL_STATE: IState = new NullStateImpl();\r\n\r\nexport const NULL_MODE_ID = 'vs.editor.nullMode';\r\n\r\nexport const NULL_LANGUAGE_IDENTIFIER = new LanguageIdentifier(NULL_MODE_ID, LanguageId.Null);\r\n\r\nexport function nullTokenize(modeId: string, buffer: string, state: IState, deltaOffset: number): TokenizationResult {\r\n\treturn new TokenizationResult([new Token(deltaOffset, '', modeId)], state);\r\n}\r\n\r\nexport function nullTokenize2(languageId: LanguageId, buffer: string, state: IState | null, deltaOffset: number): TokenizationResult2 {\r\n\tlet tokens = new Uint32Array(2);\r\n\ttokens[0] = deltaOffset;\r\n\ttokens[1] = (\r\n\t\t(languageId << MetadataConsts.LANGUAGEID_OFFSET)\r\n\t\t| (StandardTokenType.Other << MetadataConsts.TOKEN_TYPE_OFFSET)\r\n\t\t| (FontStyle.None << MetadataConsts.FONT_STYLE_OFFSET)\r\n\t\t| (ColorId.DefaultForeground << MetadataConsts.FOREGROUND_OFFSET)\r\n\t\t| (ColorId.DefaultBackground << MetadataConsts.BACKGROUND_OFFSET)\r\n\t) >>> 0;\r\n\r\n\treturn new TokenizationResult2(tokens, state === null ? NULL_STATE : state);\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as arrays from 'vs/base/common/arrays';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport { LineTokens } from 'vs/editor/common/core/lineTokens';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { IRange } from 'vs/editor/common/core/range';\r\nimport { TokenizationResult2 } from 'vs/editor/common/core/token';\r\nimport { RawContentChangedType } from 'vs/editor/common/model/textModelEvents';\r\nimport { IState, ITokenizationSupport, LanguageIdentifier, TokenizationRegistry } from 'vs/editor/common/modes';\r\nimport { nullTokenize2 } from 'vs/editor/common/modes/nullMode';\r\nimport { TextModel } from 'vs/editor/common/model/textModel';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { StopWatch } from 'vs/base/common/stopwatch';\r\nimport { MultilineTokensBuilder, countEOL } from 'vs/editor/common/model/tokensStore';\r\nimport * as platform from 'vs/base/common/platform';\r\n\r\nconst enum Constants {\r\n\tCHEAP_TOKENIZATION_LENGTH_LIMIT = 2048\r\n}\r\n\r\nexport class TokenizationStateStore {\r\n\tprivate _beginState: (IState | null)[];\r\n\tprivate _valid: boolean[];\r\n\tprivate _len: number;\r\n\tprivate _invalidLineStartIndex: number;\r\n\r\n\tconstructor() {\r\n\t\tthis._beginState = [];\r\n\t\tthis._valid = [];\r\n\t\tthis._len = 0;\r\n\t\tthis._invalidLineStartIndex = 0;\r\n\t}\r\n\r\n\tprivate _reset(initialState: IState | null): void {\r\n\t\tthis._beginState = [];\r\n\t\tthis._valid = [];\r\n\t\tthis._len = 0;\r\n\t\tthis._invalidLineStartIndex = 0;\r\n\r\n\t\tif (initialState) {\r\n\t\t\tthis._setBeginState(0, initialState);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic flush(initialState: IState | null): void {\r\n\t\tthis._reset(initialState);\r\n\t}\r\n\r\n\tpublic get invalidLineStartIndex() {\r\n\t\treturn this._invalidLineStartIndex;\r\n\t}\r\n\r\n\tprivate _invalidateLine(lineIndex: number): void {\r\n\t\tif (lineIndex < this._len) {\r\n\t\t\tthis._valid[lineIndex] = false;\r\n\t\t}\r\n\r\n\t\tif (lineIndex < this._invalidLineStartIndex) {\r\n\t\t\tthis._invalidLineStartIndex = lineIndex;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _isValid(lineIndex: number): boolean {\r\n\t\tif (lineIndex < this._len) {\r\n\t\t\treturn this._valid[lineIndex];\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic getBeginState(lineIndex: number): IState | null {\r\n\t\tif (lineIndex < this._len) {\r\n\t\t\treturn this._beginState[lineIndex];\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate _ensureLine(lineIndex: number): void {\r\n\t\twhile (lineIndex >= this._len) {\r\n\t\t\tthis._beginState[this._len] = null;\r\n\t\t\tthis._valid[this._len] = false;\r\n\t\t\tthis._len++;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _deleteLines(start: number, deleteCount: number): void {\r\n\t\tif (deleteCount === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (start + deleteCount > this._len) {\r\n\t\t\tdeleteCount = this._len - start;\r\n\t\t}\r\n\t\tthis._beginState.splice(start, deleteCount);\r\n\t\tthis._valid.splice(start, deleteCount);\r\n\t\tthis._len -= deleteCount;\r\n\t}\r\n\r\n\tprivate _insertLines(insertIndex: number, insertCount: number): void {\r\n\t\tif (insertCount === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tlet beginState: (IState | null)[] = [];\r\n\t\tlet valid: boolean[] = [];\r\n\t\tfor (let i = 0; i < insertCount; i++) {\r\n\t\t\tbeginState[i] = null;\r\n\t\t\tvalid[i] = false;\r\n\t\t}\r\n\t\tthis._beginState = arrays.arrayInsert(this._beginState, insertIndex, beginState);\r\n\t\tthis._valid = arrays.arrayInsert(this._valid, insertIndex, valid);\r\n\t\tthis._len += insertCount;\r\n\t}\r\n\r\n\tprivate _setValid(lineIndex: number, valid: boolean): void {\r\n\t\tthis._ensureLine(lineIndex);\r\n\t\tthis._valid[lineIndex] = valid;\r\n\t}\r\n\r\n\tprivate _setBeginState(lineIndex: number, beginState: IState | null): void {\r\n\t\tthis._ensureLine(lineIndex);\r\n\t\tthis._beginState[lineIndex] = beginState;\r\n\t}\r\n\r\n\tpublic setEndState(linesLength: number, lineIndex: number, endState: IState): void {\r\n\t\tthis._setValid(lineIndex, true);\r\n\t\tthis._invalidLineStartIndex = lineIndex + 1;\r\n\r\n\t\t// Check if this was the last line\r\n\t\tif (lineIndex === linesLength - 1) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// Check if the end state has changed\r\n\t\tconst previousEndState = this.getBeginState(lineIndex + 1);\r\n\t\tif (previousEndState === null || !endState.equals(previousEndState)) {\r\n\t\t\tthis._setBeginState(lineIndex + 1, endState);\r\n\t\t\tthis._invalidateLine(lineIndex + 1);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// Perhaps we can skip tokenizing some lines...\r\n\t\tlet i = lineIndex + 1;\r\n\t\twhile (i < linesLength) {\r\n\t\t\tif (!this._isValid(i)) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\ti++;\r\n\t\t}\r\n\t\tthis._invalidLineStartIndex = i;\r\n\t}\r\n\r\n\tpublic setFakeTokens(lineIndex: number): void {\r\n\t\tthis._setValid(lineIndex, false);\r\n\t}\r\n\r\n\t//#region Editing\r\n\r\n\tpublic applyEdits(range: IRange, eolCount: number): void {\r\n\t\tconst deletingLinesCnt = range.endLineNumber - range.startLineNumber;\r\n\t\tconst insertingLinesCnt = eolCount;\r\n\t\tconst editingLinesCnt = Math.min(deletingLinesCnt, insertingLinesCnt);\r\n\r\n\t\tfor (let j = editingLinesCnt; j >= 0; j--) {\r\n\t\t\tthis._invalidateLine(range.startLineNumber + j - 1);\r\n\t\t}\r\n\r\n\t\tthis._acceptDeleteRange(range);\r\n\t\tthis._acceptInsertText(new Position(range.startLineNumber, range.startColumn), eolCount);\r\n\t}\r\n\r\n\tprivate _acceptDeleteRange(range: IRange): void {\r\n\r\n\t\tconst firstLineIndex = range.startLineNumber - 1;\r\n\t\tif (firstLineIndex >= this._len) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._deleteLines(range.startLineNumber, range.endLineNumber - range.startLineNumber);\r\n\t}\r\n\r\n\tprivate _acceptInsertText(position: Position, eolCount: number): void {\r\n\r\n\t\tconst lineIndex = position.lineNumber - 1;\r\n\t\tif (lineIndex >= this._len) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._insertLines(position.lineNumber, eolCount);\r\n\t}\r\n\r\n\t//#endregion\r\n}\r\n\r\nexport class TextModelTokenization extends Disposable {\r\n\r\n\tprivate readonly _textModel: TextModel;\r\n\tprivate readonly _tokenizationStateStore: TokenizationStateStore;\r\n\tprivate _isDisposed: boolean;\r\n\tprivate _tokenizationSupport: ITokenizationSupport | null;\r\n\r\n\tconstructor(textModel: TextModel) {\r\n\t\tsuper();\r\n\t\tthis._isDisposed = false;\r\n\t\tthis._textModel = textModel;\r\n\t\tthis._tokenizationStateStore = new TokenizationStateStore();\r\n\t\tthis._tokenizationSupport = null;\r\n\r\n\t\tthis._register(TokenizationRegistry.onDidChange((e) => {\r\n\t\t\tconst languageIdentifier = this._textModel.getLanguageIdentifier();\r\n\t\t\tif (e.changedLanguages.indexOf(languageIdentifier.language) === -1) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tthis._resetTokenizationState();\r\n\t\t\tthis._textModel.clearTokens();\r\n\t\t}));\r\n\r\n\t\tthis._register(this._textModel.onDidChangeRawContentFast((e) => {\r\n\t\t\tif (e.containsEvent(RawContentChangedType.Flush)) {\r\n\t\t\t\tthis._resetTokenizationState();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._register(this._textModel.onDidChangeContentFast((e) => {\r\n\t\t\tfor (let i = 0, len = e.changes.length; i < len; i++) {\r\n\t\t\t\tconst change = e.changes[i];\r\n\t\t\t\tconst [eolCount] = countEOL(change.text);\r\n\t\t\t\tthis._tokenizationStateStore.applyEdits(change.range, eolCount);\r\n\t\t\t}\r\n\r\n\t\t\tthis._beginBackgroundTokenization();\r\n\t\t}));\r\n\r\n\t\tthis._register(this._textModel.onDidChangeAttached(() => {\r\n\t\t\tthis._beginBackgroundTokenization();\r\n\t\t}));\r\n\r\n\t\tthis._register(this._textModel.onDidChangeLanguage(() => {\r\n\t\t\tthis._resetTokenizationState();\r\n\t\t\tthis._textModel.clearTokens();\r\n\t\t}));\r\n\r\n\t\tthis._resetTokenizationState();\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._isDisposed = true;\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tprivate _resetTokenizationState(): void {\r\n\t\tconst [tokenizationSupport, initialState] = initializeTokenization(this._textModel);\r\n\t\tthis._tokenizationSupport = tokenizationSupport;\r\n\t\tthis._tokenizationStateStore.flush(initialState);\r\n\t\tthis._beginBackgroundTokenization();\r\n\t}\r\n\r\n\tprivate _beginBackgroundTokenization(): void {\r\n\t\tif (this._textModel.isAttachedToEditor() && this._hasLinesToTokenize()) {\r\n\t\t\tplatform.setImmediate(() => {\r\n\t\t\t\tif (this._isDisposed) {\r\n\t\t\t\t\t// disposed in the meantime\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\tthis._revalidateTokensNow();\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _revalidateTokensNow(toLineNumber: number = this._textModel.getLineCount()): void {\r\n\t\tconst MAX_ALLOWED_TIME = 1;\r\n\t\tconst builder = new MultilineTokensBuilder();\r\n\t\tconst sw = StopWatch.create(false);\r\n\r\n\t\twhile (this._hasLinesToTokenize()) {\r\n\t\t\tif (sw.elapsed() > MAX_ALLOWED_TIME) {\r\n\t\t\t\t// Stop if MAX_ALLOWED_TIME is reached\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tconst tokenizedLineNumber = this._tokenizeOneInvalidLine(builder);\r\n\r\n\t\t\tif (tokenizedLineNumber >= toLineNumber) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._beginBackgroundTokenization();\r\n\t\tthis._textModel.setTokens(builder.tokens);\r\n\t}\r\n\r\n\tpublic tokenizeViewport(startLineNumber: number, endLineNumber: number): void {\r\n\t\tconst builder = new MultilineTokensBuilder();\r\n\t\tthis._tokenizeViewport(builder, startLineNumber, endLineNumber);\r\n\t\tthis._textModel.setTokens(builder.tokens);\r\n\t}\r\n\r\n\tpublic reset(): void {\r\n\t\tthis._resetTokenizationState();\r\n\t\tthis._textModel.clearTokens();\r\n\t}\r\n\r\n\tpublic forceTokenization(lineNumber: number): void {\r\n\t\tconst builder = new MultilineTokensBuilder();\r\n\t\tthis._updateTokensUntilLine(builder, lineNumber);\r\n\t\tthis._textModel.setTokens(builder.tokens);\r\n\t}\r\n\r\n\tpublic isCheapToTokenize(lineNumber: number): boolean {\r\n\t\tif (!this._tokenizationSupport) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tconst firstInvalidLineNumber = this._tokenizationStateStore.invalidLineStartIndex + 1;\r\n\t\tif (lineNumber > firstInvalidLineNumber) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tif (lineNumber < firstInvalidLineNumber) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tif (this._textModel.getLineLength(lineNumber) < Constants.CHEAP_TOKENIZATION_LENGTH_LIMIT) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\t}\r\n\r\n\tprivate _hasLinesToTokenize(): boolean {\r\n\t\tif (!this._tokenizationSupport) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn (this._tokenizationStateStore.invalidLineStartIndex < this._textModel.getLineCount());\r\n\t}\r\n\r\n\tprivate _tokenizeOneInvalidLine(builder: MultilineTokensBuilder): number {\r\n\t\tif (!this._hasLinesToTokenize()) {\r\n\t\t\treturn this._textModel.getLineCount() + 1;\r\n\t\t}\r\n\t\tconst lineNumber = this._tokenizationStateStore.invalidLineStartIndex + 1;\r\n\t\tthis._updateTokensUntilLine(builder, lineNumber);\r\n\t\treturn lineNumber;\r\n\t}\r\n\r\n\tprivate _updateTokensUntilLine(builder: MultilineTokensBuilder, lineNumber: number): void {\r\n\t\tif (!this._tokenizationSupport) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst languageIdentifier = this._textModel.getLanguageIdentifier();\r\n\t\tconst linesLength = this._textModel.getLineCount();\r\n\t\tconst endLineIndex = lineNumber - 1;\r\n\r\n\t\t// Validate all states up to and including endLineIndex\r\n\t\tfor (let lineIndex = this._tokenizationStateStore.invalidLineStartIndex; lineIndex <= endLineIndex; lineIndex++) {\r\n\t\t\tconst text = this._textModel.getLineContent(lineIndex + 1);\r\n\t\t\tconst lineStartState = this._tokenizationStateStore.getBeginState(lineIndex);\r\n\r\n\t\t\tconst r = safeTokenize(languageIdentifier, this._tokenizationSupport, text, true, lineStartState!);\r\n\t\t\tbuilder.add(lineIndex + 1, r.tokens);\r\n\t\t\tthis._tokenizationStateStore.setEndState(linesLength, lineIndex, r.endState);\r\n\t\t\tlineIndex = this._tokenizationStateStore.invalidLineStartIndex - 1; // -1 because the outer loop increments it\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _tokenizeViewport(builder: MultilineTokensBuilder, startLineNumber: number, endLineNumber: number): void {\r\n\t\tif (!this._tokenizationSupport) {\r\n\t\t\t// nothing to do\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (endLineNumber <= this._tokenizationStateStore.invalidLineStartIndex) {\r\n\t\t\t// nothing to do\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (startLineNumber <= this._tokenizationStateStore.invalidLineStartIndex) {\r\n\t\t\t// tokenization has reached the viewport start...\r\n\t\t\tthis._updateTokensUntilLine(builder, endLineNumber);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet nonWhitespaceColumn = this._textModel.getLineFirstNonWhitespaceColumn(startLineNumber);\r\n\t\tlet fakeLines: string[] = [];\r\n\t\tlet initialState: IState | null = null;\r\n\t\tfor (let i = startLineNumber - 1; nonWhitespaceColumn > 0 && i >= 1; i--) {\r\n\t\t\tlet newNonWhitespaceIndex = this._textModel.getLineFirstNonWhitespaceColumn(i);\r\n\r\n\t\t\tif (newNonWhitespaceIndex === 0) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (newNonWhitespaceIndex < nonWhitespaceColumn) {\r\n\t\t\t\tinitialState = this._tokenizationStateStore.getBeginState(i - 1);\r\n\t\t\t\tif (initialState) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tfakeLines.push(this._textModel.getLineContent(i));\r\n\t\t\t\tnonWhitespaceColumn = newNonWhitespaceIndex;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!initialState) {\r\n\t\t\tinitialState = this._tokenizationSupport.getInitialState();\r\n\t\t}\r\n\r\n\t\tconst languageIdentifier = this._textModel.getLanguageIdentifier();\r\n\t\tlet state = initialState;\r\n\t\tfor (let i = fakeLines.length - 1; i >= 0; i--) {\r\n\t\t\tlet r = safeTokenize(languageIdentifier, this._tokenizationSupport, fakeLines[i], false, state);\r\n\t\t\tstate = r.endState;\r\n\t\t}\r\n\r\n\t\tfor (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {\r\n\t\t\tlet text = this._textModel.getLineContent(lineNumber);\r\n\t\t\tlet r = safeTokenize(languageIdentifier, this._tokenizationSupport, text, true, state);\r\n\t\t\tbuilder.add(lineNumber, r.tokens);\r\n\t\t\tthis._tokenizationStateStore.setFakeTokens(lineNumber - 1);\r\n\t\t\tstate = r.endState;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction initializeTokenization(textModel: TextModel): [ITokenizationSupport | null, IState | null] {\r\n\tconst languageIdentifier = textModel.getLanguageIdentifier();\r\n\tlet tokenizationSupport = (\r\n\t\ttextModel.isTooLargeForTokenization()\r\n\t\t\t? null\r\n\t\t\t: TokenizationRegistry.get(languageIdentifier.language)\r\n\t);\r\n\tlet initialState: IState | null = null;\r\n\tif (tokenizationSupport) {\r\n\t\ttry {\r\n\t\t\tinitialState = tokenizationSupport.getInitialState();\r\n\t\t} catch (e) {\r\n\t\t\tonUnexpectedError(e);\r\n\t\t\ttokenizationSupport = null;\r\n\t\t}\r\n\t}\r\n\treturn [tokenizationSupport, initialState];\r\n}\r\n\r\nfunction safeTokenize(languageIdentifier: LanguageIdentifier, tokenizationSupport: ITokenizationSupport | null, text: string, hasEOL: boolean, state: IState): TokenizationResult2 {\r\n\tlet r: TokenizationResult2 | null = null;\r\n\r\n\tif (tokenizationSupport) {\r\n\t\ttry {\r\n\t\t\tr = tokenizationSupport.tokenize2(text, hasEOL, state.clone(), 0);\r\n\t\t} catch (e) {\r\n\t\t\tonUnexpectedError(e);\r\n\t\t}\r\n\t}\r\n\r\n\tif (!r) {\r\n\t\tr = nullTokenize2(languageIdentifier.id, text, state, 0);\r\n\t}\r\n\r\n\tLineTokens.convertToEndOffset(r.tokens, text.length);\r\n\treturn r;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { IMarkdownString } from 'vs/base/common/htmlContent';\r\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { EDITOR_MODEL_DEFAULTS } from 'vs/editor/common/config/editorOptions';\r\nimport { LineTokens } from 'vs/editor/common/core/lineTokens';\r\nimport { IPosition, Position } from 'vs/editor/common/core/position';\r\nimport { IRange, Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport * as model from 'vs/editor/common/model';\r\nimport { EditStack } from 'vs/editor/common/model/editStack';\r\nimport { guessIndentation } from 'vs/editor/common/model/indentationGuesser';\r\nimport { IntervalNode, IntervalTree, getNodeIsInOverviewRuler, recomputeMaxEnd } from 'vs/editor/common/model/intervalTree';\r\nimport { PieceTreeTextBufferBuilder } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder';\r\nimport { IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelLanguageConfigurationChangedEvent, IModelOptionsChangedEvent, IModelTokensChangedEvent, InternalModelContentChangeEvent, ModelRawChange, ModelRawContentChangedEvent, ModelRawEOLChanged, ModelRawFlush, ModelRawLineChanged, ModelRawLinesDeleted, ModelRawLinesInserted } from 'vs/editor/common/model/textModelEvents';\r\nimport { SearchData, SearchParams, TextModelSearch } from 'vs/editor/common/model/textModelSearch';\r\nimport { TextModelTokenization } from 'vs/editor/common/model/textModelTokens';\r\nimport { getWordAtText } from 'vs/editor/common/model/wordHelper';\r\nimport { LanguageId, LanguageIdentifier, FormattingOptions } from 'vs/editor/common/modes';\r\nimport { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';\r\nimport { NULL_LANGUAGE_IDENTIFIER } from 'vs/editor/common/modes/nullMode';\r\nimport { ignoreBracketsInToken } from 'vs/editor/common/modes/supports';\r\nimport { BracketsUtils, RichEditBracket, RichEditBrackets } from 'vs/editor/common/modes/supports/richEditBrackets';\r\nimport { ThemeColor } from 'vs/platform/theme/common/themeService';\r\nimport { TokensStore, MultilineTokens, countEOL, MultilineTokens2, TokensStore2 } from 'vs/editor/common/model/tokensStore';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { EditorTheme } from 'vs/editor/common/view/viewContext';\r\nimport { IUndoRedoService, ResourceEditStackSnapshot } from 'vs/platform/undoRedo/common/undoRedo';\r\nimport { TextChange } from 'vs/editor/common/model/textChange';\r\nimport { Constants } from 'vs/base/common/uint';\r\nimport { PieceTreeTextBuffer } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer';\r\n\r\nfunction createTextBufferBuilder() {\r\n\treturn new PieceTreeTextBufferBuilder();\r\n}\r\n\r\nexport function createTextBufferFactory(text: string): model.ITextBufferFactory {\r\n\tconst builder = createTextBufferBuilder();\r\n\tbuilder.acceptChunk(text);\r\n\treturn builder.finish();\r\n}\r\n\r\nexport function createTextBuffer(value: string | model.ITextBufferFactory, defaultEOL: model.DefaultEndOfLine): { textBuffer: model.ITextBuffer; disposable: IDisposable; } {\r\n\tconst factory = (typeof value === 'string' ? createTextBufferFactory(value) : value);\r\n\treturn factory.create(defaultEOL);\r\n}\r\n\r\nlet MODEL_ID = 0;\r\n\r\nconst LIMIT_FIND_COUNT = 999;\r\nexport const LONG_LINE_BOUNDARY = 10000;\r\n\r\nclass TextModelSnapshot implements model.ITextSnapshot {\r\n\r\n\tprivate readonly _source: model.ITextSnapshot;\r\n\tprivate _eos: boolean;\r\n\r\n\tconstructor(source: model.ITextSnapshot) {\r\n\t\tthis._source = source;\r\n\t\tthis._eos = false;\r\n\t}\r\n\r\n\tpublic read(): string | null {\r\n\t\tif (this._eos) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet result: string[] = [], resultCnt = 0, resultLength = 0;\r\n\r\n\t\tdo {\r\n\t\t\tlet tmp = this._source.read();\r\n\r\n\t\t\tif (tmp === null) {\r\n\t\t\t\t// end-of-stream\r\n\t\t\t\tthis._eos = true;\r\n\t\t\t\tif (resultCnt === 0) {\r\n\t\t\t\t\treturn null;\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn result.join('');\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (tmp.length > 0) {\r\n\t\t\t\tresult[resultCnt++] = tmp;\r\n\t\t\t\tresultLength += tmp.length;\r\n\t\t\t}\r\n\r\n\t\t\tif (resultLength >= 64 * 1024) {\r\n\t\t\t\treturn result.join('');\r\n\t\t\t}\r\n\t\t} while (true);\r\n\t}\r\n}\r\n\r\nconst invalidFunc = () => { throw new Error(`Invalid change accessor`); };\r\n\r\nconst enum StringOffsetValidationType {\r\n\t/**\r\n\t * Even allowed in surrogate pairs\r\n\t */\r\n\tRelaxed = 0,\r\n\t/**\r\n\t * Not allowed in surrogate pairs\r\n\t */\r\n\tSurrogatePairs = 1,\r\n}\r\n\r\ntype ContinueBracketSearchPredicate = null | (() => boolean);\r\n\r\nclass BracketSearchCanceled {\r\n\tpublic static INSTANCE = new BracketSearchCanceled();\r\n\t_searchCanceledBrand = undefined;\r\n\tprivate constructor() { }\r\n}\r\n\r\nfunction stripBracketSearchCanceled(result: T | null | BracketSearchCanceled): T | null {\r\n\tif (result instanceof BracketSearchCanceled) {\r\n\t\treturn null;\r\n\t}\r\n\treturn result;\r\n}\r\n\r\nexport class TextModel extends Disposable implements model.ITextModel {\r\n\r\n\tprivate static readonly MODEL_SYNC_LIMIT = 50 * 1024 * 1024; // 50 MB\r\n\tprivate static readonly LARGE_FILE_SIZE_THRESHOLD = 20 * 1024 * 1024; // 20 MB;\r\n\tprivate static readonly LARGE_FILE_LINE_COUNT_THRESHOLD = 300 * 1000; // 300K lines\r\n\r\n\tpublic static DEFAULT_CREATION_OPTIONS: model.ITextModelCreationOptions = {\r\n\t\tisForSimpleWidget: false,\r\n\t\ttabSize: EDITOR_MODEL_DEFAULTS.tabSize,\r\n\t\tindentSize: EDITOR_MODEL_DEFAULTS.indentSize,\r\n\t\tinsertSpaces: EDITOR_MODEL_DEFAULTS.insertSpaces,\r\n\t\tdetectIndentation: false,\r\n\t\tdefaultEOL: model.DefaultEndOfLine.LF,\r\n\t\ttrimAutoWhitespace: EDITOR_MODEL_DEFAULTS.trimAutoWhitespace,\r\n\t\tlargeFileOptimizations: EDITOR_MODEL_DEFAULTS.largeFileOptimizations,\r\n\t};\r\n\r\n\tpublic static resolveOptions(textBuffer: model.ITextBuffer, options: model.ITextModelCreationOptions): model.TextModelResolvedOptions {\r\n\t\tif (options.detectIndentation) {\r\n\t\t\tconst guessedIndentation = guessIndentation(textBuffer, options.tabSize, options.insertSpaces);\r\n\t\t\treturn new model.TextModelResolvedOptions({\r\n\t\t\t\ttabSize: guessedIndentation.tabSize,\r\n\t\t\t\tindentSize: guessedIndentation.tabSize, // TODO@Alex: guess indentSize independent of tabSize\r\n\t\t\t\tinsertSpaces: guessedIndentation.insertSpaces,\r\n\t\t\t\ttrimAutoWhitespace: options.trimAutoWhitespace,\r\n\t\t\t\tdefaultEOL: options.defaultEOL\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\treturn new model.TextModelResolvedOptions({\r\n\t\t\ttabSize: options.tabSize,\r\n\t\t\tindentSize: options.indentSize,\r\n\t\t\tinsertSpaces: options.insertSpaces,\r\n\t\t\ttrimAutoWhitespace: options.trimAutoWhitespace,\r\n\t\t\tdefaultEOL: options.defaultEOL\r\n\t\t});\r\n\r\n\t}\r\n\r\n\t//#region Events\r\n\tprivate readonly _onWillDispose: Emitter = this._register(new Emitter());\r\n\tpublic readonly onWillDispose: Event = this._onWillDispose.event;\r\n\r\n\tprivate readonly _onDidChangeDecorations: DidChangeDecorationsEmitter = this._register(new DidChangeDecorationsEmitter());\r\n\tpublic readonly onDidChangeDecorations: Event = this._onDidChangeDecorations.event;\r\n\r\n\tprivate readonly _onDidChangeLanguage: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidChangeLanguage: Event = this._onDidChangeLanguage.event;\r\n\r\n\tprivate readonly _onDidChangeLanguageConfiguration: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidChangeLanguageConfiguration: Event = this._onDidChangeLanguageConfiguration.event;\r\n\r\n\tprivate readonly _onDidChangeTokens: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidChangeTokens: Event = this._onDidChangeTokens.event;\r\n\r\n\tprivate readonly _onDidChangeOptions: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidChangeOptions: Event = this._onDidChangeOptions.event;\r\n\r\n\tprivate readonly _onDidChangeAttached: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidChangeAttached: Event = this._onDidChangeAttached.event;\r\n\r\n\tprivate readonly _eventEmitter: DidChangeContentEmitter = this._register(new DidChangeContentEmitter());\r\n\tpublic onDidChangeRawContentFast(listener: (e: ModelRawContentChangedEvent) => void): IDisposable {\r\n\t\treturn this._eventEmitter.fastEvent((e: InternalModelContentChangeEvent) => listener(e.rawContentChangedEvent));\r\n\t}\r\n\tpublic onDidChangeContentFast(listener: (e: IModelContentChangedEvent) => void): IDisposable {\r\n\t\treturn this._eventEmitter.fastEvent((e: InternalModelContentChangeEvent) => listener(e.contentChangedEvent));\r\n\t}\r\n\tpublic onDidChangeContent(listener: (e: IModelContentChangedEvent) => void): IDisposable {\r\n\t\treturn this._eventEmitter.slowEvent((e: InternalModelContentChangeEvent) => listener(e.contentChangedEvent));\r\n\t}\r\n\t//#endregion\r\n\r\n\tpublic readonly id: string;\r\n\tpublic readonly isForSimpleWidget: boolean;\r\n\tprivate readonly _associatedResource: URI;\r\n\tprivate readonly _undoRedoService: IUndoRedoService;\r\n\tprivate _attachedEditorCount: number;\r\n\tprivate _buffer: model.ITextBuffer;\r\n\tprivate _bufferDisposable: IDisposable;\r\n\tprivate _options: model.TextModelResolvedOptions;\r\n\r\n\tprivate _isDisposed: boolean;\r\n\tprivate _isDisposing: boolean;\r\n\tprivate _versionId: number;\r\n\t/**\r\n\t * Unlike, versionId, this can go down (via undo) or go to previous values (via redo)\r\n\t */\r\n\tprivate _alternativeVersionId: number;\r\n\tprivate _initialUndoRedoSnapshot: ResourceEditStackSnapshot | null;\r\n\tprivate readonly _isTooLargeForSyncing: boolean;\r\n\tprivate readonly _isTooLargeForTokenization: boolean;\r\n\r\n\t//#region Editing\r\n\tprivate readonly _commandManager: EditStack;\r\n\tprivate _isUndoing: boolean;\r\n\tprivate _isRedoing: boolean;\r\n\tprivate _trimAutoWhitespaceLines: number[] | null;\r\n\t//#endregion\r\n\r\n\t//#region Decorations\r\n\t/**\r\n\t * Used to workaround broken clients that might attempt using a decoration id generated by a different model.\r\n\t * It is not globally unique in order to limit it to one character.\r\n\t */\r\n\tprivate readonly _instanceId: string;\r\n\tprivate _lastDecorationId: number;\r\n\tprivate _decorations: { [decorationId: string]: IntervalNode; };\r\n\tprivate _decorationsTree: DecorationsTrees;\r\n\t//#endregion\r\n\r\n\t//#region Tokenization\r\n\tprivate _languageIdentifier: LanguageIdentifier;\r\n\tprivate readonly _languageRegistryListener: IDisposable;\r\n\tprivate readonly _tokens: TokensStore;\r\n\tprivate readonly _tokens2: TokensStore2;\r\n\tprivate readonly _tokenization: TextModelTokenization;\r\n\t//#endregion\r\n\r\n\tconstructor(\r\n\t\tsource: string | model.ITextBufferFactory,\r\n\t\tcreationOptions: model.ITextModelCreationOptions,\r\n\t\tlanguageIdentifier: LanguageIdentifier | null,\r\n\t\tassociatedResource: URI | null = null,\r\n\t\tundoRedoService: IUndoRedoService\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\t// Generate a new unique model id\r\n\t\tMODEL_ID++;\r\n\t\tthis.id = '$model' + MODEL_ID;\r\n\t\tthis.isForSimpleWidget = creationOptions.isForSimpleWidget;\r\n\t\tif (typeof associatedResource === 'undefined' || associatedResource === null) {\r\n\t\t\tthis._associatedResource = URI.parse('inmemory://model/' + MODEL_ID);\r\n\t\t} else {\r\n\t\t\tthis._associatedResource = associatedResource;\r\n\t\t}\r\n\t\tthis._undoRedoService = undoRedoService;\r\n\t\tthis._attachedEditorCount = 0;\r\n\r\n\t\tconst { textBuffer, disposable } = createTextBuffer(source, creationOptions.defaultEOL);\r\n\t\tthis._buffer = textBuffer;\r\n\t\tthis._bufferDisposable = disposable;\r\n\r\n\t\tthis._options = TextModel.resolveOptions(this._buffer, creationOptions);\r\n\r\n\t\tconst bufferLineCount = this._buffer.getLineCount();\r\n\t\tconst bufferTextLength = this._buffer.getValueLengthInRange(new Range(1, 1, bufferLineCount, this._buffer.getLineLength(bufferLineCount) + 1), model.EndOfLinePreference.TextDefined);\r\n\r\n\t\t// !!! Make a decision in the ctor and permanently respect this decision !!!\r\n\t\t// If a model is too large at construction time, it will never get tokenized,\r\n\t\t// under no circumstances.\r\n\t\tif (creationOptions.largeFileOptimizations) {\r\n\t\t\tthis._isTooLargeForTokenization = (\r\n\t\t\t\t(bufferTextLength > TextModel.LARGE_FILE_SIZE_THRESHOLD)\r\n\t\t\t\t|| (bufferLineCount > TextModel.LARGE_FILE_LINE_COUNT_THRESHOLD)\r\n\t\t\t);\r\n\t\t} else {\r\n\t\t\tthis._isTooLargeForTokenization = false;\r\n\t\t}\r\n\r\n\t\tthis._isTooLargeForSyncing = (bufferTextLength > TextModel.MODEL_SYNC_LIMIT);\r\n\r\n\t\tthis._versionId = 1;\r\n\t\tthis._alternativeVersionId = 1;\r\n\t\tthis._initialUndoRedoSnapshot = null;\r\n\r\n\t\tthis._isDisposed = false;\r\n\t\tthis._isDisposing = false;\r\n\r\n\t\tthis._languageIdentifier = languageIdentifier || NULL_LANGUAGE_IDENTIFIER;\r\n\r\n\t\tthis._languageRegistryListener = LanguageConfigurationRegistry.onDidChange((e) => {\r\n\t\t\tif (e.languageIdentifier.id === this._languageIdentifier.id) {\r\n\t\t\t\tthis._onDidChangeLanguageConfiguration.fire({});\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tthis._instanceId = strings.singleLetterHash(MODEL_ID);\r\n\t\tthis._lastDecorationId = 0;\r\n\t\tthis._decorations = Object.create(null);\r\n\t\tthis._decorationsTree = new DecorationsTrees();\r\n\r\n\t\tthis._commandManager = new EditStack(this, undoRedoService);\r\n\t\tthis._isUndoing = false;\r\n\t\tthis._isRedoing = false;\r\n\t\tthis._trimAutoWhitespaceLines = null;\r\n\r\n\t\tthis._tokens = new TokensStore();\r\n\t\tthis._tokens2 = new TokensStore2();\r\n\t\tthis._tokenization = new TextModelTokenization(this);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._isDisposing = true;\r\n\t\tthis._onWillDispose.fire();\r\n\t\tthis._languageRegistryListener.dispose();\r\n\t\tthis._tokenization.dispose();\r\n\t\tthis._isDisposed = true;\r\n\t\tsuper.dispose();\r\n\t\tthis._bufferDisposable.dispose();\r\n\t\tthis._isDisposing = false;\r\n\t\t// Manually release reference to previous text buffer to avoid large leaks\r\n\t\t// in case someone leaks a TextModel reference\r\n\t\tconst emptyDisposedTextBuffer = new PieceTreeTextBuffer([], '', '\\n', false, false, true, true);\r\n\t\temptyDisposedTextBuffer.dispose();\r\n\t\tthis._buffer = emptyDisposedTextBuffer;\r\n\t}\r\n\r\n\tprivate _assertNotDisposed(): void {\r\n\t\tif (this._isDisposed) {\r\n\t\t\tthrow new Error('Model is disposed!');\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _emitContentChangedEvent(rawChange: ModelRawContentChangedEvent, change: IModelContentChangedEvent): void {\r\n\t\tif (this._isDisposing) {\r\n\t\t\t// Do not confuse listeners by emitting any event after disposing\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._eventEmitter.fire(new InternalModelContentChangeEvent(rawChange, change));\r\n\t}\r\n\r\n\tpublic setValue(value: string): void {\r\n\t\tthis._assertNotDisposed();\r\n\t\tif (value === null) {\r\n\t\t\t// There's nothing to do\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst { textBuffer, disposable } = createTextBuffer(value, this._options.defaultEOL);\r\n\t\tthis._setValueFromTextBuffer(textBuffer, disposable);\r\n\t}\r\n\r\n\tprivate _createContentChanged2(range: Range, rangeOffset: number, rangeLength: number, text: string, isUndoing: boolean, isRedoing: boolean, isFlush: boolean): IModelContentChangedEvent {\r\n\t\treturn {\r\n\t\t\tchanges: [{\r\n\t\t\t\trange: range,\r\n\t\t\t\trangeOffset: rangeOffset,\r\n\t\t\t\trangeLength: rangeLength,\r\n\t\t\t\ttext: text,\r\n\t\t\t}],\r\n\t\t\teol: this._buffer.getEOL(),\r\n\t\t\tversionId: this.getVersionId(),\r\n\t\t\tisUndoing: isUndoing,\r\n\t\t\tisRedoing: isRedoing,\r\n\t\t\tisFlush: isFlush\r\n\t\t};\r\n\t}\r\n\r\n\tprivate _setValueFromTextBuffer(textBuffer: model.ITextBuffer, textBufferDisposable: IDisposable): void {\r\n\t\tthis._assertNotDisposed();\r\n\t\tconst oldFullModelRange = this.getFullModelRange();\r\n\t\tconst oldModelValueLength = this.getValueLengthInRange(oldFullModelRange);\r\n\t\tconst endLineNumber = this.getLineCount();\r\n\t\tconst endColumn = this.getLineMaxColumn(endLineNumber);\r\n\r\n\t\tthis._buffer = textBuffer;\r\n\t\tthis._bufferDisposable.dispose();\r\n\t\tthis._bufferDisposable = textBufferDisposable;\r\n\t\tthis._increaseVersionId();\r\n\r\n\t\t// Flush all tokens\r\n\t\tthis._tokens.flush();\r\n\t\tthis._tokens2.flush();\r\n\r\n\t\t// Destroy all my decorations\r\n\t\tthis._decorations = Object.create(null);\r\n\t\tthis._decorationsTree = new DecorationsTrees();\r\n\r\n\t\t// Destroy my edit history and settings\r\n\t\tthis._commandManager.clear();\r\n\t\tthis._trimAutoWhitespaceLines = null;\r\n\r\n\t\tthis._emitContentChangedEvent(\r\n\t\t\tnew ModelRawContentChangedEvent(\r\n\t\t\t\t[\r\n\t\t\t\t\tnew ModelRawFlush()\r\n\t\t\t\t],\r\n\t\t\t\tthis._versionId,\r\n\t\t\t\tfalse,\r\n\t\t\t\tfalse\r\n\t\t\t),\r\n\t\t\tthis._createContentChanged2(new Range(1, 1, endLineNumber, endColumn), 0, oldModelValueLength, this.getValue(), false, false, true)\r\n\t\t);\r\n\t}\r\n\r\n\tpublic setEOL(eol: model.EndOfLineSequence): void {\r\n\t\tthis._assertNotDisposed();\r\n\t\tconst newEOL = (eol === model.EndOfLineSequence.CRLF ? '\\r\\n' : '\\n');\r\n\t\tif (this._buffer.getEOL() === newEOL) {\r\n\t\t\t// Nothing to do\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst oldFullModelRange = this.getFullModelRange();\r\n\t\tconst oldModelValueLength = this.getValueLengthInRange(oldFullModelRange);\r\n\t\tconst endLineNumber = this.getLineCount();\r\n\t\tconst endColumn = this.getLineMaxColumn(endLineNumber);\r\n\r\n\t\tthis._onBeforeEOLChange();\r\n\t\tthis._buffer.setEOL(newEOL);\r\n\t\tthis._increaseVersionId();\r\n\t\tthis._onAfterEOLChange();\r\n\r\n\t\tthis._emitContentChangedEvent(\r\n\t\t\tnew ModelRawContentChangedEvent(\r\n\t\t\t\t[\r\n\t\t\t\t\tnew ModelRawEOLChanged()\r\n\t\t\t\t],\r\n\t\t\t\tthis._versionId,\r\n\t\t\t\tfalse,\r\n\t\t\t\tfalse\r\n\t\t\t),\r\n\t\t\tthis._createContentChanged2(new Range(1, 1, endLineNumber, endColumn), 0, oldModelValueLength, this.getValue(), false, false, false)\r\n\t\t);\r\n\t}\r\n\r\n\tprivate _onBeforeEOLChange(): void {\r\n\t\t// Ensure all decorations get their `range` set.\r\n\t\tconst versionId = this.getVersionId();\r\n\t\tconst allDecorations = this._decorationsTree.search(0, false, false, versionId);\r\n\t\tthis._ensureNodesHaveRanges(allDecorations);\r\n\t}\r\n\r\n\tprivate _onAfterEOLChange(): void {\r\n\t\t// Transform back `range` to offsets\r\n\t\tconst versionId = this.getVersionId();\r\n\t\tconst allDecorations = this._decorationsTree.collectNodesPostOrder();\r\n\t\tfor (let i = 0, len = allDecorations.length; i < len; i++) {\r\n\t\t\tconst node = allDecorations[i];\r\n\r\n\t\t\tconst delta = node.cachedAbsoluteStart - node.start;\r\n\r\n\t\t\tconst startOffset = this._buffer.getOffsetAt(node.range.startLineNumber, node.range.startColumn);\r\n\t\t\tconst endOffset = this._buffer.getOffsetAt(node.range.endLineNumber, node.range.endColumn);\r\n\r\n\t\t\tnode.cachedAbsoluteStart = startOffset;\r\n\t\t\tnode.cachedAbsoluteEnd = endOffset;\r\n\t\t\tnode.cachedVersionId = versionId;\r\n\r\n\t\t\tnode.start = startOffset - delta;\r\n\t\t\tnode.end = endOffset - delta;\r\n\r\n\t\t\trecomputeMaxEnd(node);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic onBeforeAttached(): void {\r\n\t\tthis._attachedEditorCount++;\r\n\t\tif (this._attachedEditorCount === 1) {\r\n\t\t\tthis._onDidChangeAttached.fire(undefined);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic onBeforeDetached(): void {\r\n\t\tthis._attachedEditorCount--;\r\n\t\tif (this._attachedEditorCount === 0) {\r\n\t\t\tthis._onDidChangeAttached.fire(undefined);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic isAttachedToEditor(): boolean {\r\n\t\treturn this._attachedEditorCount > 0;\r\n\t}\r\n\r\n\tpublic getAttachedEditorCount(): number {\r\n\t\treturn this._attachedEditorCount;\r\n\t}\r\n\r\n\tpublic isTooLargeForSyncing(): boolean {\r\n\t\treturn this._isTooLargeForSyncing;\r\n\t}\r\n\r\n\tpublic isTooLargeForTokenization(): boolean {\r\n\t\treturn this._isTooLargeForTokenization;\r\n\t}\r\n\r\n\tpublic isDisposed(): boolean {\r\n\t\treturn this._isDisposed;\r\n\t}\r\n\r\n\tpublic isDominatedByLongLines(): boolean {\r\n\t\tthis._assertNotDisposed();\r\n\t\tif (this.isTooLargeForTokenization()) {\r\n\t\t\t// Cannot word wrap huge files anyways, so it doesn't really matter\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tlet smallLineCharCount = 0;\r\n\t\tlet longLineCharCount = 0;\r\n\r\n\t\tconst lineCount = this._buffer.getLineCount();\r\n\t\tfor (let lineNumber = 1; lineNumber <= lineCount; lineNumber++) {\r\n\t\t\tconst lineLength = this._buffer.getLineLength(lineNumber);\r\n\t\t\tif (lineLength >= LONG_LINE_BOUNDARY) {\r\n\t\t\t\tlongLineCharCount += lineLength;\r\n\t\t\t} else {\r\n\t\t\t\tsmallLineCharCount += lineLength;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn (longLineCharCount > smallLineCharCount);\r\n\t}\r\n\r\n\tpublic get uri(): URI {\r\n\t\treturn this._associatedResource;\r\n\t}\r\n\r\n\t//#region Options\r\n\r\n\tpublic getOptions(): model.TextModelResolvedOptions {\r\n\t\tthis._assertNotDisposed();\r\n\t\treturn this._options;\r\n\t}\r\n\r\n\tpublic getFormattingOptions(): FormattingOptions {\r\n\t\treturn {\r\n\t\t\ttabSize: this._options.indentSize,\r\n\t\t\tinsertSpaces: this._options.insertSpaces\r\n\t\t};\r\n\t}\r\n\r\n\tpublic updateOptions(_newOpts: model.ITextModelUpdateOptions): void {\r\n\t\tthis._assertNotDisposed();\r\n\t\tlet tabSize = (typeof _newOpts.tabSize !== 'undefined') ? _newOpts.tabSize : this._options.tabSize;\r\n\t\tlet indentSize = (typeof _newOpts.indentSize !== 'undefined') ? _newOpts.indentSize : this._options.indentSize;\r\n\t\tlet insertSpaces = (typeof _newOpts.insertSpaces !== 'undefined') ? _newOpts.insertSpaces : this._options.insertSpaces;\r\n\t\tlet trimAutoWhitespace = (typeof _newOpts.trimAutoWhitespace !== 'undefined') ? _newOpts.trimAutoWhitespace : this._options.trimAutoWhitespace;\r\n\r\n\t\tlet newOpts = new model.TextModelResolvedOptions({\r\n\t\t\ttabSize: tabSize,\r\n\t\t\tindentSize: indentSize,\r\n\t\t\tinsertSpaces: insertSpaces,\r\n\t\t\tdefaultEOL: this._options.defaultEOL,\r\n\t\t\ttrimAutoWhitespace: trimAutoWhitespace\r\n\t\t});\r\n\r\n\t\tif (this._options.equals(newOpts)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet e = this._options.createChangeEvent(newOpts);\r\n\t\tthis._options = newOpts;\r\n\r\n\t\tthis._onDidChangeOptions.fire(e);\r\n\t}\r\n\r\n\tpublic detectIndentation(defaultInsertSpaces: boolean, defaultTabSize: number): void {\r\n\t\tthis._assertNotDisposed();\r\n\t\tlet guessedIndentation = guessIndentation(this._buffer, defaultTabSize, defaultInsertSpaces);\r\n\t\tthis.updateOptions({\r\n\t\t\tinsertSpaces: guessedIndentation.insertSpaces,\r\n\t\t\ttabSize: guessedIndentation.tabSize,\r\n\t\t\tindentSize: guessedIndentation.tabSize, // TODO@Alex: guess indentSize independent of tabSize\r\n\t\t});\r\n\t}\r\n\r\n\tprivate static _normalizeIndentationFromWhitespace(str: string, indentSize: number, insertSpaces: boolean): string {\r\n\t\tlet spacesCnt = 0;\r\n\t\tfor (let i = 0; i < str.length; i++) {\r\n\t\t\tif (str.charAt(i) === '\\t') {\r\n\t\t\t\tspacesCnt += indentSize;\r\n\t\t\t} else {\r\n\t\t\t\tspacesCnt++;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet result = '';\r\n\t\tif (!insertSpaces) {\r\n\t\t\tlet tabsCnt = Math.floor(spacesCnt / indentSize);\r\n\t\t\tspacesCnt = spacesCnt % indentSize;\r\n\t\t\tfor (let i = 0; i < tabsCnt; i++) {\r\n\t\t\t\tresult += '\\t';\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tfor (let i = 0; i < spacesCnt; i++) {\r\n\t\t\tresult += ' ';\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic static normalizeIndentation(str: string, indentSize: number, insertSpaces: boolean): string {\r\n\t\tlet firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(str);\r\n\t\tif (firstNonWhitespaceIndex === -1) {\r\n\t\t\tfirstNonWhitespaceIndex = str.length;\r\n\t\t}\r\n\t\treturn TextModel._normalizeIndentationFromWhitespace(str.substring(0, firstNonWhitespaceIndex), indentSize, insertSpaces) + str.substring(firstNonWhitespaceIndex);\r\n\t}\r\n\r\n\tpublic normalizeIndentation(str: string): string {\r\n\t\tthis._assertNotDisposed();\r\n\t\treturn TextModel.normalizeIndentation(str, this._options.indentSize, this._options.insertSpaces);\r\n\t}\r\n\r\n\t//#endregion\r\n\r\n\t//#region Reading\r\n\r\n\tpublic getVersionId(): number {\r\n\t\tthis._assertNotDisposed();\r\n\t\treturn this._versionId;\r\n\t}\r\n\r\n\tpublic mightContainRTL(): boolean {\r\n\t\treturn this._buffer.mightContainRTL();\r\n\t}\r\n\r\n\tpublic mightContainUnusualLineTerminators(): boolean {\r\n\t\treturn this._buffer.mightContainUnusualLineTerminators();\r\n\t}\r\n\r\n\tpublic removeUnusualLineTerminators(selections: Selection[] | null = null): void {\r\n\t\tconst matches = this.findMatches(strings.UNUSUAL_LINE_TERMINATORS.source, false, true, false, null, false, Constants.MAX_SAFE_SMALL_INTEGER);\r\n\t\tthis._buffer.resetMightContainUnusualLineTerminators();\r\n\t\tthis.pushEditOperations(selections, matches.map(m => ({ range: m.range, text: null })), () => null);\r\n\t}\r\n\r\n\tpublic mightContainNonBasicASCII(): boolean {\r\n\t\treturn this._buffer.mightContainNonBasicASCII();\r\n\t}\r\n\r\n\tpublic getAlternativeVersionId(): number {\r\n\t\tthis._assertNotDisposed();\r\n\t\treturn this._alternativeVersionId;\r\n\t}\r\n\r\n\tpublic getInitialUndoRedoSnapshot(): ResourceEditStackSnapshot | null {\r\n\t\tthis._assertNotDisposed();\r\n\t\treturn this._initialUndoRedoSnapshot;\r\n\t}\r\n\r\n\tpublic getOffsetAt(rawPosition: IPosition): number {\r\n\t\tthis._assertNotDisposed();\r\n\t\tlet position = this._validatePosition(rawPosition.lineNumber, rawPosition.column, StringOffsetValidationType.Relaxed);\r\n\t\treturn this._buffer.getOffsetAt(position.lineNumber, position.column);\r\n\t}\r\n\r\n\tpublic getPositionAt(rawOffset: number): Position {\r\n\t\tthis._assertNotDisposed();\r\n\t\tlet offset = (Math.min(this._buffer.getLength(), Math.max(0, rawOffset)));\r\n\t\treturn this._buffer.getPositionAt(offset);\r\n\t}\r\n\r\n\tprivate _increaseVersionId(): void {\r\n\t\tthis._versionId = this._versionId + 1;\r\n\t\tthis._alternativeVersionId = this._versionId;\r\n\t}\r\n\r\n\tpublic _overwriteVersionId(versionId: number): void {\r\n\t\tthis._versionId = versionId;\r\n\t}\r\n\r\n\tpublic _overwriteAlternativeVersionId(newAlternativeVersionId: number): void {\r\n\t\tthis._alternativeVersionId = newAlternativeVersionId;\r\n\t}\r\n\r\n\tpublic _overwriteInitialUndoRedoSnapshot(newInitialUndoRedoSnapshot: ResourceEditStackSnapshot | null): void {\r\n\t\tthis._initialUndoRedoSnapshot = newInitialUndoRedoSnapshot;\r\n\t}\r\n\r\n\tpublic getValue(eol?: model.EndOfLinePreference, preserveBOM: boolean = false): string {\r\n\t\tthis._assertNotDisposed();\r\n\t\tconst fullModelRange = this.getFullModelRange();\r\n\t\tconst fullModelValue = this.getValueInRange(fullModelRange, eol);\r\n\r\n\t\tif (preserveBOM) {\r\n\t\t\treturn this._buffer.getBOM() + fullModelValue;\r\n\t\t}\r\n\r\n\t\treturn fullModelValue;\r\n\t}\r\n\r\n\tpublic createSnapshot(preserveBOM: boolean = false): model.ITextSnapshot {\r\n\t\treturn new TextModelSnapshot(this._buffer.createSnapshot(preserveBOM));\r\n\t}\r\n\r\n\tpublic getValueLength(eol?: model.EndOfLinePreference, preserveBOM: boolean = false): number {\r\n\t\tthis._assertNotDisposed();\r\n\t\tconst fullModelRange = this.getFullModelRange();\r\n\t\tconst fullModelValue = this.getValueLengthInRange(fullModelRange, eol);\r\n\r\n\t\tif (preserveBOM) {\r\n\t\t\treturn this._buffer.getBOM().length + fullModelValue;\r\n\t\t}\r\n\r\n\t\treturn fullModelValue;\r\n\t}\r\n\r\n\tpublic getValueInRange(rawRange: IRange, eol: model.EndOfLinePreference = model.EndOfLinePreference.TextDefined): string {\r\n\t\tthis._assertNotDisposed();\r\n\t\treturn this._buffer.getValueInRange(this.validateRange(rawRange), eol);\r\n\t}\r\n\r\n\tpublic getValueLengthInRange(rawRange: IRange, eol: model.EndOfLinePreference = model.EndOfLinePreference.TextDefined): number {\r\n\t\tthis._assertNotDisposed();\r\n\t\treturn this._buffer.getValueLengthInRange(this.validateRange(rawRange), eol);\r\n\t}\r\n\r\n\tpublic getCharacterCountInRange(rawRange: IRange, eol: model.EndOfLinePreference = model.EndOfLinePreference.TextDefined): number {\r\n\t\tthis._assertNotDisposed();\r\n\t\treturn this._buffer.getCharacterCountInRange(this.validateRange(rawRange), eol);\r\n\t}\r\n\r\n\tpublic getLineCount(): number {\r\n\t\tthis._assertNotDisposed();\r\n\t\treturn this._buffer.getLineCount();\r\n\t}\r\n\r\n\tpublic getLineContent(lineNumber: number): string {\r\n\t\tthis._assertNotDisposed();\r\n\t\tif (lineNumber < 1 || lineNumber > this.getLineCount()) {\r\n\t\t\tthrow new Error('Illegal value for lineNumber');\r\n\t\t}\r\n\r\n\t\treturn this._buffer.getLineContent(lineNumber);\r\n\t}\r\n\r\n\tpublic getLineLength(lineNumber: number): number {\r\n\t\tthis._assertNotDisposed();\r\n\t\tif (lineNumber < 1 || lineNumber > this.getLineCount()) {\r\n\t\t\tthrow new Error('Illegal value for lineNumber');\r\n\t\t}\r\n\r\n\t\treturn this._buffer.getLineLength(lineNumber);\r\n\t}\r\n\r\n\tpublic getLinesContent(): string[] {\r\n\t\tthis._assertNotDisposed();\r\n\t\treturn this._buffer.getLinesContent();\r\n\t}\r\n\r\n\tpublic getEOL(): string {\r\n\t\tthis._assertNotDisposed();\r\n\t\treturn this._buffer.getEOL();\r\n\t}\r\n\r\n\tpublic getEndOfLineSequence(): model.EndOfLineSequence {\r\n\t\tthis._assertNotDisposed();\r\n\t\treturn (\r\n\t\t\tthis._buffer.getEOL() === '\\n'\r\n\t\t\t\t? model.EndOfLineSequence.LF\r\n\t\t\t\t: model.EndOfLineSequence.CRLF\r\n\t\t);\r\n\t}\r\n\r\n\tpublic getLineMinColumn(lineNumber: number): number {\r\n\t\tthis._assertNotDisposed();\r\n\t\treturn 1;\r\n\t}\r\n\r\n\tpublic getLineMaxColumn(lineNumber: number): number {\r\n\t\tthis._assertNotDisposed();\r\n\t\tif (lineNumber < 1 || lineNumber > this.getLineCount()) {\r\n\t\t\tthrow new Error('Illegal value for lineNumber');\r\n\t\t}\r\n\t\treturn this._buffer.getLineLength(lineNumber) + 1;\r\n\t}\r\n\r\n\tpublic getLineFirstNonWhitespaceColumn(lineNumber: number): number {\r\n\t\tthis._assertNotDisposed();\r\n\t\tif (lineNumber < 1 || lineNumber > this.getLineCount()) {\r\n\t\t\tthrow new Error('Illegal value for lineNumber');\r\n\t\t}\r\n\t\treturn this._buffer.getLineFirstNonWhitespaceColumn(lineNumber);\r\n\t}\r\n\r\n\tpublic getLineLastNonWhitespaceColumn(lineNumber: number): number {\r\n\t\tthis._assertNotDisposed();\r\n\t\tif (lineNumber < 1 || lineNumber > this.getLineCount()) {\r\n\t\t\tthrow new Error('Illegal value for lineNumber');\r\n\t\t}\r\n\t\treturn this._buffer.getLineLastNonWhitespaceColumn(lineNumber);\r\n\t}\r\n\r\n\t/**\r\n\t * Validates `range` is within buffer bounds, but allows it to sit in between surrogate pairs, etc.\r\n\t * Will try to not allocate if possible.\r\n\t */\r\n\tprivate _validateRangeRelaxedNoAllocations(range: IRange): Range {\r\n\t\tconst linesCount = this._buffer.getLineCount();\r\n\r\n\t\tconst initialStartLineNumber = range.startLineNumber;\r\n\t\tconst initialStartColumn = range.startColumn;\r\n\t\tlet startLineNumber: number;\r\n\t\tlet startColumn: number;\r\n\r\n\t\tif (initialStartLineNumber < 1) {\r\n\t\t\tstartLineNumber = 1;\r\n\t\t\tstartColumn = 1;\r\n\t\t} else if (initialStartLineNumber > linesCount) {\r\n\t\t\tstartLineNumber = linesCount;\r\n\t\t\tstartColumn = this.getLineMaxColumn(startLineNumber);\r\n\t\t} else {\r\n\t\t\tstartLineNumber = initialStartLineNumber | 0;\r\n\t\t\tif (initialStartColumn <= 1) {\r\n\t\t\t\tstartColumn = 1;\r\n\t\t\t} else {\r\n\t\t\t\tconst maxColumn = this.getLineMaxColumn(startLineNumber);\r\n\t\t\t\tif (initialStartColumn >= maxColumn) {\r\n\t\t\t\t\tstartColumn = maxColumn;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tstartColumn = initialStartColumn | 0;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst initialEndLineNumber = range.endLineNumber;\r\n\t\tconst initialEndColumn = range.endColumn;\r\n\t\tlet endLineNumber: number;\r\n\t\tlet endColumn: number;\r\n\r\n\t\tif (initialEndLineNumber < 1) {\r\n\t\t\tendLineNumber = 1;\r\n\t\t\tendColumn = 1;\r\n\t\t} else if (initialEndLineNumber > linesCount) {\r\n\t\t\tendLineNumber = linesCount;\r\n\t\t\tendColumn = this.getLineMaxColumn(endLineNumber);\r\n\t\t} else {\r\n\t\t\tendLineNumber = initialEndLineNumber | 0;\r\n\t\t\tif (initialEndColumn <= 1) {\r\n\t\t\t\tendColumn = 1;\r\n\t\t\t} else {\r\n\t\t\t\tconst maxColumn = this.getLineMaxColumn(endLineNumber);\r\n\t\t\t\tif (initialEndColumn >= maxColumn) {\r\n\t\t\t\t\tendColumn = maxColumn;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tendColumn = initialEndColumn | 0;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (\r\n\t\t\tinitialStartLineNumber === startLineNumber\r\n\t\t\t&& initialStartColumn === startColumn\r\n\t\t\t&& initialEndLineNumber === endLineNumber\r\n\t\t\t&& initialEndColumn === endColumn\r\n\t\t\t&& range instanceof Range\r\n\t\t\t&& !(range instanceof Selection)\r\n\t\t) {\r\n\t\t\treturn range;\r\n\t\t}\r\n\r\n\t\treturn new Range(startLineNumber, startColumn, endLineNumber, endColumn);\r\n\t}\r\n\r\n\tprivate _isValidPosition(lineNumber: number, column: number, validationType: StringOffsetValidationType): boolean {\r\n\t\tif (typeof lineNumber !== 'number' || typeof column !== 'number') {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tif (isNaN(lineNumber) || isNaN(column)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tif (lineNumber < 1 || column < 1) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tif ((lineNumber | 0) !== lineNumber || (column | 0) !== column) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tconst lineCount = this._buffer.getLineCount();\r\n\t\tif (lineNumber > lineCount) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tif (column === 1) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tconst maxColumn = this.getLineMaxColumn(lineNumber);\r\n\t\tif (column > maxColumn) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tif (validationType === StringOffsetValidationType.SurrogatePairs) {\r\n\t\t\t// !!At this point, column > 1\r\n\t\t\tconst charCodeBefore = this._buffer.getLineCharCode(lineNumber, column - 2);\r\n\t\t\tif (strings.isHighSurrogate(charCodeBefore)) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tprivate _validatePosition(_lineNumber: number, _column: number, validationType: StringOffsetValidationType): Position {\r\n\t\tconst lineNumber = Math.floor((typeof _lineNumber === 'number' && !isNaN(_lineNumber)) ? _lineNumber : 1);\r\n\t\tconst column = Math.floor((typeof _column === 'number' && !isNaN(_column)) ? _column : 1);\r\n\t\tconst lineCount = this._buffer.getLineCount();\r\n\r\n\t\tif (lineNumber < 1) {\r\n\t\t\treturn new Position(1, 1);\r\n\t\t}\r\n\r\n\t\tif (lineNumber > lineCount) {\r\n\t\t\treturn new Position(lineCount, this.getLineMaxColumn(lineCount));\r\n\t\t}\r\n\r\n\t\tif (column <= 1) {\r\n\t\t\treturn new Position(lineNumber, 1);\r\n\t\t}\r\n\r\n\t\tconst maxColumn = this.getLineMaxColumn(lineNumber);\r\n\t\tif (column >= maxColumn) {\r\n\t\t\treturn new Position(lineNumber, maxColumn);\r\n\t\t}\r\n\r\n\t\tif (validationType === StringOffsetValidationType.SurrogatePairs) {\r\n\t\t\t// If the position would end up in the middle of a high-low surrogate pair,\r\n\t\t\t// we move it to before the pair\r\n\t\t\t// !!At this point, column > 1\r\n\t\t\tconst charCodeBefore = this._buffer.getLineCharCode(lineNumber, column - 2);\r\n\t\t\tif (strings.isHighSurrogate(charCodeBefore)) {\r\n\t\t\t\treturn new Position(lineNumber, column - 1);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn new Position(lineNumber, column);\r\n\t}\r\n\r\n\tpublic validatePosition(position: IPosition): Position {\r\n\t\tconst validationType = StringOffsetValidationType.SurrogatePairs;\r\n\t\tthis._assertNotDisposed();\r\n\r\n\t\t// Avoid object allocation and cover most likely case\r\n\t\tif (position instanceof Position) {\r\n\t\t\tif (this._isValidPosition(position.lineNumber, position.column, validationType)) {\r\n\t\t\t\treturn position;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this._validatePosition(position.lineNumber, position.column, validationType);\r\n\t}\r\n\r\n\tprivate _isValidRange(range: Range, validationType: StringOffsetValidationType): boolean {\r\n\t\tconst startLineNumber = range.startLineNumber;\r\n\t\tconst startColumn = range.startColumn;\r\n\t\tconst endLineNumber = range.endLineNumber;\r\n\t\tconst endColumn = range.endColumn;\r\n\r\n\t\tif (!this._isValidPosition(startLineNumber, startColumn, StringOffsetValidationType.Relaxed)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (!this._isValidPosition(endLineNumber, endColumn, StringOffsetValidationType.Relaxed)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tif (validationType === StringOffsetValidationType.SurrogatePairs) {\r\n\t\t\tconst charCodeBeforeStart = (startColumn > 1 ? this._buffer.getLineCharCode(startLineNumber, startColumn - 2) : 0);\r\n\t\t\tconst charCodeBeforeEnd = (endColumn > 1 && endColumn <= this._buffer.getLineLength(endLineNumber) ? this._buffer.getLineCharCode(endLineNumber, endColumn - 2) : 0);\r\n\r\n\t\t\tconst startInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeStart);\r\n\t\t\tconst endInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeEnd);\r\n\r\n\t\t\tif (!startInsideSurrogatePair && !endInsideSurrogatePair) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic validateRange(_range: IRange): Range {\r\n\t\tconst validationType = StringOffsetValidationType.SurrogatePairs;\r\n\t\tthis._assertNotDisposed();\r\n\r\n\t\t// Avoid object allocation and cover most likely case\r\n\t\tif ((_range instanceof Range) && !(_range instanceof Selection)) {\r\n\t\t\tif (this._isValidRange(_range, validationType)) {\r\n\t\t\t\treturn _range;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst start = this._validatePosition(_range.startLineNumber, _range.startColumn, StringOffsetValidationType.Relaxed);\r\n\t\tconst end = this._validatePosition(_range.endLineNumber, _range.endColumn, StringOffsetValidationType.Relaxed);\r\n\r\n\t\tconst startLineNumber = start.lineNumber;\r\n\t\tconst startColumn = start.column;\r\n\t\tconst endLineNumber = end.lineNumber;\r\n\t\tconst endColumn = end.column;\r\n\r\n\t\tif (validationType === StringOffsetValidationType.SurrogatePairs) {\r\n\t\t\tconst charCodeBeforeStart = (startColumn > 1 ? this._buffer.getLineCharCode(startLineNumber, startColumn - 2) : 0);\r\n\t\t\tconst charCodeBeforeEnd = (endColumn > 1 && endColumn <= this._buffer.getLineLength(endLineNumber) ? this._buffer.getLineCharCode(endLineNumber, endColumn - 2) : 0);\r\n\r\n\t\t\tconst startInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeStart);\r\n\t\t\tconst endInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeEnd);\r\n\r\n\t\t\tif (!startInsideSurrogatePair && !endInsideSurrogatePair) {\r\n\t\t\t\treturn new Range(startLineNumber, startColumn, endLineNumber, endColumn);\r\n\t\t\t}\r\n\r\n\t\t\tif (startLineNumber === endLineNumber && startColumn === endColumn) {\r\n\t\t\t\t// do not expand a collapsed range, simply move it to a valid location\r\n\t\t\t\treturn new Range(startLineNumber, startColumn - 1, endLineNumber, endColumn - 1);\r\n\t\t\t}\r\n\r\n\t\t\tif (startInsideSurrogatePair && endInsideSurrogatePair) {\r\n\t\t\t\t// expand range at both ends\r\n\t\t\t\treturn new Range(startLineNumber, startColumn - 1, endLineNumber, endColumn + 1);\r\n\t\t\t}\r\n\r\n\t\t\tif (startInsideSurrogatePair) {\r\n\t\t\t\t// only expand range at the start\r\n\t\t\t\treturn new Range(startLineNumber, startColumn - 1, endLineNumber, endColumn);\r\n\t\t\t}\r\n\r\n\t\t\t// only expand range at the end\r\n\t\t\treturn new Range(startLineNumber, startColumn, endLineNumber, endColumn + 1);\r\n\t\t}\r\n\r\n\t\treturn new Range(startLineNumber, startColumn, endLineNumber, endColumn);\r\n\t}\r\n\r\n\tpublic modifyPosition(rawPosition: IPosition, offset: number): Position {\r\n\t\tthis._assertNotDisposed();\r\n\t\tlet candidate = this.getOffsetAt(rawPosition) + offset;\r\n\t\treturn this.getPositionAt(Math.min(this._buffer.getLength(), Math.max(0, candidate)));\r\n\t}\r\n\r\n\tpublic getFullModelRange(): Range {\r\n\t\tthis._assertNotDisposed();\r\n\t\tconst lineCount = this.getLineCount();\r\n\t\treturn new Range(1, 1, lineCount, this.getLineMaxColumn(lineCount));\r\n\t}\r\n\r\n\tprivate findMatchesLineByLine(searchRange: Range, searchData: SearchData, captureMatches: boolean, limitResultCount: number): model.FindMatch[] {\r\n\t\treturn this._buffer.findMatchesLineByLine(searchRange, searchData, captureMatches, limitResultCount);\r\n\t}\r\n\r\n\tpublic findMatches(searchString: string, rawSearchScope: any, isRegex: boolean, matchCase: boolean, wordSeparators: string | null, captureMatches: boolean, limitResultCount: number = LIMIT_FIND_COUNT): model.FindMatch[] {\r\n\t\tthis._assertNotDisposed();\r\n\r\n\t\tlet searchRanges: Range[] | null = null;\r\n\r\n\t\tif (rawSearchScope !== null) {\r\n\t\t\tif (!Array.isArray(rawSearchScope)) {\r\n\t\t\t\trawSearchScope = [rawSearchScope];\r\n\t\t\t}\r\n\r\n\t\t\tif (rawSearchScope.every((searchScope: Range) => Range.isIRange(searchScope))) {\r\n\t\t\t\tsearchRanges = rawSearchScope.map((searchScope: Range) => this.validateRange(searchScope));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (searchRanges === null) {\r\n\t\t\tsearchRanges = [this.getFullModelRange()];\r\n\t\t}\r\n\r\n\t\tsearchRanges = searchRanges.sort((d1, d2) => d1.startLineNumber - d2.startLineNumber || d1.startColumn - d2.startColumn);\r\n\r\n\t\tconst uniqueSearchRanges: Range[] = [];\r\n\t\tuniqueSearchRanges.push(searchRanges.reduce((prev, curr) => {\r\n\t\t\tif (Range.areIntersecting(prev, curr)) {\r\n\t\t\t\treturn prev.plusRange(curr);\r\n\t\t\t}\r\n\r\n\t\t\tuniqueSearchRanges.push(prev);\r\n\t\t\treturn curr;\r\n\t\t}));\r\n\r\n\t\tlet matchMapper: (value: Range, index: number, array: Range[]) => model.FindMatch[];\r\n\t\tif (!isRegex && searchString.indexOf('\\n') < 0) {\r\n\t\t\t// not regex, not multi line\r\n\t\t\tconst searchParams = new SearchParams(searchString, isRegex, matchCase, wordSeparators);\r\n\t\t\tconst searchData = searchParams.parseSearchRequest();\r\n\r\n\t\t\tif (!searchData) {\r\n\t\t\t\treturn [];\r\n\t\t\t}\r\n\r\n\t\t\tmatchMapper = (searchRange: Range) => this.findMatchesLineByLine(searchRange, searchData, captureMatches, limitResultCount);\r\n\t\t} else {\r\n\t\t\tmatchMapper = (searchRange: Range) => TextModelSearch.findMatches(this, new SearchParams(searchString, isRegex, matchCase, wordSeparators), searchRange, captureMatches, limitResultCount);\r\n\t\t}\r\n\r\n\t\treturn uniqueSearchRanges.map(matchMapper).reduce((arr, matches: model.FindMatch[]) => arr.concat(matches), []);\r\n\t}\r\n\r\n\tpublic findNextMatch(searchString: string, rawSearchStart: IPosition, isRegex: boolean, matchCase: boolean, wordSeparators: string, captureMatches: boolean): model.FindMatch | null {\r\n\t\tthis._assertNotDisposed();\r\n\t\tconst searchStart = this.validatePosition(rawSearchStart);\r\n\r\n\t\tif (!isRegex && searchString.indexOf('\\n') < 0) {\r\n\t\t\tconst searchParams = new SearchParams(searchString, isRegex, matchCase, wordSeparators);\r\n\t\t\tconst searchData = searchParams.parseSearchRequest();\r\n\t\t\tif (!searchData) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\r\n\t\t\tconst lineCount = this.getLineCount();\r\n\t\t\tlet searchRange = new Range(searchStart.lineNumber, searchStart.column, lineCount, this.getLineMaxColumn(lineCount));\r\n\t\t\tlet ret = this.findMatchesLineByLine(searchRange, searchData, captureMatches, 1);\r\n\t\t\tTextModelSearch.findNextMatch(this, new SearchParams(searchString, isRegex, matchCase, wordSeparators), searchStart, captureMatches);\r\n\t\t\tif (ret.length > 0) {\r\n\t\t\t\treturn ret[0];\r\n\t\t\t}\r\n\r\n\t\t\tsearchRange = new Range(1, 1, searchStart.lineNumber, this.getLineMaxColumn(searchStart.lineNumber));\r\n\t\t\tret = this.findMatchesLineByLine(searchRange, searchData, captureMatches, 1);\r\n\r\n\t\t\tif (ret.length > 0) {\r\n\t\t\t\treturn ret[0];\r\n\t\t\t}\r\n\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\treturn TextModelSearch.findNextMatch(this, new SearchParams(searchString, isRegex, matchCase, wordSeparators), searchStart, captureMatches);\r\n\t}\r\n\r\n\tpublic findPreviousMatch(searchString: string, rawSearchStart: IPosition, isRegex: boolean, matchCase: boolean, wordSeparators: string, captureMatches: boolean): model.FindMatch | null {\r\n\t\tthis._assertNotDisposed();\r\n\t\tconst searchStart = this.validatePosition(rawSearchStart);\r\n\t\treturn TextModelSearch.findPreviousMatch(this, new SearchParams(searchString, isRegex, matchCase, wordSeparators), searchStart, captureMatches);\r\n\t}\r\n\r\n\t//#endregion\r\n\r\n\t//#region Editing\r\n\r\n\tpublic pushStackElement(): void {\r\n\t\tthis._commandManager.pushStackElement();\r\n\t}\r\n\r\n\tpublic popStackElement(): void {\r\n\t\tthis._commandManager.popStackElement();\r\n\t}\r\n\r\n\tpublic pushEOL(eol: model.EndOfLineSequence): void {\r\n\t\tconst currentEOL = (this.getEOL() === '\\n' ? model.EndOfLineSequence.LF : model.EndOfLineSequence.CRLF);\r\n\t\tif (currentEOL === eol) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\ttry {\r\n\t\t\tthis._onDidChangeDecorations.beginDeferredEmit();\r\n\t\t\tthis._eventEmitter.beginDeferredEmit();\r\n\t\t\tif (this._initialUndoRedoSnapshot === null) {\r\n\t\t\t\tthis._initialUndoRedoSnapshot = this._undoRedoService.createSnapshot(this.uri);\r\n\t\t\t}\r\n\t\t\tthis._commandManager.pushEOL(eol);\r\n\t\t} finally {\r\n\t\t\tthis._eventEmitter.endDeferredEmit();\r\n\t\t\tthis._onDidChangeDecorations.endDeferredEmit();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _validateEditOperation(rawOperation: model.IIdentifiedSingleEditOperation): model.ValidAnnotatedEditOperation {\r\n\t\tif (rawOperation instanceof model.ValidAnnotatedEditOperation) {\r\n\t\t\treturn rawOperation;\r\n\t\t}\r\n\t\treturn new model.ValidAnnotatedEditOperation(\r\n\t\t\trawOperation.identifier || null,\r\n\t\t\tthis.validateRange(rawOperation.range),\r\n\t\t\trawOperation.text,\r\n\t\t\trawOperation.forceMoveMarkers || false,\r\n\t\t\trawOperation.isAutoWhitespaceEdit || false,\r\n\t\t\trawOperation._isTracked || false\r\n\t\t);\r\n\t}\r\n\r\n\tprivate _validateEditOperations(rawOperations: model.IIdentifiedSingleEditOperation[]): model.ValidAnnotatedEditOperation[] {\r\n\t\tconst result: model.ValidAnnotatedEditOperation[] = [];\r\n\t\tfor (let i = 0, len = rawOperations.length; i < len; i++) {\r\n\t\t\tresult[i] = this._validateEditOperation(rawOperations[i]);\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic pushEditOperations(beforeCursorState: Selection[] | null, editOperations: model.IIdentifiedSingleEditOperation[], cursorStateComputer: model.ICursorStateComputer | null): Selection[] | null {\r\n\t\ttry {\r\n\t\t\tthis._onDidChangeDecorations.beginDeferredEmit();\r\n\t\t\tthis._eventEmitter.beginDeferredEmit();\r\n\t\t\treturn this._pushEditOperations(beforeCursorState, this._validateEditOperations(editOperations), cursorStateComputer);\r\n\t\t} finally {\r\n\t\t\tthis._eventEmitter.endDeferredEmit();\r\n\t\t\tthis._onDidChangeDecorations.endDeferredEmit();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _pushEditOperations(beforeCursorState: Selection[] | null, editOperations: model.ValidAnnotatedEditOperation[], cursorStateComputer: model.ICursorStateComputer | null): Selection[] | null {\r\n\t\tif (this._options.trimAutoWhitespace && this._trimAutoWhitespaceLines) {\r\n\t\t\t// Go through each saved line number and insert a trim whitespace edit\r\n\t\t\t// if it is safe to do so (no conflicts with other edits).\r\n\r\n\t\t\tlet incomingEdits = editOperations.map((op) => {\r\n\t\t\t\treturn {\r\n\t\t\t\t\trange: this.validateRange(op.range),\r\n\t\t\t\t\ttext: op.text\r\n\t\t\t\t};\r\n\t\t\t});\r\n\r\n\t\t\t// Sometimes, auto-formatters change ranges automatically which can cause undesired auto whitespace trimming near the cursor\r\n\t\t\t// We'll use the following heuristic: if the edits occur near the cursor, then it's ok to trim auto whitespace\r\n\t\t\tlet editsAreNearCursors = true;\r\n\t\t\tif (beforeCursorState) {\r\n\t\t\t\tfor (let i = 0, len = beforeCursorState.length; i < len; i++) {\r\n\t\t\t\t\tlet sel = beforeCursorState[i];\r\n\t\t\t\t\tlet foundEditNearSel = false;\r\n\t\t\t\t\tfor (let j = 0, lenJ = incomingEdits.length; j < lenJ; j++) {\r\n\t\t\t\t\t\tlet editRange = incomingEdits[j].range;\r\n\t\t\t\t\t\tlet selIsAbove = editRange.startLineNumber > sel.endLineNumber;\r\n\t\t\t\t\t\tlet selIsBelow = sel.startLineNumber > editRange.endLineNumber;\r\n\t\t\t\t\t\tif (!selIsAbove && !selIsBelow) {\r\n\t\t\t\t\t\t\tfoundEditNearSel = true;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (!foundEditNearSel) {\r\n\t\t\t\t\t\teditsAreNearCursors = false;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (editsAreNearCursors) {\r\n\t\t\t\tfor (let i = 0, len = this._trimAutoWhitespaceLines.length; i < len; i++) {\r\n\t\t\t\t\tlet trimLineNumber = this._trimAutoWhitespaceLines[i];\r\n\t\t\t\t\tlet maxLineColumn = this.getLineMaxColumn(trimLineNumber);\r\n\r\n\t\t\t\t\tlet allowTrimLine = true;\r\n\t\t\t\t\tfor (let j = 0, lenJ = incomingEdits.length; j < lenJ; j++) {\r\n\t\t\t\t\t\tlet editRange = incomingEdits[j].range;\r\n\t\t\t\t\t\tlet editText = incomingEdits[j].text;\r\n\r\n\t\t\t\t\t\tif (trimLineNumber < editRange.startLineNumber || trimLineNumber > editRange.endLineNumber) {\r\n\t\t\t\t\t\t\t// `trimLine` is completely outside this edit\r\n\t\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// At this point:\r\n\t\t\t\t\t\t// editRange.startLineNumber <= trimLine <= editRange.endLineNumber\r\n\r\n\t\t\t\t\t\tif (\r\n\t\t\t\t\t\t\ttrimLineNumber === editRange.startLineNumber && editRange.startColumn === maxLineColumn\r\n\t\t\t\t\t\t\t&& editRange.isEmpty() && editText && editText.length > 0 && editText.charAt(0) === '\\n'\r\n\t\t\t\t\t\t) {\r\n\t\t\t\t\t\t\t// This edit inserts a new line (and maybe other text) after `trimLine`\r\n\t\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif (\r\n\t\t\t\t\t\t\ttrimLineNumber === editRange.startLineNumber && editRange.startColumn === 1\r\n\t\t\t\t\t\t\t&& editRange.isEmpty() && editText && editText.length > 0 && editText.charAt(editText.length - 1) === '\\n'\r\n\t\t\t\t\t\t) {\r\n\t\t\t\t\t\t\t// This edit inserts a new line (and maybe other text) before `trimLine`\r\n\t\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// Looks like we can't trim this line as it would interfere with an incoming edit\r\n\t\t\t\t\t\tallowTrimLine = false;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (allowTrimLine) {\r\n\t\t\t\t\t\tconst trimRange = new Range(trimLineNumber, 1, trimLineNumber, maxLineColumn);\r\n\t\t\t\t\t\teditOperations.push(new model.ValidAnnotatedEditOperation(null, trimRange, null, false, false, false));\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tthis._trimAutoWhitespaceLines = null;\r\n\t\t}\r\n\t\tif (this._initialUndoRedoSnapshot === null) {\r\n\t\t\tthis._initialUndoRedoSnapshot = this._undoRedoService.createSnapshot(this.uri);\r\n\t\t}\r\n\t\treturn this._commandManager.pushEditOperation(beforeCursorState, editOperations, cursorStateComputer);\r\n\t}\r\n\r\n\t_applyUndo(changes: TextChange[], eol: model.EndOfLineSequence, resultingAlternativeVersionId: number, resultingSelection: Selection[] | null): void {\r\n\t\tconst edits = changes.map((change) => {\r\n\t\t\tconst rangeStart = this.getPositionAt(change.newPosition);\r\n\t\t\tconst rangeEnd = this.getPositionAt(change.newEnd);\r\n\t\t\treturn {\r\n\t\t\t\trange: new Range(rangeStart.lineNumber, rangeStart.column, rangeEnd.lineNumber, rangeEnd.column),\r\n\t\t\t\ttext: change.oldText\r\n\t\t\t};\r\n\t\t});\r\n\t\tthis._applyUndoRedoEdits(edits, eol, true, false, resultingAlternativeVersionId, resultingSelection);\r\n\t}\r\n\r\n\t_applyRedo(changes: TextChange[], eol: model.EndOfLineSequence, resultingAlternativeVersionId: number, resultingSelection: Selection[] | null): void {\r\n\t\tconst edits = changes.map((change) => {\r\n\t\t\tconst rangeStart = this.getPositionAt(change.oldPosition);\r\n\t\t\tconst rangeEnd = this.getPositionAt(change.oldEnd);\r\n\t\t\treturn {\r\n\t\t\t\trange: new Range(rangeStart.lineNumber, rangeStart.column, rangeEnd.lineNumber, rangeEnd.column),\r\n\t\t\t\ttext: change.newText\r\n\t\t\t};\r\n\t\t});\r\n\t\tthis._applyUndoRedoEdits(edits, eol, false, true, resultingAlternativeVersionId, resultingSelection);\r\n\t}\r\n\r\n\tprivate _applyUndoRedoEdits(edits: model.IIdentifiedSingleEditOperation[], eol: model.EndOfLineSequence, isUndoing: boolean, isRedoing: boolean, resultingAlternativeVersionId: number, resultingSelection: Selection[] | null): void {\r\n\t\ttry {\r\n\t\t\tthis._onDidChangeDecorations.beginDeferredEmit();\r\n\t\t\tthis._eventEmitter.beginDeferredEmit();\r\n\t\t\tthis._isUndoing = isUndoing;\r\n\t\t\tthis._isRedoing = isRedoing;\r\n\t\t\tthis.applyEdits(edits, false);\r\n\t\t\tthis.setEOL(eol);\r\n\t\t\tthis._overwriteAlternativeVersionId(resultingAlternativeVersionId);\r\n\t\t} finally {\r\n\t\t\tthis._isUndoing = false;\r\n\t\t\tthis._isRedoing = false;\r\n\t\t\tthis._eventEmitter.endDeferredEmit(resultingSelection);\r\n\t\t\tthis._onDidChangeDecorations.endDeferredEmit();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic applyEdits(operations: model.IIdentifiedSingleEditOperation[]): void;\r\n\tpublic applyEdits(operations: model.IIdentifiedSingleEditOperation[], computeUndoEdits: false): void;\r\n\tpublic applyEdits(operations: model.IIdentifiedSingleEditOperation[], computeUndoEdits: true): model.IValidEditOperation[];\r\n\tpublic applyEdits(rawOperations: model.IIdentifiedSingleEditOperation[], computeUndoEdits: boolean = false): void | model.IValidEditOperation[] {\r\n\t\ttry {\r\n\t\t\tthis._onDidChangeDecorations.beginDeferredEmit();\r\n\t\t\tthis._eventEmitter.beginDeferredEmit();\r\n\t\t\tconst operations = this._validateEditOperations(rawOperations);\r\n\t\t\treturn this._doApplyEdits(operations, computeUndoEdits);\r\n\t\t} finally {\r\n\t\t\tthis._eventEmitter.endDeferredEmit();\r\n\t\t\tthis._onDidChangeDecorations.endDeferredEmit();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _doApplyEdits(rawOperations: model.ValidAnnotatedEditOperation[], computeUndoEdits: boolean): void | model.IValidEditOperation[] {\r\n\r\n\t\tconst oldLineCount = this._buffer.getLineCount();\r\n\t\tconst result = this._buffer.applyEdits(rawOperations, this._options.trimAutoWhitespace, computeUndoEdits);\r\n\t\tconst newLineCount = this._buffer.getLineCount();\r\n\r\n\t\tconst contentChanges = result.changes;\r\n\t\tthis._trimAutoWhitespaceLines = result.trimAutoWhitespaceLineNumbers;\r\n\r\n\t\tif (contentChanges.length !== 0) {\r\n\t\t\tlet rawContentChanges: ModelRawChange[] = [];\r\n\r\n\t\t\tlet lineCount = oldLineCount;\r\n\t\t\tfor (let i = 0, len = contentChanges.length; i < len; i++) {\r\n\t\t\t\tconst change = contentChanges[i];\r\n\t\t\t\tconst [eolCount, firstLineLength, lastLineLength] = countEOL(change.text);\r\n\t\t\t\tthis._tokens.acceptEdit(change.range, eolCount, firstLineLength);\r\n\t\t\t\tthis._tokens2.acceptEdit(change.range, eolCount, firstLineLength, lastLineLength, change.text.length > 0 ? change.text.charCodeAt(0) : CharCode.Null);\r\n\t\t\t\tthis._onDidChangeDecorations.fire();\r\n\t\t\t\tthis._decorationsTree.acceptReplace(change.rangeOffset, change.rangeLength, change.text.length, change.forceMoveMarkers);\r\n\r\n\t\t\t\tconst startLineNumber = change.range.startLineNumber;\r\n\t\t\t\tconst endLineNumber = change.range.endLineNumber;\r\n\r\n\t\t\t\tconst deletingLinesCnt = endLineNumber - startLineNumber;\r\n\t\t\t\tconst insertingLinesCnt = eolCount;\r\n\t\t\t\tconst editingLinesCnt = Math.min(deletingLinesCnt, insertingLinesCnt);\r\n\r\n\t\t\t\tconst changeLineCountDelta = (insertingLinesCnt - deletingLinesCnt);\r\n\r\n\t\t\t\tfor (let j = editingLinesCnt; j >= 0; j--) {\r\n\t\t\t\t\tconst editLineNumber = startLineNumber + j;\r\n\t\t\t\t\tconst currentEditLineNumber = newLineCount - lineCount - changeLineCountDelta + editLineNumber;\r\n\t\t\t\t\trawContentChanges.push(new ModelRawLineChanged(editLineNumber, this.getLineContent(currentEditLineNumber)));\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (editingLinesCnt < deletingLinesCnt) {\r\n\t\t\t\t\t// Must delete some lines\r\n\t\t\t\t\tconst spliceStartLineNumber = startLineNumber + editingLinesCnt;\r\n\t\t\t\t\trawContentChanges.push(new ModelRawLinesDeleted(spliceStartLineNumber + 1, endLineNumber));\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (editingLinesCnt < insertingLinesCnt) {\r\n\t\t\t\t\t// Must insert some lines\r\n\t\t\t\t\tconst spliceLineNumber = startLineNumber + editingLinesCnt;\r\n\t\t\t\t\tconst cnt = insertingLinesCnt - editingLinesCnt;\r\n\t\t\t\t\tconst fromLineNumber = newLineCount - lineCount - cnt + spliceLineNumber + 1;\r\n\t\t\t\t\tlet newLines: string[] = [];\r\n\t\t\t\t\tfor (let i = 0; i < cnt; i++) {\r\n\t\t\t\t\t\tlet lineNumber = fromLineNumber + i;\r\n\t\t\t\t\t\tnewLines[lineNumber - fromLineNumber] = this.getLineContent(lineNumber);\r\n\t\t\t\t\t}\r\n\t\t\t\t\trawContentChanges.push(new ModelRawLinesInserted(spliceLineNumber + 1, startLineNumber + insertingLinesCnt, newLines));\r\n\t\t\t\t}\r\n\r\n\t\t\t\tlineCount += changeLineCountDelta;\r\n\t\t\t}\r\n\r\n\t\t\tthis._increaseVersionId();\r\n\r\n\t\t\tthis._emitContentChangedEvent(\r\n\t\t\t\tnew ModelRawContentChangedEvent(\r\n\t\t\t\t\trawContentChanges,\r\n\t\t\t\t\tthis.getVersionId(),\r\n\t\t\t\t\tthis._isUndoing,\r\n\t\t\t\t\tthis._isRedoing\r\n\t\t\t\t),\r\n\t\t\t\t{\r\n\t\t\t\t\tchanges: contentChanges,\r\n\t\t\t\t\teol: this._buffer.getEOL(),\r\n\t\t\t\t\tversionId: this.getVersionId(),\r\n\t\t\t\t\tisUndoing: this._isUndoing,\r\n\t\t\t\t\tisRedoing: this._isRedoing,\r\n\t\t\t\t\tisFlush: false\r\n\t\t\t\t}\r\n\t\t\t);\r\n\t\t}\r\n\r\n\t\treturn (result.reverseEdits === null ? undefined : result.reverseEdits);\r\n\t}\r\n\r\n\tpublic undo(): void | Promise {\r\n\t\treturn this._undoRedoService.undo(this.uri);\r\n\t}\r\n\r\n\tpublic canUndo(): boolean {\r\n\t\treturn this._undoRedoService.canUndo(this.uri);\r\n\t}\r\n\r\n\tpublic redo(): void | Promise {\r\n\t\treturn this._undoRedoService.redo(this.uri);\r\n\t}\r\n\r\n\tpublic canRedo(): boolean {\r\n\t\treturn this._undoRedoService.canRedo(this.uri);\r\n\t}\r\n\r\n\t//#endregion\r\n\r\n\t//#region Decorations\r\n\r\n\tpublic changeDecorations(callback: (changeAccessor: model.IModelDecorationsChangeAccessor) => T, ownerId: number = 0): T | null {\r\n\t\tthis._assertNotDisposed();\r\n\r\n\t\ttry {\r\n\t\t\tthis._onDidChangeDecorations.beginDeferredEmit();\r\n\t\t\treturn this._changeDecorations(ownerId, callback);\r\n\t\t} finally {\r\n\t\t\tthis._onDidChangeDecorations.endDeferredEmit();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _changeDecorations(ownerId: number, callback: (changeAccessor: model.IModelDecorationsChangeAccessor) => T): T | null {\r\n\t\tlet changeAccessor: model.IModelDecorationsChangeAccessor = {\r\n\t\t\taddDecoration: (range: IRange, options: model.IModelDecorationOptions): string => {\r\n\t\t\t\treturn this._deltaDecorationsImpl(ownerId, [], [{ range: range, options: options }])[0];\r\n\t\t\t},\r\n\t\t\tchangeDecoration: (id: string, newRange: IRange): void => {\r\n\t\t\t\tthis._changeDecorationImpl(id, newRange);\r\n\t\t\t},\r\n\t\t\tchangeDecorationOptions: (id: string, options: model.IModelDecorationOptions) => {\r\n\t\t\t\tthis._changeDecorationOptionsImpl(id, _normalizeOptions(options));\r\n\t\t\t},\r\n\t\t\tremoveDecoration: (id: string): void => {\r\n\t\t\t\tthis._deltaDecorationsImpl(ownerId, [id], []);\r\n\t\t\t},\r\n\t\t\tdeltaDecorations: (oldDecorations: string[], newDecorations: model.IModelDeltaDecoration[]): string[] => {\r\n\t\t\t\tif (oldDecorations.length === 0 && newDecorations.length === 0) {\r\n\t\t\t\t\t// nothing to do\r\n\t\t\t\t\treturn [];\r\n\t\t\t\t}\r\n\t\t\t\treturn this._deltaDecorationsImpl(ownerId, oldDecorations, newDecorations);\r\n\t\t\t}\r\n\t\t};\r\n\t\tlet result: T | null = null;\r\n\t\ttry {\r\n\t\t\tresult = callback(changeAccessor);\r\n\t\t} catch (e) {\r\n\t\t\tonUnexpectedError(e);\r\n\t\t}\r\n\t\t// Invalidate change accessor\r\n\t\tchangeAccessor.addDecoration = invalidFunc;\r\n\t\tchangeAccessor.changeDecoration = invalidFunc;\r\n\t\tchangeAccessor.changeDecorationOptions = invalidFunc;\r\n\t\tchangeAccessor.removeDecoration = invalidFunc;\r\n\t\tchangeAccessor.deltaDecorations = invalidFunc;\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic deltaDecorations(oldDecorations: string[], newDecorations: model.IModelDeltaDecoration[], ownerId: number = 0): string[] {\r\n\t\tthis._assertNotDisposed();\r\n\t\tif (!oldDecorations) {\r\n\t\t\toldDecorations = [];\r\n\t\t}\r\n\t\tif (oldDecorations.length === 0 && newDecorations.length === 0) {\r\n\t\t\t// nothing to do\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\tthis._onDidChangeDecorations.beginDeferredEmit();\r\n\t\t\treturn this._deltaDecorationsImpl(ownerId, oldDecorations, newDecorations);\r\n\t\t} finally {\r\n\t\t\tthis._onDidChangeDecorations.endDeferredEmit();\r\n\t\t}\r\n\t}\r\n\r\n\t_getTrackedRange(id: string): Range | null {\r\n\t\treturn this.getDecorationRange(id);\r\n\t}\r\n\r\n\t_setTrackedRange(id: string | null, newRange: null, newStickiness: model.TrackedRangeStickiness): null;\r\n\t_setTrackedRange(id: string | null, newRange: Range, newStickiness: model.TrackedRangeStickiness): string;\r\n\t_setTrackedRange(id: string | null, newRange: Range | null, newStickiness: model.TrackedRangeStickiness): string | null {\r\n\t\tconst node = (id ? this._decorations[id] : null);\r\n\r\n\t\tif (!node) {\r\n\t\t\tif (!newRange) {\r\n\t\t\t\t// node doesn't exist, the request is to delete => nothing to do\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t\t// node doesn't exist, the request is to set => add the tracked range\r\n\t\t\treturn this._deltaDecorationsImpl(0, [], [{ range: newRange, options: TRACKED_RANGE_OPTIONS[newStickiness] }])[0];\r\n\t\t}\r\n\r\n\t\tif (!newRange) {\r\n\t\t\t// node exists, the request is to delete => delete node\r\n\t\t\tthis._decorationsTree.delete(node);\r\n\t\t\tdelete this._decorations[node.id];\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\t// node exists, the request is to set => change the tracked range and its options\r\n\t\tconst range = this._validateRangeRelaxedNoAllocations(newRange);\r\n\t\tconst startOffset = this._buffer.getOffsetAt(range.startLineNumber, range.startColumn);\r\n\t\tconst endOffset = this._buffer.getOffsetAt(range.endLineNumber, range.endColumn);\r\n\t\tthis._decorationsTree.delete(node);\r\n\t\tnode.reset(this.getVersionId(), startOffset, endOffset, range);\r\n\t\tnode.setOptions(TRACKED_RANGE_OPTIONS[newStickiness]);\r\n\t\tthis._decorationsTree.insert(node);\r\n\t\treturn node.id;\r\n\t}\r\n\r\n\tpublic removeAllDecorationsWithOwnerId(ownerId: number): void {\r\n\t\tif (this._isDisposed) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst nodes = this._decorationsTree.collectNodesFromOwner(ownerId);\r\n\t\tfor (let i = 0, len = nodes.length; i < len; i++) {\r\n\t\t\tconst node = nodes[i];\r\n\r\n\t\t\tthis._decorationsTree.delete(node);\r\n\t\t\tdelete this._decorations[node.id];\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getDecorationOptions(decorationId: string): model.IModelDecorationOptions | null {\r\n\t\tconst node = this._decorations[decorationId];\r\n\t\tif (!node) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn node.options;\r\n\t}\r\n\r\n\tpublic getDecorationRange(decorationId: string): Range | null {\r\n\t\tconst node = this._decorations[decorationId];\r\n\t\tif (!node) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tconst versionId = this.getVersionId();\r\n\t\tif (node.cachedVersionId !== versionId) {\r\n\t\t\tthis._decorationsTree.resolveNode(node, versionId);\r\n\t\t}\r\n\t\tif (node.range === null) {\r\n\t\t\tnode.range = this._getRangeAt(node.cachedAbsoluteStart, node.cachedAbsoluteEnd);\r\n\t\t}\r\n\t\treturn node.range;\r\n\t}\r\n\r\n\tpublic getLineDecorations(lineNumber: number, ownerId: number = 0, filterOutValidation: boolean = false): model.IModelDecoration[] {\r\n\t\tif (lineNumber < 1 || lineNumber > this.getLineCount()) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\treturn this.getLinesDecorations(lineNumber, lineNumber, ownerId, filterOutValidation);\r\n\t}\r\n\r\n\tpublic getLinesDecorations(_startLineNumber: number, _endLineNumber: number, ownerId: number = 0, filterOutValidation: boolean = false): model.IModelDecoration[] {\r\n\t\tlet lineCount = this.getLineCount();\r\n\t\tlet startLineNumber = Math.min(lineCount, Math.max(1, _startLineNumber));\r\n\t\tlet endLineNumber = Math.min(lineCount, Math.max(1, _endLineNumber));\r\n\t\tlet endColumn = this.getLineMaxColumn(endLineNumber);\r\n\t\treturn this._getDecorationsInRange(new Range(startLineNumber, 1, endLineNumber, endColumn), ownerId, filterOutValidation);\r\n\t}\r\n\r\n\tpublic getDecorationsInRange(range: IRange, ownerId: number = 0, filterOutValidation: boolean = false): model.IModelDecoration[] {\r\n\t\tlet validatedRange = this.validateRange(range);\r\n\t\treturn this._getDecorationsInRange(validatedRange, ownerId, filterOutValidation);\r\n\t}\r\n\r\n\tpublic getOverviewRulerDecorations(ownerId: number = 0, filterOutValidation: boolean = false): model.IModelDecoration[] {\r\n\t\tconst versionId = this.getVersionId();\r\n\t\tconst result = this._decorationsTree.search(ownerId, filterOutValidation, true, versionId);\r\n\t\treturn this._ensureNodesHaveRanges(result);\r\n\t}\r\n\r\n\tpublic getAllDecorations(ownerId: number = 0, filterOutValidation: boolean = false): model.IModelDecoration[] {\r\n\t\tconst versionId = this.getVersionId();\r\n\t\tconst result = this._decorationsTree.search(ownerId, filterOutValidation, false, versionId);\r\n\t\treturn this._ensureNodesHaveRanges(result);\r\n\t}\r\n\r\n\tprivate _getDecorationsInRange(filterRange: Range, filterOwnerId: number, filterOutValidation: boolean): IntervalNode[] {\r\n\t\tconst startOffset = this._buffer.getOffsetAt(filterRange.startLineNumber, filterRange.startColumn);\r\n\t\tconst endOffset = this._buffer.getOffsetAt(filterRange.endLineNumber, filterRange.endColumn);\r\n\r\n\t\tconst versionId = this.getVersionId();\r\n\t\tconst result = this._decorationsTree.intervalSearch(startOffset, endOffset, filterOwnerId, filterOutValidation, versionId);\r\n\r\n\t\treturn this._ensureNodesHaveRanges(result);\r\n\t}\r\n\r\n\tprivate _ensureNodesHaveRanges(nodes: IntervalNode[]): IntervalNode[] {\r\n\t\tfor (let i = 0, len = nodes.length; i < len; i++) {\r\n\t\t\tconst node = nodes[i];\r\n\t\t\tif (node.range === null) {\r\n\t\t\t\tnode.range = this._getRangeAt(node.cachedAbsoluteStart, node.cachedAbsoluteEnd);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn nodes;\r\n\t}\r\n\r\n\tprivate _getRangeAt(start: number, end: number): Range {\r\n\t\treturn this._buffer.getRangeAt(start, end - start);\r\n\t}\r\n\r\n\tprivate _changeDecorationImpl(decorationId: string, _range: IRange): void {\r\n\t\tconst node = this._decorations[decorationId];\r\n\t\tif (!node) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst range = this._validateRangeRelaxedNoAllocations(_range);\r\n\t\tconst startOffset = this._buffer.getOffsetAt(range.startLineNumber, range.startColumn);\r\n\t\tconst endOffset = this._buffer.getOffsetAt(range.endLineNumber, range.endColumn);\r\n\r\n\t\tthis._decorationsTree.delete(node);\r\n\t\tnode.reset(this.getVersionId(), startOffset, endOffset, range);\r\n\t\tthis._decorationsTree.insert(node);\r\n\t\tthis._onDidChangeDecorations.checkAffectedAndFire(node.options);\r\n\t}\r\n\r\n\tprivate _changeDecorationOptionsImpl(decorationId: string, options: ModelDecorationOptions): void {\r\n\t\tconst node = this._decorations[decorationId];\r\n\t\tif (!node) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst nodeWasInOverviewRuler = (node.options.overviewRuler && node.options.overviewRuler.color ? true : false);\r\n\t\tconst nodeIsInOverviewRuler = (options.overviewRuler && options.overviewRuler.color ? true : false);\r\n\r\n\t\tthis._onDidChangeDecorations.checkAffectedAndFire(node.options);\r\n\t\tthis._onDidChangeDecorations.checkAffectedAndFire(options);\r\n\r\n\t\tif (nodeWasInOverviewRuler !== nodeIsInOverviewRuler) {\r\n\t\t\t// Delete + Insert due to an overview ruler status change\r\n\t\t\tthis._decorationsTree.delete(node);\r\n\t\t\tnode.setOptions(options);\r\n\t\t\tthis._decorationsTree.insert(node);\r\n\t\t} else {\r\n\t\t\tnode.setOptions(options);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _deltaDecorationsImpl(ownerId: number, oldDecorationsIds: string[], newDecorations: model.IModelDeltaDecoration[]): string[] {\r\n\t\tconst versionId = this.getVersionId();\r\n\r\n\t\tconst oldDecorationsLen = oldDecorationsIds.length;\r\n\t\tlet oldDecorationIndex = 0;\r\n\r\n\t\tconst newDecorationsLen = newDecorations.length;\r\n\t\tlet newDecorationIndex = 0;\r\n\r\n\t\tlet result = new Array(newDecorationsLen);\r\n\t\twhile (oldDecorationIndex < oldDecorationsLen || newDecorationIndex < newDecorationsLen) {\r\n\r\n\t\t\tlet node: IntervalNode | null = null;\r\n\r\n\t\t\tif (oldDecorationIndex < oldDecorationsLen) {\r\n\t\t\t\t// (1) get ourselves an old node\r\n\t\t\t\tdo {\r\n\t\t\t\t\tnode = this._decorations[oldDecorationsIds[oldDecorationIndex++]];\r\n\t\t\t\t} while (!node && oldDecorationIndex < oldDecorationsLen);\r\n\r\n\t\t\t\t// (2) remove the node from the tree (if it exists)\r\n\t\t\t\tif (node) {\r\n\t\t\t\t\tthis._decorationsTree.delete(node);\r\n\t\t\t\t\tthis._onDidChangeDecorations.checkAffectedAndFire(node.options);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (newDecorationIndex < newDecorationsLen) {\r\n\t\t\t\t// (3) create a new node if necessary\r\n\t\t\t\tif (!node) {\r\n\t\t\t\t\tconst internalDecorationId = (++this._lastDecorationId);\r\n\t\t\t\t\tconst decorationId = `${this._instanceId};${internalDecorationId}`;\r\n\t\t\t\t\tnode = new IntervalNode(decorationId, 0, 0);\r\n\t\t\t\t\tthis._decorations[decorationId] = node;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// (4) initialize node\r\n\t\t\t\tconst newDecoration = newDecorations[newDecorationIndex];\r\n\t\t\t\tconst range = this._validateRangeRelaxedNoAllocations(newDecoration.range);\r\n\t\t\t\tconst options = _normalizeOptions(newDecoration.options);\r\n\t\t\t\tconst startOffset = this._buffer.getOffsetAt(range.startLineNumber, range.startColumn);\r\n\t\t\t\tconst endOffset = this._buffer.getOffsetAt(range.endLineNumber, range.endColumn);\r\n\r\n\t\t\t\tnode.ownerId = ownerId;\r\n\t\t\t\tnode.reset(versionId, startOffset, endOffset, range);\r\n\t\t\t\tnode.setOptions(options);\r\n\t\t\t\tthis._onDidChangeDecorations.checkAffectedAndFire(options);\r\n\r\n\t\t\t\tthis._decorationsTree.insert(node);\r\n\r\n\t\t\t\tresult[newDecorationIndex] = node.id;\r\n\r\n\t\t\t\tnewDecorationIndex++;\r\n\t\t\t} else {\r\n\t\t\t\tif (node) {\r\n\t\t\t\t\tdelete this._decorations[node.id];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic setTokens(tokens: MultilineTokens[]): void {\r\n\t\tif (tokens.length === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet ranges: { fromLineNumber: number; toLineNumber: number; }[] = [];\r\n\r\n\t\tfor (let i = 0, len = tokens.length; i < len; i++) {\r\n\t\t\tconst element = tokens[i];\r\n\t\t\tlet minChangedLineNumber = 0;\r\n\t\t\tlet maxChangedLineNumber = 0;\r\n\t\t\tlet hasChange = false;\r\n\t\t\tfor (let j = 0, lenJ = element.tokens.length; j < lenJ; j++) {\r\n\t\t\t\tconst lineNumber = element.startLineNumber + j;\r\n\t\t\t\tif (hasChange) {\r\n\t\t\t\t\tthis._tokens.setTokens(this._languageIdentifier.id, lineNumber - 1, this._buffer.getLineLength(lineNumber), element.tokens[j], false);\r\n\t\t\t\t\tmaxChangedLineNumber = lineNumber;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tconst lineHasChange = this._tokens.setTokens(this._languageIdentifier.id, lineNumber - 1, this._buffer.getLineLength(lineNumber), element.tokens[j], true);\r\n\t\t\t\t\tif (lineHasChange) {\r\n\t\t\t\t\t\thasChange = true;\r\n\t\t\t\t\t\tminChangedLineNumber = lineNumber;\r\n\t\t\t\t\t\tmaxChangedLineNumber = lineNumber;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (hasChange) {\r\n\t\t\t\tranges.push({ fromLineNumber: minChangedLineNumber, toLineNumber: maxChangedLineNumber });\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (ranges.length > 0) {\r\n\t\t\tthis._emitModelTokensChangedEvent({\r\n\t\t\t\ttokenizationSupportChanged: false,\r\n\t\t\t\tsemanticTokensApplied: false,\r\n\t\t\t\tranges: ranges\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tpublic setSemanticTokens(tokens: MultilineTokens2[] | null, isComplete: boolean): void {\r\n\t\tthis._tokens2.set(tokens, isComplete);\r\n\r\n\t\tthis._emitModelTokensChangedEvent({\r\n\t\t\ttokenizationSupportChanged: false,\r\n\t\t\tsemanticTokensApplied: tokens !== null,\r\n\t\t\tranges: [{ fromLineNumber: 1, toLineNumber: this.getLineCount() }]\r\n\t\t});\r\n\t}\r\n\r\n\tpublic hasCompleteSemanticTokens(): boolean {\r\n\t\treturn this._tokens2.isComplete();\r\n\t}\r\n\r\n\tpublic hasSomeSemanticTokens(): boolean {\r\n\t\treturn !this._tokens2.isEmpty();\r\n\t}\r\n\r\n\tpublic setPartialSemanticTokens(range: Range, tokens: MultilineTokens2[]): void {\r\n\t\tif (this.hasCompleteSemanticTokens()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst changedRange = this._tokens2.setPartial(range, tokens);\r\n\r\n\t\tthis._emitModelTokensChangedEvent({\r\n\t\t\ttokenizationSupportChanged: false,\r\n\t\t\tsemanticTokensApplied: true,\r\n\t\t\tranges: [{ fromLineNumber: changedRange.startLineNumber, toLineNumber: changedRange.endLineNumber }]\r\n\t\t});\r\n\t}\r\n\r\n\tpublic tokenizeViewport(startLineNumber: number, endLineNumber: number): void {\r\n\t\tstartLineNumber = Math.max(1, startLineNumber);\r\n\t\tendLineNumber = Math.min(this._buffer.getLineCount(), endLineNumber);\r\n\t\tthis._tokenization.tokenizeViewport(startLineNumber, endLineNumber);\r\n\t}\r\n\r\n\tpublic clearTokens(): void {\r\n\t\tthis._tokens.flush();\r\n\t\tthis._emitModelTokensChangedEvent({\r\n\t\t\ttokenizationSupportChanged: true,\r\n\t\t\tsemanticTokensApplied: false,\r\n\t\t\tranges: [{\r\n\t\t\t\tfromLineNumber: 1,\r\n\t\t\t\ttoLineNumber: this._buffer.getLineCount()\r\n\t\t\t}]\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _emitModelTokensChangedEvent(e: IModelTokensChangedEvent): void {\r\n\t\tif (!this._isDisposing) {\r\n\t\t\tthis._onDidChangeTokens.fire(e);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic resetTokenization(): void {\r\n\t\tthis._tokenization.reset();\r\n\t}\r\n\r\n\tpublic forceTokenization(lineNumber: number): void {\r\n\t\tif (lineNumber < 1 || lineNumber > this.getLineCount()) {\r\n\t\t\tthrow new Error('Illegal value for lineNumber');\r\n\t\t}\r\n\r\n\t\tthis._tokenization.forceTokenization(lineNumber);\r\n\t}\r\n\r\n\tpublic isCheapToTokenize(lineNumber: number): boolean {\r\n\t\treturn this._tokenization.isCheapToTokenize(lineNumber);\r\n\t}\r\n\r\n\tpublic tokenizeIfCheap(lineNumber: number): void {\r\n\t\tif (this.isCheapToTokenize(lineNumber)) {\r\n\t\t\tthis.forceTokenization(lineNumber);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getLineTokens(lineNumber: number): LineTokens {\r\n\t\tif (lineNumber < 1 || lineNumber > this.getLineCount()) {\r\n\t\t\tthrow new Error('Illegal value for lineNumber');\r\n\t\t}\r\n\r\n\t\treturn this._getLineTokens(lineNumber);\r\n\t}\r\n\r\n\tprivate _getLineTokens(lineNumber: number): LineTokens {\r\n\t\tconst lineText = this.getLineContent(lineNumber);\r\n\t\tconst syntacticTokens = this._tokens.getTokens(this._languageIdentifier.id, lineNumber - 1, lineText);\r\n\t\treturn this._tokens2.addSemanticTokens(lineNumber, syntacticTokens);\r\n\t}\r\n\r\n\tpublic getLanguageIdentifier(): LanguageIdentifier {\r\n\t\treturn this._languageIdentifier;\r\n\t}\r\n\r\n\tpublic getModeId(): string {\r\n\t\treturn this._languageIdentifier.language;\r\n\t}\r\n\r\n\tpublic setMode(languageIdentifier: LanguageIdentifier): void {\r\n\t\tif (this._languageIdentifier.id === languageIdentifier.id) {\r\n\t\t\t// There's nothing to do\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet e: IModelLanguageChangedEvent = {\r\n\t\t\toldLanguage: this._languageIdentifier.language,\r\n\t\t\tnewLanguage: languageIdentifier.language\r\n\t\t};\r\n\r\n\t\tthis._languageIdentifier = languageIdentifier;\r\n\r\n\t\tthis._onDidChangeLanguage.fire(e);\r\n\t\tthis._onDidChangeLanguageConfiguration.fire({});\r\n\t}\r\n\r\n\tpublic getLanguageIdAtPosition(lineNumber: number, column: number): LanguageId {\r\n\t\tconst position = this.validatePosition(new Position(lineNumber, column));\r\n\t\tconst lineTokens = this.getLineTokens(position.lineNumber);\r\n\t\treturn lineTokens.getLanguageId(lineTokens.findTokenIndexAtOffset(position.column - 1));\r\n\t}\r\n\r\n\t// Having tokens allows implementing additional helper methods\r\n\r\n\tpublic getWordAtPosition(_position: IPosition): model.IWordAtPosition | null {\r\n\t\tthis._assertNotDisposed();\r\n\t\tconst position = this.validatePosition(_position);\r\n\t\tconst lineContent = this.getLineContent(position.lineNumber);\r\n\t\tconst lineTokens = this._getLineTokens(position.lineNumber);\r\n\t\tconst tokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1);\r\n\r\n\t\t// (1). First try checking right biased word\r\n\t\tconst [rbStartOffset, rbEndOffset] = TextModel._findLanguageBoundaries(lineTokens, tokenIndex);\r\n\t\tconst rightBiasedWord = getWordAtText(\r\n\t\t\tposition.column,\r\n\t\t\tLanguageConfigurationRegistry.getWordDefinition(lineTokens.getLanguageId(tokenIndex)),\r\n\t\t\tlineContent.substring(rbStartOffset, rbEndOffset),\r\n\t\t\trbStartOffset\r\n\t\t);\r\n\t\t// Make sure the result touches the original passed in position\r\n\t\tif (rightBiasedWord && rightBiasedWord.startColumn <= _position.column && _position.column <= rightBiasedWord.endColumn) {\r\n\t\t\treturn rightBiasedWord;\r\n\t\t}\r\n\r\n\t\t// (2). Else, if we were at a language boundary, check the left biased word\r\n\t\tif (tokenIndex > 0 && rbStartOffset === position.column - 1) {\r\n\t\t\t// edge case, where `position` sits between two tokens belonging to two different languages\r\n\t\t\tconst [lbStartOffset, lbEndOffset] = TextModel._findLanguageBoundaries(lineTokens, tokenIndex - 1);\r\n\t\t\tconst leftBiasedWord = getWordAtText(\r\n\t\t\t\tposition.column,\r\n\t\t\t\tLanguageConfigurationRegistry.getWordDefinition(lineTokens.getLanguageId(tokenIndex - 1)),\r\n\t\t\t\tlineContent.substring(lbStartOffset, lbEndOffset),\r\n\t\t\t\tlbStartOffset\r\n\t\t\t);\r\n\t\t\t// Make sure the result touches the original passed in position\r\n\t\t\tif (leftBiasedWord && leftBiasedWord.startColumn <= _position.column && _position.column <= leftBiasedWord.endColumn) {\r\n\t\t\t\treturn leftBiasedWord;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate static _findLanguageBoundaries(lineTokens: LineTokens, tokenIndex: number): [number, number] {\r\n\t\tconst languageId = lineTokens.getLanguageId(tokenIndex);\r\n\r\n\t\t// go left until a different language is hit\r\n\t\tlet startOffset = 0;\r\n\t\tfor (let i = tokenIndex; i >= 0 && lineTokens.getLanguageId(i) === languageId; i--) {\r\n\t\t\tstartOffset = lineTokens.getStartOffset(i);\r\n\t\t}\r\n\r\n\t\t// go right until a different language is hit\r\n\t\tlet endOffset = lineTokens.getLineContent().length;\r\n\t\tfor (let i = tokenIndex, tokenCount = lineTokens.getCount(); i < tokenCount && lineTokens.getLanguageId(i) === languageId; i++) {\r\n\t\t\tendOffset = lineTokens.getEndOffset(i);\r\n\t\t}\r\n\r\n\t\treturn [startOffset, endOffset];\r\n\t}\r\n\r\n\tpublic getWordUntilPosition(position: IPosition): model.IWordAtPosition {\r\n\t\tconst wordAtPosition = this.getWordAtPosition(position);\r\n\t\tif (!wordAtPosition) {\r\n\t\t\treturn {\r\n\t\t\t\tword: '',\r\n\t\t\t\tstartColumn: position.column,\r\n\t\t\t\tendColumn: position.column\r\n\t\t\t};\r\n\t\t}\r\n\t\treturn {\r\n\t\t\tword: wordAtPosition.word.substr(0, position.column - wordAtPosition.startColumn),\r\n\t\t\tstartColumn: wordAtPosition.startColumn,\r\n\t\t\tendColumn: position.column\r\n\t\t};\r\n\t}\r\n\r\n\tpublic findMatchingBracketUp(_bracket: string, _position: IPosition): Range | null {\r\n\t\tlet bracket = _bracket.toLowerCase();\r\n\t\tlet position = this.validatePosition(_position);\r\n\r\n\t\tlet lineTokens = this._getLineTokens(position.lineNumber);\r\n\t\tlet languageId = lineTokens.getLanguageId(lineTokens.findTokenIndexAtOffset(position.column - 1));\r\n\t\tlet bracketsSupport = LanguageConfigurationRegistry.getBracketsSupport(languageId);\r\n\r\n\t\tif (!bracketsSupport) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet data = bracketsSupport.textIsBracket[bracket];\r\n\r\n\t\tif (!data) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\treturn stripBracketSearchCanceled(this._findMatchingBracketUp(data, position, null));\r\n\t}\r\n\r\n\tpublic matchBracket(position: IPosition): [Range, Range] | null {\r\n\t\treturn this._matchBracket(this.validatePosition(position));\r\n\t}\r\n\r\n\tprivate _matchBracket(position: Position): [Range, Range] | null {\r\n\t\tconst lineNumber = position.lineNumber;\r\n\t\tconst lineTokens = this._getLineTokens(lineNumber);\r\n\t\tconst tokenCount = lineTokens.getCount();\r\n\t\tconst lineText = this._buffer.getLineContent(lineNumber);\r\n\r\n\t\tconst tokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1);\r\n\t\tif (tokenIndex < 0) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tconst currentModeBrackets = LanguageConfigurationRegistry.getBracketsSupport(lineTokens.getLanguageId(tokenIndex));\r\n\r\n\t\t// check that the token is not to be ignored\r\n\t\tif (currentModeBrackets && !ignoreBracketsInToken(lineTokens.getStandardTokenType(tokenIndex))) {\r\n\t\t\t// limit search to not go before `maxBracketLength`\r\n\t\t\tlet searchStartOffset = Math.max(0, position.column - 1 - currentModeBrackets.maxBracketLength);\r\n\t\t\tfor (let i = tokenIndex - 1; i >= 0; i--) {\r\n\t\t\t\tconst tokenEndOffset = lineTokens.getEndOffset(i);\r\n\t\t\t\tif (tokenEndOffset <= searchStartOffset) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tif (ignoreBracketsInToken(lineTokens.getStandardTokenType(i))) {\r\n\t\t\t\t\tsearchStartOffset = tokenEndOffset;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t// limit search to not go after `maxBracketLength`\r\n\t\t\tconst searchEndOffset = Math.min(lineText.length, position.column - 1 + currentModeBrackets.maxBracketLength);\r\n\r\n\t\t\t// it might be the case that [currentTokenStart -> currentTokenEnd] contains multiple brackets\r\n\t\t\t// `bestResult` will contain the most right-side result\r\n\t\t\tlet bestResult: [Range, Range] | null = null;\r\n\t\t\twhile (true) {\r\n\t\t\t\tconst foundBracket = BracketsUtils.findNextBracketInRange(currentModeBrackets.forwardRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);\r\n\t\t\t\tif (!foundBracket) {\r\n\t\t\t\t\t// there are no more brackets in this text\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// check that we didn't hit a bracket too far away from position\r\n\t\t\t\tif (foundBracket.startColumn <= position.column && position.column <= foundBracket.endColumn) {\r\n\t\t\t\t\tconst foundBracketText = lineText.substring(foundBracket.startColumn - 1, foundBracket.endColumn - 1).toLowerCase();\r\n\t\t\t\t\tconst r = this._matchFoundBracket(foundBracket, currentModeBrackets.textIsBracket[foundBracketText], currentModeBrackets.textIsOpenBracket[foundBracketText], null);\r\n\t\t\t\t\tif (r) {\r\n\t\t\t\t\t\tif (r instanceof BracketSearchCanceled) {\r\n\t\t\t\t\t\t\treturn null;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tbestResult = r;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tsearchStartOffset = foundBracket.endColumn - 1;\r\n\t\t\t}\r\n\r\n\t\t\tif (bestResult) {\r\n\t\t\t\treturn bestResult;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// If position is in between two tokens, try also looking in the previous token\r\n\t\tif (tokenIndex > 0 && lineTokens.getStartOffset(tokenIndex) === position.column - 1) {\r\n\t\t\tconst prevTokenIndex = tokenIndex - 1;\r\n\t\t\tconst prevModeBrackets = LanguageConfigurationRegistry.getBracketsSupport(lineTokens.getLanguageId(prevTokenIndex));\r\n\r\n\t\t\t// check that previous token is not to be ignored\r\n\t\t\tif (prevModeBrackets && !ignoreBracketsInToken(lineTokens.getStandardTokenType(prevTokenIndex))) {\r\n\t\t\t\t// limit search in case previous token is very large, there's no need to go beyond `maxBracketLength`\r\n\t\t\t\tconst searchStartOffset = Math.max(0, position.column - 1 - prevModeBrackets.maxBracketLength);\r\n\t\t\t\tlet searchEndOffset = Math.min(lineText.length, position.column - 1 + prevModeBrackets.maxBracketLength);\r\n\t\t\t\tfor (let i = prevTokenIndex + 1; i < tokenCount; i++) {\r\n\t\t\t\t\tconst tokenStartOffset = lineTokens.getStartOffset(i);\r\n\t\t\t\t\tif (tokenStartOffset >= searchEndOffset) {\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (ignoreBracketsInToken(lineTokens.getStandardTokenType(i))) {\r\n\t\t\t\t\t\tsearchEndOffset = tokenStartOffset;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tconst foundBracket = BracketsUtils.findPrevBracketInRange(prevModeBrackets.reversedRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);\r\n\r\n\t\t\t\t// check that we didn't hit a bracket too far away from position\r\n\t\t\t\tif (foundBracket && foundBracket.startColumn <= position.column && position.column <= foundBracket.endColumn) {\r\n\t\t\t\t\tconst foundBracketText = lineText.substring(foundBracket.startColumn - 1, foundBracket.endColumn - 1).toLowerCase();\r\n\t\t\t\t\tconst r = this._matchFoundBracket(foundBracket, prevModeBrackets.textIsBracket[foundBracketText], prevModeBrackets.textIsOpenBracket[foundBracketText], null);\r\n\t\t\t\t\tif (r) {\r\n\t\t\t\t\t\tif (r instanceof BracketSearchCanceled) {\r\n\t\t\t\t\t\t\treturn null;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\treturn r;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate _matchFoundBracket(foundBracket: Range, data: RichEditBracket, isOpen: boolean, continueSearchPredicate: ContinueBracketSearchPredicate): [Range, Range] | null | BracketSearchCanceled {\r\n\t\tif (!data) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst matched = (\r\n\t\t\tisOpen\r\n\t\t\t\t? this._findMatchingBracketDown(data, foundBracket.getEndPosition(), continueSearchPredicate)\r\n\t\t\t\t: this._findMatchingBracketUp(data, foundBracket.getStartPosition(), continueSearchPredicate)\r\n\t\t);\r\n\r\n\t\tif (!matched) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (matched instanceof BracketSearchCanceled) {\r\n\t\t\treturn matched;\r\n\t\t}\r\n\r\n\t\treturn [foundBracket, matched];\r\n\t}\r\n\r\n\tprivate _findMatchingBracketUp(bracket: RichEditBracket, position: Position, continueSearchPredicate: ContinueBracketSearchPredicate): Range | null | BracketSearchCanceled {\r\n\t\t// console.log('_findMatchingBracketUp: ', 'bracket: ', JSON.stringify(bracket), 'startPosition: ', String(position));\r\n\r\n\t\tconst languageId = bracket.languageIdentifier.id;\r\n\t\tconst reversedBracketRegex = bracket.reversedRegex;\r\n\t\tlet count = -1;\r\n\r\n\t\tlet totalCallCount = 0;\r\n\t\tconst searchPrevMatchingBracketInRange = (lineNumber: number, lineText: string, searchStartOffset: number, searchEndOffset: number): Range | null | BracketSearchCanceled => {\r\n\t\t\twhile (true) {\r\n\t\t\t\tif (continueSearchPredicate && (++totalCallCount) % 100 === 0 && !continueSearchPredicate()) {\r\n\t\t\t\t\treturn BracketSearchCanceled.INSTANCE;\r\n\t\t\t\t}\r\n\t\t\t\tconst r = BracketsUtils.findPrevBracketInRange(reversedBracketRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);\r\n\t\t\t\tif (!r) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst hitText = lineText.substring(r.startColumn - 1, r.endColumn - 1).toLowerCase();\r\n\t\t\t\tif (bracket.isOpen(hitText)) {\r\n\t\t\t\t\tcount++;\r\n\t\t\t\t} else if (bracket.isClose(hitText)) {\r\n\t\t\t\t\tcount--;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (count === 0) {\r\n\t\t\t\t\treturn r;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tsearchEndOffset = r.startColumn - 1;\r\n\t\t\t}\r\n\r\n\t\t\treturn null;\r\n\t\t};\r\n\r\n\t\tfor (let lineNumber = position.lineNumber; lineNumber >= 1; lineNumber--) {\r\n\t\t\tconst lineTokens = this._getLineTokens(lineNumber);\r\n\t\t\tconst tokenCount = lineTokens.getCount();\r\n\t\t\tconst lineText = this._buffer.getLineContent(lineNumber);\r\n\r\n\t\t\tlet tokenIndex = tokenCount - 1;\r\n\t\t\tlet searchStartOffset = lineText.length;\r\n\t\t\tlet searchEndOffset = lineText.length;\r\n\t\t\tif (lineNumber === position.lineNumber) {\r\n\t\t\t\ttokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1);\r\n\t\t\t\tsearchStartOffset = position.column - 1;\r\n\t\t\t\tsearchEndOffset = position.column - 1;\r\n\t\t\t}\r\n\r\n\t\t\tlet prevSearchInToken = true;\r\n\t\t\tfor (; tokenIndex >= 0; tokenIndex--) {\r\n\t\t\t\tconst searchInToken = (lineTokens.getLanguageId(tokenIndex) === languageId && !ignoreBracketsInToken(lineTokens.getStandardTokenType(tokenIndex)));\r\n\r\n\t\t\t\tif (searchInToken) {\r\n\t\t\t\t\t// this token should be searched\r\n\t\t\t\t\tif (prevSearchInToken) {\r\n\t\t\t\t\t\t// the previous token should be searched, simply extend searchStartOffset\r\n\t\t\t\t\t\tsearchStartOffset = lineTokens.getStartOffset(tokenIndex);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t// the previous token should not be searched\r\n\t\t\t\t\t\tsearchStartOffset = lineTokens.getStartOffset(tokenIndex);\r\n\t\t\t\t\t\tsearchEndOffset = lineTokens.getEndOffset(tokenIndex);\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// this token should not be searched\r\n\t\t\t\t\tif (prevSearchInToken && searchStartOffset !== searchEndOffset) {\r\n\t\t\t\t\t\tconst r = searchPrevMatchingBracketInRange(lineNumber, lineText, searchStartOffset, searchEndOffset);\r\n\t\t\t\t\t\tif (r) {\r\n\t\t\t\t\t\t\treturn r;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tprevSearchInToken = searchInToken;\r\n\t\t\t}\r\n\r\n\t\t\tif (prevSearchInToken && searchStartOffset !== searchEndOffset) {\r\n\t\t\t\tconst r = searchPrevMatchingBracketInRange(lineNumber, lineText, searchStartOffset, searchEndOffset);\r\n\t\t\t\tif (r) {\r\n\t\t\t\t\treturn r;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate _findMatchingBracketDown(bracket: RichEditBracket, position: Position, continueSearchPredicate: ContinueBracketSearchPredicate): Range | null | BracketSearchCanceled {\r\n\t\t// console.log('_findMatchingBracketDown: ', 'bracket: ', JSON.stringify(bracket), 'startPosition: ', String(position));\r\n\r\n\t\tconst languageId = bracket.languageIdentifier.id;\r\n\t\tconst bracketRegex = bracket.forwardRegex;\r\n\t\tlet count = 1;\r\n\r\n\t\tlet totalCallCount = 0;\r\n\t\tconst searchNextMatchingBracketInRange = (lineNumber: number, lineText: string, searchStartOffset: number, searchEndOffset: number): Range | null | BracketSearchCanceled => {\r\n\t\t\twhile (true) {\r\n\t\t\t\tif (continueSearchPredicate && (++totalCallCount) % 100 === 0 && !continueSearchPredicate()) {\r\n\t\t\t\t\treturn BracketSearchCanceled.INSTANCE;\r\n\t\t\t\t}\r\n\t\t\t\tconst r = BracketsUtils.findNextBracketInRange(bracketRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);\r\n\t\t\t\tif (!r) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst hitText = lineText.substring(r.startColumn - 1, r.endColumn - 1).toLowerCase();\r\n\t\t\t\tif (bracket.isOpen(hitText)) {\r\n\t\t\t\t\tcount++;\r\n\t\t\t\t} else if (bracket.isClose(hitText)) {\r\n\t\t\t\t\tcount--;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (count === 0) {\r\n\t\t\t\t\treturn r;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tsearchStartOffset = r.endColumn - 1;\r\n\t\t\t}\r\n\r\n\t\t\treturn null;\r\n\t\t};\r\n\r\n\t\tconst lineCount = this.getLineCount();\r\n\t\tfor (let lineNumber = position.lineNumber; lineNumber <= lineCount; lineNumber++) {\r\n\t\t\tconst lineTokens = this._getLineTokens(lineNumber);\r\n\t\t\tconst tokenCount = lineTokens.getCount();\r\n\t\t\tconst lineText = this._buffer.getLineContent(lineNumber);\r\n\r\n\t\t\tlet tokenIndex = 0;\r\n\t\t\tlet searchStartOffset = 0;\r\n\t\t\tlet searchEndOffset = 0;\r\n\t\t\tif (lineNumber === position.lineNumber) {\r\n\t\t\t\ttokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1);\r\n\t\t\t\tsearchStartOffset = position.column - 1;\r\n\t\t\t\tsearchEndOffset = position.column - 1;\r\n\t\t\t}\r\n\r\n\t\t\tlet prevSearchInToken = true;\r\n\t\t\tfor (; tokenIndex < tokenCount; tokenIndex++) {\r\n\t\t\t\tconst searchInToken = (lineTokens.getLanguageId(tokenIndex) === languageId && !ignoreBracketsInToken(lineTokens.getStandardTokenType(tokenIndex)));\r\n\r\n\t\t\t\tif (searchInToken) {\r\n\t\t\t\t\t// this token should be searched\r\n\t\t\t\t\tif (prevSearchInToken) {\r\n\t\t\t\t\t\t// the previous token should be searched, simply extend searchEndOffset\r\n\t\t\t\t\t\tsearchEndOffset = lineTokens.getEndOffset(tokenIndex);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t// the previous token should not be searched\r\n\t\t\t\t\t\tsearchStartOffset = lineTokens.getStartOffset(tokenIndex);\r\n\t\t\t\t\t\tsearchEndOffset = lineTokens.getEndOffset(tokenIndex);\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// this token should not be searched\r\n\t\t\t\t\tif (prevSearchInToken && searchStartOffset !== searchEndOffset) {\r\n\t\t\t\t\t\tconst r = searchNextMatchingBracketInRange(lineNumber, lineText, searchStartOffset, searchEndOffset);\r\n\t\t\t\t\t\tif (r) {\r\n\t\t\t\t\t\t\treturn r;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tprevSearchInToken = searchInToken;\r\n\t\t\t}\r\n\r\n\t\t\tif (prevSearchInToken && searchStartOffset !== searchEndOffset) {\r\n\t\t\t\tconst r = searchNextMatchingBracketInRange(lineNumber, lineText, searchStartOffset, searchEndOffset);\r\n\t\t\t\tif (r) {\r\n\t\t\t\t\treturn r;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic findPrevBracket(_position: IPosition): model.IFoundBracket | null {\r\n\t\tconst position = this.validatePosition(_position);\r\n\r\n\t\tlet languageId: LanguageId = -1;\r\n\t\tlet modeBrackets: RichEditBrackets | null = null;\r\n\t\tfor (let lineNumber = position.lineNumber; lineNumber >= 1; lineNumber--) {\r\n\t\t\tconst lineTokens = this._getLineTokens(lineNumber);\r\n\t\t\tconst tokenCount = lineTokens.getCount();\r\n\t\t\tconst lineText = this._buffer.getLineContent(lineNumber);\r\n\r\n\t\t\tlet tokenIndex = tokenCount - 1;\r\n\t\t\tlet searchStartOffset = lineText.length;\r\n\t\t\tlet searchEndOffset = lineText.length;\r\n\t\t\tif (lineNumber === position.lineNumber) {\r\n\t\t\t\ttokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1);\r\n\t\t\t\tsearchStartOffset = position.column - 1;\r\n\t\t\t\tsearchEndOffset = position.column - 1;\r\n\t\t\t\tconst tokenLanguageId = lineTokens.getLanguageId(tokenIndex);\r\n\t\t\t\tif (languageId !== tokenLanguageId) {\r\n\t\t\t\t\tlanguageId = tokenLanguageId;\r\n\t\t\t\t\tmodeBrackets = LanguageConfigurationRegistry.getBracketsSupport(languageId);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tlet prevSearchInToken = true;\r\n\t\t\tfor (; tokenIndex >= 0; tokenIndex--) {\r\n\t\t\t\tconst tokenLanguageId = lineTokens.getLanguageId(tokenIndex);\r\n\r\n\t\t\t\tif (languageId !== tokenLanguageId) {\r\n\t\t\t\t\t// language id change!\r\n\t\t\t\t\tif (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) {\r\n\t\t\t\t\t\tconst r = BracketsUtils.findPrevBracketInRange(modeBrackets.reversedRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);\r\n\t\t\t\t\t\tif (r) {\r\n\t\t\t\t\t\t\treturn this._toFoundBracket(modeBrackets, r);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tprevSearchInToken = false;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tlanguageId = tokenLanguageId;\r\n\t\t\t\t\tmodeBrackets = LanguageConfigurationRegistry.getBracketsSupport(languageId);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst searchInToken = (!!modeBrackets && !ignoreBracketsInToken(lineTokens.getStandardTokenType(tokenIndex)));\r\n\r\n\t\t\t\tif (searchInToken) {\r\n\t\t\t\t\t// this token should be searched\r\n\t\t\t\t\tif (prevSearchInToken) {\r\n\t\t\t\t\t\t// the previous token should be searched, simply extend searchStartOffset\r\n\t\t\t\t\t\tsearchStartOffset = lineTokens.getStartOffset(tokenIndex);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t// the previous token should not be searched\r\n\t\t\t\t\t\tsearchStartOffset = lineTokens.getStartOffset(tokenIndex);\r\n\t\t\t\t\t\tsearchEndOffset = lineTokens.getEndOffset(tokenIndex);\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// this token should not be searched\r\n\t\t\t\t\tif (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) {\r\n\t\t\t\t\t\tconst r = BracketsUtils.findPrevBracketInRange(modeBrackets.reversedRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);\r\n\t\t\t\t\t\tif (r) {\r\n\t\t\t\t\t\t\treturn this._toFoundBracket(modeBrackets, r);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tprevSearchInToken = searchInToken;\r\n\t\t\t}\r\n\r\n\t\t\tif (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) {\r\n\t\t\t\tconst r = BracketsUtils.findPrevBracketInRange(modeBrackets.reversedRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);\r\n\t\t\t\tif (r) {\r\n\t\t\t\t\treturn this._toFoundBracket(modeBrackets, r);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic findNextBracket(_position: IPosition): model.IFoundBracket | null {\r\n\t\tconst position = this.validatePosition(_position);\r\n\t\tconst lineCount = this.getLineCount();\r\n\r\n\t\tlet languageId: LanguageId = -1;\r\n\t\tlet modeBrackets: RichEditBrackets | null = null;\r\n\t\tfor (let lineNumber = position.lineNumber; lineNumber <= lineCount; lineNumber++) {\r\n\t\t\tconst lineTokens = this._getLineTokens(lineNumber);\r\n\t\t\tconst tokenCount = lineTokens.getCount();\r\n\t\t\tconst lineText = this._buffer.getLineContent(lineNumber);\r\n\r\n\t\t\tlet tokenIndex = 0;\r\n\t\t\tlet searchStartOffset = 0;\r\n\t\t\tlet searchEndOffset = 0;\r\n\t\t\tif (lineNumber === position.lineNumber) {\r\n\t\t\t\ttokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1);\r\n\t\t\t\tsearchStartOffset = position.column - 1;\r\n\t\t\t\tsearchEndOffset = position.column - 1;\r\n\t\t\t\tconst tokenLanguageId = lineTokens.getLanguageId(tokenIndex);\r\n\t\t\t\tif (languageId !== tokenLanguageId) {\r\n\t\t\t\t\tlanguageId = tokenLanguageId;\r\n\t\t\t\t\tmodeBrackets = LanguageConfigurationRegistry.getBracketsSupport(languageId);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tlet prevSearchInToken = true;\r\n\t\t\tfor (; tokenIndex < tokenCount; tokenIndex++) {\r\n\t\t\t\tconst tokenLanguageId = lineTokens.getLanguageId(tokenIndex);\r\n\r\n\t\t\t\tif (languageId !== tokenLanguageId) {\r\n\t\t\t\t\t// language id change!\r\n\t\t\t\t\tif (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) {\r\n\t\t\t\t\t\tconst r = BracketsUtils.findNextBracketInRange(modeBrackets.forwardRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);\r\n\t\t\t\t\t\tif (r) {\r\n\t\t\t\t\t\t\treturn this._toFoundBracket(modeBrackets, r);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tprevSearchInToken = false;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tlanguageId = tokenLanguageId;\r\n\t\t\t\t\tmodeBrackets = LanguageConfigurationRegistry.getBracketsSupport(languageId);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst searchInToken = (!!modeBrackets && !ignoreBracketsInToken(lineTokens.getStandardTokenType(tokenIndex)));\r\n\t\t\t\tif (searchInToken) {\r\n\t\t\t\t\t// this token should be searched\r\n\t\t\t\t\tif (prevSearchInToken) {\r\n\t\t\t\t\t\t// the previous token should be searched, simply extend searchEndOffset\r\n\t\t\t\t\t\tsearchEndOffset = lineTokens.getEndOffset(tokenIndex);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t// the previous token should not be searched\r\n\t\t\t\t\t\tsearchStartOffset = lineTokens.getStartOffset(tokenIndex);\r\n\t\t\t\t\t\tsearchEndOffset = lineTokens.getEndOffset(tokenIndex);\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// this token should not be searched\r\n\t\t\t\t\tif (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) {\r\n\t\t\t\t\t\tconst r = BracketsUtils.findNextBracketInRange(modeBrackets.forwardRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);\r\n\t\t\t\t\t\tif (r) {\r\n\t\t\t\t\t\t\treturn this._toFoundBracket(modeBrackets, r);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tprevSearchInToken = searchInToken;\r\n\t\t\t}\r\n\r\n\t\t\tif (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) {\r\n\t\t\t\tconst r = BracketsUtils.findNextBracketInRange(modeBrackets.forwardRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);\r\n\t\t\t\tif (r) {\r\n\t\t\t\t\treturn this._toFoundBracket(modeBrackets, r);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic findEnclosingBrackets(_position: IPosition, maxDuration?: number): [Range, Range] | null {\r\n\t\tlet continueSearchPredicate: ContinueBracketSearchPredicate;\r\n\t\tif (typeof maxDuration === 'undefined') {\r\n\t\t\tcontinueSearchPredicate = null;\r\n\t\t} else {\r\n\t\t\tconst startTime = Date.now();\r\n\t\t\tcontinueSearchPredicate = () => {\r\n\t\t\t\treturn (Date.now() - startTime <= maxDuration);\r\n\t\t\t};\r\n\t\t}\r\n\t\tconst position = this.validatePosition(_position);\r\n\t\tconst lineCount = this.getLineCount();\r\n\t\tconst savedCounts = new Map();\r\n\r\n\t\tlet counts: number[] = [];\r\n\t\tconst resetCounts = (languageId: number, modeBrackets: RichEditBrackets | null) => {\r\n\t\t\tif (!savedCounts.has(languageId)) {\r\n\t\t\t\tlet tmp = [];\r\n\t\t\t\tfor (let i = 0, len = modeBrackets ? modeBrackets.brackets.length : 0; i < len; i++) {\r\n\t\t\t\t\ttmp[i] = 0;\r\n\t\t\t\t}\r\n\t\t\t\tsavedCounts.set(languageId, tmp);\r\n\t\t\t}\r\n\t\t\tcounts = savedCounts.get(languageId)!;\r\n\t\t};\r\n\r\n\t\tlet totalCallCount = 0;\r\n\t\tconst searchInRange = (modeBrackets: RichEditBrackets, lineNumber: number, lineText: string, searchStartOffset: number, searchEndOffset: number): [Range, Range] | null | BracketSearchCanceled => {\r\n\t\t\twhile (true) {\r\n\t\t\t\tif (continueSearchPredicate && (++totalCallCount) % 100 === 0 && !continueSearchPredicate()) {\r\n\t\t\t\t\treturn BracketSearchCanceled.INSTANCE;\r\n\t\t\t\t}\r\n\t\t\t\tconst r = BracketsUtils.findNextBracketInRange(modeBrackets.forwardRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);\r\n\t\t\t\tif (!r) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst hitText = lineText.substring(r.startColumn - 1, r.endColumn - 1).toLowerCase();\r\n\t\t\t\tconst bracket = modeBrackets.textIsBracket[hitText];\r\n\t\t\t\tif (bracket) {\r\n\t\t\t\t\tif (bracket.isOpen(hitText)) {\r\n\t\t\t\t\t\tcounts[bracket.index]++;\r\n\t\t\t\t\t} else if (bracket.isClose(hitText)) {\r\n\t\t\t\t\t\tcounts[bracket.index]--;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (counts[bracket.index] === -1) {\r\n\t\t\t\t\t\treturn this._matchFoundBracket(r, bracket, false, continueSearchPredicate);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tsearchStartOffset = r.endColumn - 1;\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t};\r\n\r\n\t\tlet languageId: LanguageId = -1;\r\n\t\tlet modeBrackets: RichEditBrackets | null = null;\r\n\t\tfor (let lineNumber = position.lineNumber; lineNumber <= lineCount; lineNumber++) {\r\n\t\t\tconst lineTokens = this._getLineTokens(lineNumber);\r\n\t\t\tconst tokenCount = lineTokens.getCount();\r\n\t\t\tconst lineText = this._buffer.getLineContent(lineNumber);\r\n\r\n\t\t\tlet tokenIndex = 0;\r\n\t\t\tlet searchStartOffset = 0;\r\n\t\t\tlet searchEndOffset = 0;\r\n\t\t\tif (lineNumber === position.lineNumber) {\r\n\t\t\t\ttokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1);\r\n\t\t\t\tsearchStartOffset = position.column - 1;\r\n\t\t\t\tsearchEndOffset = position.column - 1;\r\n\t\t\t\tconst tokenLanguageId = lineTokens.getLanguageId(tokenIndex);\r\n\t\t\t\tif (languageId !== tokenLanguageId) {\r\n\t\t\t\t\tlanguageId = tokenLanguageId;\r\n\t\t\t\t\tmodeBrackets = LanguageConfigurationRegistry.getBracketsSupport(languageId);\r\n\t\t\t\t\tresetCounts(languageId, modeBrackets);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tlet prevSearchInToken = true;\r\n\t\t\tfor (; tokenIndex < tokenCount; tokenIndex++) {\r\n\t\t\t\tconst tokenLanguageId = lineTokens.getLanguageId(tokenIndex);\r\n\r\n\t\t\t\tif (languageId !== tokenLanguageId) {\r\n\t\t\t\t\t// language id change!\r\n\t\t\t\t\tif (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) {\r\n\t\t\t\t\t\tconst r = searchInRange(modeBrackets, lineNumber, lineText, searchStartOffset, searchEndOffset);\r\n\t\t\t\t\t\tif (r) {\r\n\t\t\t\t\t\t\treturn stripBracketSearchCanceled(r);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tprevSearchInToken = false;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tlanguageId = tokenLanguageId;\r\n\t\t\t\t\tmodeBrackets = LanguageConfigurationRegistry.getBracketsSupport(languageId);\r\n\t\t\t\t\tresetCounts(languageId, modeBrackets);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst searchInToken = (!!modeBrackets && !ignoreBracketsInToken(lineTokens.getStandardTokenType(tokenIndex)));\r\n\t\t\t\tif (searchInToken) {\r\n\t\t\t\t\t// this token should be searched\r\n\t\t\t\t\tif (prevSearchInToken) {\r\n\t\t\t\t\t\t// the previous token should be searched, simply extend searchEndOffset\r\n\t\t\t\t\t\tsearchEndOffset = lineTokens.getEndOffset(tokenIndex);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t// the previous token should not be searched\r\n\t\t\t\t\t\tsearchStartOffset = lineTokens.getStartOffset(tokenIndex);\r\n\t\t\t\t\t\tsearchEndOffset = lineTokens.getEndOffset(tokenIndex);\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// this token should not be searched\r\n\t\t\t\t\tif (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) {\r\n\t\t\t\t\t\tconst r = searchInRange(modeBrackets, lineNumber, lineText, searchStartOffset, searchEndOffset);\r\n\t\t\t\t\t\tif (r) {\r\n\t\t\t\t\t\t\treturn stripBracketSearchCanceled(r);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tprevSearchInToken = searchInToken;\r\n\t\t\t}\r\n\r\n\t\t\tif (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) {\r\n\t\t\t\tconst r = searchInRange(modeBrackets, lineNumber, lineText, searchStartOffset, searchEndOffset);\r\n\t\t\t\tif (r) {\r\n\t\t\t\t\treturn stripBracketSearchCanceled(r);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate _toFoundBracket(modeBrackets: RichEditBrackets, r: Range): model.IFoundBracket | null {\r\n\t\tif (!r) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet text = this.getValueInRange(r);\r\n\t\ttext = text.toLowerCase();\r\n\r\n\t\tlet data = modeBrackets.textIsBracket[text];\r\n\t\tif (!data) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\trange: r,\r\n\t\t\topen: data.open,\r\n\t\t\tclose: data.close,\r\n\t\t\tisOpen: modeBrackets.textIsOpenBracket[text]\r\n\t\t};\r\n\t}\r\n\r\n\t/**\r\n\t * Returns:\r\n\t * - -1 => the line consists of whitespace\r\n\t * - otherwise => the indent level is returned value\r\n\t */\r\n\tpublic static computeIndentLevel(line: string, tabSize: number): number {\r\n\t\tlet indent = 0;\r\n\t\tlet i = 0;\r\n\t\tlet len = line.length;\r\n\r\n\t\twhile (i < len) {\r\n\t\t\tlet chCode = line.charCodeAt(i);\r\n\t\t\tif (chCode === CharCode.Space) {\r\n\t\t\t\tindent++;\r\n\t\t\t} else if (chCode === CharCode.Tab) {\r\n\t\t\t\tindent = indent - indent % tabSize + tabSize;\r\n\t\t\t} else {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\ti++;\r\n\t\t}\r\n\r\n\t\tif (i === len) {\r\n\t\t\treturn -1; // line only consists of whitespace\r\n\t\t}\r\n\r\n\t\treturn indent;\r\n\t}\r\n\r\n\tprivate _computeIndentLevel(lineIndex: number): number {\r\n\t\treturn TextModel.computeIndentLevel(this._buffer.getLineContent(lineIndex + 1), this._options.tabSize);\r\n\t}\r\n\r\n\tpublic getActiveIndentGuide(lineNumber: number, minLineNumber: number, maxLineNumber: number): model.IActiveIndentGuideInfo {\r\n\t\tthis._assertNotDisposed();\r\n\t\tconst lineCount = this.getLineCount();\r\n\r\n\t\tif (lineNumber < 1 || lineNumber > lineCount) {\r\n\t\t\tthrow new Error('Illegal value for lineNumber');\r\n\t\t}\r\n\r\n\t\tconst foldingRules = LanguageConfigurationRegistry.getFoldingRules(this._languageIdentifier.id);\r\n\t\tconst offSide = Boolean(foldingRules && foldingRules.offSide);\r\n\r\n\t\tlet up_aboveContentLineIndex = -2; /* -2 is a marker for not having computed it */\r\n\t\tlet up_aboveContentLineIndent = -1;\r\n\t\tlet up_belowContentLineIndex = -2; /* -2 is a marker for not having computed it */\r\n\t\tlet up_belowContentLineIndent = -1;\r\n\t\tconst up_resolveIndents = (lineNumber: number) => {\r\n\t\t\tif (up_aboveContentLineIndex !== -1 && (up_aboveContentLineIndex === -2 || up_aboveContentLineIndex > lineNumber - 1)) {\r\n\t\t\t\tup_aboveContentLineIndex = -1;\r\n\t\t\t\tup_aboveContentLineIndent = -1;\r\n\r\n\t\t\t\t// must find previous line with content\r\n\t\t\t\tfor (let lineIndex = lineNumber - 2; lineIndex >= 0; lineIndex--) {\r\n\t\t\t\t\tlet indent = this._computeIndentLevel(lineIndex);\r\n\t\t\t\t\tif (indent >= 0) {\r\n\t\t\t\t\t\tup_aboveContentLineIndex = lineIndex;\r\n\t\t\t\t\t\tup_aboveContentLineIndent = indent;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (up_belowContentLineIndex === -2) {\r\n\t\t\t\tup_belowContentLineIndex = -1;\r\n\t\t\t\tup_belowContentLineIndent = -1;\r\n\r\n\t\t\t\t// must find next line with content\r\n\t\t\t\tfor (let lineIndex = lineNumber; lineIndex < lineCount; lineIndex++) {\r\n\t\t\t\t\tlet indent = this._computeIndentLevel(lineIndex);\r\n\t\t\t\t\tif (indent >= 0) {\r\n\t\t\t\t\t\tup_belowContentLineIndex = lineIndex;\r\n\t\t\t\t\t\tup_belowContentLineIndent = indent;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tlet down_aboveContentLineIndex = -2; /* -2 is a marker for not having computed it */\r\n\t\tlet down_aboveContentLineIndent = -1;\r\n\t\tlet down_belowContentLineIndex = -2; /* -2 is a marker for not having computed it */\r\n\t\tlet down_belowContentLineIndent = -1;\r\n\t\tconst down_resolveIndents = (lineNumber: number) => {\r\n\t\t\tif (down_aboveContentLineIndex === -2) {\r\n\t\t\t\tdown_aboveContentLineIndex = -1;\r\n\t\t\t\tdown_aboveContentLineIndent = -1;\r\n\r\n\t\t\t\t// must find previous line with content\r\n\t\t\t\tfor (let lineIndex = lineNumber - 2; lineIndex >= 0; lineIndex--) {\r\n\t\t\t\t\tlet indent = this._computeIndentLevel(lineIndex);\r\n\t\t\t\t\tif (indent >= 0) {\r\n\t\t\t\t\t\tdown_aboveContentLineIndex = lineIndex;\r\n\t\t\t\t\t\tdown_aboveContentLineIndent = indent;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (down_belowContentLineIndex !== -1 && (down_belowContentLineIndex === -2 || down_belowContentLineIndex < lineNumber - 1)) {\r\n\t\t\t\tdown_belowContentLineIndex = -1;\r\n\t\t\t\tdown_belowContentLineIndent = -1;\r\n\r\n\t\t\t\t// must find next line with content\r\n\t\t\t\tfor (let lineIndex = lineNumber; lineIndex < lineCount; lineIndex++) {\r\n\t\t\t\t\tlet indent = this._computeIndentLevel(lineIndex);\r\n\t\t\t\t\tif (indent >= 0) {\r\n\t\t\t\t\t\tdown_belowContentLineIndex = lineIndex;\r\n\t\t\t\t\t\tdown_belowContentLineIndent = indent;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tlet startLineNumber = 0;\r\n\t\tlet goUp = true;\r\n\t\tlet endLineNumber = 0;\r\n\t\tlet goDown = true;\r\n\t\tlet indent = 0;\r\n\r\n\t\tlet initialIndent = 0;\r\n\r\n\t\tfor (let distance = 0; goUp || goDown; distance++) {\r\n\t\t\tconst upLineNumber = lineNumber - distance;\r\n\t\t\tconst downLineNumber = lineNumber + distance;\r\n\r\n\t\t\tif (distance > 1 && (upLineNumber < 1 || upLineNumber < minLineNumber)) {\r\n\t\t\t\tgoUp = false;\r\n\t\t\t}\r\n\t\t\tif (distance > 1 && (downLineNumber > lineCount || downLineNumber > maxLineNumber)) {\r\n\t\t\t\tgoDown = false;\r\n\t\t\t}\r\n\t\t\tif (distance > 50000) {\r\n\t\t\t\t// stop processing\r\n\t\t\t\tgoUp = false;\r\n\t\t\t\tgoDown = false;\r\n\t\t\t}\r\n\r\n\t\t\tlet upLineIndentLevel: number = -1;\r\n\t\t\tif (goUp) {\r\n\t\t\t\t// compute indent level going up\r\n\t\t\t\tconst currentIndent = this._computeIndentLevel(upLineNumber - 1);\r\n\t\t\t\tif (currentIndent >= 0) {\r\n\t\t\t\t\t// This line has content (besides whitespace)\r\n\t\t\t\t\t// Use the line's indent\r\n\t\t\t\t\tup_belowContentLineIndex = upLineNumber - 1;\r\n\t\t\t\t\tup_belowContentLineIndent = currentIndent;\r\n\t\t\t\t\tupLineIndentLevel = Math.ceil(currentIndent / this._options.indentSize);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tup_resolveIndents(upLineNumber);\r\n\t\t\t\t\tupLineIndentLevel = this._getIndentLevelForWhitespaceLine(offSide, up_aboveContentLineIndent, up_belowContentLineIndent);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tlet downLineIndentLevel = -1;\r\n\t\t\tif (goDown) {\r\n\t\t\t\t// compute indent level going down\r\n\t\t\t\tconst currentIndent = this._computeIndentLevel(downLineNumber - 1);\r\n\t\t\t\tif (currentIndent >= 0) {\r\n\t\t\t\t\t// This line has content (besides whitespace)\r\n\t\t\t\t\t// Use the line's indent\r\n\t\t\t\t\tdown_aboveContentLineIndex = downLineNumber - 1;\r\n\t\t\t\t\tdown_aboveContentLineIndent = currentIndent;\r\n\t\t\t\t\tdownLineIndentLevel = Math.ceil(currentIndent / this._options.indentSize);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tdown_resolveIndents(downLineNumber);\r\n\t\t\t\t\tdownLineIndentLevel = this._getIndentLevelForWhitespaceLine(offSide, down_aboveContentLineIndent, down_belowContentLineIndent);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (distance === 0) {\r\n\t\t\t\tinitialIndent = upLineIndentLevel;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (distance === 1) {\r\n\t\t\t\tif (downLineNumber <= lineCount && downLineIndentLevel >= 0 && initialIndent + 1 === downLineIndentLevel) {\r\n\t\t\t\t\t// This is the beginning of a scope, we have special handling here, since we want the\r\n\t\t\t\t\t// child scope indent to be active, not the parent scope\r\n\t\t\t\t\tgoUp = false;\r\n\t\t\t\t\tstartLineNumber = downLineNumber;\r\n\t\t\t\t\tendLineNumber = downLineNumber;\r\n\t\t\t\t\tindent = downLineIndentLevel;\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (upLineNumber >= 1 && upLineIndentLevel >= 0 && upLineIndentLevel - 1 === initialIndent) {\r\n\t\t\t\t\t// This is the end of a scope, just like above\r\n\t\t\t\t\tgoDown = false;\r\n\t\t\t\t\tstartLineNumber = upLineNumber;\r\n\t\t\t\t\tendLineNumber = upLineNumber;\r\n\t\t\t\t\tindent = upLineIndentLevel;\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tstartLineNumber = lineNumber;\r\n\t\t\t\tendLineNumber = lineNumber;\r\n\t\t\t\tindent = initialIndent;\r\n\t\t\t\tif (indent === 0) {\r\n\t\t\t\t\t// No need to continue\r\n\t\t\t\t\treturn { startLineNumber, endLineNumber, indent };\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (goUp) {\r\n\t\t\t\tif (upLineIndentLevel >= indent) {\r\n\t\t\t\t\tstartLineNumber = upLineNumber;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tgoUp = false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (goDown) {\r\n\t\t\t\tif (downLineIndentLevel >= indent) {\r\n\t\t\t\t\tendLineNumber = downLineNumber;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tgoDown = false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn { startLineNumber, endLineNumber, indent };\r\n\t}\r\n\r\n\tpublic getLinesIndentGuides(startLineNumber: number, endLineNumber: number): number[] {\r\n\t\tthis._assertNotDisposed();\r\n\t\tconst lineCount = this.getLineCount();\r\n\r\n\t\tif (startLineNumber < 1 || startLineNumber > lineCount) {\r\n\t\t\tthrow new Error('Illegal value for startLineNumber');\r\n\t\t}\r\n\t\tif (endLineNumber < 1 || endLineNumber > lineCount) {\r\n\t\t\tthrow new Error('Illegal value for endLineNumber');\r\n\t\t}\r\n\r\n\t\tconst foldingRules = LanguageConfigurationRegistry.getFoldingRules(this._languageIdentifier.id);\r\n\t\tconst offSide = Boolean(foldingRules && foldingRules.offSide);\r\n\r\n\t\tlet result: number[] = new Array(endLineNumber - startLineNumber + 1);\r\n\r\n\t\tlet aboveContentLineIndex = -2; /* -2 is a marker for not having computed it */\r\n\t\tlet aboveContentLineIndent = -1;\r\n\r\n\t\tlet belowContentLineIndex = -2; /* -2 is a marker for not having computed it */\r\n\t\tlet belowContentLineIndent = -1;\r\n\r\n\t\tfor (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {\r\n\t\t\tlet resultIndex = lineNumber - startLineNumber;\r\n\r\n\t\t\tconst currentIndent = this._computeIndentLevel(lineNumber - 1);\r\n\t\t\tif (currentIndent >= 0) {\r\n\t\t\t\t// This line has content (besides whitespace)\r\n\t\t\t\t// Use the line's indent\r\n\t\t\t\taboveContentLineIndex = lineNumber - 1;\r\n\t\t\t\taboveContentLineIndent = currentIndent;\r\n\t\t\t\tresult[resultIndex] = Math.ceil(currentIndent / this._options.indentSize);\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (aboveContentLineIndex === -2) {\r\n\t\t\t\taboveContentLineIndex = -1;\r\n\t\t\t\taboveContentLineIndent = -1;\r\n\r\n\t\t\t\t// must find previous line with content\r\n\t\t\t\tfor (let lineIndex = lineNumber - 2; lineIndex >= 0; lineIndex--) {\r\n\t\t\t\t\tlet indent = this._computeIndentLevel(lineIndex);\r\n\t\t\t\t\tif (indent >= 0) {\r\n\t\t\t\t\t\taboveContentLineIndex = lineIndex;\r\n\t\t\t\t\t\taboveContentLineIndent = indent;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (belowContentLineIndex !== -1 && (belowContentLineIndex === -2 || belowContentLineIndex < lineNumber - 1)) {\r\n\t\t\t\tbelowContentLineIndex = -1;\r\n\t\t\t\tbelowContentLineIndent = -1;\r\n\r\n\t\t\t\t// must find next line with content\r\n\t\t\t\tfor (let lineIndex = lineNumber; lineIndex < lineCount; lineIndex++) {\r\n\t\t\t\t\tlet indent = this._computeIndentLevel(lineIndex);\r\n\t\t\t\t\tif (indent >= 0) {\r\n\t\t\t\t\t\tbelowContentLineIndex = lineIndex;\r\n\t\t\t\t\t\tbelowContentLineIndent = indent;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tresult[resultIndex] = this._getIndentLevelForWhitespaceLine(offSide, aboveContentLineIndent, belowContentLineIndent);\r\n\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate _getIndentLevelForWhitespaceLine(offSide: boolean, aboveContentLineIndent: number, belowContentLineIndent: number): number {\r\n\t\tif (aboveContentLineIndent === -1 || belowContentLineIndent === -1) {\r\n\t\t\t// At the top or bottom of the file\r\n\t\t\treturn 0;\r\n\r\n\t\t} else if (aboveContentLineIndent < belowContentLineIndent) {\r\n\t\t\t// we are inside the region above\r\n\t\t\treturn (1 + Math.floor(aboveContentLineIndent / this._options.indentSize));\r\n\r\n\t\t} else if (aboveContentLineIndent === belowContentLineIndent) {\r\n\t\t\t// we are in between two regions\r\n\t\t\treturn Math.ceil(belowContentLineIndent / this._options.indentSize);\r\n\r\n\t\t} else {\r\n\r\n\t\t\tif (offSide) {\r\n\t\t\t\t// same level as region below\r\n\t\t\t\treturn Math.ceil(belowContentLineIndent / this._options.indentSize);\r\n\t\t\t} else {\r\n\t\t\t\t// we are inside the region that ends below\r\n\t\t\t\treturn (1 + Math.floor(belowContentLineIndent / this._options.indentSize));\r\n\t\t\t}\r\n\r\n\t\t}\r\n\t}\r\n\r\n\t//#endregion\r\n}\r\n\r\n//#region Decorations\r\n\r\nclass DecorationsTrees {\r\n\r\n\t/**\r\n\t * This tree holds decorations that do not show up in the overview ruler.\r\n\t */\r\n\tprivate readonly _decorationsTree0: IntervalTree;\r\n\r\n\t/**\r\n\t * This tree holds decorations that show up in the overview ruler.\r\n\t */\r\n\tprivate readonly _decorationsTree1: IntervalTree;\r\n\r\n\tconstructor() {\r\n\t\tthis._decorationsTree0 = new IntervalTree();\r\n\t\tthis._decorationsTree1 = new IntervalTree();\r\n\t}\r\n\r\n\tpublic intervalSearch(start: number, end: number, filterOwnerId: number, filterOutValidation: boolean, cachedVersionId: number): IntervalNode[] {\r\n\t\tconst r0 = this._decorationsTree0.intervalSearch(start, end, filterOwnerId, filterOutValidation, cachedVersionId);\r\n\t\tconst r1 = this._decorationsTree1.intervalSearch(start, end, filterOwnerId, filterOutValidation, cachedVersionId);\r\n\t\treturn r0.concat(r1);\r\n\t}\r\n\r\n\tpublic search(filterOwnerId: number, filterOutValidation: boolean, overviewRulerOnly: boolean, cachedVersionId: number): IntervalNode[] {\r\n\t\tif (overviewRulerOnly) {\r\n\t\t\treturn this._decorationsTree1.search(filterOwnerId, filterOutValidation, cachedVersionId);\r\n\t\t} else {\r\n\t\t\tconst r0 = this._decorationsTree0.search(filterOwnerId, filterOutValidation, cachedVersionId);\r\n\t\t\tconst r1 = this._decorationsTree1.search(filterOwnerId, filterOutValidation, cachedVersionId);\r\n\t\t\treturn r0.concat(r1);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic collectNodesFromOwner(ownerId: number): IntervalNode[] {\r\n\t\tconst r0 = this._decorationsTree0.collectNodesFromOwner(ownerId);\r\n\t\tconst r1 = this._decorationsTree1.collectNodesFromOwner(ownerId);\r\n\t\treturn r0.concat(r1);\r\n\t}\r\n\r\n\tpublic collectNodesPostOrder(): IntervalNode[] {\r\n\t\tconst r0 = this._decorationsTree0.collectNodesPostOrder();\r\n\t\tconst r1 = this._decorationsTree1.collectNodesPostOrder();\r\n\t\treturn r0.concat(r1);\r\n\t}\r\n\r\n\tpublic insert(node: IntervalNode): void {\r\n\t\tif (getNodeIsInOverviewRuler(node)) {\r\n\t\t\tthis._decorationsTree1.insert(node);\r\n\t\t} else {\r\n\t\t\tthis._decorationsTree0.insert(node);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic delete(node: IntervalNode): void {\r\n\t\tif (getNodeIsInOverviewRuler(node)) {\r\n\t\t\tthis._decorationsTree1.delete(node);\r\n\t\t} else {\r\n\t\t\tthis._decorationsTree0.delete(node);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic resolveNode(node: IntervalNode, cachedVersionId: number): void {\r\n\t\tif (getNodeIsInOverviewRuler(node)) {\r\n\t\t\tthis._decorationsTree1.resolveNode(node, cachedVersionId);\r\n\t\t} else {\r\n\t\t\tthis._decorationsTree0.resolveNode(node, cachedVersionId);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic acceptReplace(offset: number, length: number, textLength: number, forceMoveMarkers: boolean): void {\r\n\t\tthis._decorationsTree0.acceptReplace(offset, length, textLength, forceMoveMarkers);\r\n\t\tthis._decorationsTree1.acceptReplace(offset, length, textLength, forceMoveMarkers);\r\n\t}\r\n}\r\n\r\nfunction cleanClassName(className: string): string {\r\n\treturn className.replace(/[^a-z0-9\\-_]/gi, ' ');\r\n}\r\n\r\nclass DecorationOptions implements model.IDecorationOptions {\r\n\treadonly color: string | ThemeColor;\r\n\treadonly darkColor: string | ThemeColor;\r\n\r\n\tconstructor(options: model.IDecorationOptions) {\r\n\t\tthis.color = options.color || '';\r\n\t\tthis.darkColor = options.darkColor || '';\r\n\r\n\t}\r\n}\r\n\r\nexport class ModelDecorationOverviewRulerOptions extends DecorationOptions {\r\n\treadonly position: model.OverviewRulerLane;\r\n\tprivate _resolvedColor: string | null;\r\n\r\n\tconstructor(options: model.IModelDecorationOverviewRulerOptions) {\r\n\t\tsuper(options);\r\n\t\tthis._resolvedColor = null;\r\n\t\tthis.position = (typeof options.position === 'number' ? options.position : model.OverviewRulerLane.Center);\r\n\t}\r\n\r\n\tpublic getColor(theme: EditorTheme): string {\r\n\t\tif (!this._resolvedColor) {\r\n\t\t\tif (theme.type !== 'light' && this.darkColor) {\r\n\t\t\t\tthis._resolvedColor = this._resolveColor(this.darkColor, theme);\r\n\t\t\t} else {\r\n\t\t\t\tthis._resolvedColor = this._resolveColor(this.color, theme);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this._resolvedColor;\r\n\t}\r\n\r\n\tpublic invalidateCachedColor(): void {\r\n\t\tthis._resolvedColor = null;\r\n\t}\r\n\r\n\tprivate _resolveColor(color: string | ThemeColor, theme: EditorTheme): string {\r\n\t\tif (typeof color === 'string') {\r\n\t\t\treturn color;\r\n\t\t}\r\n\t\tlet c = color ? theme.getColor(color.id) : null;\r\n\t\tif (!c) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\treturn c.toString();\r\n\t}\r\n}\r\n\r\nexport class ModelDecorationMinimapOptions extends DecorationOptions {\r\n\treadonly position: model.MinimapPosition;\r\n\tprivate _resolvedColor: Color | undefined;\r\n\r\n\r\n\tconstructor(options: model.IModelDecorationMinimapOptions) {\r\n\t\tsuper(options);\r\n\t\tthis.position = options.position;\r\n\t}\r\n\r\n\tpublic getColor(theme: EditorTheme): Color | undefined {\r\n\t\tif (!this._resolvedColor) {\r\n\t\t\tif (theme.type !== 'light' && this.darkColor) {\r\n\t\t\t\tthis._resolvedColor = this._resolveColor(this.darkColor, theme);\r\n\t\t\t} else {\r\n\t\t\t\tthis._resolvedColor = this._resolveColor(this.color, theme);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this._resolvedColor;\r\n\t}\r\n\r\n\tpublic invalidateCachedColor(): void {\r\n\t\tthis._resolvedColor = undefined;\r\n\t}\r\n\r\n\tprivate _resolveColor(color: string | ThemeColor, theme: EditorTheme): Color | undefined {\r\n\t\tif (typeof color === 'string') {\r\n\t\t\treturn Color.fromHex(color);\r\n\t\t}\r\n\t\treturn theme.getColor(color.id);\r\n\t}\r\n}\r\n\r\nexport class ModelDecorationOptions implements model.IModelDecorationOptions {\r\n\r\n\tpublic static EMPTY: ModelDecorationOptions;\r\n\r\n\tpublic static register(options: model.IModelDecorationOptions): ModelDecorationOptions {\r\n\t\treturn new ModelDecorationOptions(options);\r\n\t}\r\n\r\n\tpublic static createDynamic(options: model.IModelDecorationOptions): ModelDecorationOptions {\r\n\t\treturn new ModelDecorationOptions(options);\r\n\t}\r\n\r\n\treadonly stickiness: model.TrackedRangeStickiness;\r\n\treadonly zIndex: number;\r\n\treadonly className: string | null;\r\n\treadonly hoverMessage: IMarkdownString | IMarkdownString[] | null;\r\n\treadonly glyphMarginHoverMessage: IMarkdownString | IMarkdownString[] | null;\r\n\treadonly isWholeLine: boolean;\r\n\treadonly showIfCollapsed: boolean;\r\n\treadonly collapseOnReplaceEdit: boolean;\r\n\treadonly overviewRuler: ModelDecorationOverviewRulerOptions | null;\r\n\treadonly minimap: ModelDecorationMinimapOptions | null;\r\n\treadonly glyphMarginClassName: string | null;\r\n\treadonly linesDecorationsClassName: string | null;\r\n\treadonly firstLineDecorationClassName: string | null;\r\n\treadonly marginClassName: string | null;\r\n\treadonly inlineClassName: string | null;\r\n\treadonly inlineClassNameAffectsLetterSpacing: boolean;\r\n\treadonly beforeContentClassName: string | null;\r\n\treadonly afterContentClassName: string | null;\r\n\r\n\tprivate constructor(options: model.IModelDecorationOptions) {\r\n\t\tthis.stickiness = options.stickiness || model.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges;\r\n\t\tthis.zIndex = options.zIndex || 0;\r\n\t\tthis.className = options.className ? cleanClassName(options.className) : null;\r\n\t\tthis.hoverMessage = options.hoverMessage || null;\r\n\t\tthis.glyphMarginHoverMessage = options.glyphMarginHoverMessage || null;\r\n\t\tthis.isWholeLine = options.isWholeLine || false;\r\n\t\tthis.showIfCollapsed = options.showIfCollapsed || false;\r\n\t\tthis.collapseOnReplaceEdit = options.collapseOnReplaceEdit || false;\r\n\t\tthis.overviewRuler = options.overviewRuler ? new ModelDecorationOverviewRulerOptions(options.overviewRuler) : null;\r\n\t\tthis.minimap = options.minimap ? new ModelDecorationMinimapOptions(options.minimap) : null;\r\n\t\tthis.glyphMarginClassName = options.glyphMarginClassName ? cleanClassName(options.glyphMarginClassName) : null;\r\n\t\tthis.linesDecorationsClassName = options.linesDecorationsClassName ? cleanClassName(options.linesDecorationsClassName) : null;\r\n\t\tthis.firstLineDecorationClassName = options.firstLineDecorationClassName ? cleanClassName(options.firstLineDecorationClassName) : null;\r\n\t\tthis.marginClassName = options.marginClassName ? cleanClassName(options.marginClassName) : null;\r\n\t\tthis.inlineClassName = options.inlineClassName ? cleanClassName(options.inlineClassName) : null;\r\n\t\tthis.inlineClassNameAffectsLetterSpacing = options.inlineClassNameAffectsLetterSpacing || false;\r\n\t\tthis.beforeContentClassName = options.beforeContentClassName ? cleanClassName(options.beforeContentClassName) : null;\r\n\t\tthis.afterContentClassName = options.afterContentClassName ? cleanClassName(options.afterContentClassName) : null;\r\n\t}\r\n}\r\nModelDecorationOptions.EMPTY = ModelDecorationOptions.register({});\r\n\r\n/**\r\n * The order carefully matches the values of the enum.\r\n */\r\nconst TRACKED_RANGE_OPTIONS = [\r\n\tModelDecorationOptions.register({ stickiness: model.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges }),\r\n\tModelDecorationOptions.register({ stickiness: model.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges }),\r\n\tModelDecorationOptions.register({ stickiness: model.TrackedRangeStickiness.GrowsOnlyWhenTypingBefore }),\r\n\tModelDecorationOptions.register({ stickiness: model.TrackedRangeStickiness.GrowsOnlyWhenTypingAfter }),\r\n];\r\n\r\nfunction _normalizeOptions(options: model.IModelDecorationOptions): ModelDecorationOptions {\r\n\tif (options instanceof ModelDecorationOptions) {\r\n\t\treturn options;\r\n\t}\r\n\treturn ModelDecorationOptions.createDynamic(options);\r\n}\r\n\r\nexport class DidChangeDecorationsEmitter extends Disposable {\r\n\r\n\tprivate readonly _actual: Emitter = this._register(new Emitter());\r\n\tpublic readonly event: Event = this._actual.event;\r\n\r\n\tprivate _deferredCnt: number;\r\n\tprivate _shouldFire: boolean;\r\n\tprivate _affectsMinimap: boolean;\r\n\tprivate _affectsOverviewRuler: boolean;\r\n\r\n\tconstructor() {\r\n\t\tsuper();\r\n\t\tthis._deferredCnt = 0;\r\n\t\tthis._shouldFire = false;\r\n\t\tthis._affectsMinimap = false;\r\n\t\tthis._affectsOverviewRuler = false;\r\n\t}\r\n\r\n\tpublic beginDeferredEmit(): void {\r\n\t\tthis._deferredCnt++;\r\n\t}\r\n\r\n\tpublic endDeferredEmit(): void {\r\n\t\tthis._deferredCnt--;\r\n\t\tif (this._deferredCnt === 0) {\r\n\t\t\tif (this._shouldFire) {\r\n\t\t\t\tconst event: IModelDecorationsChangedEvent = {\r\n\t\t\t\t\taffectsMinimap: this._affectsMinimap,\r\n\t\t\t\t\taffectsOverviewRuler: this._affectsOverviewRuler,\r\n\t\t\t\t};\r\n\t\t\t\tthis._shouldFire = false;\r\n\t\t\t\tthis._affectsMinimap = false;\r\n\t\t\t\tthis._affectsOverviewRuler = false;\r\n\t\t\t\tthis._actual.fire(event);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic checkAffectedAndFire(options: ModelDecorationOptions): void {\r\n\t\tif (!this._affectsMinimap) {\r\n\t\t\tthis._affectsMinimap = options.minimap && options.minimap.position ? true : false;\r\n\t\t}\r\n\t\tif (!this._affectsOverviewRuler) {\r\n\t\t\tthis._affectsOverviewRuler = options.overviewRuler && options.overviewRuler.color ? true : false;\r\n\t\t}\r\n\t\tthis._shouldFire = true;\r\n\t}\r\n\r\n\tpublic fire(): void {\r\n\t\tthis._affectsMinimap = true;\r\n\t\tthis._affectsOverviewRuler = true;\r\n\t\tthis._shouldFire = true;\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\nexport class DidChangeContentEmitter extends Disposable {\r\n\r\n\t/**\r\n\t * Both `fastEvent` and `slowEvent` work the same way and contain the same events, but first we invoke `fastEvent` and then `slowEvent`.\r\n\t */\r\n\tprivate readonly _fastEmitter: Emitter = this._register(new Emitter());\r\n\tpublic readonly fastEvent: Event = this._fastEmitter.event;\r\n\tprivate readonly _slowEmitter: Emitter = this._register(new Emitter());\r\n\tpublic readonly slowEvent: Event = this._slowEmitter.event;\r\n\r\n\tprivate _deferredCnt: number;\r\n\tprivate _deferredEvent: InternalModelContentChangeEvent | null;\r\n\r\n\tconstructor() {\r\n\t\tsuper();\r\n\t\tthis._deferredCnt = 0;\r\n\t\tthis._deferredEvent = null;\r\n\t}\r\n\r\n\tpublic beginDeferredEmit(): void {\r\n\t\tthis._deferredCnt++;\r\n\t}\r\n\r\n\tpublic endDeferredEmit(resultingSelection: Selection[] | null = null): void {\r\n\t\tthis._deferredCnt--;\r\n\t\tif (this._deferredCnt === 0) {\r\n\t\t\tif (this._deferredEvent !== null) {\r\n\t\t\t\tthis._deferredEvent.rawContentChangedEvent.resultingSelection = resultingSelection;\r\n\t\t\t\tconst e = this._deferredEvent;\r\n\t\t\t\tthis._deferredEvent = null;\r\n\t\t\t\tthis._fastEmitter.fire(e);\r\n\t\t\t\tthis._slowEmitter.fire(e);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic fire(e: InternalModelContentChangeEvent): void {\r\n\t\tif (this._deferredCnt > 0) {\r\n\t\t\tif (this._deferredEvent) {\r\n\t\t\t\tthis._deferredEvent = this._deferredEvent.merge(e);\r\n\t\t\t} else {\r\n\t\t\t\tthis._deferredEvent = e;\r\n\t\t\t}\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._fastEmitter.fire(e);\r\n\t\tthis._slowEmitter.fire(e);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { EditorAutoClosingStrategy, EditorAutoSurroundStrategy, ConfigurationChangedEvent, EditorAutoClosingOvertypeStrategy, EditorOption, EditorAutoIndentStrategy } from 'vs/editor/common/config/editorOptions';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { ISelection, Selection } from 'vs/editor/common/core/selection';\r\nimport { ICommand, IConfiguration } from 'vs/editor/common/editorCommon';\r\nimport { ITextModel, TextModelResolvedOptions } from 'vs/editor/common/model';\r\nimport { TextModel } from 'vs/editor/common/model/textModel';\r\nimport { LanguageIdentifier } from 'vs/editor/common/modes';\r\nimport { AutoClosingPairs, IAutoClosingPair } from 'vs/editor/common/modes/languageConfiguration';\r\nimport { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';\r\nimport { ICoordinatesConverter } from 'vs/editor/common/viewModel/viewModel';\r\nimport { Constants } from 'vs/base/common/uint';\r\n\r\nexport interface IColumnSelectData {\r\n\tisReal: boolean;\r\n\tfromViewLineNumber: number;\r\n\tfromViewVisualColumn: number;\r\n\ttoViewLineNumber: number;\r\n\ttoViewVisualColumn: number;\r\n}\r\n\r\n/**\r\n * This is an operation type that will be recorded for undo/redo purposes.\r\n * The goal is to introduce an undo stop when the controller switches between different operation types.\r\n */\r\nexport const enum EditOperationType {\r\n\tOther = 0,\r\n\tTyping = 1,\r\n\tDeletingLeft = 2,\r\n\tDeletingRight = 3\r\n}\r\n\r\nexport interface CharacterMap {\r\n\t[char: string]: string;\r\n}\r\n\r\nconst autoCloseAlways = () => true;\r\nconst autoCloseNever = () => false;\r\nconst autoCloseBeforeWhitespace = (chr: string) => (chr === ' ' || chr === '\\t');\r\n\r\nexport class CursorConfiguration {\r\n\t_cursorMoveConfigurationBrand: void;\r\n\r\n\tpublic readonly readOnly: boolean;\r\n\tpublic readonly tabSize: number;\r\n\tpublic readonly indentSize: number;\r\n\tpublic readonly insertSpaces: boolean;\r\n\tpublic readonly stickyTabStops: boolean;\r\n\tpublic readonly pageSize: number;\r\n\tpublic readonly lineHeight: number;\r\n\tpublic readonly useTabStops: boolean;\r\n\tpublic readonly wordSeparators: string;\r\n\tpublic readonly emptySelectionClipboard: boolean;\r\n\tpublic readonly copyWithSyntaxHighlighting: boolean;\r\n\tpublic readonly multiCursorMergeOverlapping: boolean;\r\n\tpublic readonly multiCursorPaste: 'spread' | 'full';\r\n\tpublic readonly autoClosingBrackets: EditorAutoClosingStrategy;\r\n\tpublic readonly autoClosingQuotes: EditorAutoClosingStrategy;\r\n\tpublic readonly autoClosingOvertype: EditorAutoClosingOvertypeStrategy;\r\n\tpublic readonly autoSurround: EditorAutoSurroundStrategy;\r\n\tpublic readonly autoIndent: EditorAutoIndentStrategy;\r\n\tpublic readonly autoClosingPairs: AutoClosingPairs;\r\n\tpublic readonly surroundingPairs: CharacterMap;\r\n\tpublic readonly shouldAutoCloseBefore: { quote: (ch: string) => boolean, bracket: (ch: string) => boolean };\r\n\r\n\tprivate readonly _languageIdentifier: LanguageIdentifier;\r\n\tprivate _electricChars: { [key: string]: boolean; } | null;\r\n\r\n\tpublic static shouldRecreate(e: ConfigurationChangedEvent): boolean {\r\n\t\treturn (\r\n\t\t\te.hasChanged(EditorOption.layoutInfo)\r\n\t\t\t|| e.hasChanged(EditorOption.wordSeparators)\r\n\t\t\t|| e.hasChanged(EditorOption.emptySelectionClipboard)\r\n\t\t\t|| e.hasChanged(EditorOption.multiCursorMergeOverlapping)\r\n\t\t\t|| e.hasChanged(EditorOption.multiCursorPaste)\r\n\t\t\t|| e.hasChanged(EditorOption.autoClosingBrackets)\r\n\t\t\t|| e.hasChanged(EditorOption.autoClosingQuotes)\r\n\t\t\t|| e.hasChanged(EditorOption.autoClosingOvertype)\r\n\t\t\t|| e.hasChanged(EditorOption.autoSurround)\r\n\t\t\t|| e.hasChanged(EditorOption.useTabStops)\r\n\t\t\t|| e.hasChanged(EditorOption.lineHeight)\r\n\t\t\t|| e.hasChanged(EditorOption.readOnly)\r\n\t\t);\r\n\t}\r\n\r\n\tconstructor(\r\n\t\tlanguageIdentifier: LanguageIdentifier,\r\n\t\tmodelOptions: TextModelResolvedOptions,\r\n\t\tconfiguration: IConfiguration\r\n\t) {\r\n\t\tthis._languageIdentifier = languageIdentifier;\r\n\r\n\t\tconst options = configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\r\n\t\tthis.readOnly = options.get(EditorOption.readOnly);\r\n\t\tthis.tabSize = modelOptions.tabSize;\r\n\t\tthis.indentSize = modelOptions.indentSize;\r\n\t\tthis.insertSpaces = modelOptions.insertSpaces;\r\n\t\tthis.stickyTabStops = options.get(EditorOption.stickyTabStops);\r\n\t\tthis.lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tthis.pageSize = Math.max(1, Math.floor(layoutInfo.height / this.lineHeight) - 2);\r\n\t\tthis.useTabStops = options.get(EditorOption.useTabStops);\r\n\t\tthis.wordSeparators = options.get(EditorOption.wordSeparators);\r\n\t\tthis.emptySelectionClipboard = options.get(EditorOption.emptySelectionClipboard);\r\n\t\tthis.copyWithSyntaxHighlighting = options.get(EditorOption.copyWithSyntaxHighlighting);\r\n\t\tthis.multiCursorMergeOverlapping = options.get(EditorOption.multiCursorMergeOverlapping);\r\n\t\tthis.multiCursorPaste = options.get(EditorOption.multiCursorPaste);\r\n\t\tthis.autoClosingBrackets = options.get(EditorOption.autoClosingBrackets);\r\n\t\tthis.autoClosingQuotes = options.get(EditorOption.autoClosingQuotes);\r\n\t\tthis.autoClosingOvertype = options.get(EditorOption.autoClosingOvertype);\r\n\t\tthis.autoSurround = options.get(EditorOption.autoSurround);\r\n\t\tthis.autoIndent = options.get(EditorOption.autoIndent);\r\n\r\n\t\tthis.surroundingPairs = {};\r\n\t\tthis._electricChars = null;\r\n\r\n\t\tthis.shouldAutoCloseBefore = {\r\n\t\t\tquote: CursorConfiguration._getShouldAutoClose(languageIdentifier, this.autoClosingQuotes),\r\n\t\t\tbracket: CursorConfiguration._getShouldAutoClose(languageIdentifier, this.autoClosingBrackets)\r\n\t\t};\r\n\r\n\t\tthis.autoClosingPairs = LanguageConfigurationRegistry.getAutoClosingPairs(languageIdentifier.id);\r\n\r\n\t\tlet surroundingPairs = CursorConfiguration._getSurroundingPairs(languageIdentifier);\r\n\t\tif (surroundingPairs) {\r\n\t\t\tfor (const pair of surroundingPairs) {\r\n\t\t\t\tthis.surroundingPairs[pair.open] = pair.close;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic get electricChars() {\r\n\t\tif (!this._electricChars) {\r\n\t\t\tthis._electricChars = {};\r\n\t\t\tlet electricChars = CursorConfiguration._getElectricCharacters(this._languageIdentifier);\r\n\t\t\tif (electricChars) {\r\n\t\t\t\tfor (const char of electricChars) {\r\n\t\t\t\t\tthis._electricChars[char] = true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this._electricChars;\r\n\t}\r\n\r\n\tpublic normalizeIndentation(str: string): string {\r\n\t\treturn TextModel.normalizeIndentation(str, this.indentSize, this.insertSpaces);\r\n\t}\r\n\r\n\tprivate static _getElectricCharacters(languageIdentifier: LanguageIdentifier): string[] | null {\r\n\t\ttry {\r\n\t\t\treturn LanguageConfigurationRegistry.getElectricCharacters(languageIdentifier.id);\r\n\t\t} catch (e) {\r\n\t\t\tonUnexpectedError(e);\r\n\t\t\treturn null;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static _getShouldAutoClose(languageIdentifier: LanguageIdentifier, autoCloseConfig: EditorAutoClosingStrategy): (ch: string) => boolean {\r\n\t\tswitch (autoCloseConfig) {\r\n\t\t\tcase 'beforeWhitespace':\r\n\t\t\t\treturn autoCloseBeforeWhitespace;\r\n\t\t\tcase 'languageDefined':\r\n\t\t\t\treturn CursorConfiguration._getLanguageDefinedShouldAutoClose(languageIdentifier);\r\n\t\t\tcase 'always':\r\n\t\t\t\treturn autoCloseAlways;\r\n\t\t\tcase 'never':\r\n\t\t\t\treturn autoCloseNever;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static _getLanguageDefinedShouldAutoClose(languageIdentifier: LanguageIdentifier): (ch: string) => boolean {\r\n\t\ttry {\r\n\t\t\tconst autoCloseBeforeSet = LanguageConfigurationRegistry.getAutoCloseBeforeSet(languageIdentifier.id);\r\n\t\t\treturn c => autoCloseBeforeSet.indexOf(c) !== -1;\r\n\t\t} catch (e) {\r\n\t\t\tonUnexpectedError(e);\r\n\t\t\treturn autoCloseNever;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static _getSurroundingPairs(languageIdentifier: LanguageIdentifier): IAutoClosingPair[] | null {\r\n\t\ttry {\r\n\t\t\treturn LanguageConfigurationRegistry.getSurroundingPairs(languageIdentifier.id);\r\n\t\t} catch (e) {\r\n\t\t\tonUnexpectedError(e);\r\n\t\t\treturn null;\r\n\t\t}\r\n\t}\r\n}\r\n\r\n/**\r\n * Represents a simple model (either the model or the view model).\r\n */\r\nexport interface ICursorSimpleModel {\r\n\tgetLineCount(): number;\r\n\tgetLineContent(lineNumber: number): string;\r\n\tgetLineMinColumn(lineNumber: number): number;\r\n\tgetLineMaxColumn(lineNumber: number): number;\r\n\tgetLineFirstNonWhitespaceColumn(lineNumber: number): number;\r\n}\r\n\r\n/**\r\n * Represents the cursor state on either the model or on the view model.\r\n */\r\nexport class SingleCursorState {\r\n\t_singleCursorStateBrand: void;\r\n\r\n\t// --- selection can start as a range (think double click and drag)\r\n\tpublic readonly selectionStart: Range;\r\n\tpublic readonly selectionStartLeftoverVisibleColumns: number;\r\n\tpublic readonly position: Position;\r\n\tpublic readonly leftoverVisibleColumns: number;\r\n\tpublic readonly selection: Selection;\r\n\r\n\tconstructor(\r\n\t\tselectionStart: Range,\r\n\t\tselectionStartLeftoverVisibleColumns: number,\r\n\t\tposition: Position,\r\n\t\tleftoverVisibleColumns: number,\r\n\t) {\r\n\t\tthis.selectionStart = selectionStart;\r\n\t\tthis.selectionStartLeftoverVisibleColumns = selectionStartLeftoverVisibleColumns;\r\n\t\tthis.position = position;\r\n\t\tthis.leftoverVisibleColumns = leftoverVisibleColumns;\r\n\t\tthis.selection = SingleCursorState._computeSelection(this.selectionStart, this.position);\r\n\t}\r\n\r\n\tpublic equals(other: SingleCursorState) {\r\n\t\treturn (\r\n\t\t\tthis.selectionStartLeftoverVisibleColumns === other.selectionStartLeftoverVisibleColumns\r\n\t\t\t&& this.leftoverVisibleColumns === other.leftoverVisibleColumns\r\n\t\t\t&& this.position.equals(other.position)\r\n\t\t\t&& this.selectionStart.equalsRange(other.selectionStart)\r\n\t\t);\r\n\t}\r\n\r\n\tpublic hasSelection(): boolean {\r\n\t\treturn (!this.selection.isEmpty() || !this.selectionStart.isEmpty());\r\n\t}\r\n\r\n\tpublic move(inSelectionMode: boolean, lineNumber: number, column: number, leftoverVisibleColumns: number): SingleCursorState {\r\n\t\tif (inSelectionMode) {\r\n\t\t\t// move just position\r\n\t\t\treturn new SingleCursorState(\r\n\t\t\t\tthis.selectionStart,\r\n\t\t\t\tthis.selectionStartLeftoverVisibleColumns,\r\n\t\t\t\tnew Position(lineNumber, column),\r\n\t\t\t\tleftoverVisibleColumns\r\n\t\t\t);\r\n\t\t} else {\r\n\t\t\t// move everything\r\n\t\t\treturn new SingleCursorState(\r\n\t\t\t\tnew Range(lineNumber, column, lineNumber, column),\r\n\t\t\t\tleftoverVisibleColumns,\r\n\t\t\t\tnew Position(lineNumber, column),\r\n\t\t\t\tleftoverVisibleColumns\r\n\t\t\t);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static _computeSelection(selectionStart: Range, position: Position): Selection {\r\n\t\tlet startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number;\r\n\t\tif (selectionStart.isEmpty()) {\r\n\t\t\tstartLineNumber = selectionStart.startLineNumber;\r\n\t\t\tstartColumn = selectionStart.startColumn;\r\n\t\t\tendLineNumber = position.lineNumber;\r\n\t\t\tendColumn = position.column;\r\n\t\t} else {\r\n\t\t\tif (position.isBeforeOrEqual(selectionStart.getStartPosition())) {\r\n\t\t\t\tstartLineNumber = selectionStart.endLineNumber;\r\n\t\t\t\tstartColumn = selectionStart.endColumn;\r\n\t\t\t\tendLineNumber = position.lineNumber;\r\n\t\t\t\tendColumn = position.column;\r\n\t\t\t} else {\r\n\t\t\t\tstartLineNumber = selectionStart.startLineNumber;\r\n\t\t\t\tstartColumn = selectionStart.startColumn;\r\n\t\t\t\tendLineNumber = position.lineNumber;\r\n\t\t\t\tendColumn = position.column;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn new Selection(\r\n\t\t\tstartLineNumber,\r\n\t\t\tstartColumn,\r\n\t\t\tendLineNumber,\r\n\t\t\tendColumn\r\n\t\t);\r\n\t}\r\n}\r\n\r\nexport class CursorContext {\r\n\t_cursorContextBrand: void;\r\n\r\n\tpublic readonly model: ITextModel;\r\n\tpublic readonly coordinatesConverter: ICoordinatesConverter;\r\n\tpublic readonly cursorConfig: CursorConfiguration;\r\n\r\n\tconstructor(model: ITextModel, coordinatesConverter: ICoordinatesConverter, cursorConfig: CursorConfiguration) {\r\n\t\tthis.model = model;\r\n\t\tthis.coordinatesConverter = coordinatesConverter;\r\n\t\tthis.cursorConfig = cursorConfig;\r\n\t}\r\n}\r\n\r\nexport class PartialModelCursorState {\r\n\treadonly modelState: SingleCursorState;\r\n\treadonly viewState: null;\r\n\r\n\tconstructor(modelState: SingleCursorState) {\r\n\t\tthis.modelState = modelState;\r\n\t\tthis.viewState = null;\r\n\t}\r\n}\r\n\r\nexport class PartialViewCursorState {\r\n\treadonly modelState: null;\r\n\treadonly viewState: SingleCursorState;\r\n\r\n\tconstructor(viewState: SingleCursorState) {\r\n\t\tthis.modelState = null;\r\n\t\tthis.viewState = viewState;\r\n\t}\r\n}\r\n\r\nexport type PartialCursorState = CursorState | PartialModelCursorState | PartialViewCursorState;\r\n\r\nexport class CursorState {\r\n\t_cursorStateBrand: void;\r\n\r\n\tpublic static fromModelState(modelState: SingleCursorState): PartialModelCursorState {\r\n\t\treturn new PartialModelCursorState(modelState);\r\n\t}\r\n\r\n\tpublic static fromViewState(viewState: SingleCursorState): PartialViewCursorState {\r\n\t\treturn new PartialViewCursorState(viewState);\r\n\t}\r\n\r\n\tpublic static fromModelSelection(modelSelection: ISelection): PartialModelCursorState {\r\n\t\tconst selectionStartLineNumber = modelSelection.selectionStartLineNumber;\r\n\t\tconst selectionStartColumn = modelSelection.selectionStartColumn;\r\n\t\tconst positionLineNumber = modelSelection.positionLineNumber;\r\n\t\tconst positionColumn = modelSelection.positionColumn;\r\n\t\tconst modelState = new SingleCursorState(\r\n\t\t\tnew Range(selectionStartLineNumber, selectionStartColumn, selectionStartLineNumber, selectionStartColumn), 0,\r\n\t\t\tnew Position(positionLineNumber, positionColumn), 0\r\n\t\t);\r\n\t\treturn CursorState.fromModelState(modelState);\r\n\t}\r\n\r\n\tpublic static fromModelSelections(modelSelections: readonly ISelection[]): PartialModelCursorState[] {\r\n\t\tlet states: PartialModelCursorState[] = [];\r\n\t\tfor (let i = 0, len = modelSelections.length; i < len; i++) {\r\n\t\t\tstates[i] = this.fromModelSelection(modelSelections[i]);\r\n\t\t}\r\n\t\treturn states;\r\n\t}\r\n\r\n\treadonly modelState: SingleCursorState;\r\n\treadonly viewState: SingleCursorState;\r\n\r\n\tconstructor(modelState: SingleCursorState, viewState: SingleCursorState) {\r\n\t\tthis.modelState = modelState;\r\n\t\tthis.viewState = viewState;\r\n\t}\r\n\r\n\tpublic equals(other: CursorState): boolean {\r\n\t\treturn (this.viewState.equals(other.viewState) && this.modelState.equals(other.modelState));\r\n\t}\r\n}\r\n\r\nexport class EditOperationResult {\r\n\t_editOperationResultBrand: void;\r\n\r\n\treadonly type: EditOperationType;\r\n\treadonly commands: Array;\r\n\treadonly shouldPushStackElementBefore: boolean;\r\n\treadonly shouldPushStackElementAfter: boolean;\r\n\r\n\tconstructor(\r\n\t\ttype: EditOperationType,\r\n\t\tcommands: Array,\r\n\t\topts: {\r\n\t\t\tshouldPushStackElementBefore: boolean;\r\n\t\t\tshouldPushStackElementAfter: boolean;\r\n\t\t}\r\n\t) {\r\n\t\tthis.type = type;\r\n\t\tthis.commands = commands;\r\n\t\tthis.shouldPushStackElementBefore = opts.shouldPushStackElementBefore;\r\n\t\tthis.shouldPushStackElementAfter = opts.shouldPushStackElementAfter;\r\n\t}\r\n}\r\n\r\n/**\r\n * Common operations that work and make sense both on the model and on the view model.\r\n */\r\nexport class CursorColumns {\r\n\r\n\tpublic static visibleColumnFromColumn(lineContent: string, column: number, tabSize: number): number {\r\n\t\tconst lineContentLength = lineContent.length;\r\n\t\tconst endOffset = column - 1 < lineContentLength ? column - 1 : lineContentLength;\r\n\r\n\t\tlet result = 0;\r\n\t\tlet i = 0;\r\n\t\twhile (i < endOffset) {\r\n\t\t\tconst codePoint = strings.getNextCodePoint(lineContent, endOffset, i);\r\n\t\t\ti += (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1);\r\n\r\n\t\t\tif (codePoint === CharCode.Tab) {\r\n\t\t\t\tresult = CursorColumns.nextRenderTabStop(result, tabSize);\r\n\t\t\t} else {\r\n\t\t\t\tlet graphemeBreakType = strings.getGraphemeBreakType(codePoint);\r\n\t\t\t\twhile (i < endOffset) {\r\n\t\t\t\t\tconst nextCodePoint = strings.getNextCodePoint(lineContent, endOffset, i);\r\n\t\t\t\t\tconst nextGraphemeBreakType = strings.getGraphemeBreakType(nextCodePoint);\r\n\t\t\t\t\tif (strings.breakBetweenGraphemeBreakType(graphemeBreakType, nextGraphemeBreakType)) {\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t\ti += (nextCodePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1);\r\n\t\t\t\t\tgraphemeBreakType = nextGraphemeBreakType;\r\n\t\t\t\t}\r\n\t\t\t\tif (strings.isFullWidthCharacter(codePoint) || strings.isEmojiImprecise(codePoint)) {\r\n\t\t\t\t\tresult = result + 2;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tresult = result + 1;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic static visibleColumnFromColumn2(config: CursorConfiguration, model: ICursorSimpleModel, position: Position): number {\r\n\t\treturn this.visibleColumnFromColumn(model.getLineContent(position.lineNumber), position.column, config.tabSize);\r\n\t}\r\n\r\n\tpublic static columnFromVisibleColumn(lineContent: string, visibleColumn: number, tabSize: number): number {\r\n\t\tif (visibleColumn <= 0) {\r\n\t\t\treturn 1;\r\n\t\t}\r\n\r\n\t\tconst lineLength = lineContent.length;\r\n\r\n\t\tlet beforeVisibleColumn = 0;\r\n\t\tlet beforeColumn = 1;\r\n\t\tlet i = 0;\r\n\t\twhile (i < lineLength) {\r\n\t\t\tconst codePoint = strings.getNextCodePoint(lineContent, lineLength, i);\r\n\t\t\ti += (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1);\r\n\r\n\t\t\tlet afterVisibleColumn: number;\r\n\t\t\tif (codePoint === CharCode.Tab) {\r\n\t\t\t\tafterVisibleColumn = CursorColumns.nextRenderTabStop(beforeVisibleColumn, tabSize);\r\n\t\t\t} else {\r\n\t\t\t\tlet graphemeBreakType = strings.getGraphemeBreakType(codePoint);\r\n\t\t\t\twhile (i < lineLength) {\r\n\t\t\t\t\tconst nextCodePoint = strings.getNextCodePoint(lineContent, lineLength, i);\r\n\t\t\t\t\tconst nextGraphemeBreakType = strings.getGraphemeBreakType(nextCodePoint);\r\n\t\t\t\t\tif (strings.breakBetweenGraphemeBreakType(graphemeBreakType, nextGraphemeBreakType)) {\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t\ti += (nextCodePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1);\r\n\t\t\t\t\tgraphemeBreakType = nextGraphemeBreakType;\r\n\t\t\t\t}\r\n\t\t\t\tif (strings.isFullWidthCharacter(codePoint) || strings.isEmojiImprecise(codePoint)) {\r\n\t\t\t\t\tafterVisibleColumn = beforeVisibleColumn + 2;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tafterVisibleColumn = beforeVisibleColumn + 1;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tconst afterColumn = i + 1;\r\n\r\n\t\t\tif (afterVisibleColumn >= visibleColumn) {\r\n\t\t\t\tconst beforeDelta = visibleColumn - beforeVisibleColumn;\r\n\t\t\t\tconst afterDelta = afterVisibleColumn - visibleColumn;\r\n\t\t\t\tif (afterDelta < beforeDelta) {\r\n\t\t\t\t\treturn afterColumn;\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn beforeColumn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tbeforeVisibleColumn = afterVisibleColumn;\r\n\t\t\tbeforeColumn = afterColumn;\r\n\t\t}\r\n\r\n\t\t// walked the entire string\r\n\t\treturn lineLength + 1;\r\n\t}\r\n\r\n\tpublic static columnFromVisibleColumn2(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, visibleColumn: number): number {\r\n\t\tlet result = this.columnFromVisibleColumn(model.getLineContent(lineNumber), visibleColumn, config.tabSize);\r\n\r\n\t\tlet minColumn = model.getLineMinColumn(lineNumber);\r\n\t\tif (result < minColumn) {\r\n\t\t\treturn minColumn;\r\n\t\t}\r\n\r\n\t\tlet maxColumn = model.getLineMaxColumn(lineNumber);\r\n\t\tif (result > maxColumn) {\r\n\t\t\treturn maxColumn;\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\t/**\r\n\t * ATTENTION: This works with 0-based columns (as oposed to the regular 1-based columns)\r\n\t */\r\n\tpublic static nextRenderTabStop(visibleColumn: number, tabSize: number): number {\r\n\t\treturn visibleColumn + tabSize - visibleColumn % tabSize;\r\n\t}\r\n\r\n\t/**\r\n\t * ATTENTION: This works with 0-based columns (as oposed to the regular 1-based columns)\r\n\t */\r\n\tpublic static nextIndentTabStop(visibleColumn: number, indentSize: number): number {\r\n\t\treturn visibleColumn + indentSize - visibleColumn % indentSize;\r\n\t}\r\n\r\n\t/**\r\n\t * ATTENTION: This works with 0-based columns (as opposed to the regular 1-based columns)\r\n\t */\r\n\tpublic static prevRenderTabStop(column: number, tabSize: number): number {\r\n\t\treturn column - 1 - (column - 1) % tabSize;\r\n\t}\r\n\r\n\t/**\r\n\t * ATTENTION: This works with 0-based columns (as opposed to the regular 1-based columns)\r\n\t */\r\n\tpublic static prevIndentTabStop(column: number, indentSize: number): number {\r\n\t\treturn column - 1 - (column - 1) % indentSize;\r\n\t}\r\n}\r\n\r\nexport function isQuote(ch: string): boolean {\r\n\treturn (ch === '\\'' || ch === '\"' || ch === '`');\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { CursorColumns } from 'vs/editor/common/controller/cursorCommon';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection, SelectionDirection } from 'vs/editor/common/core/selection';\r\nimport { ICommand, ICursorStateComputerData, IEditOperationBuilder } from 'vs/editor/common/editorCommon';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';\r\nimport { EditorAutoIndentStrategy } from 'vs/editor/common/config/editorOptions';\r\n\r\nexport interface IShiftCommandOpts {\r\n\tisUnshift: boolean;\r\n\ttabSize: number;\r\n\tindentSize: number;\r\n\tinsertSpaces: boolean;\r\n\tuseTabStops: boolean;\r\n\tautoIndent: EditorAutoIndentStrategy;\r\n}\r\n\r\nconst repeatCache: { [str: string]: string[]; } = Object.create(null);\r\nexport function cachedStringRepeat(str: string, count: number): string {\r\n\tif (!repeatCache[str]) {\r\n\t\trepeatCache[str] = ['', str];\r\n\t}\r\n\tconst cache = repeatCache[str];\r\n\tfor (let i = cache.length; i <= count; i++) {\r\n\t\tcache[i] = cache[i - 1] + str;\r\n\t}\r\n\treturn cache[count];\r\n}\r\n\r\nexport class ShiftCommand implements ICommand {\r\n\r\n\tpublic static unshiftIndent(line: string, column: number, tabSize: number, indentSize: number, insertSpaces: boolean): string {\r\n\t\t// Determine the visible column where the content starts\r\n\t\tconst contentStartVisibleColumn = CursorColumns.visibleColumnFromColumn(line, column, tabSize);\r\n\r\n\t\tif (insertSpaces) {\r\n\t\t\tconst indent = cachedStringRepeat(' ', indentSize);\r\n\t\t\tconst desiredTabStop = CursorColumns.prevIndentTabStop(contentStartVisibleColumn, indentSize);\r\n\t\t\tconst indentCount = desiredTabStop / indentSize; // will be an integer\r\n\t\t\treturn cachedStringRepeat(indent, indentCount);\r\n\t\t} else {\r\n\t\t\tconst indent = '\\t';\r\n\t\t\tconst desiredTabStop = CursorColumns.prevRenderTabStop(contentStartVisibleColumn, tabSize);\r\n\t\t\tconst indentCount = desiredTabStop / tabSize; // will be an integer\r\n\t\t\treturn cachedStringRepeat(indent, indentCount);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic static shiftIndent(line: string, column: number, tabSize: number, indentSize: number, insertSpaces: boolean): string {\r\n\t\t// Determine the visible column where the content starts\r\n\t\tconst contentStartVisibleColumn = CursorColumns.visibleColumnFromColumn(line, column, tabSize);\r\n\r\n\t\tif (insertSpaces) {\r\n\t\t\tconst indent = cachedStringRepeat(' ', indentSize);\r\n\t\t\tconst desiredTabStop = CursorColumns.nextIndentTabStop(contentStartVisibleColumn, indentSize);\r\n\t\t\tconst indentCount = desiredTabStop / indentSize; // will be an integer\r\n\t\t\treturn cachedStringRepeat(indent, indentCount);\r\n\t\t} else {\r\n\t\t\tconst indent = '\\t';\r\n\t\t\tconst desiredTabStop = CursorColumns.nextRenderTabStop(contentStartVisibleColumn, tabSize);\r\n\t\t\tconst indentCount = desiredTabStop / tabSize; // will be an integer\r\n\t\t\treturn cachedStringRepeat(indent, indentCount);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate readonly _opts: IShiftCommandOpts;\r\n\tprivate readonly _selection: Selection;\r\n\tprivate _selectionId: string | null;\r\n\tprivate _useLastEditRangeForCursorEndPosition: boolean;\r\n\tprivate _selectionStartColumnStaysPut: boolean;\r\n\r\n\tconstructor(range: Selection, opts: IShiftCommandOpts) {\r\n\t\tthis._opts = opts;\r\n\t\tthis._selection = range;\r\n\t\tthis._selectionId = null;\r\n\t\tthis._useLastEditRangeForCursorEndPosition = false;\r\n\t\tthis._selectionStartColumnStaysPut = false;\r\n\t}\r\n\r\n\tprivate _addEditOperation(builder: IEditOperationBuilder, range: Range, text: string) {\r\n\t\tif (this._useLastEditRangeForCursorEndPosition) {\r\n\t\t\tbuilder.addTrackedEditOperation(range, text);\r\n\t\t} else {\r\n\t\t\tbuilder.addEditOperation(range, text);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\r\n\t\tconst startLine = this._selection.startLineNumber;\r\n\r\n\t\tlet endLine = this._selection.endLineNumber;\r\n\t\tif (this._selection.endColumn === 1 && startLine !== endLine) {\r\n\t\t\tendLine = endLine - 1;\r\n\t\t}\r\n\r\n\t\tconst { tabSize, indentSize, insertSpaces } = this._opts;\r\n\t\tconst shouldIndentEmptyLines = (startLine === endLine);\r\n\r\n\t\tif (this._opts.useTabStops) {\r\n\t\t\t// if indenting or outdenting on a whitespace only line\r\n\t\t\tif (this._selection.isEmpty()) {\r\n\t\t\t\tif (/^\\s*$/.test(model.getLineContent(startLine))) {\r\n\t\t\t\t\tthis._useLastEditRangeForCursorEndPosition = true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// keep track of previous line's \"miss-alignment\"\r\n\t\t\tlet previousLineExtraSpaces = 0, extraSpaces = 0;\r\n\t\t\tfor (let lineNumber = startLine; lineNumber <= endLine; lineNumber++, previousLineExtraSpaces = extraSpaces) {\r\n\t\t\t\textraSpaces = 0;\r\n\t\t\t\tlet lineText = model.getLineContent(lineNumber);\r\n\t\t\t\tlet indentationEndIndex = strings.firstNonWhitespaceIndex(lineText);\r\n\r\n\t\t\t\tif (this._opts.isUnshift && (lineText.length === 0 || indentationEndIndex === 0)) {\r\n\t\t\t\t\t// empty line or line with no leading whitespace => nothing to do\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (!shouldIndentEmptyLines && !this._opts.isUnshift && lineText.length === 0) {\r\n\t\t\t\t\t// do not indent empty lines => nothing to do\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (indentationEndIndex === -1) {\r\n\t\t\t\t\t// the entire line is whitespace\r\n\t\t\t\t\tindentationEndIndex = lineText.length;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (lineNumber > 1) {\r\n\t\t\t\t\tlet contentStartVisibleColumn = CursorColumns.visibleColumnFromColumn(lineText, indentationEndIndex + 1, tabSize);\r\n\t\t\t\t\tif (contentStartVisibleColumn % indentSize !== 0) {\r\n\t\t\t\t\t\t// The current line is \"miss-aligned\", so let's see if this is expected...\r\n\t\t\t\t\t\t// This can only happen when it has trailing commas in the indent\r\n\t\t\t\t\t\tif (model.isCheapToTokenize(lineNumber - 1)) {\r\n\t\t\t\t\t\t\tlet enterAction = LanguageConfigurationRegistry.getEnterAction(this._opts.autoIndent, model, new Range(lineNumber - 1, model.getLineMaxColumn(lineNumber - 1), lineNumber - 1, model.getLineMaxColumn(lineNumber - 1)));\r\n\t\t\t\t\t\t\tif (enterAction) {\r\n\t\t\t\t\t\t\t\textraSpaces = previousLineExtraSpaces;\r\n\t\t\t\t\t\t\t\tif (enterAction.appendText) {\r\n\t\t\t\t\t\t\t\t\tfor (let j = 0, lenJ = enterAction.appendText.length; j < lenJ && extraSpaces < indentSize; j++) {\r\n\t\t\t\t\t\t\t\t\t\tif (enterAction.appendText.charCodeAt(j) === CharCode.Space) {\r\n\t\t\t\t\t\t\t\t\t\t\textraSpaces++;\r\n\t\t\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\tif (enterAction.removeText) {\r\n\t\t\t\t\t\t\t\t\textraSpaces = Math.max(0, extraSpaces - enterAction.removeText);\r\n\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\t// Act as if `prefixSpaces` is not part of the indentation\r\n\t\t\t\t\t\t\t\tfor (let j = 0; j < extraSpaces; j++) {\r\n\t\t\t\t\t\t\t\t\tif (indentationEndIndex === 0 || lineText.charCodeAt(indentationEndIndex - 1) !== CharCode.Space) {\r\n\t\t\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\tindentationEndIndex--;\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\tif (this._opts.isUnshift && indentationEndIndex === 0) {\r\n\t\t\t\t\t// line with no leading whitespace => nothing to do\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tlet desiredIndent: string;\r\n\t\t\t\tif (this._opts.isUnshift) {\r\n\t\t\t\t\tdesiredIndent = ShiftCommand.unshiftIndent(lineText, indentationEndIndex + 1, tabSize, indentSize, insertSpaces);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tdesiredIndent = ShiftCommand.shiftIndent(lineText, indentationEndIndex + 1, tabSize, indentSize, insertSpaces);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis._addEditOperation(builder, new Range(lineNumber, 1, lineNumber, indentationEndIndex + 1), desiredIndent);\r\n\t\t\t\tif (lineNumber === startLine && !this._selection.isEmpty()) {\r\n\t\t\t\t\t// Force the startColumn to stay put because we're inserting after it\r\n\t\t\t\t\tthis._selectionStartColumnStaysPut = (this._selection.startColumn <= indentationEndIndex + 1);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else {\r\n\r\n\t\t\t// if indenting or outdenting on a whitespace only line\r\n\t\t\tif (!this._opts.isUnshift && this._selection.isEmpty() && model.getLineLength(startLine) === 0) {\r\n\t\t\t\tthis._useLastEditRangeForCursorEndPosition = true;\r\n\t\t\t}\r\n\r\n\t\t\tconst oneIndent = (insertSpaces ? cachedStringRepeat(' ', indentSize) : '\\t');\r\n\r\n\t\t\tfor (let lineNumber = startLine; lineNumber <= endLine; lineNumber++) {\r\n\t\t\t\tconst lineText = model.getLineContent(lineNumber);\r\n\t\t\t\tlet indentationEndIndex = strings.firstNonWhitespaceIndex(lineText);\r\n\r\n\t\t\t\tif (this._opts.isUnshift && (lineText.length === 0 || indentationEndIndex === 0)) {\r\n\t\t\t\t\t// empty line or line with no leading whitespace => nothing to do\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (!shouldIndentEmptyLines && !this._opts.isUnshift && lineText.length === 0) {\r\n\t\t\t\t\t// do not indent empty lines => nothing to do\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (indentationEndIndex === -1) {\r\n\t\t\t\t\t// the entire line is whitespace\r\n\t\t\t\t\tindentationEndIndex = lineText.length;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (this._opts.isUnshift && indentationEndIndex === 0) {\r\n\t\t\t\t\t// line with no leading whitespace => nothing to do\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (this._opts.isUnshift) {\r\n\r\n\t\t\t\t\tindentationEndIndex = Math.min(indentationEndIndex, indentSize);\r\n\t\t\t\t\tfor (let i = 0; i < indentationEndIndex; i++) {\r\n\t\t\t\t\t\tconst chr = lineText.charCodeAt(i);\r\n\t\t\t\t\t\tif (chr === CharCode.Tab) {\r\n\t\t\t\t\t\t\tindentationEndIndex = i + 1;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tthis._addEditOperation(builder, new Range(lineNumber, 1, lineNumber, indentationEndIndex + 1), '');\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis._addEditOperation(builder, new Range(lineNumber, 1, lineNumber, 1), oneIndent);\r\n\t\t\t\t\tif (lineNumber === startLine && !this._selection.isEmpty()) {\r\n\t\t\t\t\t\t// Force the startColumn to stay put because we're inserting after it\r\n\t\t\t\t\t\tthis._selectionStartColumnStaysPut = (this._selection.startColumn === 1);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._selectionId = builder.trackSelection(this._selection);\r\n\t}\r\n\r\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\r\n\t\tif (this._useLastEditRangeForCursorEndPosition) {\r\n\t\t\tlet lastOp = helper.getInverseEditOperations()[0];\r\n\t\t\treturn new Selection(lastOp.range.endLineNumber, lastOp.range.endColumn, lastOp.range.endLineNumber, lastOp.range.endColumn);\r\n\t\t}\r\n\t\tconst result = helper.getTrackedSelection(this._selectionId!);\r\n\r\n\t\tif (this._selectionStartColumnStaysPut) {\r\n\t\t\t// The selection start should not move\r\n\t\t\tlet initialStartColumn = this._selection.startColumn;\r\n\t\t\tlet resultStartColumn = result.startColumn;\r\n\t\t\tif (resultStartColumn <= initialStartColumn) {\r\n\t\t\t\treturn result;\r\n\t\t\t}\r\n\r\n\t\t\tif (result.getDirection() === SelectionDirection.LTR) {\r\n\t\t\t\treturn new Selection(result.startLineNumber, initialStartColumn, result.endLineNumber, result.endColumn);\r\n\t\t\t}\r\n\t\t\treturn new Selection(result.endLineNumber, result.endColumn, result.startLineNumber, initialStartColumn);\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport { CursorColumns } from 'vs/editor/common/controller/cursorCommon';\r\n\r\nexport const enum Direction {\r\n\tLeft,\r\n\tRight,\r\n\tNearest,\r\n}\r\n\r\nexport class AtomicTabMoveOperations {\r\n\t/**\r\n\t * Get the visible column at the position. If we get to a non-whitespace character first\r\n\t * or past the end of string then return -1.\r\n\t *\r\n\t * **Note** `position` and the return value are 0-based.\r\n\t */\r\n\tpublic static whitespaceVisibleColumn(lineContent: string, position: number, tabSize: number): [number, number, number] {\r\n\t\tconst lineLength = lineContent.length;\r\n\t\tlet visibleColumn = 0;\r\n\t\tlet prevTabStopPosition = -1;\r\n\t\tlet prevTabStopVisibleColumn = -1;\r\n\t\tfor (let i = 0; i < lineLength; i++) {\r\n\t\t\tif (i === position) {\r\n\t\t\t\treturn [prevTabStopPosition, prevTabStopVisibleColumn, visibleColumn];\r\n\t\t\t}\r\n\t\t\tif (visibleColumn % tabSize === 0) {\r\n\t\t\t\tprevTabStopPosition = i;\r\n\t\t\t\tprevTabStopVisibleColumn = visibleColumn;\r\n\t\t\t}\r\n\t\t\tconst chCode = lineContent.charCodeAt(i);\r\n\t\t\tswitch (chCode) {\r\n\t\t\t\tcase CharCode.Space:\r\n\t\t\t\t\tvisibleColumn += 1;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase CharCode.Tab:\r\n\t\t\t\t\t// Skip to the next multiple of tabSize.\r\n\t\t\t\t\tvisibleColumn = CursorColumns.nextRenderTabStop(visibleColumn, tabSize);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tdefault:\r\n\t\t\t\t\treturn [-1, -1, -1];\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (position === lineLength) {\r\n\t\t\treturn [prevTabStopPosition, prevTabStopVisibleColumn, visibleColumn];\r\n\t\t}\r\n\t\treturn [-1, -1, -1];\r\n\t}\r\n\r\n\t/**\r\n\t * Return the position that should result from a move left, right or to the\r\n\t * nearest tab, if atomic tabs are enabled. Left and right are used for the\r\n\t * arrow key movements, nearest is used for mouse selection. It returns\r\n\t * -1 if atomic tabs are not relevant and you should fall back to normal\r\n\t * behaviour.\r\n\t *\r\n\t * **Note**: `position` and the return value are 0-based.\r\n\t */\r\n\tpublic static atomicPosition(lineContent: string, position: number, tabSize: number, direction: Direction): number {\r\n\t\tconst lineLength = lineContent.length;\r\n\r\n\t\t// Get the 0-based visible column corresponding to the position, or return\r\n\t\t// -1 if it is not in the initial whitespace.\r\n\t\tconst [prevTabStopPosition, prevTabStopVisibleColumn, visibleColumn] = AtomicTabMoveOperations.whitespaceVisibleColumn(lineContent, position, tabSize);\r\n\r\n\t\tif (visibleColumn === -1) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\r\n\t\t// Is the output left or right of the current position. The case for nearest\r\n\t\t// where it is the same as the current position is handled in the switch.\r\n\t\tlet left: boolean;\r\n\t\tswitch (direction) {\r\n\t\t\tcase Direction.Left:\r\n\t\t\t\tleft = true;\r\n\t\t\t\tbreak;\r\n\t\t\tcase Direction.Right:\r\n\t\t\t\tleft = false;\r\n\t\t\t\tbreak;\r\n\t\t\tcase Direction.Nearest:\r\n\t\t\t\t// The code below assumes the output position is either left or right\r\n\t\t\t\t// of the input position. If it is the same, return immediately.\r\n\t\t\t\tif (visibleColumn % tabSize === 0) {\r\n\t\t\t\t\treturn position;\r\n\t\t\t\t}\r\n\t\t\t\t// Go to the nearest indentation.\r\n\t\t\t\tleft = visibleColumn % tabSize <= (tabSize / 2);\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\t// If going left, we can just use the info about the last tab stop position and\r\n\t\t// last tab stop visible column that we computed in the first walk over the whitespace.\r\n\t\tif (left) {\r\n\t\t\tif (prevTabStopPosition === -1) {\r\n\t\t\t\treturn -1;\r\n\t\t\t}\r\n\t\t\t// If the direction is left, we need to keep scanning right to ensure\r\n\t\t\t// that targetVisibleColumn + tabSize is before non-whitespace.\r\n\t\t\t// This is so that when we press left at the end of a partial\r\n\t\t\t// indentation it only goes one character. For example ' foo' with\r\n\t\t\t// tabSize 4, should jump from position 6 to position 5, not 4.\r\n\t\t\tlet currentVisibleColumn = prevTabStopVisibleColumn;\r\n\t\t\tfor (let i = prevTabStopPosition; i < lineLength; ++i) {\r\n\t\t\t\tif (currentVisibleColumn === prevTabStopVisibleColumn + tabSize) {\r\n\t\t\t\t\t// It is a full indentation.\r\n\t\t\t\t\treturn prevTabStopPosition;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst chCode = lineContent.charCodeAt(i);\r\n\t\t\t\tswitch (chCode) {\r\n\t\t\t\t\tcase CharCode.Space:\r\n\t\t\t\t\t\tcurrentVisibleColumn += 1;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tcase CharCode.Tab:\r\n\t\t\t\t\t\tcurrentVisibleColumn = CursorColumns.nextRenderTabStop(currentVisibleColumn, tabSize);\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tdefault:\r\n\t\t\t\t\t\treturn -1;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (currentVisibleColumn === prevTabStopVisibleColumn + tabSize) {\r\n\t\t\t\treturn prevTabStopPosition;\r\n\t\t\t}\r\n\t\t\t// It must have been a partial indentation.\r\n\t\t\treturn -1;\r\n\t\t}\r\n\r\n\t\t// We are going right.\r\n\t\tconst targetVisibleColumn = CursorColumns.nextRenderTabStop(visibleColumn, tabSize);\r\n\r\n\t\t// We can just continue from where whitespaceVisibleColumn got to.\r\n\t\tlet currentVisibleColumn = visibleColumn;\r\n\t\tfor (let i = position; i < lineLength; i++) {\r\n\t\t\tif (currentVisibleColumn === targetVisibleColumn) {\r\n\t\t\t\treturn i;\r\n\t\t\t}\r\n\r\n\t\t\tconst chCode = lineContent.charCodeAt(i);\r\n\t\t\tswitch (chCode) {\r\n\t\t\t\tcase CharCode.Space:\r\n\t\t\t\t\tcurrentVisibleColumn += 1;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase CharCode.Tab:\r\n\t\t\t\t\tcurrentVisibleColumn = CursorColumns.nextRenderTabStop(currentVisibleColumn, tabSize);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tdefault:\r\n\t\t\t\t\treturn -1;\r\n\t\t\t}\r\n\t\t}\r\n\t\t// This condition handles when the target column is at the end of the line.\r\n\t\tif (currentVisibleColumn === targetVisibleColumn) {\r\n\t\t\treturn lineLength;\r\n\t\t}\r\n\t\treturn -1;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CursorColumns, CursorConfiguration, ICursorSimpleModel, SingleCursorState, IColumnSelectData } from 'vs/editor/common/controller/cursorCommon';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\n\r\nexport interface IColumnSelectResult {\r\n\tviewStates: SingleCursorState[];\r\n\treversed: boolean;\r\n\tfromLineNumber: number;\r\n\tfromVisualColumn: number;\r\n\ttoLineNumber: number;\r\n\ttoVisualColumn: number;\r\n}\r\n\r\nexport class ColumnSelection {\r\n\r\n\tpublic static columnSelect(config: CursorConfiguration, model: ICursorSimpleModel, fromLineNumber: number, fromVisibleColumn: number, toLineNumber: number, toVisibleColumn: number): IColumnSelectResult {\r\n\t\tlet lineCount = Math.abs(toLineNumber - fromLineNumber) + 1;\r\n\t\tlet reversed = (fromLineNumber > toLineNumber);\r\n\t\tlet isRTL = (fromVisibleColumn > toVisibleColumn);\r\n\t\tlet isLTR = (fromVisibleColumn < toVisibleColumn);\r\n\r\n\t\tlet result: SingleCursorState[] = [];\r\n\r\n\t\t// console.log(`fromVisibleColumn: ${fromVisibleColumn}, toVisibleColumn: ${toVisibleColumn}`);\r\n\r\n\t\tfor (let i = 0; i < lineCount; i++) {\r\n\t\t\tlet lineNumber = fromLineNumber + (reversed ? -i : i);\r\n\r\n\t\t\tlet startColumn = CursorColumns.columnFromVisibleColumn2(config, model, lineNumber, fromVisibleColumn);\r\n\t\t\tlet endColumn = CursorColumns.columnFromVisibleColumn2(config, model, lineNumber, toVisibleColumn);\r\n\t\t\tlet visibleStartColumn = CursorColumns.visibleColumnFromColumn2(config, model, new Position(lineNumber, startColumn));\r\n\t\t\tlet visibleEndColumn = CursorColumns.visibleColumnFromColumn2(config, model, new Position(lineNumber, endColumn));\r\n\r\n\t\t\t// console.log(`lineNumber: ${lineNumber}: visibleStartColumn: ${visibleStartColumn}, visibleEndColumn: ${visibleEndColumn}`);\r\n\r\n\t\t\tif (isLTR) {\r\n\t\t\t\tif (visibleStartColumn > toVisibleColumn) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\tif (visibleEndColumn < fromVisibleColumn) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (isRTL) {\r\n\t\t\t\tif (visibleEndColumn > fromVisibleColumn) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\tif (visibleStartColumn < toVisibleColumn) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tresult.push(new SingleCursorState(\r\n\t\t\t\tnew Range(lineNumber, startColumn, lineNumber, startColumn), 0,\r\n\t\t\t\tnew Position(lineNumber, endColumn), 0\r\n\t\t\t));\r\n\t\t}\r\n\r\n\t\tif (result.length === 0) {\r\n\t\t\t// We are after all the lines, so add cursor at the end of each line\r\n\t\t\tfor (let i = 0; i < lineCount; i++) {\r\n\t\t\t\tconst lineNumber = fromLineNumber + (reversed ? -i : i);\r\n\t\t\t\tconst maxColumn = model.getLineMaxColumn(lineNumber);\r\n\r\n\t\t\t\tresult.push(new SingleCursorState(\r\n\t\t\t\t\tnew Range(lineNumber, maxColumn, lineNumber, maxColumn), 0,\r\n\t\t\t\t\tnew Position(lineNumber, maxColumn), 0\r\n\t\t\t\t));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tviewStates: result,\r\n\t\t\treversed: reversed,\r\n\t\t\tfromLineNumber: fromLineNumber,\r\n\t\t\tfromVisualColumn: fromVisibleColumn,\r\n\t\t\ttoLineNumber: toLineNumber,\r\n\t\t\ttoVisualColumn: toVisibleColumn\r\n\t\t};\r\n\t}\r\n\r\n\tpublic static columnSelectLeft(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData): IColumnSelectResult {\r\n\t\tlet toViewVisualColumn = prevColumnSelectData.toViewVisualColumn;\r\n\t\tif (toViewVisualColumn > 1) {\r\n\t\t\ttoViewVisualColumn--;\r\n\t\t}\r\n\r\n\t\treturn ColumnSelection.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, prevColumnSelectData.toViewLineNumber, toViewVisualColumn);\r\n\t}\r\n\r\n\tpublic static columnSelectRight(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData): IColumnSelectResult {\r\n\t\tlet maxVisualViewColumn = 0;\r\n\t\tconst minViewLineNumber = Math.min(prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.toViewLineNumber);\r\n\t\tconst maxViewLineNumber = Math.max(prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.toViewLineNumber);\r\n\t\tfor (let lineNumber = minViewLineNumber; lineNumber <= maxViewLineNumber; lineNumber++) {\r\n\t\t\tconst lineMaxViewColumn = model.getLineMaxColumn(lineNumber);\r\n\t\t\tconst lineMaxVisualViewColumn = CursorColumns.visibleColumnFromColumn2(config, model, new Position(lineNumber, lineMaxViewColumn));\r\n\t\t\tmaxVisualViewColumn = Math.max(maxVisualViewColumn, lineMaxVisualViewColumn);\r\n\t\t}\r\n\r\n\t\tlet toViewVisualColumn = prevColumnSelectData.toViewVisualColumn;\r\n\t\tif (toViewVisualColumn < maxVisualViewColumn) {\r\n\t\t\ttoViewVisualColumn++;\r\n\t\t}\r\n\r\n\t\treturn this.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, prevColumnSelectData.toViewLineNumber, toViewVisualColumn);\r\n\t}\r\n\r\n\tpublic static columnSelectUp(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData, isPaged: boolean): IColumnSelectResult {\r\n\t\tconst linesCount = isPaged ? config.pageSize : 1;\r\n\t\tconst toViewLineNumber = Math.max(1, prevColumnSelectData.toViewLineNumber - linesCount);\r\n\t\treturn this.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, toViewLineNumber, prevColumnSelectData.toViewVisualColumn);\r\n\t}\r\n\r\n\tpublic static columnSelectDown(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData, isPaged: boolean): IColumnSelectResult {\r\n\t\tconst linesCount = isPaged ? config.pageSize : 1;\r\n\t\tconst toViewLineNumber = Math.min(model.getLineCount(), prevColumnSelectData.toViewLineNumber + linesCount);\r\n\t\treturn this.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, toViewLineNumber, prevColumnSelectData.toViewVisualColumn);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CursorColumns, CursorConfiguration, ICursorSimpleModel, SingleCursorState } from 'vs/editor/common/controller/cursorCommon';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { Constants } from 'vs/base/common/uint';\r\nimport { AtomicTabMoveOperations, Direction } from 'vs/editor/common/controller/cursorAtomicMoveOperations';\r\n\r\nexport class CursorPosition {\r\n\t_cursorPositionBrand: void;\r\n\r\n\tpublic readonly lineNumber: number;\r\n\tpublic readonly column: number;\r\n\tpublic readonly leftoverVisibleColumns: number;\r\n\r\n\tconstructor(lineNumber: number, column: number, leftoverVisibleColumns: number) {\r\n\t\tthis.lineNumber = lineNumber;\r\n\t\tthis.column = column;\r\n\t\tthis.leftoverVisibleColumns = leftoverVisibleColumns;\r\n\t}\r\n}\r\n\r\nexport class MoveOperations {\r\n\r\n\tpublic static leftPosition(model: ICursorSimpleModel, lineNumber: number, column: number): Position {\r\n\t\tif (column > model.getLineMinColumn(lineNumber)) {\r\n\t\t\tcolumn = column - strings.prevCharLength(model.getLineContent(lineNumber), column - 1);\r\n\t\t} else if (lineNumber > 1) {\r\n\t\t\tlineNumber = lineNumber - 1;\r\n\t\t\tcolumn = model.getLineMaxColumn(lineNumber);\r\n\t\t}\r\n\t\treturn new Position(lineNumber, column);\r\n\t}\r\n\r\n\tpublic static leftPositionAtomicSoftTabs(model: ICursorSimpleModel, lineNumber: number, column: number, tabSize: number): Position {\r\n\t\tconst minColumn = model.getLineMinColumn(lineNumber);\r\n\t\tconst lineContent = model.getLineContent(lineNumber);\r\n\t\tconst newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, column - 1, tabSize, Direction.Left);\r\n\t\tif (newPosition === -1 || newPosition + 1 < minColumn) {\r\n\t\t\treturn this.leftPosition(model, lineNumber, column);\r\n\t\t}\r\n\t\treturn new Position(lineNumber, newPosition + 1);\r\n\t}\r\n\r\n\tpublic static left(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition {\r\n\t\tconst pos = config.stickyTabStops\r\n\t\t\t? MoveOperations.leftPositionAtomicSoftTabs(model, lineNumber, column, config.tabSize)\r\n\t\t\t: MoveOperations.leftPosition(model, lineNumber, column);\r\n\t\treturn new CursorPosition(pos.lineNumber, pos.column, 0);\r\n\t}\r\n\r\n\tpublic static moveLeft(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, noOfColumns: number): SingleCursorState {\r\n\t\tlet lineNumber: number,\r\n\t\t\tcolumn: number;\r\n\r\n\t\tif (cursor.hasSelection() && !inSelectionMode) {\r\n\t\t\t// If we are in selection mode, move left without selection cancels selection and puts cursor at the beginning of the selection\r\n\t\t\tlineNumber = cursor.selection.startLineNumber;\r\n\t\t\tcolumn = cursor.selection.startColumn;\r\n\t\t} else {\r\n\t\t\tlet r = MoveOperations.left(config, model, cursor.position.lineNumber, cursor.position.column - (noOfColumns - 1));\r\n\t\t\tlineNumber = r.lineNumber;\r\n\t\t\tcolumn = r.column;\r\n\t\t}\r\n\r\n\t\treturn cursor.move(inSelectionMode, lineNumber, column, 0);\r\n\t}\r\n\r\n\tpublic static rightPosition(model: ICursorSimpleModel, lineNumber: number, column: number): Position {\r\n\t\tif (column < model.getLineMaxColumn(lineNumber)) {\r\n\t\t\tcolumn = column + strings.nextCharLength(model.getLineContent(lineNumber), column - 1);\r\n\t\t} else if (lineNumber < model.getLineCount()) {\r\n\t\t\tlineNumber = lineNumber + 1;\r\n\t\t\tcolumn = model.getLineMinColumn(lineNumber);\r\n\t\t}\r\n\t\treturn new Position(lineNumber, column);\r\n\t}\r\n\r\n\tpublic static rightPositionAtomicSoftTabs(model: ICursorSimpleModel, lineNumber: number, column: number, tabSize: number, indentSize: number): Position {\r\n\t\tconst lineContent = model.getLineContent(lineNumber);\r\n\t\tconst newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, column - 1, tabSize, Direction.Right);\r\n\t\tif (newPosition === -1) {\r\n\t\t\treturn this.rightPosition(model, lineNumber, column);\r\n\t\t}\r\n\t\treturn new Position(lineNumber, newPosition + 1);\r\n\t}\r\n\r\n\tpublic static right(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition {\r\n\t\tconst pos = config.stickyTabStops\r\n\t\t\t? MoveOperations.rightPositionAtomicSoftTabs(model, lineNumber, column, config.tabSize, config.indentSize)\r\n\t\t\t: MoveOperations.rightPosition(model, lineNumber, column);\r\n\t\treturn new CursorPosition(pos.lineNumber, pos.column, 0);\r\n\t}\r\n\r\n\tpublic static moveRight(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, noOfColumns: number): SingleCursorState {\r\n\t\tlet lineNumber: number,\r\n\t\t\tcolumn: number;\r\n\r\n\t\tif (cursor.hasSelection() && !inSelectionMode) {\r\n\t\t\t// If we are in selection mode, move right without selection cancels selection and puts cursor at the end of the selection\r\n\t\t\tlineNumber = cursor.selection.endLineNumber;\r\n\t\t\tcolumn = cursor.selection.endColumn;\r\n\t\t} else {\r\n\t\t\tlet r = MoveOperations.right(config, model, cursor.position.lineNumber, cursor.position.column + (noOfColumns - 1));\r\n\t\t\tlineNumber = r.lineNumber;\r\n\t\t\tcolumn = r.column;\r\n\t\t}\r\n\r\n\t\treturn cursor.move(inSelectionMode, lineNumber, column, 0);\r\n\t}\r\n\r\n\tpublic static down(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number, leftoverVisibleColumns: number, count: number, allowMoveOnLastLine: boolean): CursorPosition {\r\n\t\tconst currentVisibleColumn = CursorColumns.visibleColumnFromColumn(model.getLineContent(lineNumber), column, config.tabSize) + leftoverVisibleColumns;\r\n\t\tconst lineCount = model.getLineCount();\r\n\t\tconst wasOnLastPosition = (lineNumber === lineCount && column === model.getLineMaxColumn(lineNumber));\r\n\r\n\t\tlineNumber = lineNumber + count;\r\n\t\tif (lineNumber > lineCount) {\r\n\t\t\tlineNumber = lineCount;\r\n\t\t\tif (allowMoveOnLastLine) {\r\n\t\t\t\tcolumn = model.getLineMaxColumn(lineNumber);\r\n\t\t\t} else {\r\n\t\t\t\tcolumn = Math.min(model.getLineMaxColumn(lineNumber), column);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tcolumn = CursorColumns.columnFromVisibleColumn2(config, model, lineNumber, currentVisibleColumn);\r\n\t\t}\r\n\r\n\t\tif (wasOnLastPosition) {\r\n\t\t\tleftoverVisibleColumns = 0;\r\n\t\t} else {\r\n\t\t\tleftoverVisibleColumns = currentVisibleColumn - CursorColumns.visibleColumnFromColumn(model.getLineContent(lineNumber), column, config.tabSize);\r\n\t\t}\r\n\r\n\t\treturn new CursorPosition(lineNumber, column, leftoverVisibleColumns);\r\n\t}\r\n\r\n\tpublic static moveDown(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, linesCount: number): SingleCursorState {\r\n\t\tlet lineNumber: number,\r\n\t\t\tcolumn: number;\r\n\r\n\t\tif (cursor.hasSelection() && !inSelectionMode) {\r\n\t\t\t// If we are in selection mode, move down acts relative to the end of selection\r\n\t\t\tlineNumber = cursor.selection.endLineNumber;\r\n\t\t\tcolumn = cursor.selection.endColumn;\r\n\t\t} else {\r\n\t\t\tlineNumber = cursor.position.lineNumber;\r\n\t\t\tcolumn = cursor.position.column;\r\n\t\t}\r\n\r\n\t\tlet r = MoveOperations.down(config, model, lineNumber, column, cursor.leftoverVisibleColumns, linesCount, true);\r\n\r\n\t\treturn cursor.move(inSelectionMode, r.lineNumber, r.column, r.leftoverVisibleColumns);\r\n\t}\r\n\r\n\tpublic static translateDown(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState): SingleCursorState {\r\n\t\tlet selection = cursor.selection;\r\n\r\n\t\tlet selectionStart = MoveOperations.down(config, model, selection.selectionStartLineNumber, selection.selectionStartColumn, cursor.selectionStartLeftoverVisibleColumns, 1, false);\r\n\t\tlet position = MoveOperations.down(config, model, selection.positionLineNumber, selection.positionColumn, cursor.leftoverVisibleColumns, 1, false);\r\n\r\n\t\treturn new SingleCursorState(\r\n\t\t\tnew Range(selectionStart.lineNumber, selectionStart.column, selectionStart.lineNumber, selectionStart.column),\r\n\t\t\tselectionStart.leftoverVisibleColumns,\r\n\t\t\tnew Position(position.lineNumber, position.column),\r\n\t\t\tposition.leftoverVisibleColumns\r\n\t\t);\r\n\t}\r\n\r\n\tpublic static up(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number, leftoverVisibleColumns: number, count: number, allowMoveOnFirstLine: boolean): CursorPosition {\r\n\t\tconst currentVisibleColumn = CursorColumns.visibleColumnFromColumn(model.getLineContent(lineNumber), column, config.tabSize) + leftoverVisibleColumns;\r\n\t\tconst wasOnFirstPosition = (lineNumber === 1 && column === 1);\r\n\r\n\t\tlineNumber = lineNumber - count;\r\n\t\tif (lineNumber < 1) {\r\n\t\t\tlineNumber = 1;\r\n\t\t\tif (allowMoveOnFirstLine) {\r\n\t\t\t\tcolumn = model.getLineMinColumn(lineNumber);\r\n\t\t\t} else {\r\n\t\t\t\tcolumn = Math.min(model.getLineMaxColumn(lineNumber), column);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tcolumn = CursorColumns.columnFromVisibleColumn2(config, model, lineNumber, currentVisibleColumn);\r\n\t\t}\r\n\r\n\t\tif (wasOnFirstPosition) {\r\n\t\t\tleftoverVisibleColumns = 0;\r\n\t\t} else {\r\n\t\t\tleftoverVisibleColumns = currentVisibleColumn - CursorColumns.visibleColumnFromColumn(model.getLineContent(lineNumber), column, config.tabSize);\r\n\t\t}\r\n\r\n\t\treturn new CursorPosition(lineNumber, column, leftoverVisibleColumns);\r\n\t}\r\n\r\n\tpublic static moveUp(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, linesCount: number): SingleCursorState {\r\n\t\tlet lineNumber: number,\r\n\t\t\tcolumn: number;\r\n\r\n\t\tif (cursor.hasSelection() && !inSelectionMode) {\r\n\t\t\t// If we are in selection mode, move up acts relative to the beginning of selection\r\n\t\t\tlineNumber = cursor.selection.startLineNumber;\r\n\t\t\tcolumn = cursor.selection.startColumn;\r\n\t\t} else {\r\n\t\t\tlineNumber = cursor.position.lineNumber;\r\n\t\t\tcolumn = cursor.position.column;\r\n\t\t}\r\n\r\n\t\tlet r = MoveOperations.up(config, model, lineNumber, column, cursor.leftoverVisibleColumns, linesCount, true);\r\n\r\n\t\treturn cursor.move(inSelectionMode, r.lineNumber, r.column, r.leftoverVisibleColumns);\r\n\t}\r\n\r\n\tpublic static translateUp(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState): SingleCursorState {\r\n\r\n\t\tlet selection = cursor.selection;\r\n\r\n\t\tlet selectionStart = MoveOperations.up(config, model, selection.selectionStartLineNumber, selection.selectionStartColumn, cursor.selectionStartLeftoverVisibleColumns, 1, false);\r\n\t\tlet position = MoveOperations.up(config, model, selection.positionLineNumber, selection.positionColumn, cursor.leftoverVisibleColumns, 1, false);\r\n\r\n\t\treturn new SingleCursorState(\r\n\t\t\tnew Range(selectionStart.lineNumber, selectionStart.column, selectionStart.lineNumber, selectionStart.column),\r\n\t\t\tselectionStart.leftoverVisibleColumns,\r\n\t\t\tnew Position(position.lineNumber, position.column),\r\n\t\t\tposition.leftoverVisibleColumns\r\n\t\t);\r\n\t}\r\n\r\n\tpublic static moveToBeginningOfLine(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean): SingleCursorState {\r\n\t\tlet lineNumber = cursor.position.lineNumber;\r\n\t\tlet minColumn = model.getLineMinColumn(lineNumber);\r\n\t\tlet firstNonBlankColumn = model.getLineFirstNonWhitespaceColumn(lineNumber) || minColumn;\r\n\r\n\t\tlet column: number;\r\n\r\n\t\tlet relevantColumnNumber = cursor.position.column;\r\n\t\tif (relevantColumnNumber === firstNonBlankColumn) {\r\n\t\t\tcolumn = minColumn;\r\n\t\t} else {\r\n\t\t\tcolumn = firstNonBlankColumn;\r\n\t\t}\r\n\r\n\t\treturn cursor.move(inSelectionMode, lineNumber, column, 0);\r\n\t}\r\n\r\n\tpublic static moveToEndOfLine(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, sticky: boolean): SingleCursorState {\r\n\t\tlet lineNumber = cursor.position.lineNumber;\r\n\t\tlet maxColumn = model.getLineMaxColumn(lineNumber);\r\n\t\treturn cursor.move(inSelectionMode, lineNumber, maxColumn, sticky ? Constants.MAX_SAFE_SMALL_INTEGER - maxColumn : 0);\r\n\t}\r\n\r\n\tpublic static moveToBeginningOfBuffer(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean): SingleCursorState {\r\n\t\treturn cursor.move(inSelectionMode, 1, 1, 0);\r\n\t}\r\n\r\n\tpublic static moveToEndOfBuffer(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean): SingleCursorState {\r\n\t\tlet lastLineNumber = model.getLineCount();\r\n\t\tlet lastColumn = model.getLineMaxColumn(lastLineNumber);\r\n\r\n\t\treturn cursor.move(inSelectionMode, lastLineNumber, lastColumn, 0);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { ReplaceCommand } from 'vs/editor/common/commands/replaceCommand';\r\nimport { EditorAutoClosingStrategy } from 'vs/editor/common/config/editorOptions';\r\nimport { CursorColumns, CursorConfiguration, EditOperationResult, EditOperationType, ICursorSimpleModel, isQuote } from 'vs/editor/common/controller/cursorCommon';\r\nimport { MoveOperations } from 'vs/editor/common/controller/cursorMoveOperations';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { ICommand } from 'vs/editor/common/editorCommon';\r\nimport { StandardAutoClosingPairConditional } from 'vs/editor/common/modes/languageConfiguration';\r\n\r\nexport class DeleteOperations {\r\n\r\n\tpublic static deleteRight(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): [boolean, Array] {\r\n\t\tlet commands: Array = [];\r\n\t\tlet shouldPushStackElementBefore = (prevEditOperationType !== EditOperationType.DeletingRight);\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tconst selection = selections[i];\r\n\r\n\t\t\tlet deleteSelection: Range = selection;\r\n\r\n\t\t\tif (deleteSelection.isEmpty()) {\r\n\t\t\t\tlet position = selection.getPosition();\r\n\t\t\t\tlet rightOfPosition = MoveOperations.right(config, model, position.lineNumber, position.column);\r\n\t\t\t\tdeleteSelection = new Range(\r\n\t\t\t\t\trightOfPosition.lineNumber,\r\n\t\t\t\t\trightOfPosition.column,\r\n\t\t\t\t\tposition.lineNumber,\r\n\t\t\t\t\tposition.column\r\n\t\t\t\t);\r\n\t\t\t}\r\n\r\n\t\t\tif (deleteSelection.isEmpty()) {\r\n\t\t\t\t// Probably at end of file => ignore\r\n\t\t\t\tcommands[i] = null;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (deleteSelection.startLineNumber !== deleteSelection.endLineNumber) {\r\n\t\t\t\tshouldPushStackElementBefore = true;\r\n\t\t\t}\r\n\r\n\t\t\tcommands[i] = new ReplaceCommand(deleteSelection, '');\r\n\t\t}\r\n\t\treturn [shouldPushStackElementBefore, commands];\r\n\t}\r\n\r\n\tpublic static isAutoClosingPairDelete(\r\n\t\tautoClosingBrackets: EditorAutoClosingStrategy,\r\n\t\tautoClosingQuotes: EditorAutoClosingStrategy,\r\n\t\tautoClosingPairsOpen: Map,\r\n\t\tmodel: ICursorSimpleModel,\r\n\t\tselections: Selection[]\r\n\t): boolean {\r\n\t\tif (autoClosingBrackets === 'never' && autoClosingQuotes === 'never') {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tconst selection = selections[i];\r\n\t\t\tconst position = selection.getPosition();\r\n\r\n\t\t\tif (!selection.isEmpty()) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\tconst lineText = model.getLineContent(position.lineNumber);\r\n\t\t\tif (position.column < 2 || position.column >= lineText.length + 1) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t\tconst character = lineText.charAt(position.column - 2);\r\n\r\n\t\t\tconst autoClosingPairCandidates = autoClosingPairsOpen.get(character);\r\n\t\t\tif (!autoClosingPairCandidates) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\tif (isQuote(character)) {\r\n\t\t\t\tif (autoClosingQuotes === 'never') {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tif (autoClosingBrackets === 'never') {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tconst afterCharacter = lineText.charAt(position.column - 1);\r\n\r\n\t\t\tlet foundAutoClosingPair = false;\r\n\t\t\tfor (const autoClosingPairCandidate of autoClosingPairCandidates) {\r\n\t\t\t\tif (autoClosingPairCandidate.open === character && autoClosingPairCandidate.close === afterCharacter) {\r\n\t\t\t\t\tfoundAutoClosingPair = true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (!foundAutoClosingPair) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tprivate static _runAutoClosingPairDelete(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): [boolean, ICommand[]] {\r\n\t\tlet commands: ICommand[] = [];\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tconst position = selections[i].getPosition();\r\n\t\t\tconst deleteSelection = new Range(\r\n\t\t\t\tposition.lineNumber,\r\n\t\t\t\tposition.column - 1,\r\n\t\t\t\tposition.lineNumber,\r\n\t\t\t\tposition.column + 1\r\n\t\t\t);\r\n\t\t\tcommands[i] = new ReplaceCommand(deleteSelection, '');\r\n\t\t}\r\n\t\treturn [true, commands];\r\n\t}\r\n\r\n\tpublic static deleteLeft(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): [boolean, Array] {\r\n\r\n\t\tif (this.isAutoClosingPairDelete(config.autoClosingBrackets, config.autoClosingQuotes, config.autoClosingPairs.autoClosingPairsOpenByEnd, model, selections)) {\r\n\t\t\treturn this._runAutoClosingPairDelete(config, model, selections);\r\n\t\t}\r\n\r\n\t\tlet commands: Array = [];\r\n\t\tlet shouldPushStackElementBefore = (prevEditOperationType !== EditOperationType.DeletingLeft);\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tconst selection = selections[i];\r\n\r\n\t\t\tlet deleteSelection: Range = selection;\r\n\r\n\t\t\tif (deleteSelection.isEmpty()) {\r\n\t\t\t\tlet position = selection.getPosition();\r\n\r\n\t\t\t\tif (config.useTabStops && position.column > 1) {\r\n\t\t\t\t\tlet lineContent = model.getLineContent(position.lineNumber);\r\n\r\n\t\t\t\t\tlet firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(lineContent);\r\n\t\t\t\t\tlet lastIndentationColumn = (\r\n\t\t\t\t\t\tfirstNonWhitespaceIndex === -1\r\n\t\t\t\t\t\t\t? /* entire string is whitespace */lineContent.length + 1\r\n\t\t\t\t\t\t\t: firstNonWhitespaceIndex + 1\r\n\t\t\t\t\t);\r\n\r\n\t\t\t\t\tif (position.column <= lastIndentationColumn) {\r\n\t\t\t\t\t\tlet fromVisibleColumn = CursorColumns.visibleColumnFromColumn2(config, model, position);\r\n\t\t\t\t\t\tlet toVisibleColumn = CursorColumns.prevIndentTabStop(fromVisibleColumn, config.indentSize);\r\n\t\t\t\t\t\tlet toColumn = CursorColumns.columnFromVisibleColumn2(config, model, position.lineNumber, toVisibleColumn);\r\n\t\t\t\t\t\tdeleteSelection = new Range(position.lineNumber, toColumn, position.lineNumber, position.column);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tdeleteSelection = new Range(position.lineNumber, position.column - 1, position.lineNumber, position.column);\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tlet leftOfPosition = MoveOperations.left(config, model, position.lineNumber, position.column);\r\n\t\t\t\t\tdeleteSelection = new Range(\r\n\t\t\t\t\t\tleftOfPosition.lineNumber,\r\n\t\t\t\t\t\tleftOfPosition.column,\r\n\t\t\t\t\t\tposition.lineNumber,\r\n\t\t\t\t\t\tposition.column\r\n\t\t\t\t\t);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (deleteSelection.isEmpty()) {\r\n\t\t\t\t// Probably at beginning of file => ignore\r\n\t\t\t\tcommands[i] = null;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (deleteSelection.startLineNumber !== deleteSelection.endLineNumber) {\r\n\t\t\t\tshouldPushStackElementBefore = true;\r\n\t\t\t}\r\n\r\n\t\t\tcommands[i] = new ReplaceCommand(deleteSelection, '');\r\n\t\t}\r\n\t\treturn [shouldPushStackElementBefore, commands];\r\n\t}\r\n\r\n\tpublic static cut(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): EditOperationResult {\r\n\t\tlet commands: Array = [];\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tconst selection = selections[i];\r\n\r\n\t\t\tif (selection.isEmpty()) {\r\n\t\t\t\tif (config.emptySelectionClipboard) {\r\n\t\t\t\t\t// This is a full line cut\r\n\r\n\t\t\t\t\tlet position = selection.getPosition();\r\n\r\n\t\t\t\t\tlet startLineNumber: number,\r\n\t\t\t\t\t\tstartColumn: number,\r\n\t\t\t\t\t\tendLineNumber: number,\r\n\t\t\t\t\t\tendColumn: number;\r\n\r\n\t\t\t\t\tif (position.lineNumber < model.getLineCount()) {\r\n\t\t\t\t\t\t// Cutting a line in the middle of the model\r\n\t\t\t\t\t\tstartLineNumber = position.lineNumber;\r\n\t\t\t\t\t\tstartColumn = 1;\r\n\t\t\t\t\t\tendLineNumber = position.lineNumber + 1;\r\n\t\t\t\t\t\tendColumn = 1;\r\n\t\t\t\t\t} else if (position.lineNumber > 1) {\r\n\t\t\t\t\t\t// Cutting the last line & there are more than 1 lines in the model\r\n\t\t\t\t\t\tstartLineNumber = position.lineNumber - 1;\r\n\t\t\t\t\t\tstartColumn = model.getLineMaxColumn(position.lineNumber - 1);\r\n\t\t\t\t\t\tendLineNumber = position.lineNumber;\r\n\t\t\t\t\t\tendColumn = model.getLineMaxColumn(position.lineNumber);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t// Cutting the single line that the model contains\r\n\t\t\t\t\t\tstartLineNumber = position.lineNumber;\r\n\t\t\t\t\t\tstartColumn = 1;\r\n\t\t\t\t\t\tendLineNumber = position.lineNumber;\r\n\t\t\t\t\t\tendColumn = model.getLineMaxColumn(position.lineNumber);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tlet deleteSelection = new Range(\r\n\t\t\t\t\t\tstartLineNumber,\r\n\t\t\t\t\t\tstartColumn,\r\n\t\t\t\t\t\tendLineNumber,\r\n\t\t\t\t\t\tendColumn\r\n\t\t\t\t\t);\r\n\r\n\t\t\t\t\tif (!deleteSelection.isEmpty()) {\r\n\t\t\t\t\t\tcommands[i] = new ReplaceCommand(deleteSelection, '');\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tcommands[i] = null;\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// Cannot cut empty selection\r\n\t\t\t\t\tcommands[i] = null;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tcommands[i] = new ReplaceCommand(selection, '');\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn new EditOperationResult(EditOperationType.Other, commands, {\r\n\t\t\tshouldPushStackElementBefore: true,\r\n\t\t\tshouldPushStackElementAfter: true\r\n\t\t});\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { ReplaceCommand, ReplaceCommandWithOffsetCursorState, ReplaceCommandWithoutChangingPosition, ReplaceCommandThatPreservesSelection } from 'vs/editor/common/commands/replaceCommand';\r\nimport { ShiftCommand } from 'vs/editor/common/commands/shiftCommand';\r\nimport { SurroundSelectionCommand } from 'vs/editor/common/commands/surroundSelectionCommand';\r\nimport { CursorColumns, CursorConfiguration, EditOperationResult, EditOperationType, ICursorSimpleModel, isQuote } from 'vs/editor/common/controller/cursorCommon';\r\nimport { WordCharacterClass, getMapForWordSeparators } from 'vs/editor/common/controller/wordCharacterClassifier';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { ICommand, ICursorStateComputerData } from 'vs/editor/common/editorCommon';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { EnterAction, IndentAction, StandardAutoClosingPairConditional } from 'vs/editor/common/modes/languageConfiguration';\r\nimport { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';\r\nimport { IElectricAction } from 'vs/editor/common/modes/supports/electricCharacter';\r\nimport { EditorAutoIndentStrategy } from 'vs/editor/common/config/editorOptions';\r\n\r\nexport class TypeOperations {\r\n\r\n\tpublic static indent(config: CursorConfiguration, model: ICursorSimpleModel | null, selections: Selection[] | null): ICommand[] {\r\n\t\tif (model === null || selections === null) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tlet commands: ICommand[] = [];\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tcommands[i] = new ShiftCommand(selections[i], {\r\n\t\t\t\tisUnshift: false,\r\n\t\t\t\ttabSize: config.tabSize,\r\n\t\t\t\tindentSize: config.indentSize,\r\n\t\t\t\tinsertSpaces: config.insertSpaces,\r\n\t\t\t\tuseTabStops: config.useTabStops,\r\n\t\t\t\tautoIndent: config.autoIndent\r\n\t\t\t});\r\n\t\t}\r\n\t\treturn commands;\r\n\t}\r\n\r\n\tpublic static outdent(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): ICommand[] {\r\n\t\tlet commands: ICommand[] = [];\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tcommands[i] = new ShiftCommand(selections[i], {\r\n\t\t\t\tisUnshift: true,\r\n\t\t\t\ttabSize: config.tabSize,\r\n\t\t\t\tindentSize: config.indentSize,\r\n\t\t\t\tinsertSpaces: config.insertSpaces,\r\n\t\t\t\tuseTabStops: config.useTabStops,\r\n\t\t\t\tautoIndent: config.autoIndent\r\n\t\t\t});\r\n\t\t}\r\n\t\treturn commands;\r\n\t}\r\n\r\n\tpublic static shiftIndent(config: CursorConfiguration, indentation: string, count?: number): string {\r\n\t\tcount = count || 1;\r\n\t\treturn ShiftCommand.shiftIndent(indentation, indentation.length + count, config.tabSize, config.indentSize, config.insertSpaces);\r\n\t}\r\n\r\n\tpublic static unshiftIndent(config: CursorConfiguration, indentation: string, count?: number): string {\r\n\t\tcount = count || 1;\r\n\t\treturn ShiftCommand.unshiftIndent(indentation, indentation.length + count, config.tabSize, config.indentSize, config.insertSpaces);\r\n\t}\r\n\r\n\tprivate static _distributedPaste(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[], text: string[]): EditOperationResult {\r\n\t\tlet commands: ICommand[] = [];\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tcommands[i] = new ReplaceCommand(selections[i], text[i]);\r\n\t\t}\r\n\t\treturn new EditOperationResult(EditOperationType.Other, commands, {\r\n\t\t\tshouldPushStackElementBefore: true,\r\n\t\t\tshouldPushStackElementAfter: true\r\n\t\t});\r\n\t}\r\n\r\n\tprivate static _simplePaste(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[], text: string, pasteOnNewLine: boolean): EditOperationResult {\r\n\t\tlet commands: ICommand[] = [];\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tconst selection = selections[i];\r\n\t\t\tlet position = selection.getPosition();\r\n\r\n\t\t\tif (pasteOnNewLine && !selection.isEmpty()) {\r\n\t\t\t\tpasteOnNewLine = false;\r\n\t\t\t}\r\n\t\t\tif (pasteOnNewLine && text.indexOf('\\n') !== text.length - 1) {\r\n\t\t\t\tpasteOnNewLine = false;\r\n\t\t\t}\r\n\r\n\t\t\tif (pasteOnNewLine) {\r\n\t\t\t\t// Paste entire line at the beginning of line\r\n\t\t\t\tlet typeSelection = new Range(position.lineNumber, 1, position.lineNumber, 1);\r\n\t\t\t\tcommands[i] = new ReplaceCommandThatPreservesSelection(typeSelection, text, selection, true);\r\n\t\t\t} else {\r\n\t\t\t\tcommands[i] = new ReplaceCommand(selection, text);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn new EditOperationResult(EditOperationType.Other, commands, {\r\n\t\t\tshouldPushStackElementBefore: true,\r\n\t\t\tshouldPushStackElementAfter: true\r\n\t\t});\r\n\t}\r\n\r\n\tprivate static _distributePasteToCursors(config: CursorConfiguration, selections: Selection[], text: string, pasteOnNewLine: boolean, multicursorText: string[]): string[] | null {\r\n\t\tif (pasteOnNewLine) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (selections.length === 1) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (multicursorText && multicursorText.length === selections.length) {\r\n\t\t\treturn multicursorText;\r\n\t\t}\r\n\r\n\t\tif (config.multiCursorPaste === 'spread') {\r\n\t\t\t// Try to spread the pasted text in case the line count matches the cursor count\r\n\t\t\t// Remove trailing \\n if present\r\n\t\t\tif (text.charCodeAt(text.length - 1) === CharCode.LineFeed) {\r\n\t\t\t\ttext = text.substr(0, text.length - 1);\r\n\t\t\t}\r\n\t\t\t// Remove trailing \\r if present\r\n\t\t\tif (text.charCodeAt(text.length - 1) === CharCode.CarriageReturn) {\r\n\t\t\t\ttext = text.substr(0, text.length - 1);\r\n\t\t\t}\r\n\t\t\tlet lines = strings.splitLines(text);\r\n\t\t\tif (lines.length === selections.length) {\r\n\t\t\t\treturn lines;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic static paste(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[], text: string, pasteOnNewLine: boolean, multicursorText: string[]): EditOperationResult {\r\n\t\tconst distributedPaste = this._distributePasteToCursors(config, selections, text, pasteOnNewLine, multicursorText);\r\n\r\n\t\tif (distributedPaste) {\r\n\t\t\tselections = selections.sort(Range.compareRangesUsingStarts);\r\n\t\t\treturn this._distributedPaste(config, model, selections, distributedPaste);\r\n\t\t} else {\r\n\t\t\treturn this._simplePaste(config, model, selections, text, pasteOnNewLine);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static _goodIndentForLine(config: CursorConfiguration, model: ITextModel, lineNumber: number): string | null {\r\n\t\tlet action: IndentAction | EnterAction | null = null;\r\n\t\tlet indentation: string = '';\r\n\r\n\t\tconst expectedIndentAction = LanguageConfigurationRegistry.getInheritIndentForLine(config.autoIndent, model, lineNumber, false);\r\n\t\tif (expectedIndentAction) {\r\n\t\t\taction = expectedIndentAction.action;\r\n\t\t\tindentation = expectedIndentAction.indentation;\r\n\t\t} else if (lineNumber > 1) {\r\n\t\t\tlet lastLineNumber: number;\r\n\t\t\tfor (lastLineNumber = lineNumber - 1; lastLineNumber >= 1; lastLineNumber--) {\r\n\t\t\t\tconst lineText = model.getLineContent(lastLineNumber);\r\n\t\t\t\tconst nonWhitespaceIdx = strings.lastNonWhitespaceIndex(lineText);\r\n\t\t\t\tif (nonWhitespaceIdx >= 0) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (lastLineNumber < 1) {\r\n\t\t\t\t// No previous line with content found\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\r\n\t\t\tconst maxColumn = model.getLineMaxColumn(lastLineNumber);\r\n\t\t\tconst expectedEnterAction = LanguageConfigurationRegistry.getEnterAction(config.autoIndent, model, new Range(lastLineNumber, maxColumn, lastLineNumber, maxColumn));\r\n\t\t\tif (expectedEnterAction) {\r\n\t\t\t\tindentation = expectedEnterAction.indentation + expectedEnterAction.appendText;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (action) {\r\n\t\t\tif (action === IndentAction.Indent) {\r\n\t\t\t\tindentation = TypeOperations.shiftIndent(config, indentation);\r\n\t\t\t}\r\n\r\n\t\t\tif (action === IndentAction.Outdent) {\r\n\t\t\t\tindentation = TypeOperations.unshiftIndent(config, indentation);\r\n\t\t\t}\r\n\r\n\t\t\tindentation = config.normalizeIndentation(indentation);\r\n\t\t}\r\n\r\n\t\tif (!indentation) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\treturn indentation;\r\n\t}\r\n\r\n\tprivate static _replaceJumpToNextIndent(config: CursorConfiguration, model: ICursorSimpleModel, selection: Selection, insertsAutoWhitespace: boolean): ReplaceCommand {\r\n\t\tlet typeText = '';\r\n\r\n\t\tlet position = selection.getStartPosition();\r\n\t\tif (config.insertSpaces) {\r\n\t\t\tlet visibleColumnFromColumn = CursorColumns.visibleColumnFromColumn2(config, model, position);\r\n\t\t\tlet indentSize = config.indentSize;\r\n\t\t\tlet spacesCnt = indentSize - (visibleColumnFromColumn % indentSize);\r\n\t\t\tfor (let i = 0; i < spacesCnt; i++) {\r\n\t\t\t\ttypeText += ' ';\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\ttypeText = '\\t';\r\n\t\t}\r\n\r\n\t\treturn new ReplaceCommand(selection, typeText, insertsAutoWhitespace);\r\n\t}\r\n\r\n\tpublic static tab(config: CursorConfiguration, model: ITextModel, selections: Selection[]): ICommand[] {\r\n\t\tlet commands: ICommand[] = [];\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tconst selection = selections[i];\r\n\r\n\t\t\tif (selection.isEmpty()) {\r\n\r\n\t\t\t\tlet lineText = model.getLineContent(selection.startLineNumber);\r\n\r\n\t\t\t\tif (/^\\s*$/.test(lineText) && model.isCheapToTokenize(selection.startLineNumber)) {\r\n\t\t\t\t\tlet goodIndent = this._goodIndentForLine(config, model, selection.startLineNumber);\r\n\t\t\t\t\tgoodIndent = goodIndent || '\\t';\r\n\t\t\t\t\tlet possibleTypeText = config.normalizeIndentation(goodIndent);\r\n\t\t\t\t\tif (!lineText.startsWith(possibleTypeText)) {\r\n\t\t\t\t\t\tcommands[i] = new ReplaceCommand(new Range(selection.startLineNumber, 1, selection.startLineNumber, lineText.length + 1), possibleTypeText, true);\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tcommands[i] = this._replaceJumpToNextIndent(config, model, selection, true);\r\n\t\t\t} else {\r\n\t\t\t\tif (selection.startLineNumber === selection.endLineNumber) {\r\n\t\t\t\t\tlet lineMaxColumn = model.getLineMaxColumn(selection.startLineNumber);\r\n\t\t\t\t\tif (selection.startColumn !== 1 || selection.endColumn !== lineMaxColumn) {\r\n\t\t\t\t\t\t// This is a single line selection that is not the entire line\r\n\t\t\t\t\t\tcommands[i] = this._replaceJumpToNextIndent(config, model, selection, false);\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tcommands[i] = new ShiftCommand(selection, {\r\n\t\t\t\t\tisUnshift: false,\r\n\t\t\t\t\ttabSize: config.tabSize,\r\n\t\t\t\t\tindentSize: config.indentSize,\r\n\t\t\t\t\tinsertSpaces: config.insertSpaces,\r\n\t\t\t\t\tuseTabStops: config.useTabStops,\r\n\t\t\t\t\tautoIndent: config.autoIndent\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn commands;\r\n\t}\r\n\r\n\tpublic static replacePreviousChar(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], txt: string, replaceCharCnt: number): EditOperationResult {\r\n\t\tlet commands: Array = [];\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tconst selection = selections[i];\r\n\t\t\tif (!selection.isEmpty()) {\r\n\t\t\t\t// looks like https://github.com/microsoft/vscode/issues/2773\r\n\t\t\t\t// where a cursor operation occurred before a canceled composition\r\n\t\t\t\t// => ignore composition\r\n\t\t\t\tcommands[i] = null;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tconst pos = selection.getPosition();\r\n\t\t\tconst startColumn = Math.max(1, pos.column - replaceCharCnt);\r\n\t\t\tconst range = new Range(pos.lineNumber, startColumn, pos.lineNumber, pos.column);\r\n\t\t\tconst oldText = model.getValueInRange(range);\r\n\t\t\tif (oldText === txt) {\r\n\t\t\t\t// => ignore composition that doesn't do anything\r\n\t\t\t\tcommands[i] = null;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tcommands[i] = new ReplaceCommand(range, txt);\r\n\t\t}\r\n\t\treturn new EditOperationResult(EditOperationType.Typing, commands, {\r\n\t\t\tshouldPushStackElementBefore: (prevEditOperationType !== EditOperationType.Typing),\r\n\t\t\tshouldPushStackElementAfter: false\r\n\t\t});\r\n\t}\r\n\r\n\tprivate static _typeCommand(range: Range, text: string, keepPosition: boolean): ICommand {\r\n\t\tif (keepPosition) {\r\n\t\t\treturn new ReplaceCommandWithoutChangingPosition(range, text, true);\r\n\t\t} else {\r\n\t\t\treturn new ReplaceCommand(range, text, true);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static _enter(config: CursorConfiguration, model: ITextModel, keepPosition: boolean, range: Range): ICommand {\r\n\t\tif (config.autoIndent === EditorAutoIndentStrategy.None) {\r\n\t\t\treturn TypeOperations._typeCommand(range, '\\n', keepPosition);\r\n\t\t}\r\n\t\tif (!model.isCheapToTokenize(range.getStartPosition().lineNumber) || config.autoIndent === EditorAutoIndentStrategy.Keep) {\r\n\t\t\tlet lineText = model.getLineContent(range.startLineNumber);\r\n\t\t\tlet indentation = strings.getLeadingWhitespace(lineText).substring(0, range.startColumn - 1);\r\n\t\t\treturn TypeOperations._typeCommand(range, '\\n' + config.normalizeIndentation(indentation), keepPosition);\r\n\t\t}\r\n\r\n\t\tconst r = LanguageConfigurationRegistry.getEnterAction(config.autoIndent, model, range);\r\n\t\tif (r) {\r\n\t\t\tif (r.indentAction === IndentAction.None) {\r\n\t\t\t\t// Nothing special\r\n\t\t\t\treturn TypeOperations._typeCommand(range, '\\n' + config.normalizeIndentation(r.indentation + r.appendText), keepPosition);\r\n\r\n\t\t\t} else if (r.indentAction === IndentAction.Indent) {\r\n\t\t\t\t// Indent once\r\n\t\t\t\treturn TypeOperations._typeCommand(range, '\\n' + config.normalizeIndentation(r.indentation + r.appendText), keepPosition);\r\n\r\n\t\t\t} else if (r.indentAction === IndentAction.IndentOutdent) {\r\n\t\t\t\t// Ultra special\r\n\t\t\t\tconst normalIndent = config.normalizeIndentation(r.indentation);\r\n\t\t\t\tconst increasedIndent = config.normalizeIndentation(r.indentation + r.appendText);\r\n\r\n\t\t\t\tconst typeText = '\\n' + increasedIndent + '\\n' + normalIndent;\r\n\r\n\t\t\t\tif (keepPosition) {\r\n\t\t\t\t\treturn new ReplaceCommandWithoutChangingPosition(range, typeText, true);\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn new ReplaceCommandWithOffsetCursorState(range, typeText, -1, increasedIndent.length - normalIndent.length, true);\r\n\t\t\t\t}\r\n\t\t\t} else if (r.indentAction === IndentAction.Outdent) {\r\n\t\t\t\tconst actualIndentation = TypeOperations.unshiftIndent(config, r.indentation);\r\n\t\t\t\treturn TypeOperations._typeCommand(range, '\\n' + config.normalizeIndentation(actualIndentation + r.appendText), keepPosition);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst lineText = model.getLineContent(range.startLineNumber);\r\n\t\tconst indentation = strings.getLeadingWhitespace(lineText).substring(0, range.startColumn - 1);\r\n\r\n\t\tif (config.autoIndent >= EditorAutoIndentStrategy.Full) {\r\n\t\t\tconst ir = LanguageConfigurationRegistry.getIndentForEnter(config.autoIndent, model, range, {\r\n\t\t\t\tunshiftIndent: (indent) => {\r\n\t\t\t\t\treturn TypeOperations.unshiftIndent(config, indent);\r\n\t\t\t\t},\r\n\t\t\t\tshiftIndent: (indent) => {\r\n\t\t\t\t\treturn TypeOperations.shiftIndent(config, indent);\r\n\t\t\t\t},\r\n\t\t\t\tnormalizeIndentation: (indent) => {\r\n\t\t\t\t\treturn config.normalizeIndentation(indent);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\t\tif (ir) {\r\n\t\t\t\tlet oldEndViewColumn = CursorColumns.visibleColumnFromColumn2(config, model, range.getEndPosition());\r\n\t\t\t\tconst oldEndColumn = range.endColumn;\r\n\t\t\t\tconst newLineContent = model.getLineContent(range.endLineNumber);\r\n\t\t\t\tconst firstNonWhitespace = strings.firstNonWhitespaceIndex(newLineContent);\r\n\t\t\t\tif (firstNonWhitespace >= 0) {\r\n\t\t\t\t\trange = range.setEndPosition(range.endLineNumber, Math.max(range.endColumn, firstNonWhitespace + 1));\r\n\t\t\t\t} else {\r\n\t\t\t\t\trange = range.setEndPosition(range.endLineNumber, model.getLineMaxColumn(range.endLineNumber));\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (keepPosition) {\r\n\t\t\t\t\treturn new ReplaceCommandWithoutChangingPosition(range, '\\n' + config.normalizeIndentation(ir.afterEnter), true);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tlet offset = 0;\r\n\t\t\t\t\tif (oldEndColumn <= firstNonWhitespace + 1) {\r\n\t\t\t\t\t\tif (!config.insertSpaces) {\r\n\t\t\t\t\t\t\toldEndViewColumn = Math.ceil(oldEndViewColumn / config.indentSize);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\toffset = Math.min(oldEndViewColumn + 1 - config.normalizeIndentation(ir.afterEnter).length - 1, 0);\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn new ReplaceCommandWithOffsetCursorState(range, '\\n' + config.normalizeIndentation(ir.afterEnter), 0, offset, true);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn TypeOperations._typeCommand(range, '\\n' + config.normalizeIndentation(indentation), keepPosition);\r\n\t}\r\n\r\n\tprivate static _isAutoIndentType(config: CursorConfiguration, model: ITextModel, selections: Selection[]): boolean {\r\n\t\tif (config.autoIndent < EditorAutoIndentStrategy.Full) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tif (!model.isCheapToTokenize(selections[i].getEndPosition().lineNumber)) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tprivate static _runAutoIndentType(config: CursorConfiguration, model: ITextModel, range: Range, ch: string): ICommand | null {\r\n\t\tconst currentIndentation = LanguageConfigurationRegistry.getIndentationAtPosition(model, range.startLineNumber, range.startColumn);\r\n\t\tconst actualIndentation = LanguageConfigurationRegistry.getIndentActionForType(config.autoIndent, model, range, ch, {\r\n\t\t\tshiftIndent: (indentation) => {\r\n\t\t\t\treturn TypeOperations.shiftIndent(config, indentation);\r\n\t\t\t},\r\n\t\t\tunshiftIndent: (indentation) => {\r\n\t\t\t\treturn TypeOperations.unshiftIndent(config, indentation);\r\n\t\t\t},\r\n\t\t});\r\n\r\n\t\tif (actualIndentation === null) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (actualIndentation !== config.normalizeIndentation(currentIndentation)) {\r\n\t\t\tconst firstNonWhitespace = model.getLineFirstNonWhitespaceColumn(range.startLineNumber);\r\n\t\t\tif (firstNonWhitespace === 0) {\r\n\t\t\t\treturn TypeOperations._typeCommand(\r\n\t\t\t\t\tnew Range(range.startLineNumber, 1, range.endLineNumber, range.endColumn),\r\n\t\t\t\t\tconfig.normalizeIndentation(actualIndentation) + ch,\r\n\t\t\t\t\tfalse\r\n\t\t\t\t);\r\n\t\t\t} else {\r\n\t\t\t\treturn TypeOperations._typeCommand(\r\n\t\t\t\t\tnew Range(range.startLineNumber, 1, range.endLineNumber, range.endColumn),\r\n\t\t\t\t\tconfig.normalizeIndentation(actualIndentation) +\r\n\t\t\t\t\tmodel.getLineContent(range.startLineNumber).substring(firstNonWhitespace - 1, range.startColumn - 1) + ch,\r\n\t\t\t\t\tfalse\r\n\t\t\t\t);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate static _isAutoClosingOvertype(config: CursorConfiguration, model: ITextModel, selections: Selection[], autoClosedCharacters: Range[], ch: string): boolean {\r\n\t\tif (config.autoClosingOvertype === 'never') {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tif (!config.autoClosingPairs.autoClosingPairsCloseSingleChar.has(ch)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tconst selection = selections[i];\r\n\r\n\t\t\tif (!selection.isEmpty()) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\tconst position = selection.getPosition();\r\n\t\t\tconst lineText = model.getLineContent(position.lineNumber);\r\n\t\t\tconst afterCharacter = lineText.charAt(position.column - 1);\r\n\r\n\t\t\tif (afterCharacter !== ch) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\t// Do not over-type quotes after a backslash\r\n\t\t\tconst chIsQuote = isQuote(ch);\r\n\t\t\tconst beforeCharacter = position.column > 2 ? lineText.charCodeAt(position.column - 2) : CharCode.Null;\r\n\t\t\tif (beforeCharacter === CharCode.Backslash && chIsQuote) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\t// Must over-type a closing character typed by the editor\r\n\t\t\tif (config.autoClosingOvertype === 'auto') {\r\n\t\t\t\tlet found = false;\r\n\t\t\t\tfor (let j = 0, lenJ = autoClosedCharacters.length; j < lenJ; j++) {\r\n\t\t\t\t\tconst autoClosedCharacter = autoClosedCharacters[j];\r\n\t\t\t\t\tif (position.lineNumber === autoClosedCharacter.startLineNumber && position.column === autoClosedCharacter.startColumn) {\r\n\t\t\t\t\t\tfound = true;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tif (!found) {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tprivate static _runAutoClosingOvertype(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string): EditOperationResult {\r\n\t\tlet commands: ICommand[] = [];\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tconst selection = selections[i];\r\n\t\t\tconst position = selection.getPosition();\r\n\t\t\tconst typeSelection = new Range(position.lineNumber, position.column, position.lineNumber, position.column + 1);\r\n\t\t\tcommands[i] = new ReplaceCommand(typeSelection, ch);\r\n\t\t}\r\n\t\treturn new EditOperationResult(EditOperationType.Typing, commands, {\r\n\t\t\tshouldPushStackElementBefore: (prevEditOperationType !== EditOperationType.Typing),\r\n\t\t\tshouldPushStackElementAfter: false\r\n\t\t});\r\n\t}\r\n\r\n\tprivate static _isBeforeClosingBrace(config: CursorConfiguration, lineAfter: string) {\r\n\t\t// If the start of lineAfter can be interpretted as both a starting or ending brace, default to returning false\r\n\t\tconst nextChar = lineAfter.charAt(0);\r\n\t\tconst potentialStartingBraces = config.autoClosingPairs.autoClosingPairsOpenByStart.get(nextChar) || [];\r\n\t\tconst potentialClosingBraces = config.autoClosingPairs.autoClosingPairsCloseByStart.get(nextChar) || [];\r\n\r\n\t\tconst isBeforeStartingBrace = potentialStartingBraces.some(x => lineAfter.startsWith(x.open));\r\n\t\tconst isBeforeClosingBrace = potentialClosingBraces.some(x => lineAfter.startsWith(x.close));\r\n\r\n\t\treturn !isBeforeStartingBrace && isBeforeClosingBrace;\r\n\t}\r\n\r\n\tprivate static _findAutoClosingPairOpen(config: CursorConfiguration, model: ITextModel, positions: Position[], ch: string): StandardAutoClosingPairConditional | null {\r\n\t\tconst autoClosingPairCandidates = config.autoClosingPairs.autoClosingPairsOpenByEnd.get(ch);\r\n\t\tif (!autoClosingPairCandidates) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\t// Determine which auto-closing pair it is\r\n\t\tlet autoClosingPair: StandardAutoClosingPairConditional | null = null;\r\n\t\tfor (const autoClosingPairCandidate of autoClosingPairCandidates) {\r\n\t\t\tif (autoClosingPair === null || autoClosingPairCandidate.open.length > autoClosingPair.open.length) {\r\n\t\t\t\tlet candidateIsMatch = true;\r\n\t\t\t\tfor (const position of positions) {\r\n\t\t\t\t\tconst relevantText = model.getValueInRange(new Range(position.lineNumber, position.column - autoClosingPairCandidate.open.length + 1, position.lineNumber, position.column));\r\n\t\t\t\t\tif (relevantText + ch !== autoClosingPairCandidate.open) {\r\n\t\t\t\t\t\tcandidateIsMatch = false;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (candidateIsMatch) {\r\n\t\t\t\t\tautoClosingPair = autoClosingPairCandidate;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn autoClosingPair;\r\n\t}\r\n\r\n\tprivate static _findSubAutoClosingPairClose(config: CursorConfiguration, autoClosingPair: StandardAutoClosingPairConditional): string {\r\n\t\tif (autoClosingPair.open.length <= 1) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\tconst lastChar = autoClosingPair.close.charAt(autoClosingPair.close.length - 1);\r\n\t\t// get candidates with the same last character as close\r\n\t\tconst subPairCandidates = config.autoClosingPairs.autoClosingPairsCloseByEnd.get(lastChar) || [];\r\n\t\tlet subPairMatch: StandardAutoClosingPairConditional | null = null;\r\n\t\tfor (const x of subPairCandidates) {\r\n\t\t\tif (x.open !== autoClosingPair.open && autoClosingPair.open.includes(x.open) && autoClosingPair.close.endsWith(x.close)) {\r\n\t\t\t\tif (!subPairMatch || x.open.length > subPairMatch.open.length) {\r\n\t\t\t\t\tsubPairMatch = x;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (subPairMatch) {\r\n\t\t\treturn subPairMatch.close;\r\n\t\t} else {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static _getAutoClosingPairClose(config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string, insertOpenCharacter: boolean): string | null {\r\n\t\tconst chIsQuote = isQuote(ch);\r\n\t\tconst autoCloseConfig = chIsQuote ? config.autoClosingQuotes : config.autoClosingBrackets;\r\n\t\tif (autoCloseConfig === 'never') {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst autoClosingPair = this._findAutoClosingPairOpen(config, model, selections.map(s => s.getPosition()), ch);\r\n\t\tif (!autoClosingPair) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst subAutoClosingPairClose = this._findSubAutoClosingPairClose(config, autoClosingPair);\r\n\t\tlet isSubAutoClosingPairPresent = true;\r\n\r\n\t\tconst shouldAutoCloseBefore = chIsQuote ? config.shouldAutoCloseBefore.quote : config.shouldAutoCloseBefore.bracket;\r\n\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tconst selection = selections[i];\r\n\t\t\tif (!selection.isEmpty()) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\r\n\t\t\tconst position = selection.getPosition();\r\n\t\t\tconst lineText = model.getLineContent(position.lineNumber);\r\n\t\t\tconst lineAfter = lineText.substring(position.column - 1);\r\n\r\n\t\t\tif (!lineAfter.startsWith(subAutoClosingPairClose)) {\r\n\t\t\t\tisSubAutoClosingPairPresent = false;\r\n\t\t\t}\r\n\r\n\t\t\t// Only consider auto closing the pair if an allowed character follows or if another autoclosed pair closing brace follows\r\n\t\t\tif (lineText.length > position.column - 1) {\r\n\t\t\t\tconst characterAfter = lineText.charAt(position.column - 1);\r\n\t\t\t\tconst isBeforeCloseBrace = TypeOperations._isBeforeClosingBrace(config, lineAfter);\r\n\r\n\t\t\t\tif (!isBeforeCloseBrace && !shouldAutoCloseBefore(characterAfter)) {\r\n\t\t\t\t\treturn null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (!model.isCheapToTokenize(position.lineNumber)) {\r\n\t\t\t\t// Do not force tokenization\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\r\n\t\t\t// Do not auto-close ' or \" after a word character\r\n\t\t\tif (autoClosingPair.open.length === 1 && chIsQuote && autoCloseConfig !== 'always') {\r\n\t\t\t\tconst wordSeparators = getMapForWordSeparators(config.wordSeparators);\r\n\t\t\t\tif (insertOpenCharacter && position.column > 1 && wordSeparators.get(lineText.charCodeAt(position.column - 2)) === WordCharacterClass.Regular) {\r\n\t\t\t\t\treturn null;\r\n\t\t\t\t}\r\n\t\t\t\tif (!insertOpenCharacter && position.column > 2 && wordSeparators.get(lineText.charCodeAt(position.column - 3)) === WordCharacterClass.Regular) {\r\n\t\t\t\t\treturn null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tmodel.forceTokenization(position.lineNumber);\r\n\t\t\tconst lineTokens = model.getLineTokens(position.lineNumber);\r\n\r\n\t\t\tlet shouldAutoClosePair = false;\r\n\t\t\ttry {\r\n\t\t\t\tshouldAutoClosePair = LanguageConfigurationRegistry.shouldAutoClosePair(autoClosingPair, lineTokens, insertOpenCharacter ? position.column : position.column - 1);\r\n\t\t\t} catch (e) {\r\n\t\t\t\tonUnexpectedError(e);\r\n\t\t\t}\r\n\r\n\t\t\tif (!shouldAutoClosePair) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (isSubAutoClosingPairPresent) {\r\n\t\t\treturn autoClosingPair.close.substring(0, autoClosingPair.close.length - subAutoClosingPairClose.length);\r\n\t\t} else {\r\n\t\t\treturn autoClosingPair.close;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static _runAutoClosingOpenCharType(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string, insertOpenCharacter: boolean, autoClosingPairClose: string): EditOperationResult {\r\n\t\tlet commands: ICommand[] = [];\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tconst selection = selections[i];\r\n\t\t\tcommands[i] = new TypeWithAutoClosingCommand(selection, ch, insertOpenCharacter, autoClosingPairClose);\r\n\t\t}\r\n\t\treturn new EditOperationResult(EditOperationType.Typing, commands, {\r\n\t\t\tshouldPushStackElementBefore: true,\r\n\t\t\tshouldPushStackElementAfter: false\r\n\t\t});\r\n\t}\r\n\r\n\tprivate static _shouldSurroundChar(config: CursorConfiguration, ch: string): boolean {\r\n\t\tif (isQuote(ch)) {\r\n\t\t\treturn (config.autoSurround === 'quotes' || config.autoSurround === 'languageDefined');\r\n\t\t} else {\r\n\t\t\t// Character is a bracket\r\n\t\t\treturn (config.autoSurround === 'brackets' || config.autoSurround === 'languageDefined');\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static _isSurroundSelectionType(config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string): boolean {\r\n\t\tif (!TypeOperations._shouldSurroundChar(config, ch) || !config.surroundingPairs.hasOwnProperty(ch)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tconst isTypingAQuoteCharacter = isQuote(ch);\r\n\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tconst selection = selections[i];\r\n\r\n\t\t\tif (selection.isEmpty()) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\tlet selectionContainsOnlyWhitespace = true;\r\n\r\n\t\t\tfor (let lineNumber = selection.startLineNumber; lineNumber <= selection.endLineNumber; lineNumber++) {\r\n\t\t\t\tconst lineText = model.getLineContent(lineNumber);\r\n\t\t\t\tconst startIndex = (lineNumber === selection.startLineNumber ? selection.startColumn - 1 : 0);\r\n\t\t\t\tconst endIndex = (lineNumber === selection.endLineNumber ? selection.endColumn - 1 : lineText.length);\r\n\t\t\t\tconst selectedText = lineText.substring(startIndex, endIndex);\r\n\t\t\t\tif (/[^ \\t]/.test(selectedText)) {\r\n\t\t\t\t\t// this selected text contains something other than whitespace\r\n\t\t\t\t\tselectionContainsOnlyWhitespace = false;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (selectionContainsOnlyWhitespace) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\tif (isTypingAQuoteCharacter && selection.startLineNumber === selection.endLineNumber && selection.startColumn + 1 === selection.endColumn) {\r\n\t\t\t\tconst selectionText = model.getValueInRange(selection);\r\n\t\t\t\tif (isQuote(selectionText)) {\r\n\t\t\t\t\t// Typing a quote character on top of another quote character\r\n\t\t\t\t\t// => disable surround selection type\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tprivate static _runSurroundSelectionType(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string): EditOperationResult {\r\n\t\tlet commands: ICommand[] = [];\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tconst selection = selections[i];\r\n\t\t\tconst closeCharacter = config.surroundingPairs[ch];\r\n\t\t\tcommands[i] = new SurroundSelectionCommand(selection, ch, closeCharacter);\r\n\t\t}\r\n\t\treturn new EditOperationResult(EditOperationType.Other, commands, {\r\n\t\t\tshouldPushStackElementBefore: true,\r\n\t\t\tshouldPushStackElementAfter: true\r\n\t\t});\r\n\t}\r\n\r\n\tprivate static _isTypeInterceptorElectricChar(config: CursorConfiguration, model: ITextModel, selections: Selection[]) {\r\n\t\tif (selections.length === 1 && model.isCheapToTokenize(selections[0].getEndPosition().lineNumber)) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tprivate static _typeInterceptorElectricChar(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selection: Selection, ch: string): EditOperationResult | null {\r\n\t\tif (!config.electricChars.hasOwnProperty(ch) || !selection.isEmpty()) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet position = selection.getPosition();\r\n\t\tmodel.forceTokenization(position.lineNumber);\r\n\t\tlet lineTokens = model.getLineTokens(position.lineNumber);\r\n\r\n\t\tlet electricAction: IElectricAction | null;\r\n\t\ttry {\r\n\t\t\telectricAction = LanguageConfigurationRegistry.onElectricCharacter(ch, lineTokens, position.column);\r\n\t\t} catch (e) {\r\n\t\t\tonUnexpectedError(e);\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (!electricAction) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (electricAction.matchOpenBracket) {\r\n\t\t\tlet endColumn = (lineTokens.getLineContent() + ch).lastIndexOf(electricAction.matchOpenBracket) + 1;\r\n\t\t\tlet match = model.findMatchingBracketUp(electricAction.matchOpenBracket, {\r\n\t\t\t\tlineNumber: position.lineNumber,\r\n\t\t\t\tcolumn: endColumn\r\n\t\t\t});\r\n\r\n\t\t\tif (match) {\r\n\t\t\t\tif (match.startLineNumber === position.lineNumber) {\r\n\t\t\t\t\t// matched something on the same line => no change in indentation\r\n\t\t\t\t\treturn null;\r\n\t\t\t\t}\r\n\t\t\t\tlet matchLine = model.getLineContent(match.startLineNumber);\r\n\t\t\t\tlet matchLineIndentation = strings.getLeadingWhitespace(matchLine);\r\n\t\t\t\tlet newIndentation = config.normalizeIndentation(matchLineIndentation);\r\n\r\n\t\t\t\tlet lineText = model.getLineContent(position.lineNumber);\r\n\t\t\t\tlet lineFirstNonBlankColumn = model.getLineFirstNonWhitespaceColumn(position.lineNumber) || position.column;\r\n\r\n\t\t\t\tlet prefix = lineText.substring(lineFirstNonBlankColumn - 1, position.column - 1);\r\n\t\t\t\tlet typeText = newIndentation + prefix + ch;\r\n\r\n\t\t\t\tlet typeSelection = new Range(position.lineNumber, 1, position.lineNumber, position.column);\r\n\r\n\t\t\t\tconst command = new ReplaceCommand(typeSelection, typeText);\r\n\t\t\t\treturn new EditOperationResult(EditOperationType.Typing, [command], {\r\n\t\t\t\t\tshouldPushStackElementBefore: false,\r\n\t\t\t\t\tshouldPushStackElementAfter: true\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\t/**\r\n\t * This is very similar with typing, but the character is already in the text buffer!\r\n\t */\r\n\tpublic static compositionEndWithInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selectionsWhenCompositionStarted: Selection[] | null, selections: Selection[], autoClosedCharacters: Range[]): EditOperationResult | null {\r\n\t\tif (!selectionsWhenCompositionStarted || Selection.selectionsArrEqual(selectionsWhenCompositionStarted, selections)) {\r\n\t\t\t// no content was typed\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet ch: string | null = null;\r\n\t\t// extract last typed character\r\n\t\tfor (const selection of selections) {\r\n\t\t\tif (!selection.isEmpty()) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t\tconst position = selection.getPosition();\r\n\t\t\tconst currentChar = model.getValueInRange(new Range(position.lineNumber, position.column - 1, position.lineNumber, position.column));\r\n\t\t\tif (ch === null) {\r\n\t\t\t\tch = currentChar;\r\n\t\t\t} else if (ch !== currentChar) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!ch) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (this._isAutoClosingOvertype(config, model, selections, autoClosedCharacters, ch)) {\r\n\t\t\t// Unfortunately, the close character is at this point \"doubled\", so we need to delete it...\r\n\t\t\tconst commands = selections.map(s => new ReplaceCommand(new Range(s.positionLineNumber, s.positionColumn, s.positionLineNumber, s.positionColumn + 1), '', false));\r\n\t\t\treturn new EditOperationResult(EditOperationType.Typing, commands, {\r\n\t\t\t\tshouldPushStackElementBefore: true,\r\n\t\t\t\tshouldPushStackElementAfter: false\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tconst autoClosingPairClose = this._getAutoClosingPairClose(config, model, selections, ch, false);\r\n\t\tif (autoClosingPairClose !== null) {\r\n\t\t\treturn this._runAutoClosingOpenCharType(prevEditOperationType, config, model, selections, ch, false, autoClosingPairClose);\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic static typeWithInterceptors(isDoingComposition: boolean, prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], autoClosedCharacters: Range[], ch: string): EditOperationResult {\r\n\r\n\t\tif (!isDoingComposition && ch === '\\n') {\r\n\t\t\tlet commands: ICommand[] = [];\r\n\t\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\t\tcommands[i] = TypeOperations._enter(config, model, false, selections[i]);\r\n\t\t\t}\r\n\t\t\treturn new EditOperationResult(EditOperationType.Typing, commands, {\r\n\t\t\t\tshouldPushStackElementBefore: true,\r\n\t\t\t\tshouldPushStackElementAfter: false,\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tif (!isDoingComposition && this._isAutoIndentType(config, model, selections)) {\r\n\t\t\tlet commands: Array = [];\r\n\t\t\tlet autoIndentFails = false;\r\n\t\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\t\tcommands[i] = this._runAutoIndentType(config, model, selections[i], ch);\r\n\t\t\t\tif (!commands[i]) {\r\n\t\t\t\t\tautoIndentFails = true;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (!autoIndentFails) {\r\n\t\t\t\treturn new EditOperationResult(EditOperationType.Typing, commands, {\r\n\t\t\t\t\tshouldPushStackElementBefore: true,\r\n\t\t\t\t\tshouldPushStackElementAfter: false,\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!isDoingComposition && this._isAutoClosingOvertype(config, model, selections, autoClosedCharacters, ch)) {\r\n\t\t\treturn this._runAutoClosingOvertype(prevEditOperationType, config, model, selections, ch);\r\n\t\t}\r\n\r\n\t\tif (!isDoingComposition) {\r\n\t\t\tconst autoClosingPairClose = this._getAutoClosingPairClose(config, model, selections, ch, true);\r\n\t\t\tif (autoClosingPairClose) {\r\n\t\t\t\treturn this._runAutoClosingOpenCharType(prevEditOperationType, config, model, selections, ch, true, autoClosingPairClose);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (this._isSurroundSelectionType(config, model, selections, ch)) {\r\n\t\t\treturn this._runSurroundSelectionType(prevEditOperationType, config, model, selections, ch);\r\n\t\t}\r\n\r\n\t\t// Electric characters make sense only when dealing with a single cursor,\r\n\t\t// as multiple cursors typing brackets for example would interfer with bracket matching\r\n\t\tif (!isDoingComposition && this._isTypeInterceptorElectricChar(config, model, selections)) {\r\n\t\t\tconst r = this._typeInterceptorElectricChar(prevEditOperationType, config, model, selections[0], ch);\r\n\t\t\tif (r) {\r\n\t\t\t\treturn r;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// A simple character type\r\n\t\tlet commands: ICommand[] = [];\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tcommands[i] = new ReplaceCommand(selections[i], ch);\r\n\t\t}\r\n\t\tlet shouldPushStackElementBefore = (prevEditOperationType !== EditOperationType.Typing);\r\n\t\tif (ch === ' ') {\r\n\t\t\tshouldPushStackElementBefore = true;\r\n\t\t}\r\n\t\treturn new EditOperationResult(EditOperationType.Typing, commands, {\r\n\t\t\tshouldPushStackElementBefore: shouldPushStackElementBefore,\r\n\t\t\tshouldPushStackElementAfter: false\r\n\t\t});\r\n\t}\r\n\r\n\tpublic static typeWithoutInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], str: string): EditOperationResult {\r\n\t\tlet commands: ICommand[] = [];\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tcommands[i] = new ReplaceCommand(selections[i], str);\r\n\t\t}\r\n\t\treturn new EditOperationResult(EditOperationType.Typing, commands, {\r\n\t\t\tshouldPushStackElementBefore: (prevEditOperationType !== EditOperationType.Typing),\r\n\t\t\tshouldPushStackElementAfter: false\r\n\t\t});\r\n\t}\r\n\r\n\tpublic static lineInsertBefore(config: CursorConfiguration, model: ITextModel | null, selections: Selection[] | null): ICommand[] {\r\n\t\tif (model === null || selections === null) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tlet commands: ICommand[] = [];\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tlet lineNumber = selections[i].positionLineNumber;\r\n\r\n\t\t\tif (lineNumber === 1) {\r\n\t\t\t\tcommands[i] = new ReplaceCommandWithoutChangingPosition(new Range(1, 1, 1, 1), '\\n');\r\n\t\t\t} else {\r\n\t\t\t\tlineNumber--;\r\n\t\t\t\tlet column = model.getLineMaxColumn(lineNumber);\r\n\r\n\t\t\t\tcommands[i] = this._enter(config, model, false, new Range(lineNumber, column, lineNumber, column));\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn commands;\r\n\t}\r\n\r\n\tpublic static lineInsertAfter(config: CursorConfiguration, model: ITextModel | null, selections: Selection[] | null): ICommand[] {\r\n\t\tif (model === null || selections === null) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tlet commands: ICommand[] = [];\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tconst lineNumber = selections[i].positionLineNumber;\r\n\t\t\tlet column = model.getLineMaxColumn(lineNumber);\r\n\t\t\tcommands[i] = this._enter(config, model, false, new Range(lineNumber, column, lineNumber, column));\r\n\t\t}\r\n\t\treturn commands;\r\n\t}\r\n\r\n\tpublic static lineBreakInsert(config: CursorConfiguration, model: ITextModel, selections: Selection[]): ICommand[] {\r\n\t\tlet commands: ICommand[] = [];\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tcommands[i] = this._enter(config, model, true, selections[i]);\r\n\t\t}\r\n\t\treturn commands;\r\n\t}\r\n}\r\n\r\nexport class TypeWithAutoClosingCommand extends ReplaceCommandWithOffsetCursorState {\r\n\r\n\tprivate readonly _openCharacter: string;\r\n\tprivate readonly _closeCharacter: string;\r\n\tpublic closeCharacterRange: Range | null;\r\n\tpublic enclosingRange: Range | null;\r\n\r\n\tconstructor(selection: Selection, openCharacter: string, insertOpenCharacter: boolean, closeCharacter: string) {\r\n\t\tsuper(selection, (insertOpenCharacter ? openCharacter : '') + closeCharacter, 0, -closeCharacter.length);\r\n\t\tthis._openCharacter = openCharacter;\r\n\t\tthis._closeCharacter = closeCharacter;\r\n\t\tthis.closeCharacterRange = null;\r\n\t\tthis.enclosingRange = null;\r\n\t}\r\n\r\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\r\n\t\tlet inverseEditOperations = helper.getInverseEditOperations();\r\n\t\tlet range = inverseEditOperations[0].range;\r\n\t\tthis.closeCharacterRange = new Range(range.startLineNumber, range.endColumn - this._closeCharacter.length, range.endLineNumber, range.endColumn);\r\n\t\tthis.enclosingRange = new Range(range.startLineNumber, range.endColumn - this._openCharacter.length - this._closeCharacter.length, range.endLineNumber, range.endColumn);\r\n\t\treturn super.computeCursorState(model, helper);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { EditorAutoClosingStrategy } from 'vs/editor/common/config/editorOptions';\r\nimport { CursorConfiguration, ICursorSimpleModel, SingleCursorState } from 'vs/editor/common/controller/cursorCommon';\r\nimport { DeleteOperations } from 'vs/editor/common/controller/cursorDeleteOperations';\r\nimport { WordCharacterClass, WordCharacterClassifier, getMapForWordSeparators } from 'vs/editor/common/controller/wordCharacterClassifier';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { ITextModel, IWordAtPosition } from 'vs/editor/common/model';\r\nimport { AutoClosingPairs } from 'vs/editor/common/modes/languageConfiguration';\r\n\r\ninterface IFindWordResult {\r\n\t/**\r\n\t * The index where the word starts.\r\n\t */\r\n\tstart: number;\r\n\t/**\r\n\t * The index where the word ends.\r\n\t */\r\n\tend: number;\r\n\t/**\r\n\t * The word type.\r\n\t */\r\n\twordType: WordType;\r\n\t/**\r\n\t * The reason the word ended.\r\n\t */\r\n\tnextCharClass: WordCharacterClass;\r\n}\r\n\r\nconst enum WordType {\r\n\tNone = 0,\r\n\tRegular = 1,\r\n\tSeparator = 2\r\n}\r\n\r\nexport const enum WordNavigationType {\r\n\tWordStart = 0,\r\n\tWordStartFast = 1,\r\n\tWordEnd = 2,\r\n\tWordAccessibility = 3 // Respect chrome defintion of a word\r\n}\r\n\r\nexport interface DeleteWordContext {\r\n\twordSeparators: WordCharacterClassifier;\r\n\tmodel: ITextModel;\r\n\tselection: Selection;\r\n\twhitespaceHeuristics: boolean;\r\n\tautoClosingBrackets: EditorAutoClosingStrategy;\r\n\tautoClosingQuotes: EditorAutoClosingStrategy;\r\n\tautoClosingPairs: AutoClosingPairs;\r\n}\r\n\r\nexport class WordOperations {\r\n\r\n\tprivate static _createWord(lineContent: string, wordType: WordType, nextCharClass: WordCharacterClass, start: number, end: number): IFindWordResult {\r\n\t\t// console.log('WORD ==> ' + start + ' => ' + end + ':::: <<<' + lineContent.substring(start, end) + '>>>');\r\n\t\treturn { start: start, end: end, wordType: wordType, nextCharClass: nextCharClass };\r\n\t}\r\n\r\n\tprivate static _findPreviousWordOnLine(wordSeparators: WordCharacterClassifier, model: ICursorSimpleModel, position: Position): IFindWordResult | null {\r\n\t\tlet lineContent = model.getLineContent(position.lineNumber);\r\n\t\treturn this._doFindPreviousWordOnLine(lineContent, wordSeparators, position);\r\n\t}\r\n\r\n\tprivate static _doFindPreviousWordOnLine(lineContent: string, wordSeparators: WordCharacterClassifier, position: Position): IFindWordResult | null {\r\n\t\tlet wordType = WordType.None;\r\n\t\tfor (let chIndex = position.column - 2; chIndex >= 0; chIndex--) {\r\n\t\t\tlet chCode = lineContent.charCodeAt(chIndex);\r\n\t\t\tlet chClass = wordSeparators.get(chCode);\r\n\r\n\t\t\tif (chClass === WordCharacterClass.Regular) {\r\n\t\t\t\tif (wordType === WordType.Separator) {\r\n\t\t\t\t\treturn this._createWord(lineContent, wordType, chClass, chIndex + 1, this._findEndOfWord(lineContent, wordSeparators, wordType, chIndex + 1));\r\n\t\t\t\t}\r\n\t\t\t\twordType = WordType.Regular;\r\n\t\t\t} else if (chClass === WordCharacterClass.WordSeparator) {\r\n\t\t\t\tif (wordType === WordType.Regular) {\r\n\t\t\t\t\treturn this._createWord(lineContent, wordType, chClass, chIndex + 1, this._findEndOfWord(lineContent, wordSeparators, wordType, chIndex + 1));\r\n\t\t\t\t}\r\n\t\t\t\twordType = WordType.Separator;\r\n\t\t\t} else if (chClass === WordCharacterClass.Whitespace) {\r\n\t\t\t\tif (wordType !== WordType.None) {\r\n\t\t\t\t\treturn this._createWord(lineContent, wordType, chClass, chIndex + 1, this._findEndOfWord(lineContent, wordSeparators, wordType, chIndex + 1));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (wordType !== WordType.None) {\r\n\t\t\treturn this._createWord(lineContent, wordType, WordCharacterClass.Whitespace, 0, this._findEndOfWord(lineContent, wordSeparators, wordType, 0));\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate static _findEndOfWord(lineContent: string, wordSeparators: WordCharacterClassifier, wordType: WordType, startIndex: number): number {\r\n\t\tlet len = lineContent.length;\r\n\t\tfor (let chIndex = startIndex; chIndex < len; chIndex++) {\r\n\t\t\tlet chCode = lineContent.charCodeAt(chIndex);\r\n\t\t\tlet chClass = wordSeparators.get(chCode);\r\n\r\n\t\t\tif (chClass === WordCharacterClass.Whitespace) {\r\n\t\t\t\treturn chIndex;\r\n\t\t\t}\r\n\t\t\tif (wordType === WordType.Regular && chClass === WordCharacterClass.WordSeparator) {\r\n\t\t\t\treturn chIndex;\r\n\t\t\t}\r\n\t\t\tif (wordType === WordType.Separator && chClass === WordCharacterClass.Regular) {\r\n\t\t\t\treturn chIndex;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn len;\r\n\t}\r\n\r\n\tprivate static _findNextWordOnLine(wordSeparators: WordCharacterClassifier, model: ICursorSimpleModel, position: Position): IFindWordResult | null {\r\n\t\tlet lineContent = model.getLineContent(position.lineNumber);\r\n\t\treturn this._doFindNextWordOnLine(lineContent, wordSeparators, position);\r\n\t}\r\n\r\n\tprivate static _doFindNextWordOnLine(lineContent: string, wordSeparators: WordCharacterClassifier, position: Position): IFindWordResult | null {\r\n\t\tlet wordType = WordType.None;\r\n\t\tlet len = lineContent.length;\r\n\r\n\t\tfor (let chIndex = position.column - 1; chIndex < len; chIndex++) {\r\n\t\t\tlet chCode = lineContent.charCodeAt(chIndex);\r\n\t\t\tlet chClass = wordSeparators.get(chCode);\r\n\r\n\t\t\tif (chClass === WordCharacterClass.Regular) {\r\n\t\t\t\tif (wordType === WordType.Separator) {\r\n\t\t\t\t\treturn this._createWord(lineContent, wordType, chClass, this._findStartOfWord(lineContent, wordSeparators, wordType, chIndex - 1), chIndex);\r\n\t\t\t\t}\r\n\t\t\t\twordType = WordType.Regular;\r\n\t\t\t} else if (chClass === WordCharacterClass.WordSeparator) {\r\n\t\t\t\tif (wordType === WordType.Regular) {\r\n\t\t\t\t\treturn this._createWord(lineContent, wordType, chClass, this._findStartOfWord(lineContent, wordSeparators, wordType, chIndex - 1), chIndex);\r\n\t\t\t\t}\r\n\t\t\t\twordType = WordType.Separator;\r\n\t\t\t} else if (chClass === WordCharacterClass.Whitespace) {\r\n\t\t\t\tif (wordType !== WordType.None) {\r\n\t\t\t\t\treturn this._createWord(lineContent, wordType, chClass, this._findStartOfWord(lineContent, wordSeparators, wordType, chIndex - 1), chIndex);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (wordType !== WordType.None) {\r\n\t\t\treturn this._createWord(lineContent, wordType, WordCharacterClass.Whitespace, this._findStartOfWord(lineContent, wordSeparators, wordType, len - 1), len);\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate static _findStartOfWord(lineContent: string, wordSeparators: WordCharacterClassifier, wordType: WordType, startIndex: number): number {\r\n\t\tfor (let chIndex = startIndex; chIndex >= 0; chIndex--) {\r\n\t\t\tlet chCode = lineContent.charCodeAt(chIndex);\r\n\t\t\tlet chClass = wordSeparators.get(chCode);\r\n\r\n\t\t\tif (chClass === WordCharacterClass.Whitespace) {\r\n\t\t\t\treturn chIndex + 1;\r\n\t\t\t}\r\n\t\t\tif (wordType === WordType.Regular && chClass === WordCharacterClass.WordSeparator) {\r\n\t\t\t\treturn chIndex + 1;\r\n\t\t\t}\r\n\t\t\tif (wordType === WordType.Separator && chClass === WordCharacterClass.Regular) {\r\n\t\t\t\treturn chIndex + 1;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn 0;\r\n\t}\r\n\r\n\tpublic static moveWordLeft(wordSeparators: WordCharacterClassifier, model: ICursorSimpleModel, position: Position, wordNavigationType: WordNavigationType): Position {\r\n\t\tlet lineNumber = position.lineNumber;\r\n\t\tlet column = position.column;\r\n\r\n\t\tif (column === 1) {\r\n\t\t\tif (lineNumber > 1) {\r\n\t\t\t\tlineNumber = lineNumber - 1;\r\n\t\t\t\tcolumn = model.getLineMaxColumn(lineNumber);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet prevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, new Position(lineNumber, column));\r\n\r\n\t\tif (wordNavigationType === WordNavigationType.WordStart) {\r\n\t\t\treturn new Position(lineNumber, prevWordOnLine ? prevWordOnLine.start + 1 : 1);\r\n\t\t}\r\n\r\n\t\tif (wordNavigationType === WordNavigationType.WordStartFast) {\r\n\t\t\tif (\r\n\t\t\t\tprevWordOnLine\r\n\t\t\t\t&& prevWordOnLine.wordType === WordType.Separator\r\n\t\t\t\t&& prevWordOnLine.end - prevWordOnLine.start === 1\r\n\t\t\t\t&& prevWordOnLine.nextCharClass === WordCharacterClass.Regular\r\n\t\t\t) {\r\n\t\t\t\t// Skip over a word made up of one single separator and followed by a regular character\r\n\t\t\t\tprevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, new Position(lineNumber, prevWordOnLine.start + 1));\r\n\t\t\t}\r\n\r\n\t\t\treturn new Position(lineNumber, prevWordOnLine ? prevWordOnLine.start + 1 : 1);\r\n\t\t}\r\n\r\n\t\tif (wordNavigationType === WordNavigationType.WordAccessibility) {\r\n\t\t\twhile (\r\n\t\t\t\tprevWordOnLine\r\n\t\t\t\t&& prevWordOnLine.wordType === WordType.Separator\r\n\t\t\t) {\r\n\t\t\t\t// Skip over words made up of only separators\r\n\t\t\t\tprevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, new Position(lineNumber, prevWordOnLine.start + 1));\r\n\t\t\t}\r\n\r\n\t\t\treturn new Position(lineNumber, prevWordOnLine ? prevWordOnLine.start + 1 : 1);\r\n\t\t}\r\n\r\n\t\t// We are stopping at the ending of words\r\n\r\n\t\tif (prevWordOnLine && column <= prevWordOnLine.end + 1) {\r\n\t\t\tprevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, new Position(lineNumber, prevWordOnLine.start + 1));\r\n\t\t}\r\n\r\n\t\treturn new Position(lineNumber, prevWordOnLine ? prevWordOnLine.end + 1 : 1);\r\n\t}\r\n\r\n\tpublic static _moveWordPartLeft(model: ICursorSimpleModel, position: Position): Position {\r\n\t\tconst lineNumber = position.lineNumber;\r\n\t\tconst maxColumn = model.getLineMaxColumn(lineNumber);\r\n\r\n\t\tif (position.column === 1) {\r\n\t\t\treturn (lineNumber > 1 ? new Position(lineNumber - 1, model.getLineMaxColumn(lineNumber - 1)) : position);\r\n\t\t}\r\n\r\n\t\tconst lineContent = model.getLineContent(lineNumber);\r\n\t\tfor (let column = position.column - 1; column > 1; column--) {\r\n\t\t\tconst left = lineContent.charCodeAt(column - 2);\r\n\t\t\tconst right = lineContent.charCodeAt(column - 1);\r\n\r\n\t\t\tif (left === CharCode.Underline && right !== CharCode.Underline) {\r\n\t\t\t\t// snake_case_variables\r\n\t\t\t\treturn new Position(lineNumber, column);\r\n\t\t\t}\r\n\r\n\t\t\tif (strings.isLowerAsciiLetter(left) && strings.isUpperAsciiLetter(right)) {\r\n\t\t\t\t// camelCaseVariables\r\n\t\t\t\treturn new Position(lineNumber, column);\r\n\t\t\t}\r\n\r\n\t\t\tif (strings.isUpperAsciiLetter(left) && strings.isUpperAsciiLetter(right)) {\r\n\t\t\t\t// thisIsACamelCaseWithOneLetterWords\r\n\t\t\t\tif (column + 1 < maxColumn) {\r\n\t\t\t\t\tconst rightRight = lineContent.charCodeAt(column);\r\n\t\t\t\t\tif (strings.isLowerAsciiLetter(rightRight)) {\r\n\t\t\t\t\t\treturn new Position(lineNumber, column);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn new Position(lineNumber, 1);\r\n\t}\r\n\r\n\tpublic static moveWordRight(wordSeparators: WordCharacterClassifier, model: ICursorSimpleModel, position: Position, wordNavigationType: WordNavigationType): Position {\r\n\t\tlet lineNumber = position.lineNumber;\r\n\t\tlet column = position.column;\r\n\r\n\t\tlet movedDown = false;\r\n\t\tif (column === model.getLineMaxColumn(lineNumber)) {\r\n\t\t\tif (lineNumber < model.getLineCount()) {\r\n\t\t\t\tmovedDown = true;\r\n\t\t\t\tlineNumber = lineNumber + 1;\r\n\t\t\t\tcolumn = 1;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet nextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, column));\r\n\r\n\t\tif (wordNavigationType === WordNavigationType.WordEnd) {\r\n\t\t\tif (nextWordOnLine && nextWordOnLine.wordType === WordType.Separator) {\r\n\t\t\t\tif (nextWordOnLine.end - nextWordOnLine.start === 1 && nextWordOnLine.nextCharClass === WordCharacterClass.Regular) {\r\n\t\t\t\t\t// Skip over a word made up of one single separator and followed by a regular character\r\n\t\t\t\t\tnextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, nextWordOnLine.end + 1));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (nextWordOnLine) {\r\n\t\t\t\tcolumn = nextWordOnLine.end + 1;\r\n\t\t\t} else {\r\n\t\t\t\tcolumn = model.getLineMaxColumn(lineNumber);\r\n\t\t\t}\r\n\t\t} else if (wordNavigationType === WordNavigationType.WordAccessibility) {\r\n\t\t\tif (movedDown) {\r\n\t\t\t\t// If we move to the next line, pretend that the cursor is right before the first character.\r\n\t\t\t\t// This is needed when the first word starts right at the first character - and in order not to miss it,\r\n\t\t\t\t// we need to start before.\r\n\t\t\t\tcolumn = 0;\r\n\t\t\t}\r\n\r\n\t\t\twhile (\r\n\t\t\t\tnextWordOnLine\r\n\t\t\t\t&& (nextWordOnLine.wordType === WordType.Separator\r\n\t\t\t\t\t|| nextWordOnLine.start + 1 <= column\r\n\t\t\t\t)\r\n\t\t\t) {\r\n\t\t\t\t// Skip over a word made up of one single separator\r\n\t\t\t\t// Also skip over word if it begins before current cursor position to ascertain we're moving forward at least 1 character.\r\n\t\t\t\tnextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, nextWordOnLine.end + 1));\r\n\t\t\t}\r\n\r\n\t\t\tif (nextWordOnLine) {\r\n\t\t\t\tcolumn = nextWordOnLine.start + 1;\r\n\t\t\t} else {\r\n\t\t\t\tcolumn = model.getLineMaxColumn(lineNumber);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tif (nextWordOnLine && !movedDown && column >= nextWordOnLine.start + 1) {\r\n\t\t\t\tnextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, nextWordOnLine.end + 1));\r\n\t\t\t}\r\n\t\t\tif (nextWordOnLine) {\r\n\t\t\t\tcolumn = nextWordOnLine.start + 1;\r\n\t\t\t} else {\r\n\t\t\t\tcolumn = model.getLineMaxColumn(lineNumber);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn new Position(lineNumber, column);\r\n\t}\r\n\r\n\tpublic static _moveWordPartRight(model: ICursorSimpleModel, position: Position): Position {\r\n\t\tconst lineNumber = position.lineNumber;\r\n\t\tconst maxColumn = model.getLineMaxColumn(lineNumber);\r\n\r\n\t\tif (position.column === maxColumn) {\r\n\t\t\treturn (lineNumber < model.getLineCount() ? new Position(lineNumber + 1, 1) : position);\r\n\t\t}\r\n\r\n\t\tconst lineContent = model.getLineContent(lineNumber);\r\n\t\tfor (let column = position.column + 1; column < maxColumn; column++) {\r\n\t\t\tconst left = lineContent.charCodeAt(column - 2);\r\n\t\t\tconst right = lineContent.charCodeAt(column - 1);\r\n\r\n\t\t\tif (left !== CharCode.Underline && right === CharCode.Underline) {\r\n\t\t\t\t// snake_case_variables\r\n\t\t\t\treturn new Position(lineNumber, column);\r\n\t\t\t}\r\n\r\n\t\t\tif (strings.isLowerAsciiLetter(left) && strings.isUpperAsciiLetter(right)) {\r\n\t\t\t\t// camelCaseVariables\r\n\t\t\t\treturn new Position(lineNumber, column);\r\n\t\t\t}\r\n\r\n\t\t\tif (strings.isUpperAsciiLetter(left) && strings.isUpperAsciiLetter(right)) {\r\n\t\t\t\t// thisIsACamelCaseWithOneLetterWords\r\n\t\t\t\tif (column + 1 < maxColumn) {\r\n\t\t\t\t\tconst rightRight = lineContent.charCodeAt(column);\r\n\t\t\t\t\tif (strings.isLowerAsciiLetter(rightRight)) {\r\n\t\t\t\t\t\treturn new Position(lineNumber, column);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn new Position(lineNumber, maxColumn);\r\n\t}\r\n\r\n\tprotected static _deleteWordLeftWhitespace(model: ICursorSimpleModel, position: Position): Range | null {\r\n\t\tconst lineContent = model.getLineContent(position.lineNumber);\r\n\t\tconst startIndex = position.column - 2;\r\n\t\tconst lastNonWhitespace = strings.lastNonWhitespaceIndex(lineContent, startIndex);\r\n\t\tif (lastNonWhitespace + 1 < startIndex) {\r\n\t\t\treturn new Range(position.lineNumber, lastNonWhitespace + 2, position.lineNumber, position.column);\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic static deleteWordLeft(ctx: DeleteWordContext, wordNavigationType: WordNavigationType): Range | null {\r\n\t\tconst wordSeparators = ctx.wordSeparators;\r\n\t\tconst model = ctx.model;\r\n\t\tconst selection = ctx.selection;\r\n\t\tconst whitespaceHeuristics = ctx.whitespaceHeuristics;\r\n\r\n\t\tif (!selection.isEmpty()) {\r\n\t\t\treturn selection;\r\n\t\t}\r\n\r\n\t\tif (DeleteOperations.isAutoClosingPairDelete(ctx.autoClosingBrackets, ctx.autoClosingQuotes, ctx.autoClosingPairs.autoClosingPairsOpenByEnd, ctx.model, [ctx.selection])) {\r\n\t\t\tconst position = ctx.selection.getPosition();\r\n\t\t\treturn new Range(position.lineNumber, position.column - 1, position.lineNumber, position.column + 1);\r\n\t\t}\r\n\r\n\t\tconst position = new Position(selection.positionLineNumber, selection.positionColumn);\r\n\r\n\t\tlet lineNumber = position.lineNumber;\r\n\t\tlet column = position.column;\r\n\r\n\t\tif (lineNumber === 1 && column === 1) {\r\n\t\t\t// Ignore deleting at beginning of file\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (whitespaceHeuristics) {\r\n\t\t\tlet r = this._deleteWordLeftWhitespace(model, position);\r\n\t\t\tif (r) {\r\n\t\t\t\treturn r;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet prevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, position);\r\n\r\n\t\tif (wordNavigationType === WordNavigationType.WordStart) {\r\n\t\t\tif (prevWordOnLine) {\r\n\t\t\t\tcolumn = prevWordOnLine.start + 1;\r\n\t\t\t} else {\r\n\t\t\t\tif (column > 1) {\r\n\t\t\t\t\tcolumn = 1;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tlineNumber--;\r\n\t\t\t\t\tcolumn = model.getLineMaxColumn(lineNumber);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tif (prevWordOnLine && column <= prevWordOnLine.end + 1) {\r\n\t\t\t\tprevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, new Position(lineNumber, prevWordOnLine.start + 1));\r\n\t\t\t}\r\n\t\t\tif (prevWordOnLine) {\r\n\t\t\t\tcolumn = prevWordOnLine.end + 1;\r\n\t\t\t} else {\r\n\t\t\t\tif (column > 1) {\r\n\t\t\t\t\tcolumn = 1;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tlineNumber--;\r\n\t\t\t\t\tcolumn = model.getLineMaxColumn(lineNumber);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn new Range(lineNumber, column, position.lineNumber, position.column);\r\n\t}\r\n\r\n\tpublic static deleteInsideWord(wordSeparators: WordCharacterClassifier, model: ITextModel, selection: Selection): Range {\r\n\t\tif (!selection.isEmpty()) {\r\n\t\t\treturn selection;\r\n\t\t}\r\n\r\n\t\tconst position = new Position(selection.positionLineNumber, selection.positionColumn);\r\n\r\n\t\tlet r = this._deleteInsideWordWhitespace(model, position);\r\n\t\tif (r) {\r\n\t\t\treturn r;\r\n\t\t}\r\n\r\n\t\treturn this._deleteInsideWordDetermineDeleteRange(wordSeparators, model, position);\r\n\t}\r\n\r\n\tprivate static _charAtIsWhitespace(str: string, index: number): boolean {\r\n\t\tconst charCode = str.charCodeAt(index);\r\n\t\treturn (charCode === CharCode.Space || charCode === CharCode.Tab);\r\n\t}\r\n\r\n\tprivate static _deleteInsideWordWhitespace(model: ICursorSimpleModel, position: Position): Range | null {\r\n\t\tconst lineContent = model.getLineContent(position.lineNumber);\r\n\t\tconst lineContentLength = lineContent.length;\r\n\r\n\t\tif (lineContentLength === 0) {\r\n\t\t\t// empty line\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet leftIndex = Math.max(position.column - 2, 0);\r\n\t\tif (!this._charAtIsWhitespace(lineContent, leftIndex)) {\r\n\t\t\t// touches a non-whitespace character to the left\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet rightIndex = Math.min(position.column - 1, lineContentLength - 1);\r\n\t\tif (!this._charAtIsWhitespace(lineContent, rightIndex)) {\r\n\t\t\t// touches a non-whitespace character to the right\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\t// walk over whitespace to the left\r\n\t\twhile (leftIndex > 0 && this._charAtIsWhitespace(lineContent, leftIndex - 1)) {\r\n\t\t\tleftIndex--;\r\n\t\t}\r\n\r\n\t\t// walk over whitespace to the right\r\n\t\twhile (rightIndex + 1 < lineContentLength && this._charAtIsWhitespace(lineContent, rightIndex + 1)) {\r\n\t\t\trightIndex++;\r\n\t\t}\r\n\r\n\t\treturn new Range(position.lineNumber, leftIndex + 1, position.lineNumber, rightIndex + 2);\r\n\t}\r\n\r\n\tprivate static _deleteInsideWordDetermineDeleteRange(wordSeparators: WordCharacterClassifier, model: ICursorSimpleModel, position: Position): Range {\r\n\t\tconst lineContent = model.getLineContent(position.lineNumber);\r\n\t\tconst lineLength = lineContent.length;\r\n\t\tif (lineLength === 0) {\r\n\t\t\t// empty line\r\n\t\t\tif (position.lineNumber > 1) {\r\n\t\t\t\treturn new Range(position.lineNumber - 1, model.getLineMaxColumn(position.lineNumber - 1), position.lineNumber, 1);\r\n\t\t\t} else {\r\n\t\t\t\tif (position.lineNumber < model.getLineCount()) {\r\n\t\t\t\t\treturn new Range(position.lineNumber, 1, position.lineNumber + 1, 1);\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// empty model\r\n\t\t\t\t\treturn new Range(position.lineNumber, 1, position.lineNumber, 1);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst touchesWord = (word: IFindWordResult) => {\r\n\t\t\treturn (word.start + 1 <= position.column && position.column <= word.end + 1);\r\n\t\t};\r\n\t\tconst createRangeWithPosition = (startColumn: number, endColumn: number) => {\r\n\t\t\tstartColumn = Math.min(startColumn, position.column);\r\n\t\t\tendColumn = Math.max(endColumn, position.column);\r\n\t\t\treturn new Range(position.lineNumber, startColumn, position.lineNumber, endColumn);\r\n\t\t};\r\n\t\tconst deleteWordAndAdjacentWhitespace = (word: IFindWordResult) => {\r\n\t\t\tlet startColumn = word.start + 1;\r\n\t\t\tlet endColumn = word.end + 1;\r\n\t\t\tlet expandedToTheRight = false;\r\n\t\t\twhile (endColumn - 1 < lineLength && this._charAtIsWhitespace(lineContent, endColumn - 1)) {\r\n\t\t\t\texpandedToTheRight = true;\r\n\t\t\t\tendColumn++;\r\n\t\t\t}\r\n\t\t\tif (!expandedToTheRight) {\r\n\t\t\t\twhile (startColumn > 1 && this._charAtIsWhitespace(lineContent, startColumn - 2)) {\r\n\t\t\t\t\tstartColumn--;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn createRangeWithPosition(startColumn, endColumn);\r\n\t\t};\r\n\r\n\t\tconst prevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, position);\r\n\t\tif (prevWordOnLine && touchesWord(prevWordOnLine)) {\r\n\t\t\treturn deleteWordAndAdjacentWhitespace(prevWordOnLine);\r\n\t\t}\r\n\t\tconst nextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, position);\r\n\t\tif (nextWordOnLine && touchesWord(nextWordOnLine)) {\r\n\t\t\treturn deleteWordAndAdjacentWhitespace(nextWordOnLine);\r\n\t\t}\r\n\t\tif (prevWordOnLine && nextWordOnLine) {\r\n\t\t\treturn createRangeWithPosition(prevWordOnLine.end + 1, nextWordOnLine.start + 1);\r\n\t\t}\r\n\t\tif (prevWordOnLine) {\r\n\t\t\treturn createRangeWithPosition(prevWordOnLine.start + 1, prevWordOnLine.end + 1);\r\n\t\t}\r\n\t\tif (nextWordOnLine) {\r\n\t\t\treturn createRangeWithPosition(nextWordOnLine.start + 1, nextWordOnLine.end + 1);\r\n\t\t}\r\n\r\n\t\treturn createRangeWithPosition(1, lineLength + 1);\r\n\t}\r\n\r\n\tpublic static _deleteWordPartLeft(model: ICursorSimpleModel, selection: Selection): Range {\r\n\t\tif (!selection.isEmpty()) {\r\n\t\t\treturn selection;\r\n\t\t}\r\n\r\n\t\tconst pos = selection.getPosition();\r\n\t\tconst toPosition = WordOperations._moveWordPartLeft(model, pos);\r\n\t\treturn new Range(pos.lineNumber, pos.column, toPosition.lineNumber, toPosition.column);\r\n\t}\r\n\r\n\tprivate static _findFirstNonWhitespaceChar(str: string, startIndex: number): number {\r\n\t\tlet len = str.length;\r\n\t\tfor (let chIndex = startIndex; chIndex < len; chIndex++) {\r\n\t\t\tlet ch = str.charAt(chIndex);\r\n\t\t\tif (ch !== ' ' && ch !== '\\t') {\r\n\t\t\t\treturn chIndex;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn len;\r\n\t}\r\n\r\n\tprotected static _deleteWordRightWhitespace(model: ICursorSimpleModel, position: Position): Range | null {\r\n\t\tconst lineContent = model.getLineContent(position.lineNumber);\r\n\t\tconst startIndex = position.column - 1;\r\n\t\tconst firstNonWhitespace = this._findFirstNonWhitespaceChar(lineContent, startIndex);\r\n\t\tif (startIndex + 1 < firstNonWhitespace) {\r\n\t\t\t// bingo\r\n\t\t\treturn new Range(position.lineNumber, position.column, position.lineNumber, firstNonWhitespace + 1);\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic static deleteWordRight(ctx: DeleteWordContext, wordNavigationType: WordNavigationType): Range | null {\r\n\t\tconst wordSeparators = ctx.wordSeparators;\r\n\t\tconst model = ctx.model;\r\n\t\tconst selection = ctx.selection;\r\n\t\tconst whitespaceHeuristics = ctx.whitespaceHeuristics;\r\n\r\n\t\tif (!selection.isEmpty()) {\r\n\t\t\treturn selection;\r\n\t\t}\r\n\r\n\t\tconst position = new Position(selection.positionLineNumber, selection.positionColumn);\r\n\r\n\t\tlet lineNumber = position.lineNumber;\r\n\t\tlet column = position.column;\r\n\r\n\t\tconst lineCount = model.getLineCount();\r\n\t\tconst maxColumn = model.getLineMaxColumn(lineNumber);\r\n\t\tif (lineNumber === lineCount && column === maxColumn) {\r\n\t\t\t// Ignore deleting at end of file\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (whitespaceHeuristics) {\r\n\t\t\tlet r = this._deleteWordRightWhitespace(model, position);\r\n\t\t\tif (r) {\r\n\t\t\t\treturn r;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet nextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, position);\r\n\r\n\t\tif (wordNavigationType === WordNavigationType.WordEnd) {\r\n\t\t\tif (nextWordOnLine) {\r\n\t\t\t\tcolumn = nextWordOnLine.end + 1;\r\n\t\t\t} else {\r\n\t\t\t\tif (column < maxColumn || lineNumber === lineCount) {\r\n\t\t\t\t\tcolumn = maxColumn;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tlineNumber++;\r\n\t\t\t\t\tnextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, 1));\r\n\t\t\t\t\tif (nextWordOnLine) {\r\n\t\t\t\t\t\tcolumn = nextWordOnLine.start + 1;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tcolumn = model.getLineMaxColumn(lineNumber);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tif (nextWordOnLine && column >= nextWordOnLine.start + 1) {\r\n\t\t\t\tnextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, nextWordOnLine.end + 1));\r\n\t\t\t}\r\n\t\t\tif (nextWordOnLine) {\r\n\t\t\t\tcolumn = nextWordOnLine.start + 1;\r\n\t\t\t} else {\r\n\t\t\t\tif (column < maxColumn || lineNumber === lineCount) {\r\n\t\t\t\t\tcolumn = maxColumn;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tlineNumber++;\r\n\t\t\t\t\tnextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, 1));\r\n\t\t\t\t\tif (nextWordOnLine) {\r\n\t\t\t\t\t\tcolumn = nextWordOnLine.start + 1;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tcolumn = model.getLineMaxColumn(lineNumber);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn new Range(lineNumber, column, position.lineNumber, position.column);\r\n\t}\r\n\r\n\tpublic static _deleteWordPartRight(model: ICursorSimpleModel, selection: Selection): Range {\r\n\t\tif (!selection.isEmpty()) {\r\n\t\t\treturn selection;\r\n\t\t}\r\n\r\n\t\tconst pos = selection.getPosition();\r\n\t\tconst toPosition = WordOperations._moveWordPartRight(model, pos);\r\n\t\treturn new Range(pos.lineNumber, pos.column, toPosition.lineNumber, toPosition.column);\r\n\t}\r\n\r\n\tprivate static _createWordAtPosition(model: ITextModel, lineNumber: number, word: IFindWordResult): IWordAtPosition {\r\n\t\tconst range = new Range(lineNumber, word.start + 1, lineNumber, word.end + 1);\r\n\t\treturn {\r\n\t\t\tword: model.getValueInRange(range),\r\n\t\t\tstartColumn: range.startColumn,\r\n\t\t\tendColumn: range.endColumn\r\n\t\t};\r\n\t}\r\n\r\n\tpublic static getWordAtPosition(model: ITextModel, _wordSeparators: string, position: Position): IWordAtPosition | null {\r\n\t\tconst wordSeparators = getMapForWordSeparators(_wordSeparators);\r\n\t\tconst prevWord = WordOperations._findPreviousWordOnLine(wordSeparators, model, position);\r\n\t\tif (prevWord && prevWord.wordType === WordType.Regular && prevWord.start <= position.column - 1 && position.column - 1 <= prevWord.end) {\r\n\t\t\treturn WordOperations._createWordAtPosition(model, position.lineNumber, prevWord);\r\n\t\t}\r\n\t\tconst nextWord = WordOperations._findNextWordOnLine(wordSeparators, model, position);\r\n\t\tif (nextWord && nextWord.wordType === WordType.Regular && nextWord.start <= position.column - 1 && position.column - 1 <= nextWord.end) {\r\n\t\t\treturn WordOperations._createWordAtPosition(model, position.lineNumber, nextWord);\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic static word(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, position: Position): SingleCursorState {\r\n\t\tconst wordSeparators = getMapForWordSeparators(config.wordSeparators);\r\n\t\tlet prevWord = WordOperations._findPreviousWordOnLine(wordSeparators, model, position);\r\n\t\tlet nextWord = WordOperations._findNextWordOnLine(wordSeparators, model, position);\r\n\r\n\t\tif (!inSelectionMode) {\r\n\t\t\t// Entering word selection for the first time\r\n\t\t\tlet startColumn: number;\r\n\t\t\tlet endColumn: number;\r\n\r\n\t\t\tif (prevWord && prevWord.wordType === WordType.Regular && prevWord.start <= position.column - 1 && position.column - 1 <= prevWord.end) {\r\n\t\t\t\t// isTouchingPrevWord\r\n\t\t\t\tstartColumn = prevWord.start + 1;\r\n\t\t\t\tendColumn = prevWord.end + 1;\r\n\t\t\t} else if (nextWord && nextWord.wordType === WordType.Regular && nextWord.start <= position.column - 1 && position.column - 1 <= nextWord.end) {\r\n\t\t\t\t// isTouchingNextWord\r\n\t\t\t\tstartColumn = nextWord.start + 1;\r\n\t\t\t\tendColumn = nextWord.end + 1;\r\n\t\t\t} else {\r\n\t\t\t\tif (prevWord) {\r\n\t\t\t\t\tstartColumn = prevWord.end + 1;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tstartColumn = 1;\r\n\t\t\t\t}\r\n\t\t\t\tif (nextWord) {\r\n\t\t\t\t\tendColumn = nextWord.start + 1;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tendColumn = model.getLineMaxColumn(position.lineNumber);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn new SingleCursorState(\r\n\t\t\t\tnew Range(position.lineNumber, startColumn, position.lineNumber, endColumn), 0,\r\n\t\t\t\tnew Position(position.lineNumber, endColumn), 0\r\n\t\t\t);\r\n\t\t}\r\n\r\n\t\tlet startColumn: number;\r\n\t\tlet endColumn: number;\r\n\r\n\t\tif (prevWord && prevWord.wordType === WordType.Regular && prevWord.start < position.column - 1 && position.column - 1 < prevWord.end) {\r\n\t\t\t// isInsidePrevWord\r\n\t\t\tstartColumn = prevWord.start + 1;\r\n\t\t\tendColumn = prevWord.end + 1;\r\n\t\t} else if (nextWord && nextWord.wordType === WordType.Regular && nextWord.start < position.column - 1 && position.column - 1 < nextWord.end) {\r\n\t\t\t// isInsideNextWord\r\n\t\t\tstartColumn = nextWord.start + 1;\r\n\t\t\tendColumn = nextWord.end + 1;\r\n\t\t} else {\r\n\t\t\tstartColumn = position.column;\r\n\t\t\tendColumn = position.column;\r\n\t\t}\r\n\r\n\t\tlet lineNumber = position.lineNumber;\r\n\t\tlet column: number;\r\n\t\tif (cursor.selectionStart.containsPosition(position)) {\r\n\t\t\tcolumn = cursor.selectionStart.endColumn;\r\n\t\t} else if (position.isBeforeOrEqual(cursor.selectionStart.getStartPosition())) {\r\n\t\t\tcolumn = startColumn;\r\n\t\t\tlet possiblePosition = new Position(lineNumber, column);\r\n\t\t\tif (cursor.selectionStart.containsPosition(possiblePosition)) {\r\n\t\t\t\tcolumn = cursor.selectionStart.endColumn;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tcolumn = endColumn;\r\n\t\t\tlet possiblePosition = new Position(lineNumber, column);\r\n\t\t\tif (cursor.selectionStart.containsPosition(possiblePosition)) {\r\n\t\t\t\tcolumn = cursor.selectionStart.startColumn;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn cursor.move(true, lineNumber, column, 0);\r\n\t}\r\n}\r\n\r\nexport class WordPartOperations extends WordOperations {\r\n\tpublic static deleteWordPartLeft(ctx: DeleteWordContext): Range {\r\n\t\tconst candidates = enforceDefined([\r\n\t\t\tWordOperations.deleteWordLeft(ctx, WordNavigationType.WordStart),\r\n\t\t\tWordOperations.deleteWordLeft(ctx, WordNavigationType.WordEnd),\r\n\t\t\tWordOperations._deleteWordPartLeft(ctx.model, ctx.selection)\r\n\t\t]);\r\n\t\tcandidates.sort(Range.compareRangesUsingEnds);\r\n\t\treturn candidates[2];\r\n\t}\r\n\r\n\tpublic static deleteWordPartRight(ctx: DeleteWordContext): Range {\r\n\t\tconst candidates = enforceDefined([\r\n\t\t\tWordOperations.deleteWordRight(ctx, WordNavigationType.WordStart),\r\n\t\t\tWordOperations.deleteWordRight(ctx, WordNavigationType.WordEnd),\r\n\t\t\tWordOperations._deleteWordPartRight(ctx.model, ctx.selection)\r\n\t\t]);\r\n\t\tcandidates.sort(Range.compareRangesUsingStarts);\r\n\t\treturn candidates[0];\r\n\t}\r\n\r\n\tpublic static moveWordPartLeft(wordSeparators: WordCharacterClassifier, model: ICursorSimpleModel, position: Position): Position {\r\n\t\tconst candidates = enforceDefined([\r\n\t\t\tWordOperations.moveWordLeft(wordSeparators, model, position, WordNavigationType.WordStart),\r\n\t\t\tWordOperations.moveWordLeft(wordSeparators, model, position, WordNavigationType.WordEnd),\r\n\t\t\tWordOperations._moveWordPartLeft(model, position)\r\n\t\t]);\r\n\t\tcandidates.sort(Position.compare);\r\n\t\treturn candidates[2];\r\n\t}\r\n\r\n\tpublic static moveWordPartRight(wordSeparators: WordCharacterClassifier, model: ICursorSimpleModel, position: Position): Position {\r\n\t\tconst candidates = enforceDefined([\r\n\t\t\tWordOperations.moveWordRight(wordSeparators, model, position, WordNavigationType.WordStart),\r\n\t\t\tWordOperations.moveWordRight(wordSeparators, model, position, WordNavigationType.WordEnd),\r\n\t\t\tWordOperations._moveWordPartRight(model, position)\r\n\t\t]);\r\n\t\tcandidates.sort(Position.compare);\r\n\t\treturn candidates[0];\r\n\t}\r\n}\r\n\r\nfunction enforceDefined(arr: Array): T[] {\r\n\treturn arr.filter(el => Boolean(el));\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as types from 'vs/base/common/types';\r\nimport { CursorState, ICursorSimpleModel, PartialCursorState, SingleCursorState } from 'vs/editor/common/controller/cursorCommon';\r\nimport { MoveOperations } from 'vs/editor/common/controller/cursorMoveOperations';\r\nimport { WordOperations } from 'vs/editor/common/controller/cursorWordOperations';\r\nimport { IPosition, Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';\r\nimport { IViewModel } from 'vs/editor/common/viewModel/viewModel';\r\n\r\nexport class CursorMoveCommands {\r\n\r\n\tpublic static addCursorDown(viewModel: IViewModel, cursors: CursorState[], useLogicalLine: boolean): PartialCursorState[] {\r\n\t\tlet result: PartialCursorState[] = [], resultLen = 0;\r\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\tconst cursor = cursors[i];\r\n\t\t\tresult[resultLen++] = new CursorState(cursor.modelState, cursor.viewState);\r\n\t\t\tif (useLogicalLine) {\r\n\t\t\t\tresult[resultLen++] = CursorState.fromModelState(MoveOperations.translateDown(viewModel.cursorConfig, viewModel.model, cursor.modelState));\r\n\t\t\t} else {\r\n\t\t\t\tresult[resultLen++] = CursorState.fromViewState(MoveOperations.translateDown(viewModel.cursorConfig, viewModel, cursor.viewState));\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic static addCursorUp(viewModel: IViewModel, cursors: CursorState[], useLogicalLine: boolean): PartialCursorState[] {\r\n\t\tlet result: PartialCursorState[] = [], resultLen = 0;\r\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\tconst cursor = cursors[i];\r\n\t\t\tresult[resultLen++] = new CursorState(cursor.modelState, cursor.viewState);\r\n\t\t\tif (useLogicalLine) {\r\n\t\t\t\tresult[resultLen++] = CursorState.fromModelState(MoveOperations.translateUp(viewModel.cursorConfig, viewModel.model, cursor.modelState));\r\n\t\t\t} else {\r\n\t\t\t\tresult[resultLen++] = CursorState.fromViewState(MoveOperations.translateUp(viewModel.cursorConfig, viewModel, cursor.viewState));\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic static moveToBeginningOfLine(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {\r\n\t\tlet result: PartialCursorState[] = [];\r\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\tconst cursor = cursors[i];\r\n\t\t\tresult[i] = this._moveToLineStart(viewModel, cursor, inSelectionMode);\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _moveToLineStart(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean): PartialCursorState {\r\n\t\tconst currentViewStateColumn = cursor.viewState.position.column;\r\n\t\tconst currentModelStateColumn = cursor.modelState.position.column;\r\n\t\tconst isFirstLineOfWrappedLine = currentViewStateColumn === currentModelStateColumn;\r\n\r\n\t\tconst currentViewStatelineNumber = cursor.viewState.position.lineNumber;\r\n\t\tconst firstNonBlankColumn = viewModel.getLineFirstNonWhitespaceColumn(currentViewStatelineNumber);\r\n\t\tconst isBeginningOfViewLine = currentViewStateColumn === firstNonBlankColumn;\r\n\r\n\t\tif (!isFirstLineOfWrappedLine && !isBeginningOfViewLine) {\r\n\t\t\treturn this._moveToLineStartByView(viewModel, cursor, inSelectionMode);\r\n\t\t} else {\r\n\t\t\treturn this._moveToLineStartByModel(viewModel, cursor, inSelectionMode);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static _moveToLineStartByView(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean): PartialCursorState {\r\n\t\treturn CursorState.fromViewState(\r\n\t\t\tMoveOperations.moveToBeginningOfLine(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode)\r\n\t\t);\r\n\t}\r\n\r\n\tprivate static _moveToLineStartByModel(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean): PartialCursorState {\r\n\t\treturn CursorState.fromModelState(\r\n\t\t\tMoveOperations.moveToBeginningOfLine(viewModel.cursorConfig, viewModel.model, cursor.modelState, inSelectionMode)\r\n\t\t);\r\n\t}\r\n\r\n\tpublic static moveToEndOfLine(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, sticky: boolean): PartialCursorState[] {\r\n\t\tlet result: PartialCursorState[] = [];\r\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\tconst cursor = cursors[i];\r\n\t\t\tresult[i] = this._moveToLineEnd(viewModel, cursor, inSelectionMode, sticky);\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _moveToLineEnd(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, sticky: boolean): PartialCursorState {\r\n\t\tconst viewStatePosition = cursor.viewState.position;\r\n\t\tconst viewModelMaxColumn = viewModel.getLineMaxColumn(viewStatePosition.lineNumber);\r\n\t\tconst isEndOfViewLine = viewStatePosition.column === viewModelMaxColumn;\r\n\r\n\t\tconst modelStatePosition = cursor.modelState.position;\r\n\t\tconst modelMaxColumn = viewModel.model.getLineMaxColumn(modelStatePosition.lineNumber);\r\n\t\tconst isEndLineOfWrappedLine = viewModelMaxColumn - viewStatePosition.column === modelMaxColumn - modelStatePosition.column;\r\n\r\n\t\tif (isEndOfViewLine || isEndLineOfWrappedLine) {\r\n\t\t\treturn this._moveToLineEndByModel(viewModel, cursor, inSelectionMode, sticky);\r\n\t\t} else {\r\n\t\t\treturn this._moveToLineEndByView(viewModel, cursor, inSelectionMode, sticky);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static _moveToLineEndByView(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, sticky: boolean): PartialCursorState {\r\n\t\treturn CursorState.fromViewState(\r\n\t\t\tMoveOperations.moveToEndOfLine(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, sticky)\r\n\t\t);\r\n\t}\r\n\r\n\tprivate static _moveToLineEndByModel(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, sticky: boolean): PartialCursorState {\r\n\t\treturn CursorState.fromModelState(\r\n\t\t\tMoveOperations.moveToEndOfLine(viewModel.cursorConfig, viewModel.model, cursor.modelState, inSelectionMode, sticky)\r\n\t\t);\r\n\t}\r\n\r\n\tpublic static expandLineSelection(viewModel: IViewModel, cursors: CursorState[]): PartialCursorState[] {\r\n\t\tlet result: PartialCursorState[] = [];\r\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\tconst cursor = cursors[i];\r\n\r\n\t\t\tconst startLineNumber = cursor.modelState.selection.startLineNumber;\r\n\t\t\tconst lineCount = viewModel.model.getLineCount();\r\n\r\n\t\t\tlet endLineNumber = cursor.modelState.selection.endLineNumber;\r\n\t\t\tlet endColumn: number;\r\n\t\t\tif (endLineNumber === lineCount) {\r\n\t\t\t\tendColumn = viewModel.model.getLineMaxColumn(lineCount);\r\n\t\t\t} else {\r\n\t\t\t\tendLineNumber++;\r\n\t\t\t\tendColumn = 1;\r\n\t\t\t}\r\n\r\n\t\t\tresult[i] = CursorState.fromModelState(new SingleCursorState(\r\n\t\t\t\tnew Range(startLineNumber, 1, startLineNumber, 1), 0,\r\n\t\t\t\tnew Position(endLineNumber, endColumn), 0\r\n\t\t\t));\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic static moveToBeginningOfBuffer(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {\r\n\t\tlet result: PartialCursorState[] = [];\r\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\tconst cursor = cursors[i];\r\n\t\t\tresult[i] = CursorState.fromModelState(MoveOperations.moveToBeginningOfBuffer(viewModel.cursorConfig, viewModel.model, cursor.modelState, inSelectionMode));\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic static moveToEndOfBuffer(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {\r\n\t\tlet result: PartialCursorState[] = [];\r\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\tconst cursor = cursors[i];\r\n\t\t\tresult[i] = CursorState.fromModelState(MoveOperations.moveToEndOfBuffer(viewModel.cursorConfig, viewModel.model, cursor.modelState, inSelectionMode));\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic static selectAll(viewModel: IViewModel, cursor: CursorState): PartialCursorState {\r\n\t\tconst lineCount = viewModel.model.getLineCount();\r\n\t\tconst maxColumn = viewModel.model.getLineMaxColumn(lineCount);\r\n\r\n\t\treturn CursorState.fromModelState(new SingleCursorState(\r\n\t\t\tnew Range(1, 1, 1, 1), 0,\r\n\t\t\tnew Position(lineCount, maxColumn), 0\r\n\t\t));\r\n\t}\r\n\r\n\tpublic static line(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, _position: IPosition, _viewPosition: IPosition): PartialCursorState {\r\n\t\tconst position = viewModel.model.validatePosition(_position);\r\n\t\tconst viewPosition = (\r\n\t\t\t_viewPosition\r\n\t\t\t\t? viewModel.coordinatesConverter.validateViewPosition(new Position(_viewPosition.lineNumber, _viewPosition.column), position)\r\n\t\t\t\t: viewModel.coordinatesConverter.convertModelPositionToViewPosition(position)\r\n\t\t);\r\n\r\n\t\tif (!inSelectionMode || !cursor.modelState.hasSelection()) {\r\n\t\t\t// Entering line selection for the first time\r\n\t\t\tconst lineCount = viewModel.model.getLineCount();\r\n\r\n\t\t\tlet selectToLineNumber = position.lineNumber + 1;\r\n\t\t\tlet selectToColumn = 1;\r\n\t\t\tif (selectToLineNumber > lineCount) {\r\n\t\t\t\tselectToLineNumber = lineCount;\r\n\t\t\t\tselectToColumn = viewModel.model.getLineMaxColumn(selectToLineNumber);\r\n\t\t\t}\r\n\r\n\t\t\treturn CursorState.fromModelState(new SingleCursorState(\r\n\t\t\t\tnew Range(position.lineNumber, 1, selectToLineNumber, selectToColumn), 0,\r\n\t\t\t\tnew Position(selectToLineNumber, selectToColumn), 0\r\n\t\t\t));\r\n\t\t}\r\n\r\n\t\t// Continuing line selection\r\n\t\tconst enteringLineNumber = cursor.modelState.selectionStart.getStartPosition().lineNumber;\r\n\r\n\t\tif (position.lineNumber < enteringLineNumber) {\r\n\r\n\t\t\treturn CursorState.fromViewState(cursor.viewState.move(\r\n\t\t\t\tcursor.modelState.hasSelection(), viewPosition.lineNumber, 1, 0\r\n\t\t\t));\r\n\r\n\t\t} else if (position.lineNumber > enteringLineNumber) {\r\n\r\n\t\t\tconst lineCount = viewModel.getLineCount();\r\n\r\n\t\t\tlet selectToViewLineNumber = viewPosition.lineNumber + 1;\r\n\t\t\tlet selectToViewColumn = 1;\r\n\t\t\tif (selectToViewLineNumber > lineCount) {\r\n\t\t\t\tselectToViewLineNumber = lineCount;\r\n\t\t\t\tselectToViewColumn = viewModel.getLineMaxColumn(selectToViewLineNumber);\r\n\t\t\t}\r\n\r\n\t\t\treturn CursorState.fromViewState(cursor.viewState.move(\r\n\t\t\t\tcursor.modelState.hasSelection(), selectToViewLineNumber, selectToViewColumn, 0\r\n\t\t\t));\r\n\r\n\t\t} else {\r\n\r\n\t\t\tconst endPositionOfSelectionStart = cursor.modelState.selectionStart.getEndPosition();\r\n\t\t\treturn CursorState.fromModelState(cursor.modelState.move(\r\n\t\t\t\tcursor.modelState.hasSelection(), endPositionOfSelectionStart.lineNumber, endPositionOfSelectionStart.column, 0\r\n\t\t\t));\r\n\r\n\t\t}\r\n\t}\r\n\r\n\tpublic static word(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, _position: IPosition): PartialCursorState {\r\n\t\tconst position = viewModel.model.validatePosition(_position);\r\n\t\treturn CursorState.fromModelState(WordOperations.word(viewModel.cursorConfig, viewModel.model, cursor.modelState, inSelectionMode, position));\r\n\t}\r\n\r\n\tpublic static cancelSelection(viewModel: IViewModel, cursor: CursorState): PartialCursorState {\r\n\t\tif (!cursor.modelState.hasSelection()) {\r\n\t\t\treturn new CursorState(cursor.modelState, cursor.viewState);\r\n\t\t}\r\n\r\n\t\tconst lineNumber = cursor.viewState.position.lineNumber;\r\n\t\tconst column = cursor.viewState.position.column;\r\n\r\n\t\treturn CursorState.fromViewState(new SingleCursorState(\r\n\t\t\tnew Range(lineNumber, column, lineNumber, column), 0,\r\n\t\t\tnew Position(lineNumber, column), 0\r\n\t\t));\r\n\t}\r\n\r\n\tpublic static moveTo(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, _position: IPosition, _viewPosition: IPosition): PartialCursorState {\r\n\t\tconst position = viewModel.model.validatePosition(_position);\r\n\t\tconst viewPosition = (\r\n\t\t\t_viewPosition\r\n\t\t\t\t? viewModel.coordinatesConverter.validateViewPosition(new Position(_viewPosition.lineNumber, _viewPosition.column), position)\r\n\t\t\t\t: viewModel.coordinatesConverter.convertModelPositionToViewPosition(position)\r\n\t\t);\r\n\t\treturn CursorState.fromViewState(cursor.viewState.move(inSelectionMode, viewPosition.lineNumber, viewPosition.column, 0));\r\n\t}\r\n\r\n\tpublic static simpleMove(viewModel: IViewModel, cursors: CursorState[], direction: CursorMove.SimpleMoveDirection, inSelectionMode: boolean, value: number, unit: CursorMove.Unit): PartialCursorState[] | null {\r\n\t\tswitch (direction) {\r\n\t\t\tcase CursorMove.Direction.Left: {\r\n\t\t\t\tif (unit === CursorMove.Unit.HalfLine) {\r\n\t\t\t\t\t// Move left by half the current line length\r\n\t\t\t\t\treturn this._moveHalfLineLeft(viewModel, cursors, inSelectionMode);\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// Move left by `moveParams.value` columns\r\n\t\t\t\t\treturn this._moveLeft(viewModel, cursors, inSelectionMode, value);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tcase CursorMove.Direction.Right: {\r\n\t\t\t\tif (unit === CursorMove.Unit.HalfLine) {\r\n\t\t\t\t\t// Move right by half the current line length\r\n\t\t\t\t\treturn this._moveHalfLineRight(viewModel, cursors, inSelectionMode);\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// Move right by `moveParams.value` columns\r\n\t\t\t\t\treturn this._moveRight(viewModel, cursors, inSelectionMode, value);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tcase CursorMove.Direction.Up: {\r\n\t\t\t\tif (unit === CursorMove.Unit.WrappedLine) {\r\n\t\t\t\t\t// Move up by view lines\r\n\t\t\t\t\treturn this._moveUpByViewLines(viewModel, cursors, inSelectionMode, value);\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// Move up by model lines\r\n\t\t\t\t\treturn this._moveUpByModelLines(viewModel, cursors, inSelectionMode, value);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tcase CursorMove.Direction.Down: {\r\n\t\t\t\tif (unit === CursorMove.Unit.WrappedLine) {\r\n\t\t\t\t\t// Move down by view lines\r\n\t\t\t\t\treturn this._moveDownByViewLines(viewModel, cursors, inSelectionMode, value);\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// Move down by model lines\r\n\t\t\t\t\treturn this._moveDownByModelLines(viewModel, cursors, inSelectionMode, value);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tcase CursorMove.Direction.WrappedLineStart: {\r\n\t\t\t\t// Move to the beginning of the current view line\r\n\t\t\t\treturn this._moveToViewMinColumn(viewModel, cursors, inSelectionMode);\r\n\t\t\t}\r\n\t\t\tcase CursorMove.Direction.WrappedLineFirstNonWhitespaceCharacter: {\r\n\t\t\t\t// Move to the first non-whitespace column of the current view line\r\n\t\t\t\treturn this._moveToViewFirstNonWhitespaceColumn(viewModel, cursors, inSelectionMode);\r\n\t\t\t}\r\n\t\t\tcase CursorMove.Direction.WrappedLineColumnCenter: {\r\n\t\t\t\t// Move to the \"center\" of the current view line\r\n\t\t\t\treturn this._moveToViewCenterColumn(viewModel, cursors, inSelectionMode);\r\n\t\t\t}\r\n\t\t\tcase CursorMove.Direction.WrappedLineEnd: {\r\n\t\t\t\t// Move to the end of the current view line\r\n\t\t\t\treturn this._moveToViewMaxColumn(viewModel, cursors, inSelectionMode);\r\n\t\t\t}\r\n\t\t\tcase CursorMove.Direction.WrappedLineLastNonWhitespaceCharacter: {\r\n\t\t\t\t// Move to the last non-whitespace column of the current view line\r\n\t\t\t\treturn this._moveToViewLastNonWhitespaceColumn(viewModel, cursors, inSelectionMode);\r\n\t\t\t}\r\n\t\t\tdefault:\r\n\t\t\t\treturn null;\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tpublic static viewportMove(viewModel: IViewModel, cursors: CursorState[], direction: CursorMove.ViewportDirection, inSelectionMode: boolean, value: number): PartialCursorState[] | null {\r\n\t\tconst visibleViewRange = viewModel.getCompletelyVisibleViewRange();\r\n\t\tconst visibleModelRange = viewModel.coordinatesConverter.convertViewRangeToModelRange(visibleViewRange);\r\n\t\tswitch (direction) {\r\n\t\t\tcase CursorMove.Direction.ViewPortTop: {\r\n\t\t\t\t// Move to the nth line start in the viewport (from the top)\r\n\t\t\t\tconst modelLineNumber = this._firstLineNumberInRange(viewModel.model, visibleModelRange, value);\r\n\t\t\t\tconst modelColumn = viewModel.model.getLineFirstNonWhitespaceColumn(modelLineNumber);\r\n\t\t\t\treturn [this._moveToModelPosition(viewModel, cursors[0], inSelectionMode, modelLineNumber, modelColumn)];\r\n\t\t\t}\r\n\t\t\tcase CursorMove.Direction.ViewPortBottom: {\r\n\t\t\t\t// Move to the nth line start in the viewport (from the bottom)\r\n\t\t\t\tconst modelLineNumber = this._lastLineNumberInRange(viewModel.model, visibleModelRange, value);\r\n\t\t\t\tconst modelColumn = viewModel.model.getLineFirstNonWhitespaceColumn(modelLineNumber);\r\n\t\t\t\treturn [this._moveToModelPosition(viewModel, cursors[0], inSelectionMode, modelLineNumber, modelColumn)];\r\n\t\t\t}\r\n\t\t\tcase CursorMove.Direction.ViewPortCenter: {\r\n\t\t\t\t// Move to the line start in the viewport center\r\n\t\t\t\tconst modelLineNumber = Math.round((visibleModelRange.startLineNumber + visibleModelRange.endLineNumber) / 2);\r\n\t\t\t\tconst modelColumn = viewModel.model.getLineFirstNonWhitespaceColumn(modelLineNumber);\r\n\t\t\t\treturn [this._moveToModelPosition(viewModel, cursors[0], inSelectionMode, modelLineNumber, modelColumn)];\r\n\t\t\t}\r\n\t\t\tcase CursorMove.Direction.ViewPortIfOutside: {\r\n\t\t\t\t// Move to a position inside the viewport\r\n\t\t\t\tlet result: PartialCursorState[] = [];\r\n\t\t\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\t\t\tconst cursor = cursors[i];\r\n\t\t\t\t\tresult[i] = this.findPositionInViewportIfOutside(viewModel, cursor, visibleViewRange, inSelectionMode);\r\n\t\t\t\t}\r\n\t\t\t\treturn result;\r\n\t\t\t}\r\n\t\t\tdefault:\r\n\t\t\t\treturn null;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic static findPositionInViewportIfOutside(viewModel: IViewModel, cursor: CursorState, visibleViewRange: Range, inSelectionMode: boolean): PartialCursorState {\r\n\t\tlet viewLineNumber = cursor.viewState.position.lineNumber;\r\n\r\n\t\tif (visibleViewRange.startLineNumber <= viewLineNumber && viewLineNumber <= visibleViewRange.endLineNumber - 1) {\r\n\t\t\t// Nothing to do, cursor is in viewport\r\n\t\t\treturn new CursorState(cursor.modelState, cursor.viewState);\r\n\r\n\t\t} else {\r\n\t\t\tif (viewLineNumber > visibleViewRange.endLineNumber - 1) {\r\n\t\t\t\tviewLineNumber = visibleViewRange.endLineNumber - 1;\r\n\t\t\t}\r\n\t\t\tif (viewLineNumber < visibleViewRange.startLineNumber) {\r\n\t\t\t\tviewLineNumber = visibleViewRange.startLineNumber;\r\n\t\t\t}\r\n\t\t\tconst viewColumn = viewModel.getLineFirstNonWhitespaceColumn(viewLineNumber);\r\n\t\t\treturn this._moveToViewPosition(viewModel, cursor, inSelectionMode, viewLineNumber, viewColumn);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Find the nth line start included in the range (from the start).\r\n\t */\r\n\tprivate static _firstLineNumberInRange(model: ICursorSimpleModel, range: Range, count: number): number {\r\n\t\tlet startLineNumber = range.startLineNumber;\r\n\t\tif (range.startColumn !== model.getLineMinColumn(startLineNumber)) {\r\n\t\t\t// Move on to the second line if the first line start is not included in the range\r\n\t\t\tstartLineNumber++;\r\n\t\t}\r\n\r\n\t\treturn Math.min(range.endLineNumber, startLineNumber + count - 1);\r\n\t}\r\n\r\n\t/**\r\n\t * Find the nth line start included in the range (from the end).\r\n\t */\r\n\tprivate static _lastLineNumberInRange(model: ICursorSimpleModel, range: Range, count: number): number {\r\n\t\tlet startLineNumber = range.startLineNumber;\r\n\t\tif (range.startColumn !== model.getLineMinColumn(startLineNumber)) {\r\n\t\t\t// Move on to the second line if the first line start is not included in the range\r\n\t\t\tstartLineNumber++;\r\n\t\t}\r\n\r\n\t\treturn Math.max(startLineNumber, range.endLineNumber - count + 1);\r\n\t}\r\n\r\n\tprivate static _moveLeft(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, noOfColumns: number): PartialCursorState[] {\r\n\t\tconst hasMultipleCursors = (cursors.length > 1);\r\n\t\tlet result: PartialCursorState[] = [];\r\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\tconst cursor = cursors[i];\r\n\t\t\tconst skipWrappingPointStop = hasMultipleCursors || !cursor.viewState.hasSelection();\r\n\t\t\tlet newViewState = MoveOperations.moveLeft(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, noOfColumns);\r\n\r\n\t\t\tif (skipWrappingPointStop\r\n\t\t\t\t&& noOfColumns === 1\r\n\t\t\t\t&& cursor.viewState.position.column === viewModel.getLineMinColumn(cursor.viewState.position.lineNumber)\r\n\t\t\t\t&& newViewState.position.lineNumber !== cursor.viewState.position.lineNumber\r\n\t\t\t) {\r\n\t\t\t\t// moved over to the previous view line\r\n\t\t\t\tconst newViewModelPosition = viewModel.coordinatesConverter.convertViewPositionToModelPosition(newViewState.position);\r\n\t\t\t\tif (newViewModelPosition.lineNumber === cursor.modelState.position.lineNumber) {\r\n\t\t\t\t\t// stayed on the same model line => pass wrapping point where 2 view positions map to a single model position\r\n\t\t\t\t\tnewViewState = MoveOperations.moveLeft(viewModel.cursorConfig, viewModel, newViewState, inSelectionMode, 1);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tresult[i] = CursorState.fromViewState(newViewState);\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _moveHalfLineLeft(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {\r\n\t\tlet result: PartialCursorState[] = [];\r\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\tconst cursor = cursors[i];\r\n\t\t\tconst viewLineNumber = cursor.viewState.position.lineNumber;\r\n\t\t\tconst halfLine = Math.round(viewModel.getLineContent(viewLineNumber).length / 2);\r\n\t\t\tresult[i] = CursorState.fromViewState(MoveOperations.moveLeft(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, halfLine));\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _moveRight(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, noOfColumns: number): PartialCursorState[] {\r\n\t\tconst hasMultipleCursors = (cursors.length > 1);\r\n\t\tlet result: PartialCursorState[] = [];\r\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\tconst cursor = cursors[i];\r\n\t\t\tconst skipWrappingPointStop = hasMultipleCursors || !cursor.viewState.hasSelection();\r\n\t\t\tlet newViewState = MoveOperations.moveRight(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, noOfColumns);\r\n\r\n\t\t\tif (skipWrappingPointStop\r\n\t\t\t\t&& noOfColumns === 1\r\n\t\t\t\t&& cursor.viewState.position.column === viewModel.getLineMaxColumn(cursor.viewState.position.lineNumber)\r\n\t\t\t\t&& newViewState.position.lineNumber !== cursor.viewState.position.lineNumber\r\n\t\t\t) {\r\n\t\t\t\t// moved over to the next view line\r\n\t\t\t\tconst newViewModelPosition = viewModel.coordinatesConverter.convertViewPositionToModelPosition(newViewState.position);\r\n\t\t\t\tif (newViewModelPosition.lineNumber === cursor.modelState.position.lineNumber) {\r\n\t\t\t\t\t// stayed on the same model line => pass wrapping point where 2 view positions map to a single model position\r\n\t\t\t\t\tnewViewState = MoveOperations.moveRight(viewModel.cursorConfig, viewModel, newViewState, inSelectionMode, 1);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tresult[i] = CursorState.fromViewState(newViewState);\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _moveHalfLineRight(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {\r\n\t\tlet result: PartialCursorState[] = [];\r\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\tconst cursor = cursors[i];\r\n\t\t\tconst viewLineNumber = cursor.viewState.position.lineNumber;\r\n\t\t\tconst halfLine = Math.round(viewModel.getLineContent(viewLineNumber).length / 2);\r\n\t\t\tresult[i] = CursorState.fromViewState(MoveOperations.moveRight(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, halfLine));\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _moveDownByViewLines(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, linesCount: number): PartialCursorState[] {\r\n\t\tlet result: PartialCursorState[] = [];\r\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\tconst cursor = cursors[i];\r\n\t\t\tresult[i] = CursorState.fromViewState(MoveOperations.moveDown(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, linesCount));\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _moveDownByModelLines(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, linesCount: number): PartialCursorState[] {\r\n\t\tlet result: PartialCursorState[] = [];\r\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\tconst cursor = cursors[i];\r\n\t\t\tresult[i] = CursorState.fromModelState(MoveOperations.moveDown(viewModel.cursorConfig, viewModel.model, cursor.modelState, inSelectionMode, linesCount));\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _moveUpByViewLines(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, linesCount: number): PartialCursorState[] {\r\n\t\tlet result: PartialCursorState[] = [];\r\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\tconst cursor = cursors[i];\r\n\t\t\tresult[i] = CursorState.fromViewState(MoveOperations.moveUp(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, linesCount));\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _moveUpByModelLines(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, linesCount: number): PartialCursorState[] {\r\n\t\tlet result: PartialCursorState[] = [];\r\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\tconst cursor = cursors[i];\r\n\t\t\tresult[i] = CursorState.fromModelState(MoveOperations.moveUp(viewModel.cursorConfig, viewModel.model, cursor.modelState, inSelectionMode, linesCount));\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _moveToViewPosition(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, toViewLineNumber: number, toViewColumn: number): PartialCursorState {\r\n\t\treturn CursorState.fromViewState(cursor.viewState.move(inSelectionMode, toViewLineNumber, toViewColumn, 0));\r\n\t}\r\n\r\n\tprivate static _moveToModelPosition(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, toModelLineNumber: number, toModelColumn: number): PartialCursorState {\r\n\t\treturn CursorState.fromModelState(cursor.modelState.move(inSelectionMode, toModelLineNumber, toModelColumn, 0));\r\n\t}\r\n\r\n\tprivate static _moveToViewMinColumn(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {\r\n\t\tlet result: PartialCursorState[] = [];\r\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\tconst cursor = cursors[i];\r\n\t\t\tconst viewLineNumber = cursor.viewState.position.lineNumber;\r\n\t\t\tconst viewColumn = viewModel.getLineMinColumn(viewLineNumber);\r\n\t\t\tresult[i] = this._moveToViewPosition(viewModel, cursor, inSelectionMode, viewLineNumber, viewColumn);\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _moveToViewFirstNonWhitespaceColumn(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {\r\n\t\tlet result: PartialCursorState[] = [];\r\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\tconst cursor = cursors[i];\r\n\t\t\tconst viewLineNumber = cursor.viewState.position.lineNumber;\r\n\t\t\tconst viewColumn = viewModel.getLineFirstNonWhitespaceColumn(viewLineNumber);\r\n\t\t\tresult[i] = this._moveToViewPosition(viewModel, cursor, inSelectionMode, viewLineNumber, viewColumn);\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _moveToViewCenterColumn(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {\r\n\t\tlet result: PartialCursorState[] = [];\r\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\tconst cursor = cursors[i];\r\n\t\t\tconst viewLineNumber = cursor.viewState.position.lineNumber;\r\n\t\t\tconst viewColumn = Math.round((viewModel.getLineMaxColumn(viewLineNumber) + viewModel.getLineMinColumn(viewLineNumber)) / 2);\r\n\t\t\tresult[i] = this._moveToViewPosition(viewModel, cursor, inSelectionMode, viewLineNumber, viewColumn);\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _moveToViewMaxColumn(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {\r\n\t\tlet result: PartialCursorState[] = [];\r\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\tconst cursor = cursors[i];\r\n\t\t\tconst viewLineNumber = cursor.viewState.position.lineNumber;\r\n\t\t\tconst viewColumn = viewModel.getLineMaxColumn(viewLineNumber);\r\n\t\t\tresult[i] = this._moveToViewPosition(viewModel, cursor, inSelectionMode, viewLineNumber, viewColumn);\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _moveToViewLastNonWhitespaceColumn(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {\r\n\t\tlet result: PartialCursorState[] = [];\r\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\tconst cursor = cursors[i];\r\n\t\t\tconst viewLineNumber = cursor.viewState.position.lineNumber;\r\n\t\t\tconst viewColumn = viewModel.getLineLastNonWhitespaceColumn(viewLineNumber);\r\n\t\t\tresult[i] = this._moveToViewPosition(viewModel, cursor, inSelectionMode, viewLineNumber, viewColumn);\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n}\r\n\r\nexport namespace CursorMove {\r\n\r\n\tconst isCursorMoveArgs = function (arg: any): boolean {\r\n\t\tif (!types.isObject(arg)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tlet cursorMoveArg: RawArguments = arg;\r\n\r\n\t\tif (!types.isString(cursorMoveArg.to)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tif (!types.isUndefined(cursorMoveArg.select) && !types.isBoolean(cursorMoveArg.select)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tif (!types.isUndefined(cursorMoveArg.by) && !types.isString(cursorMoveArg.by)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tif (!types.isUndefined(cursorMoveArg.value) && !types.isNumber(cursorMoveArg.value)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t};\r\n\r\n\texport const description = {\r\n\t\tdescription: 'Move cursor to a logical position in the view',\r\n\t\targs: [\r\n\t\t\t{\r\n\t\t\t\tname: 'Cursor move argument object',\r\n\t\t\t\tdescription: `Property-value pairs that can be passed through this argument:\r\n\t\t\t\t\t* 'to': A mandatory logical position value providing where to move the cursor.\r\n\t\t\t\t\t\t\\`\\`\\`\r\n\t\t\t\t\t\t'left', 'right', 'up', 'down'\r\n\t\t\t\t\t\t'wrappedLineStart', 'wrappedLineEnd', 'wrappedLineColumnCenter'\r\n\t\t\t\t\t\t'wrappedLineFirstNonWhitespaceCharacter', 'wrappedLineLastNonWhitespaceCharacter'\r\n\t\t\t\t\t\t'viewPortTop', 'viewPortCenter', 'viewPortBottom', 'viewPortIfOutside'\r\n\t\t\t\t\t\t\\`\\`\\`\r\n\t\t\t\t\t* 'by': Unit to move. Default is computed based on 'to' value.\r\n\t\t\t\t\t\t\\`\\`\\`\r\n\t\t\t\t\t\t'line', 'wrappedLine', 'character', 'halfLine'\r\n\t\t\t\t\t\t\\`\\`\\`\r\n\t\t\t\t\t* 'value': Number of units to move. Default is '1'.\r\n\t\t\t\t\t* 'select': If 'true' makes the selection. Default is 'false'.\r\n\t\t\t\t`,\r\n\t\t\t\tconstraint: isCursorMoveArgs,\r\n\t\t\t\tschema: {\r\n\t\t\t\t\t'type': 'object',\r\n\t\t\t\t\t'required': ['to'],\r\n\t\t\t\t\t'properties': {\r\n\t\t\t\t\t\t'to': {\r\n\t\t\t\t\t\t\t'type': 'string',\r\n\t\t\t\t\t\t\t'enum': ['left', 'right', 'up', 'down', 'wrappedLineStart', 'wrappedLineEnd', 'wrappedLineColumnCenter', 'wrappedLineFirstNonWhitespaceCharacter', 'wrappedLineLastNonWhitespaceCharacter', 'viewPortTop', 'viewPortCenter', 'viewPortBottom', 'viewPortIfOutside']\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t'by': {\r\n\t\t\t\t\t\t\t'type': 'string',\r\n\t\t\t\t\t\t\t'enum': ['line', 'wrappedLine', 'character', 'halfLine']\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t'value': {\r\n\t\t\t\t\t\t\t'type': 'number',\r\n\t\t\t\t\t\t\t'default': 1\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t'select': {\r\n\t\t\t\t\t\t\t'type': 'boolean',\r\n\t\t\t\t\t\t\t'default': false\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t]\r\n\t};\r\n\r\n\t/**\r\n\t * Positions in the view for cursor move command.\r\n\t */\r\n\texport const RawDirection = {\r\n\t\tLeft: 'left',\r\n\t\tRight: 'right',\r\n\t\tUp: 'up',\r\n\t\tDown: 'down',\r\n\r\n\t\tWrappedLineStart: 'wrappedLineStart',\r\n\t\tWrappedLineFirstNonWhitespaceCharacter: 'wrappedLineFirstNonWhitespaceCharacter',\r\n\t\tWrappedLineColumnCenter: 'wrappedLineColumnCenter',\r\n\t\tWrappedLineEnd: 'wrappedLineEnd',\r\n\t\tWrappedLineLastNonWhitespaceCharacter: 'wrappedLineLastNonWhitespaceCharacter',\r\n\r\n\t\tViewPortTop: 'viewPortTop',\r\n\t\tViewPortCenter: 'viewPortCenter',\r\n\t\tViewPortBottom: 'viewPortBottom',\r\n\r\n\t\tViewPortIfOutside: 'viewPortIfOutside'\r\n\t};\r\n\r\n\t/**\r\n\t * Units for Cursor move 'by' argument\r\n\t */\r\n\texport const RawUnit = {\r\n\t\tLine: 'line',\r\n\t\tWrappedLine: 'wrappedLine',\r\n\t\tCharacter: 'character',\r\n\t\tHalfLine: 'halfLine'\r\n\t};\r\n\r\n\t/**\r\n\t * Arguments for Cursor move command\r\n\t */\r\n\texport interface RawArguments {\r\n\t\tto: string;\r\n\t\tselect?: boolean;\r\n\t\tby?: string;\r\n\t\tvalue?: number;\r\n\t}\r\n\r\n\texport function parse(args: RawArguments): ParsedArguments | null {\r\n\t\tif (!args.to) {\r\n\t\t\t// illegal arguments\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet direction: Direction;\r\n\t\tswitch (args.to) {\r\n\t\t\tcase RawDirection.Left:\r\n\t\t\t\tdirection = Direction.Left;\r\n\t\t\t\tbreak;\r\n\t\t\tcase RawDirection.Right:\r\n\t\t\t\tdirection = Direction.Right;\r\n\t\t\t\tbreak;\r\n\t\t\tcase RawDirection.Up:\r\n\t\t\t\tdirection = Direction.Up;\r\n\t\t\t\tbreak;\r\n\t\t\tcase RawDirection.Down:\r\n\t\t\t\tdirection = Direction.Down;\r\n\t\t\t\tbreak;\r\n\t\t\tcase RawDirection.WrappedLineStart:\r\n\t\t\t\tdirection = Direction.WrappedLineStart;\r\n\t\t\t\tbreak;\r\n\t\t\tcase RawDirection.WrappedLineFirstNonWhitespaceCharacter:\r\n\t\t\t\tdirection = Direction.WrappedLineFirstNonWhitespaceCharacter;\r\n\t\t\t\tbreak;\r\n\t\t\tcase RawDirection.WrappedLineColumnCenter:\r\n\t\t\t\tdirection = Direction.WrappedLineColumnCenter;\r\n\t\t\t\tbreak;\r\n\t\t\tcase RawDirection.WrappedLineEnd:\r\n\t\t\t\tdirection = Direction.WrappedLineEnd;\r\n\t\t\t\tbreak;\r\n\t\t\tcase RawDirection.WrappedLineLastNonWhitespaceCharacter:\r\n\t\t\t\tdirection = Direction.WrappedLineLastNonWhitespaceCharacter;\r\n\t\t\t\tbreak;\r\n\t\t\tcase RawDirection.ViewPortTop:\r\n\t\t\t\tdirection = Direction.ViewPortTop;\r\n\t\t\t\tbreak;\r\n\t\t\tcase RawDirection.ViewPortBottom:\r\n\t\t\t\tdirection = Direction.ViewPortBottom;\r\n\t\t\t\tbreak;\r\n\t\t\tcase RawDirection.ViewPortCenter:\r\n\t\t\t\tdirection = Direction.ViewPortCenter;\r\n\t\t\t\tbreak;\r\n\t\t\tcase RawDirection.ViewPortIfOutside:\r\n\t\t\t\tdirection = Direction.ViewPortIfOutside;\r\n\t\t\t\tbreak;\r\n\t\t\tdefault:\r\n\t\t\t\t// illegal arguments\r\n\t\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet unit = Unit.None;\r\n\t\tswitch (args.by) {\r\n\t\t\tcase RawUnit.Line:\r\n\t\t\t\tunit = Unit.Line;\r\n\t\t\t\tbreak;\r\n\t\t\tcase RawUnit.WrappedLine:\r\n\t\t\t\tunit = Unit.WrappedLine;\r\n\t\t\t\tbreak;\r\n\t\t\tcase RawUnit.Character:\r\n\t\t\t\tunit = Unit.Character;\r\n\t\t\t\tbreak;\r\n\t\t\tcase RawUnit.HalfLine:\r\n\t\t\t\tunit = Unit.HalfLine;\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tdirection: direction,\r\n\t\t\tunit: unit,\r\n\t\t\tselect: (!!args.select),\r\n\t\t\tvalue: (args.value || 1)\r\n\t\t};\r\n\t}\r\n\r\n\texport interface ParsedArguments {\r\n\t\tdirection: Direction;\r\n\t\tunit: Unit;\r\n\t\tselect: boolean;\r\n\t\tvalue: number;\r\n\t}\r\n\r\n\texport interface SimpleMoveArguments {\r\n\t\tdirection: SimpleMoveDirection;\r\n\t\tunit: Unit;\r\n\t\tselect: boolean;\r\n\t\tvalue: number;\r\n\t}\r\n\r\n\texport const enum Direction {\r\n\t\tLeft,\r\n\t\tRight,\r\n\t\tUp,\r\n\t\tDown,\r\n\r\n\t\tWrappedLineStart,\r\n\t\tWrappedLineFirstNonWhitespaceCharacter,\r\n\t\tWrappedLineColumnCenter,\r\n\t\tWrappedLineEnd,\r\n\t\tWrappedLineLastNonWhitespaceCharacter,\r\n\r\n\t\tViewPortTop,\r\n\t\tViewPortCenter,\r\n\t\tViewPortBottom,\r\n\r\n\t\tViewPortIfOutside,\r\n\t}\r\n\r\n\texport type SimpleMoveDirection = (\r\n\t\tDirection.Left\r\n\t\t| Direction.Right\r\n\t\t| Direction.Up\r\n\t\t| Direction.Down\r\n\t\t| Direction.WrappedLineStart\r\n\t\t| Direction.WrappedLineFirstNonWhitespaceCharacter\r\n\t\t| Direction.WrappedLineColumnCenter\r\n\t\t| Direction.WrappedLineEnd\r\n\t\t| Direction.WrappedLineLastNonWhitespaceCharacter\r\n\t);\r\n\r\n\texport type ViewportDirection = (\r\n\t\tDirection.ViewPortTop\r\n\t\t| Direction.ViewPortCenter\r\n\t\t| Direction.ViewPortBottom\r\n\t\t| Direction.ViewPortIfOutside\r\n\t);\r\n\r\n\texport const enum Unit {\r\n\t\tNone,\r\n\t\tLine,\r\n\t\tWrappedLine,\r\n\t\tCharacter,\r\n\t\tHalfLine,\r\n\t}\r\n\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CursorContext, CursorState, SingleCursorState } from 'vs/editor/common/controller/cursorCommon';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection, SelectionDirection } from 'vs/editor/common/core/selection';\r\nimport { TrackedRangeStickiness } from 'vs/editor/common/model';\r\n\r\nexport class OneCursor {\r\n\r\n\tpublic modelState!: SingleCursorState;\r\n\tpublic viewState!: SingleCursorState;\r\n\r\n\tprivate _selTrackedRange: string | null;\r\n\tprivate _trackSelection: boolean;\r\n\r\n\tconstructor(context: CursorContext) {\r\n\t\tthis._selTrackedRange = null;\r\n\t\tthis._trackSelection = true;\r\n\r\n\t\tthis._setState(\r\n\t\t\tcontext,\r\n\t\t\tnew SingleCursorState(new Range(1, 1, 1, 1), 0, new Position(1, 1), 0),\r\n\t\t\tnew SingleCursorState(new Range(1, 1, 1, 1), 0, new Position(1, 1), 0)\r\n\t\t);\r\n\t}\r\n\r\n\tpublic dispose(context: CursorContext): void {\r\n\t\tthis._removeTrackedRange(context);\r\n\t}\r\n\r\n\tpublic startTrackingSelection(context: CursorContext): void {\r\n\t\tthis._trackSelection = true;\r\n\t\tthis._updateTrackedRange(context);\r\n\t}\r\n\r\n\tpublic stopTrackingSelection(context: CursorContext): void {\r\n\t\tthis._trackSelection = false;\r\n\t\tthis._removeTrackedRange(context);\r\n\t}\r\n\r\n\tprivate _updateTrackedRange(context: CursorContext): void {\r\n\t\tif (!this._trackSelection) {\r\n\t\t\t// don't track the selection\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._selTrackedRange = context.model._setTrackedRange(this._selTrackedRange, this.modelState.selection, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges);\r\n\t}\r\n\r\n\tprivate _removeTrackedRange(context: CursorContext): void {\r\n\t\tthis._selTrackedRange = context.model._setTrackedRange(this._selTrackedRange, null, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges);\r\n\t}\r\n\r\n\tpublic asCursorState(): CursorState {\r\n\t\treturn new CursorState(this.modelState, this.viewState);\r\n\t}\r\n\r\n\tpublic readSelectionFromMarkers(context: CursorContext): Selection {\r\n\t\tconst range = context.model._getTrackedRange(this._selTrackedRange!)!;\r\n\t\tif (this.modelState.selection.getDirection() === SelectionDirection.LTR) {\r\n\t\t\treturn new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);\r\n\t\t}\r\n\t\treturn new Selection(range.endLineNumber, range.endColumn, range.startLineNumber, range.startColumn);\r\n\t}\r\n\r\n\tpublic ensureValidState(context: CursorContext): void {\r\n\t\tthis._setState(context, this.modelState, this.viewState);\r\n\t}\r\n\r\n\tpublic setState(context: CursorContext, modelState: SingleCursorState | null, viewState: SingleCursorState | null): void {\r\n\t\tthis._setState(context, modelState, viewState);\r\n\t}\r\n\r\n\tprivate _setState(context: CursorContext, modelState: SingleCursorState | null, viewState: SingleCursorState | null): void {\r\n\t\tif (!modelState) {\r\n\t\t\tif (!viewState) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t// We only have the view state => compute the model state\r\n\t\t\tconst selectionStart = context.model.validateRange(\r\n\t\t\t\tcontext.coordinatesConverter.convertViewRangeToModelRange(viewState.selectionStart)\r\n\t\t\t);\r\n\r\n\t\t\tconst position = context.model.validatePosition(\r\n\t\t\t\tcontext.coordinatesConverter.convertViewPositionToModelPosition(viewState.position)\r\n\t\t\t);\r\n\r\n\t\t\tmodelState = new SingleCursorState(selectionStart, viewState.selectionStartLeftoverVisibleColumns, position, viewState.leftoverVisibleColumns);\r\n\t\t} else {\r\n\t\t\t// Validate new model state\r\n\t\t\tconst selectionStart = context.model.validateRange(modelState.selectionStart);\r\n\t\t\tconst selectionStartLeftoverVisibleColumns = modelState.selectionStart.equalsRange(selectionStart) ? modelState.selectionStartLeftoverVisibleColumns : 0;\r\n\r\n\t\t\tconst position = context.model.validatePosition(\r\n\t\t\t\tmodelState.position\r\n\t\t\t);\r\n\t\t\tconst leftoverVisibleColumns = modelState.position.equals(position) ? modelState.leftoverVisibleColumns : 0;\r\n\r\n\t\t\tmodelState = new SingleCursorState(selectionStart, selectionStartLeftoverVisibleColumns, position, leftoverVisibleColumns);\r\n\t\t}\r\n\r\n\t\tif (!viewState) {\r\n\t\t\t// We only have the model state => compute the view state\r\n\t\t\tconst viewSelectionStart1 = context.coordinatesConverter.convertModelPositionToViewPosition(new Position(modelState.selectionStart.startLineNumber, modelState.selectionStart.startColumn));\r\n\t\t\tconst viewSelectionStart2 = context.coordinatesConverter.convertModelPositionToViewPosition(new Position(modelState.selectionStart.endLineNumber, modelState.selectionStart.endColumn));\r\n\t\t\tconst viewSelectionStart = new Range(viewSelectionStart1.lineNumber, viewSelectionStart1.column, viewSelectionStart2.lineNumber, viewSelectionStart2.column);\r\n\t\t\tconst viewPosition = context.coordinatesConverter.convertModelPositionToViewPosition(modelState.position);\r\n\t\t\tviewState = new SingleCursorState(viewSelectionStart, modelState.selectionStartLeftoverVisibleColumns, viewPosition, modelState.leftoverVisibleColumns);\r\n\t\t} else {\r\n\t\t\t// Validate new view state\r\n\t\t\tconst viewSelectionStart = context.coordinatesConverter.validateViewRange(viewState.selectionStart, modelState.selectionStart);\r\n\t\t\tconst viewPosition = context.coordinatesConverter.validateViewPosition(viewState.position, modelState.position);\r\n\t\t\tviewState = new SingleCursorState(viewSelectionStart, modelState.selectionStartLeftoverVisibleColumns, viewPosition, modelState.leftoverVisibleColumns);\r\n\t\t}\r\n\r\n\t\tthis.modelState = modelState;\r\n\t\tthis.viewState = viewState;\r\n\r\n\t\tthis._updateTrackedRange(context);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CursorContext, CursorState, PartialCursorState } from 'vs/editor/common/controller/cursorCommon';\r\nimport { OneCursor } from 'vs/editor/common/controller/oneCursor';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { ISelection, Selection } from 'vs/editor/common/core/selection';\r\n\r\nexport class CursorCollection {\r\n\r\n\tprivate context: CursorContext;\r\n\r\n\tprivate primaryCursor: OneCursor;\r\n\tprivate secondaryCursors: OneCursor[];\r\n\r\n\t// An index which identifies the last cursor that was added / moved (think Ctrl+drag)\r\n\tprivate lastAddedCursorIndex: number;\r\n\r\n\tconstructor(context: CursorContext) {\r\n\t\tthis.context = context;\r\n\t\tthis.primaryCursor = new OneCursor(context);\r\n\t\tthis.secondaryCursors = [];\r\n\t\tthis.lastAddedCursorIndex = 0;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis.primaryCursor.dispose(this.context);\r\n\t\tthis.killSecondaryCursors();\r\n\t}\r\n\r\n\tpublic startTrackingSelections(): void {\r\n\t\tthis.primaryCursor.startTrackingSelection(this.context);\r\n\t\tfor (let i = 0, len = this.secondaryCursors.length; i < len; i++) {\r\n\t\t\tthis.secondaryCursors[i].startTrackingSelection(this.context);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic stopTrackingSelections(): void {\r\n\t\tthis.primaryCursor.stopTrackingSelection(this.context);\r\n\t\tfor (let i = 0, len = this.secondaryCursors.length; i < len; i++) {\r\n\t\t\tthis.secondaryCursors[i].stopTrackingSelection(this.context);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic updateContext(context: CursorContext): void {\r\n\t\tthis.context = context;\r\n\t}\r\n\r\n\tpublic ensureValidState(): void {\r\n\t\tthis.primaryCursor.ensureValidState(this.context);\r\n\t\tfor (let i = 0, len = this.secondaryCursors.length; i < len; i++) {\r\n\t\t\tthis.secondaryCursors[i].ensureValidState(this.context);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic readSelectionFromMarkers(): Selection[] {\r\n\t\tlet result: Selection[] = [];\r\n\t\tresult[0] = this.primaryCursor.readSelectionFromMarkers(this.context);\r\n\t\tfor (let i = 0, len = this.secondaryCursors.length; i < len; i++) {\r\n\t\t\tresult[i + 1] = this.secondaryCursors[i].readSelectionFromMarkers(this.context);\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic getAll(): CursorState[] {\r\n\t\tlet result: CursorState[] = [];\r\n\t\tresult[0] = this.primaryCursor.asCursorState();\r\n\t\tfor (let i = 0, len = this.secondaryCursors.length; i < len; i++) {\r\n\t\t\tresult[i + 1] = this.secondaryCursors[i].asCursorState();\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic getViewPositions(): Position[] {\r\n\t\tlet result: Position[] = [];\r\n\t\tresult[0] = this.primaryCursor.viewState.position;\r\n\t\tfor (let i = 0, len = this.secondaryCursors.length; i < len; i++) {\r\n\t\t\tresult[i + 1] = this.secondaryCursors[i].viewState.position;\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic getTopMostViewPosition(): Position {\r\n\t\tlet result = this.primaryCursor.viewState.position;\r\n\t\tfor (let i = 0, len = this.secondaryCursors.length; i < len; i++) {\r\n\t\t\tconst viewPosition = this.secondaryCursors[i].viewState.position;\r\n\t\t\tif (viewPosition.isBefore(result)) {\r\n\t\t\t\tresult = viewPosition;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic getBottomMostViewPosition(): Position {\r\n\t\tlet result = this.primaryCursor.viewState.position;\r\n\t\tfor (let i = 0, len = this.secondaryCursors.length; i < len; i++) {\r\n\t\t\tconst viewPosition = this.secondaryCursors[i].viewState.position;\r\n\t\t\tif (result.isBeforeOrEqual(viewPosition)) {\r\n\t\t\t\tresult = viewPosition;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic getSelections(): Selection[] {\r\n\t\tlet result: Selection[] = [];\r\n\t\tresult[0] = this.primaryCursor.modelState.selection;\r\n\t\tfor (let i = 0, len = this.secondaryCursors.length; i < len; i++) {\r\n\t\t\tresult[i + 1] = this.secondaryCursors[i].modelState.selection;\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic getViewSelections(): Selection[] {\r\n\t\tlet result: Selection[] = [];\r\n\t\tresult[0] = this.primaryCursor.viewState.selection;\r\n\t\tfor (let i = 0, len = this.secondaryCursors.length; i < len; i++) {\r\n\t\t\tresult[i + 1] = this.secondaryCursors[i].viewState.selection;\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic setSelections(selections: ISelection[]): void {\r\n\t\tthis.setStates(CursorState.fromModelSelections(selections));\r\n\t}\r\n\r\n\tpublic getPrimaryCursor(): CursorState {\r\n\t\treturn this.primaryCursor.asCursorState();\r\n\t}\r\n\r\n\tpublic setStates(states: PartialCursorState[] | null): void {\r\n\t\tif (states === null) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis.primaryCursor.setState(this.context, states[0].modelState, states[0].viewState);\r\n\t\tthis._setSecondaryStates(states.slice(1));\r\n\t}\r\n\r\n\t/**\r\n\t * Creates or disposes secondary cursors as necessary to match the number of `secondarySelections`.\r\n\t */\r\n\tprivate _setSecondaryStates(secondaryStates: PartialCursorState[]): void {\r\n\t\tconst secondaryCursorsLength = this.secondaryCursors.length;\r\n\t\tconst secondaryStatesLength = secondaryStates.length;\r\n\r\n\t\tif (secondaryCursorsLength < secondaryStatesLength) {\r\n\t\t\tlet createCnt = secondaryStatesLength - secondaryCursorsLength;\r\n\t\t\tfor (let i = 0; i < createCnt; i++) {\r\n\t\t\t\tthis._addSecondaryCursor();\r\n\t\t\t}\r\n\t\t} else if (secondaryCursorsLength > secondaryStatesLength) {\r\n\t\t\tlet removeCnt = secondaryCursorsLength - secondaryStatesLength;\r\n\t\t\tfor (let i = 0; i < removeCnt; i++) {\r\n\t\t\t\tthis._removeSecondaryCursor(this.secondaryCursors.length - 1);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tfor (let i = 0; i < secondaryStatesLength; i++) {\r\n\t\t\tthis.secondaryCursors[i].setState(this.context, secondaryStates[i].modelState, secondaryStates[i].viewState);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic killSecondaryCursors(): void {\r\n\t\tthis._setSecondaryStates([]);\r\n\t}\r\n\r\n\tprivate _addSecondaryCursor(): void {\r\n\t\tthis.secondaryCursors.push(new OneCursor(this.context));\r\n\t\tthis.lastAddedCursorIndex = this.secondaryCursors.length;\r\n\t}\r\n\r\n\tpublic getLastAddedCursorIndex(): number {\r\n\t\tif (this.secondaryCursors.length === 0 || this.lastAddedCursorIndex === 0) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t\treturn this.lastAddedCursorIndex;\r\n\t}\r\n\r\n\tprivate _removeSecondaryCursor(removeIndex: number): void {\r\n\t\tif (this.lastAddedCursorIndex >= removeIndex + 1) {\r\n\t\t\tthis.lastAddedCursorIndex--;\r\n\t\t}\r\n\t\tthis.secondaryCursors[removeIndex].dispose(this.context);\r\n\t\tthis.secondaryCursors.splice(removeIndex, 1);\r\n\t}\r\n\r\n\tprivate _getAll(): OneCursor[] {\r\n\t\tlet result: OneCursor[] = [];\r\n\t\tresult[0] = this.primaryCursor;\r\n\t\tfor (let i = 0, len = this.secondaryCursors.length; i < len; i++) {\r\n\t\t\tresult[i + 1] = this.secondaryCursors[i];\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic normalize(): void {\r\n\t\tif (this.secondaryCursors.length === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tlet cursors = this._getAll();\r\n\r\n\t\tinterface SortedCursor {\r\n\t\t\tindex: number;\r\n\t\t\tselection: Selection;\r\n\t\t}\r\n\t\tlet sortedCursors: SortedCursor[] = [];\r\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\tsortedCursors.push({\r\n\t\t\t\tindex: i,\r\n\t\t\t\tselection: cursors[i].modelState.selection,\r\n\t\t\t});\r\n\t\t}\r\n\t\tsortedCursors.sort((a, b) => {\r\n\t\t\tif (a.selection.startLineNumber === b.selection.startLineNumber) {\r\n\t\t\t\treturn a.selection.startColumn - b.selection.startColumn;\r\n\t\t\t}\r\n\t\t\treturn a.selection.startLineNumber - b.selection.startLineNumber;\r\n\t\t});\r\n\r\n\t\tfor (let sortedCursorIndex = 0; sortedCursorIndex < sortedCursors.length - 1; sortedCursorIndex++) {\r\n\t\t\tconst current = sortedCursors[sortedCursorIndex];\r\n\t\t\tconst next = sortedCursors[sortedCursorIndex + 1];\r\n\r\n\t\t\tconst currentSelection = current.selection;\r\n\t\t\tconst nextSelection = next.selection;\r\n\r\n\t\t\tif (!this.context.cursorConfig.multiCursorMergeOverlapping) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tlet shouldMergeCursors: boolean;\r\n\t\t\tif (nextSelection.isEmpty() || currentSelection.isEmpty()) {\r\n\t\t\t\t// Merge touching cursors if one of them is collapsed\r\n\t\t\t\tshouldMergeCursors = nextSelection.getStartPosition().isBeforeOrEqual(currentSelection.getEndPosition());\r\n\t\t\t} else {\r\n\t\t\t\t// Merge only overlapping cursors (i.e. allow touching ranges)\r\n\t\t\t\tshouldMergeCursors = nextSelection.getStartPosition().isBefore(currentSelection.getEndPosition());\r\n\t\t\t}\r\n\r\n\t\t\tif (shouldMergeCursors) {\r\n\t\t\t\tconst winnerSortedCursorIndex = current.index < next.index ? sortedCursorIndex : sortedCursorIndex + 1;\r\n\t\t\t\tconst looserSortedCursorIndex = current.index < next.index ? sortedCursorIndex + 1 : sortedCursorIndex;\r\n\r\n\t\t\t\tconst looserIndex = sortedCursors[looserSortedCursorIndex].index;\r\n\t\t\t\tconst winnerIndex = sortedCursors[winnerSortedCursorIndex].index;\r\n\r\n\t\t\t\tconst looserSelection = sortedCursors[looserSortedCursorIndex].selection;\r\n\t\t\t\tconst winnerSelection = sortedCursors[winnerSortedCursorIndex].selection;\r\n\r\n\t\t\t\tif (!looserSelection.equalsSelection(winnerSelection)) {\r\n\t\t\t\t\tconst resultingRange = looserSelection.plusRange(winnerSelection);\r\n\t\t\t\t\tconst looserSelectionIsLTR = (looserSelection.selectionStartLineNumber === looserSelection.startLineNumber && looserSelection.selectionStartColumn === looserSelection.startColumn);\r\n\t\t\t\t\tconst winnerSelectionIsLTR = (winnerSelection.selectionStartLineNumber === winnerSelection.startLineNumber && winnerSelection.selectionStartColumn === winnerSelection.startColumn);\r\n\r\n\t\t\t\t\t// Give more importance to the last added cursor (think Ctrl-dragging + hitting another cursor)\r\n\t\t\t\t\tlet resultingSelectionIsLTR: boolean;\r\n\t\t\t\t\tif (looserIndex === this.lastAddedCursorIndex) {\r\n\t\t\t\t\t\tresultingSelectionIsLTR = looserSelectionIsLTR;\r\n\t\t\t\t\t\tthis.lastAddedCursorIndex = winnerIndex;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t// Winner takes it all\r\n\t\t\t\t\t\tresultingSelectionIsLTR = winnerSelectionIsLTR;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tlet resultingSelection: Selection;\r\n\t\t\t\t\tif (resultingSelectionIsLTR) {\r\n\t\t\t\t\t\tresultingSelection = new Selection(resultingRange.startLineNumber, resultingRange.startColumn, resultingRange.endLineNumber, resultingRange.endColumn);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tresultingSelection = new Selection(resultingRange.endLineNumber, resultingRange.endColumn, resultingRange.startLineNumber, resultingRange.startColumn);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tsortedCursors[winnerSortedCursorIndex].selection = resultingSelection;\r\n\t\t\t\t\tconst resultingState = CursorState.fromModelSelection(resultingSelection);\r\n\t\t\t\t\tcursors[winnerIndex].setState(this.context, resultingState.modelState, resultingState.viewState);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfor (const sortedCursor of sortedCursors) {\r\n\t\t\t\t\tif (sortedCursor.index > looserIndex) {\r\n\t\t\t\t\t\tsortedCursor.index--;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tcursors.splice(looserIndex, 1);\r\n\t\t\t\tsortedCursors.splice(looserSortedCursorIndex, 1);\r\n\t\t\t\tthis._removeSecondaryCursor(looserIndex - 1);\r\n\r\n\t\t\t\tsortedCursorIndex--;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { CursorCollection } from 'vs/editor/common/controller/cursorCollection';\r\nimport { CursorColumns, CursorConfiguration, CursorContext, CursorState, EditOperationResult, EditOperationType, IColumnSelectData, PartialCursorState, ICursorSimpleModel } from 'vs/editor/common/controller/cursorCommon';\r\nimport { DeleteOperations } from 'vs/editor/common/controller/cursorDeleteOperations';\r\nimport { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents';\r\nimport { TypeOperations, TypeWithAutoClosingCommand } from 'vs/editor/common/controller/cursorTypeOperations';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range, IRange } from 'vs/editor/common/core/range';\r\nimport { ISelection, Selection, SelectionDirection } from 'vs/editor/common/core/selection';\r\nimport * as editorCommon from 'vs/editor/common/editorCommon';\r\nimport { ITextModel, TrackedRangeStickiness, IModelDeltaDecoration, ICursorStateComputer, IIdentifiedSingleEditOperation, IValidEditOperation } from 'vs/editor/common/model';\r\nimport { RawContentChangedType, ModelRawContentChangedEvent } from 'vs/editor/common/model/textModelEvents';\r\nimport { VerticalRevealType, ViewCursorStateChangedEvent, ViewRevealRangeRequestEvent } from 'vs/editor/common/view/viewEvents';\r\nimport { dispose, Disposable } from 'vs/base/common/lifecycle';\r\nimport { ICoordinatesConverter } from 'vs/editor/common/viewModel/viewModel';\r\nimport { CursorStateChangedEvent, ViewModelEventsCollector } from 'vs/editor/common/viewModel/viewModelEventDispatcher';\r\n\r\n/**\r\n * A snapshot of the cursor and the model state\r\n */\r\nexport class CursorModelState {\r\n\r\n\tpublic readonly modelVersionId: number;\r\n\tpublic readonly cursorState: CursorState[];\r\n\r\n\tconstructor(model: ITextModel, cursor: Cursor) {\r\n\t\tthis.modelVersionId = model.getVersionId();\r\n\t\tthis.cursorState = cursor.getCursorStates();\r\n\t}\r\n\r\n\tpublic equals(other: CursorModelState | null): boolean {\r\n\t\tif (!other) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (this.modelVersionId !== other.modelVersionId) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (this.cursorState.length !== other.cursorState.length) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tfor (let i = 0, len = this.cursorState.length; i < len; i++) {\r\n\t\t\tif (!this.cursorState[i].equals(other.cursorState[i])) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n}\r\n\r\nclass AutoClosedAction {\r\n\r\n\tpublic static getAllAutoClosedCharacters(autoClosedActions: AutoClosedAction[]): Range[] {\r\n\t\tlet autoClosedCharacters: Range[] = [];\r\n\t\tfor (const autoClosedAction of autoClosedActions) {\r\n\t\t\tautoClosedCharacters = autoClosedCharacters.concat(autoClosedAction.getAutoClosedCharactersRanges());\r\n\t\t}\r\n\t\treturn autoClosedCharacters;\r\n\t}\r\n\r\n\tprivate readonly _model: ITextModel;\r\n\r\n\tprivate _autoClosedCharactersDecorations: string[];\r\n\tprivate _autoClosedEnclosingDecorations: string[];\r\n\r\n\tconstructor(model: ITextModel, autoClosedCharactersDecorations: string[], autoClosedEnclosingDecorations: string[]) {\r\n\t\tthis._model = model;\r\n\t\tthis._autoClosedCharactersDecorations = autoClosedCharactersDecorations;\r\n\t\tthis._autoClosedEnclosingDecorations = autoClosedEnclosingDecorations;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._autoClosedCharactersDecorations = this._model.deltaDecorations(this._autoClosedCharactersDecorations, []);\r\n\t\tthis._autoClosedEnclosingDecorations = this._model.deltaDecorations(this._autoClosedEnclosingDecorations, []);\r\n\t}\r\n\r\n\tpublic getAutoClosedCharactersRanges(): Range[] {\r\n\t\tlet result: Range[] = [];\r\n\t\tfor (let i = 0; i < this._autoClosedCharactersDecorations.length; i++) {\r\n\t\t\tconst decorationRange = this._model.getDecorationRange(this._autoClosedCharactersDecorations[i]);\r\n\t\t\tif (decorationRange) {\r\n\t\t\t\tresult.push(decorationRange);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic isValid(selections: Range[]): boolean {\r\n\t\tlet enclosingRanges: Range[] = [];\r\n\t\tfor (let i = 0; i < this._autoClosedEnclosingDecorations.length; i++) {\r\n\t\t\tconst decorationRange = this._model.getDecorationRange(this._autoClosedEnclosingDecorations[i]);\r\n\t\t\tif (decorationRange) {\r\n\t\t\t\tenclosingRanges.push(decorationRange);\r\n\t\t\t\tif (decorationRange.startLineNumber !== decorationRange.endLineNumber) {\r\n\t\t\t\t\t// Stop tracking if the range becomes multiline...\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tenclosingRanges.sort(Range.compareRangesUsingStarts);\r\n\r\n\t\tselections.sort(Range.compareRangesUsingStarts);\r\n\r\n\t\tfor (let i = 0; i < selections.length; i++) {\r\n\t\t\tif (i >= enclosingRanges.length) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t\tif (!enclosingRanges[i].strictContainsRange(selections[i])) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n}\r\n\r\nexport class Cursor extends Disposable {\r\n\r\n\tpublic static readonly MAX_CURSOR_COUNT = 10000;\r\n\r\n\tprivate readonly _model: ITextModel;\r\n\tprivate _knownModelVersionId: number;\r\n\tprivate readonly _viewModel: ICursorSimpleModel;\r\n\tprivate readonly _coordinatesConverter: ICoordinatesConverter;\r\n\tpublic context: CursorContext;\r\n\tprivate _cursors: CursorCollection;\r\n\r\n\tprivate _hasFocus: boolean;\r\n\tprivate _isHandling: boolean;\r\n\tprivate _isDoingComposition: boolean;\r\n\tprivate _selectionsWhenCompositionStarted: Selection[] | null;\r\n\tprivate _columnSelectData: IColumnSelectData | null;\r\n\tprivate _autoClosedActions: AutoClosedAction[];\r\n\tprivate _prevEditOperationType: EditOperationType;\r\n\r\n\tconstructor(model: ITextModel, viewModel: ICursorSimpleModel, coordinatesConverter: ICoordinatesConverter, cursorConfig: CursorConfiguration) {\r\n\t\tsuper();\r\n\t\tthis._model = model;\r\n\t\tthis._knownModelVersionId = this._model.getVersionId();\r\n\t\tthis._viewModel = viewModel;\r\n\t\tthis._coordinatesConverter = coordinatesConverter;\r\n\t\tthis.context = new CursorContext(this._model, this._coordinatesConverter, cursorConfig);\r\n\t\tthis._cursors = new CursorCollection(this.context);\r\n\r\n\t\tthis._hasFocus = false;\r\n\t\tthis._isHandling = false;\r\n\t\tthis._isDoingComposition = false;\r\n\t\tthis._selectionsWhenCompositionStarted = null;\r\n\t\tthis._columnSelectData = null;\r\n\t\tthis._autoClosedActions = [];\r\n\t\tthis._prevEditOperationType = EditOperationType.Other;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._cursors.dispose();\r\n\t\tthis._autoClosedActions = dispose(this._autoClosedActions);\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tpublic updateConfiguration(cursorConfig: CursorConfiguration): void {\r\n\t\tthis.context = new CursorContext(this._model, this._coordinatesConverter, cursorConfig);\r\n\t\tthis._cursors.updateContext(this.context);\r\n\t}\r\n\r\n\tpublic onLineMappingChanged(eventsCollector: ViewModelEventsCollector): void {\r\n\t\tif (this._knownModelVersionId !== this._model.getVersionId()) {\r\n\t\t\t// There are model change events that I didn't yet receive.\r\n\t\t\t//\r\n\t\t\t// This can happen when editing the model, and the view model receives the change events first,\r\n\t\t\t// and the view model emits line mapping changed events, all before the cursor gets a chance to\r\n\t\t\t// recover from markers.\r\n\t\t\t//\r\n\t\t\t// The model change listener above will be called soon and we'll ensure a valid cursor state there.\r\n\t\t\treturn;\r\n\t\t}\r\n\t\t// Ensure valid state\r\n\t\tthis.setStates(eventsCollector, 'viewModel', CursorChangeReason.NotSet, this.getCursorStates());\r\n\t}\r\n\r\n\tpublic setHasFocus(hasFocus: boolean): void {\r\n\t\tthis._hasFocus = hasFocus;\r\n\t}\r\n\r\n\tprivate _validateAutoClosedActions(): void {\r\n\t\tif (this._autoClosedActions.length > 0) {\r\n\t\t\tlet selections: Range[] = this._cursors.getSelections();\r\n\t\t\tfor (let i = 0; i < this._autoClosedActions.length; i++) {\r\n\t\t\t\tconst autoClosedAction = this._autoClosedActions[i];\r\n\t\t\t\tif (!autoClosedAction.isValid(selections)) {\r\n\t\t\t\t\tautoClosedAction.dispose();\r\n\t\t\t\t\tthis._autoClosedActions.splice(i, 1);\r\n\t\t\t\t\ti--;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t// ------ some getters/setters\r\n\r\n\tpublic getPrimaryCursorState(): CursorState {\r\n\t\treturn this._cursors.getPrimaryCursor();\r\n\t}\r\n\r\n\tpublic getLastAddedCursorIndex(): number {\r\n\t\treturn this._cursors.getLastAddedCursorIndex();\r\n\t}\r\n\r\n\tpublic getCursorStates(): CursorState[] {\r\n\t\treturn this._cursors.getAll();\r\n\t}\r\n\r\n\tpublic setStates(eventsCollector: ViewModelEventsCollector, source: string | null | undefined, reason: CursorChangeReason, states: PartialCursorState[] | null): boolean {\r\n\t\tlet reachedMaxCursorCount = false;\r\n\t\tif (states !== null && states.length > Cursor.MAX_CURSOR_COUNT) {\r\n\t\t\tstates = states.slice(0, Cursor.MAX_CURSOR_COUNT);\r\n\t\t\treachedMaxCursorCount = true;\r\n\t\t}\r\n\r\n\t\tconst oldState = new CursorModelState(this._model, this);\r\n\r\n\t\tthis._cursors.setStates(states);\r\n\t\tthis._cursors.normalize();\r\n\t\tthis._columnSelectData = null;\r\n\r\n\t\tthis._validateAutoClosedActions();\r\n\r\n\t\treturn this._emitStateChangedIfNecessary(eventsCollector, source, reason, oldState, reachedMaxCursorCount);\r\n\t}\r\n\r\n\tpublic setCursorColumnSelectData(columnSelectData: IColumnSelectData): void {\r\n\t\tthis._columnSelectData = columnSelectData;\r\n\t}\r\n\r\n\tpublic revealPrimary(eventsCollector: ViewModelEventsCollector, source: string | null | undefined, revealHorizontal: boolean, scrollType: editorCommon.ScrollType): void {\r\n\t\tconst viewPositions = this._cursors.getViewPositions();\r\n\t\tif (viewPositions.length > 1) {\r\n\t\t\tthis._emitCursorRevealRange(eventsCollector, source, null, this._cursors.getViewSelections(), VerticalRevealType.Simple, revealHorizontal, scrollType);\r\n\t\t\treturn;\r\n\t\t} else {\r\n\t\t\tconst viewPosition = viewPositions[0];\r\n\t\t\tconst viewRange = new Range(viewPosition.lineNumber, viewPosition.column, viewPosition.lineNumber, viewPosition.column);\r\n\t\t\tthis._emitCursorRevealRange(eventsCollector, source, viewRange, null, VerticalRevealType.Simple, revealHorizontal, scrollType);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _revealPrimaryCursor(eventsCollector: ViewModelEventsCollector, source: string | null | undefined, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType): void {\r\n\t\tconst viewPositions = this._cursors.getViewPositions();\r\n\t\tif (viewPositions.length > 1) {\r\n\t\t\tthis._emitCursorRevealRange(eventsCollector, source, null, this._cursors.getViewSelections(), verticalType, revealHorizontal, scrollType);\r\n\t\t} else {\r\n\t\t\tconst viewPosition = viewPositions[0];\r\n\t\t\tconst viewRange = new Range(viewPosition.lineNumber, viewPosition.column, viewPosition.lineNumber, viewPosition.column);\r\n\t\t\tthis._emitCursorRevealRange(eventsCollector, source, viewRange, null, verticalType, revealHorizontal, scrollType);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _emitCursorRevealRange(eventsCollector: ViewModelEventsCollector, source: string | null | undefined, viewRange: Range | null, viewSelections: Selection[] | null, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType) {\r\n\t\teventsCollector.emitViewEvent(new ViewRevealRangeRequestEvent(source, viewRange, viewSelections, verticalType, revealHorizontal, scrollType));\r\n\t}\r\n\r\n\tpublic saveState(): editorCommon.ICursorState[] {\r\n\r\n\t\tlet result: editorCommon.ICursorState[] = [];\r\n\r\n\t\tconst selections = this._cursors.getSelections();\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tconst selection = selections[i];\r\n\r\n\t\t\tresult.push({\r\n\t\t\t\tinSelectionMode: !selection.isEmpty(),\r\n\t\t\t\tselectionStart: {\r\n\t\t\t\t\tlineNumber: selection.selectionStartLineNumber,\r\n\t\t\t\t\tcolumn: selection.selectionStartColumn,\r\n\t\t\t\t},\r\n\t\t\t\tposition: {\r\n\t\t\t\t\tlineNumber: selection.positionLineNumber,\r\n\t\t\t\t\tcolumn: selection.positionColumn,\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic restoreState(eventsCollector: ViewModelEventsCollector, states: editorCommon.ICursorState[]): void {\r\n\r\n\t\tlet desiredSelections: ISelection[] = [];\r\n\r\n\t\tfor (let i = 0, len = states.length; i < len; i++) {\r\n\t\t\tconst state = states[i];\r\n\r\n\t\t\tlet positionLineNumber = 1;\r\n\t\t\tlet positionColumn = 1;\r\n\r\n\t\t\t// Avoid missing properties on the literal\r\n\t\t\tif (state.position && state.position.lineNumber) {\r\n\t\t\t\tpositionLineNumber = state.position.lineNumber;\r\n\t\t\t}\r\n\t\t\tif (state.position && state.position.column) {\r\n\t\t\t\tpositionColumn = state.position.column;\r\n\t\t\t}\r\n\r\n\t\t\tlet selectionStartLineNumber = positionLineNumber;\r\n\t\t\tlet selectionStartColumn = positionColumn;\r\n\r\n\t\t\t// Avoid missing properties on the literal\r\n\t\t\tif (state.selectionStart && state.selectionStart.lineNumber) {\r\n\t\t\t\tselectionStartLineNumber = state.selectionStart.lineNumber;\r\n\t\t\t}\r\n\t\t\tif (state.selectionStart && state.selectionStart.column) {\r\n\t\t\t\tselectionStartColumn = state.selectionStart.column;\r\n\t\t\t}\r\n\r\n\t\t\tdesiredSelections.push({\r\n\t\t\t\tselectionStartLineNumber: selectionStartLineNumber,\r\n\t\t\t\tselectionStartColumn: selectionStartColumn,\r\n\t\t\t\tpositionLineNumber: positionLineNumber,\r\n\t\t\t\tpositionColumn: positionColumn\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tthis.setStates(eventsCollector, 'restoreState', CursorChangeReason.NotSet, CursorState.fromModelSelections(desiredSelections));\r\n\t\tthis.revealPrimary(eventsCollector, 'restoreState', true, editorCommon.ScrollType.Immediate);\r\n\t}\r\n\r\n\tpublic onModelContentChanged(eventsCollector: ViewModelEventsCollector, e: ModelRawContentChangedEvent): void {\r\n\r\n\t\tthis._knownModelVersionId = e.versionId;\r\n\t\tif (this._isHandling) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst hadFlushEvent = e.containsEvent(RawContentChangedType.Flush);\r\n\t\tthis._prevEditOperationType = EditOperationType.Other;\r\n\r\n\t\tif (hadFlushEvent) {\r\n\t\t\t// a model.setValue() was called\r\n\t\t\tthis._cursors.dispose();\r\n\t\t\tthis._cursors = new CursorCollection(this.context);\r\n\t\t\tthis._validateAutoClosedActions();\r\n\t\t\tthis._emitStateChangedIfNecessary(eventsCollector, 'model', CursorChangeReason.ContentFlush, null, false);\r\n\t\t} else {\r\n\t\t\tif (this._hasFocus && e.resultingSelection && e.resultingSelection.length > 0) {\r\n\t\t\t\tconst cursorState = CursorState.fromModelSelections(e.resultingSelection);\r\n\t\t\t\tif (this.setStates(eventsCollector, 'modelChange', e.isUndoing ? CursorChangeReason.Undo : e.isRedoing ? CursorChangeReason.Redo : CursorChangeReason.RecoverFromMarkers, cursorState)) {\r\n\t\t\t\t\tthis._revealPrimaryCursor(eventsCollector, 'modelChange', VerticalRevealType.Simple, true, editorCommon.ScrollType.Smooth);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tconst selectionsFromMarkers = this._cursors.readSelectionFromMarkers();\r\n\t\t\t\tthis.setStates(eventsCollector, 'modelChange', CursorChangeReason.RecoverFromMarkers, CursorState.fromModelSelections(selectionsFromMarkers));\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getSelection(): Selection {\r\n\t\treturn this._cursors.getPrimaryCursor().modelState.selection;\r\n\t}\r\n\r\n\tpublic getTopMostViewPosition(): Position {\r\n\t\treturn this._cursors.getTopMostViewPosition();\r\n\t}\r\n\r\n\tpublic getBottomMostViewPosition(): Position {\r\n\t\treturn this._cursors.getBottomMostViewPosition();\r\n\t}\r\n\r\n\tpublic getCursorColumnSelectData(): IColumnSelectData {\r\n\t\tif (this._columnSelectData) {\r\n\t\t\treturn this._columnSelectData;\r\n\t\t}\r\n\t\tconst primaryCursor = this._cursors.getPrimaryCursor();\r\n\t\tconst viewSelectionStart = primaryCursor.viewState.selectionStart.getStartPosition();\r\n\t\tconst viewPosition = primaryCursor.viewState.position;\r\n\t\treturn {\r\n\t\t\tisReal: false,\r\n\t\t\tfromViewLineNumber: viewSelectionStart.lineNumber,\r\n\t\t\tfromViewVisualColumn: CursorColumns.visibleColumnFromColumn2(this.context.cursorConfig, this._viewModel, viewSelectionStart),\r\n\t\t\ttoViewLineNumber: viewPosition.lineNumber,\r\n\t\t\ttoViewVisualColumn: CursorColumns.visibleColumnFromColumn2(this.context.cursorConfig, this._viewModel, viewPosition),\r\n\t\t};\r\n\t}\r\n\r\n\tpublic getSelections(): Selection[] {\r\n\t\treturn this._cursors.getSelections();\r\n\t}\r\n\r\n\tpublic setSelections(eventsCollector: ViewModelEventsCollector, source: string | null | undefined, selections: readonly ISelection[], reason: CursorChangeReason): void {\r\n\t\tthis.setStates(eventsCollector, source, reason, CursorState.fromModelSelections(selections));\r\n\t}\r\n\r\n\tpublic getPrevEditOperationType(): EditOperationType {\r\n\t\treturn this._prevEditOperationType;\r\n\t}\r\n\r\n\tpublic setPrevEditOperationType(type: EditOperationType): void {\r\n\t\tthis._prevEditOperationType = type;\r\n\t}\r\n\r\n\t// ------ auxiliary handling logic\r\n\r\n\tprivate _pushAutoClosedAction(autoClosedCharactersRanges: Range[], autoClosedEnclosingRanges: Range[]): void {\r\n\t\tlet autoClosedCharactersDeltaDecorations: IModelDeltaDecoration[] = [];\r\n\t\tlet autoClosedEnclosingDeltaDecorations: IModelDeltaDecoration[] = [];\r\n\r\n\t\tfor (let i = 0, len = autoClosedCharactersRanges.length; i < len; i++) {\r\n\t\t\tautoClosedCharactersDeltaDecorations.push({\r\n\t\t\t\trange: autoClosedCharactersRanges[i],\r\n\t\t\t\toptions: {\r\n\t\t\t\t\tinlineClassName: 'auto-closed-character',\r\n\t\t\t\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t\tautoClosedEnclosingDeltaDecorations.push({\r\n\t\t\t\trange: autoClosedEnclosingRanges[i],\r\n\t\t\t\toptions: {\r\n\t\t\t\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tconst autoClosedCharactersDecorations = this._model.deltaDecorations([], autoClosedCharactersDeltaDecorations);\r\n\t\tconst autoClosedEnclosingDecorations = this._model.deltaDecorations([], autoClosedEnclosingDeltaDecorations);\r\n\t\tthis._autoClosedActions.push(new AutoClosedAction(this._model, autoClosedCharactersDecorations, autoClosedEnclosingDecorations));\r\n\t}\r\n\r\n\tprivate _executeEditOperation(opResult: EditOperationResult | null): void {\r\n\r\n\t\tif (!opResult) {\r\n\t\t\t// Nothing to execute\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (opResult.shouldPushStackElementBefore) {\r\n\t\t\tthis._model.pushStackElement();\r\n\t\t}\r\n\r\n\t\tconst result = CommandExecutor.executeCommands(this._model, this._cursors.getSelections(), opResult.commands);\r\n\t\tif (result) {\r\n\t\t\t// The commands were applied correctly\r\n\t\t\tthis._interpretCommandResult(result);\r\n\r\n\t\t\t// Check for auto-closing closed characters\r\n\t\t\tlet autoClosedCharactersRanges: Range[] = [];\r\n\t\t\tlet autoClosedEnclosingRanges: Range[] = [];\r\n\r\n\t\t\tfor (let i = 0; i < opResult.commands.length; i++) {\r\n\t\t\t\tconst command = opResult.commands[i];\r\n\t\t\t\tif (command instanceof TypeWithAutoClosingCommand && command.enclosingRange && command.closeCharacterRange) {\r\n\t\t\t\t\tautoClosedCharactersRanges.push(command.closeCharacterRange);\r\n\t\t\t\t\tautoClosedEnclosingRanges.push(command.enclosingRange);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (autoClosedCharactersRanges.length > 0) {\r\n\t\t\t\tthis._pushAutoClosedAction(autoClosedCharactersRanges, autoClosedEnclosingRanges);\r\n\t\t\t}\r\n\r\n\t\t\tthis._prevEditOperationType = opResult.type;\r\n\t\t}\r\n\r\n\t\tif (opResult.shouldPushStackElementAfter) {\r\n\t\t\tthis._model.pushStackElement();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _interpretCommandResult(cursorState: Selection[] | null): void {\r\n\t\tif (!cursorState || cursorState.length === 0) {\r\n\t\t\tcursorState = this._cursors.readSelectionFromMarkers();\r\n\t\t}\r\n\r\n\t\tthis._columnSelectData = null;\r\n\t\tthis._cursors.setSelections(cursorState);\r\n\t\tthis._cursors.normalize();\r\n\t}\r\n\r\n\t// -----------------------------------------------------------------------------------------------------------\r\n\t// ----- emitting events\r\n\r\n\tprivate _emitStateChangedIfNecessary(eventsCollector: ViewModelEventsCollector, source: string | null | undefined, reason: CursorChangeReason, oldState: CursorModelState | null, reachedMaxCursorCount: boolean): boolean {\r\n\t\tconst newState = new CursorModelState(this._model, this);\r\n\t\tif (newState.equals(oldState)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tconst selections = this._cursors.getSelections();\r\n\t\tconst viewSelections = this._cursors.getViewSelections();\r\n\r\n\t\t// Let the view get the event first.\r\n\t\teventsCollector.emitViewEvent(new ViewCursorStateChangedEvent(viewSelections, selections));\r\n\r\n\t\t// Only after the view has been notified, let the rest of the world know...\r\n\t\tif (!oldState\r\n\t\t\t|| oldState.cursorState.length !== newState.cursorState.length\r\n\t\t\t|| newState.cursorState.some((newCursorState, i) => !newCursorState.modelState.equals(oldState.cursorState[i].modelState))\r\n\t\t) {\r\n\t\t\tconst oldSelections = oldState ? oldState.cursorState.map(s => s.modelState.selection) : null;\r\n\t\t\tconst oldModelVersionId = oldState ? oldState.modelVersionId : 0;\r\n\t\t\teventsCollector.emitOutgoingEvent(new CursorStateChangedEvent(oldSelections, selections, oldModelVersionId, newState.modelVersionId, source || 'keyboard', reason, reachedMaxCursorCount));\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// -----------------------------------------------------------------------------------------------------------\r\n\t// ----- handlers beyond this point\r\n\r\n\tprivate _findAutoClosingPairs(edits: IIdentifiedSingleEditOperation[]): [number, number][] | null {\r\n\t\tif (!edits.length) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet indices: [number, number][] = [];\r\n\t\tfor (let i = 0, len = edits.length; i < len; i++) {\r\n\t\t\tconst edit = edits[i];\r\n\t\t\tif (!edit.text || edit.text.indexOf('\\n') >= 0) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\r\n\t\t\tconst m = edit.text.match(/([)\\]}>'\"`])([^)\\]}>'\"`]*)$/);\r\n\t\t\tif (!m) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t\tconst closeChar = m[1];\r\n\r\n\t\t\tconst autoClosingPairsCandidates = this.context.cursorConfig.autoClosingPairs.autoClosingPairsCloseSingleChar.get(closeChar);\r\n\t\t\tif (!autoClosingPairsCandidates || autoClosingPairsCandidates.length !== 1) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\r\n\t\t\tconst openChar = autoClosingPairsCandidates[0].open;\r\n\t\t\tconst closeCharIndex = edit.text.length - m[2].length - 1;\r\n\t\t\tconst openCharIndex = edit.text.lastIndexOf(openChar, closeCharIndex - 1);\r\n\t\t\tif (openCharIndex === -1) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\r\n\t\t\tindices.push([openCharIndex, closeCharIndex]);\r\n\t\t}\r\n\r\n\t\treturn indices;\r\n\t}\r\n\r\n\tpublic executeEdits(eventsCollector: ViewModelEventsCollector, source: string | null | undefined, edits: IIdentifiedSingleEditOperation[], cursorStateComputer: ICursorStateComputer): void {\r\n\t\tlet autoClosingIndices: [number, number][] | null = null;\r\n\t\tif (source === 'snippet') {\r\n\t\t\tautoClosingIndices = this._findAutoClosingPairs(edits);\r\n\t\t}\r\n\r\n\t\tif (autoClosingIndices) {\r\n\t\t\tedits[0]._isTracked = true;\r\n\t\t}\r\n\t\tlet autoClosedCharactersRanges: Range[] = [];\r\n\t\tlet autoClosedEnclosingRanges: Range[] = [];\r\n\t\tconst selections = this._model.pushEditOperations(this.getSelections(), edits, (undoEdits) => {\r\n\t\t\tif (autoClosingIndices) {\r\n\t\t\t\tfor (let i = 0, len = autoClosingIndices.length; i < len; i++) {\r\n\t\t\t\t\tconst [openCharInnerIndex, closeCharInnerIndex] = autoClosingIndices[i];\r\n\t\t\t\t\tconst undoEdit = undoEdits[i];\r\n\t\t\t\t\tconst lineNumber = undoEdit.range.startLineNumber;\r\n\t\t\t\t\tconst openCharIndex = undoEdit.range.startColumn - 1 + openCharInnerIndex;\r\n\t\t\t\t\tconst closeCharIndex = undoEdit.range.startColumn - 1 + closeCharInnerIndex;\r\n\r\n\t\t\t\t\tautoClosedCharactersRanges.push(new Range(lineNumber, closeCharIndex + 1, lineNumber, closeCharIndex + 2));\r\n\t\t\t\t\tautoClosedEnclosingRanges.push(new Range(lineNumber, openCharIndex + 1, lineNumber, closeCharIndex + 2));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tconst selections = cursorStateComputer(undoEdits);\r\n\t\t\tif (selections) {\r\n\t\t\t\t// Don't recover the selection from markers because\r\n\t\t\t\t// we know what it should be.\r\n\t\t\t\tthis._isHandling = true;\r\n\t\t\t}\r\n\r\n\t\t\treturn selections;\r\n\t\t});\r\n\t\tif (selections) {\r\n\t\t\tthis._isHandling = false;\r\n\t\t\tthis.setSelections(eventsCollector, source, selections, CursorChangeReason.NotSet);\r\n\t\t}\r\n\t\tif (autoClosedCharactersRanges.length > 0) {\r\n\t\t\tthis._pushAutoClosedAction(autoClosedCharactersRanges, autoClosedEnclosingRanges);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _executeEdit(callback: () => void, eventsCollector: ViewModelEventsCollector, source: string | null | undefined, cursorChangeReason: CursorChangeReason = CursorChangeReason.NotSet): void {\r\n\t\tif (this.context.cursorConfig.readOnly) {\r\n\t\t\t// we cannot edit when read only...\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst oldState = new CursorModelState(this._model, this);\r\n\t\tthis._cursors.stopTrackingSelections();\r\n\t\tthis._isHandling = true;\r\n\r\n\t\ttry {\r\n\t\t\tthis._cursors.ensureValidState();\r\n\t\t\tcallback();\r\n\t\t} catch (err) {\r\n\t\t\tonUnexpectedError(err);\r\n\t\t}\r\n\r\n\t\tthis._isHandling = false;\r\n\t\tthis._cursors.startTrackingSelections();\r\n\t\tthis._validateAutoClosedActions();\r\n\t\tif (this._emitStateChangedIfNecessary(eventsCollector, source, cursorChangeReason, oldState, false)) {\r\n\t\t\tthis._revealPrimaryCursor(eventsCollector, source, VerticalRevealType.Simple, true, editorCommon.ScrollType.Smooth);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic setIsDoingComposition(isDoingComposition: boolean): void {\r\n\t\tthis._isDoingComposition = isDoingComposition;\r\n\t}\r\n\r\n\tpublic startComposition(eventsCollector: ViewModelEventsCollector): void {\r\n\t\tthis._selectionsWhenCompositionStarted = this.getSelections().slice(0);\r\n\t}\r\n\r\n\tpublic endComposition(eventsCollector: ViewModelEventsCollector, source?: string | null | undefined): void {\r\n\t\tthis._executeEdit(() => {\r\n\t\t\tif (source === 'keyboard') {\r\n\t\t\t\t// composition finishes, let's check if we need to auto complete if necessary.\r\n\t\t\t\tconst autoClosedCharacters = AutoClosedAction.getAllAutoClosedCharacters(this._autoClosedActions);\r\n\t\t\t\tthis._executeEditOperation(TypeOperations.compositionEndWithInterceptors(this._prevEditOperationType, this.context.cursorConfig, this._model, this._selectionsWhenCompositionStarted, this.getSelections(), autoClosedCharacters));\r\n\t\t\t\tthis._selectionsWhenCompositionStarted = null;\r\n\t\t\t}\r\n\t\t}, eventsCollector, source);\r\n\t}\r\n\r\n\tpublic type(eventsCollector: ViewModelEventsCollector, text: string, source?: string | null | undefined): void {\r\n\t\tthis._executeEdit(() => {\r\n\t\t\tif (source === 'keyboard') {\r\n\t\t\t\t// If this event is coming straight from the keyboard, look for electric characters and enter\r\n\r\n\t\t\t\tconst len = text.length;\r\n\t\t\t\tlet offset = 0;\r\n\t\t\t\twhile (offset < len) {\r\n\t\t\t\t\tconst charLength = strings.nextCharLength(text, offset);\r\n\t\t\t\t\tconst chr = text.substr(offset, charLength);\r\n\r\n\t\t\t\t\t// Here we must interpret each typed character individually\r\n\t\t\t\t\tconst autoClosedCharacters = AutoClosedAction.getAllAutoClosedCharacters(this._autoClosedActions);\r\n\t\t\t\t\tthis._executeEditOperation(TypeOperations.typeWithInterceptors(this._isDoingComposition, this._prevEditOperationType, this.context.cursorConfig, this._model, this.getSelections(), autoClosedCharacters, chr));\r\n\r\n\t\t\t\t\toffset += charLength;\r\n\t\t\t\t}\r\n\r\n\t\t\t} else {\r\n\t\t\t\tthis._executeEditOperation(TypeOperations.typeWithoutInterceptors(this._prevEditOperationType, this.context.cursorConfig, this._model, this.getSelections(), text));\r\n\t\t\t}\r\n\t\t}, eventsCollector, source);\r\n\t}\r\n\r\n\tpublic replacePreviousChar(eventsCollector: ViewModelEventsCollector, text: string, replaceCharCnt: number, source?: string | null | undefined): void {\r\n\t\tthis._executeEdit(() => {\r\n\t\t\tthis._executeEditOperation(TypeOperations.replacePreviousChar(this._prevEditOperationType, this.context.cursorConfig, this._model, this.getSelections(), text, replaceCharCnt));\r\n\t\t}, eventsCollector, source);\r\n\t}\r\n\r\n\tpublic paste(eventsCollector: ViewModelEventsCollector, text: string, pasteOnNewLine: boolean, multicursorText?: string[] | null | undefined, source?: string | null | undefined): void {\r\n\t\tthis._executeEdit(() => {\r\n\t\t\tthis._executeEditOperation(TypeOperations.paste(this.context.cursorConfig, this._model, this.getSelections(), text, pasteOnNewLine, multicursorText || []));\r\n\t\t}, eventsCollector, source, CursorChangeReason.Paste);\r\n\t}\r\n\r\n\tpublic cut(eventsCollector: ViewModelEventsCollector, source?: string | null | undefined): void {\r\n\t\tthis._executeEdit(() => {\r\n\t\t\tthis._executeEditOperation(DeleteOperations.cut(this.context.cursorConfig, this._model, this.getSelections()));\r\n\t\t}, eventsCollector, source);\r\n\t}\r\n\r\n\tpublic executeCommand(eventsCollector: ViewModelEventsCollector, command: editorCommon.ICommand, source?: string | null | undefined): void {\r\n\t\tthis._executeEdit(() => {\r\n\t\t\tthis._cursors.killSecondaryCursors();\r\n\r\n\t\t\tthis._executeEditOperation(new EditOperationResult(EditOperationType.Other, [command], {\r\n\t\t\t\tshouldPushStackElementBefore: false,\r\n\t\t\t\tshouldPushStackElementAfter: false\r\n\t\t\t}));\r\n\t\t}, eventsCollector, source);\r\n\t}\r\n\r\n\tpublic executeCommands(eventsCollector: ViewModelEventsCollector, commands: editorCommon.ICommand[], source?: string | null | undefined): void {\r\n\t\tthis._executeEdit(() => {\r\n\t\t\tthis._executeEditOperation(new EditOperationResult(EditOperationType.Other, commands, {\r\n\t\t\t\tshouldPushStackElementBefore: false,\r\n\t\t\t\tshouldPushStackElementAfter: false\r\n\t\t\t}));\r\n\t\t}, eventsCollector, source);\r\n\t}\r\n}\r\n\r\ninterface IExecContext {\r\n\treadonly model: ITextModel;\r\n\treadonly selectionsBefore: Selection[];\r\n\treadonly trackedRanges: string[];\r\n\treadonly trackedRangesDirection: SelectionDirection[];\r\n}\r\n\r\ninterface ICommandData {\r\n\toperations: IIdentifiedSingleEditOperation[];\r\n\thadTrackedEditOperation: boolean;\r\n}\r\n\r\ninterface ICommandsData {\r\n\toperations: IIdentifiedSingleEditOperation[];\r\n\thadTrackedEditOperation: boolean;\r\n}\r\n\r\nclass CommandExecutor {\r\n\r\n\tpublic static executeCommands(model: ITextModel, selectionsBefore: Selection[], commands: (editorCommon.ICommand | null)[]): Selection[] | null {\r\n\r\n\t\tconst ctx: IExecContext = {\r\n\t\t\tmodel: model,\r\n\t\t\tselectionsBefore: selectionsBefore,\r\n\t\t\ttrackedRanges: [],\r\n\t\t\ttrackedRangesDirection: []\r\n\t\t};\r\n\r\n\t\tconst result = this._innerExecuteCommands(ctx, commands);\r\n\r\n\t\tfor (let i = 0, len = ctx.trackedRanges.length; i < len; i++) {\r\n\t\t\tctx.model._setTrackedRange(ctx.trackedRanges[i], null, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges);\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _innerExecuteCommands(ctx: IExecContext, commands: (editorCommon.ICommand | null)[]): Selection[] | null {\r\n\r\n\t\tif (this._arrayIsEmpty(commands)) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst commandsData = this._getEditOperations(ctx, commands);\r\n\t\tif (commandsData.operations.length === 0) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst rawOperations = commandsData.operations;\r\n\r\n\t\tconst loserCursorsMap = this._getLoserCursorMap(rawOperations);\r\n\t\tif (loserCursorsMap.hasOwnProperty('0')) {\r\n\t\t\t// These commands are very messed up\r\n\t\t\tconsole.warn('Ignoring commands');\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\t// Remove operations belonging to losing cursors\r\n\t\tlet filteredOperations: IIdentifiedSingleEditOperation[] = [];\r\n\t\tfor (let i = 0, len = rawOperations.length; i < len; i++) {\r\n\t\t\tif (!loserCursorsMap.hasOwnProperty(rawOperations[i].identifier!.major.toString())) {\r\n\t\t\t\tfilteredOperations.push(rawOperations[i]);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// TODO@Alex: find a better way to do this.\r\n\t\t// give the hint that edit operations are tracked to the model\r\n\t\tif (commandsData.hadTrackedEditOperation && filteredOperations.length > 0) {\r\n\t\t\tfilteredOperations[0]._isTracked = true;\r\n\t\t}\r\n\t\tlet selectionsAfter = ctx.model.pushEditOperations(ctx.selectionsBefore, filteredOperations, (inverseEditOperations: IValidEditOperation[]): Selection[] => {\r\n\t\t\tlet groupedInverseEditOperations: IValidEditOperation[][] = [];\r\n\t\t\tfor (let i = 0; i < ctx.selectionsBefore.length; i++) {\r\n\t\t\t\tgroupedInverseEditOperations[i] = [];\r\n\t\t\t}\r\n\t\t\tfor (const op of inverseEditOperations) {\r\n\t\t\t\tif (!op.identifier) {\r\n\t\t\t\t\t// perhaps auto whitespace trim edits\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\tgroupedInverseEditOperations[op.identifier.major].push(op);\r\n\t\t\t}\r\n\t\t\tconst minorBasedSorter = (a: IValidEditOperation, b: IValidEditOperation) => {\r\n\t\t\t\treturn a.identifier!.minor - b.identifier!.minor;\r\n\t\t\t};\r\n\t\t\tlet cursorSelections: Selection[] = [];\r\n\t\t\tfor (let i = 0; i < ctx.selectionsBefore.length; i++) {\r\n\t\t\t\tif (groupedInverseEditOperations[i].length > 0) {\r\n\t\t\t\t\tgroupedInverseEditOperations[i].sort(minorBasedSorter);\r\n\t\t\t\t\tcursorSelections[i] = commands[i]!.computeCursorState(ctx.model, {\r\n\t\t\t\t\t\tgetInverseEditOperations: () => {\r\n\t\t\t\t\t\t\treturn groupedInverseEditOperations[i];\r\n\t\t\t\t\t\t},\r\n\r\n\t\t\t\t\t\tgetTrackedSelection: (id: string) => {\r\n\t\t\t\t\t\t\tconst idx = parseInt(id, 10);\r\n\t\t\t\t\t\t\tconst range = ctx.model._getTrackedRange(ctx.trackedRanges[idx])!;\r\n\t\t\t\t\t\t\tif (ctx.trackedRangesDirection[idx] === SelectionDirection.LTR) {\r\n\t\t\t\t\t\t\t\treturn new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\treturn new Selection(range.endLineNumber, range.endColumn, range.startLineNumber, range.startColumn);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t});\r\n\t\t\t\t} else {\r\n\t\t\t\t\tcursorSelections[i] = ctx.selectionsBefore[i];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn cursorSelections;\r\n\t\t});\r\n\t\tif (!selectionsAfter) {\r\n\t\t\tselectionsAfter = ctx.selectionsBefore;\r\n\t\t}\r\n\r\n\t\t// Extract losing cursors\r\n\t\tlet losingCursors: number[] = [];\r\n\t\tfor (let losingCursorIndex in loserCursorsMap) {\r\n\t\t\tif (loserCursorsMap.hasOwnProperty(losingCursorIndex)) {\r\n\t\t\t\tlosingCursors.push(parseInt(losingCursorIndex, 10));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Sort losing cursors descending\r\n\t\tlosingCursors.sort((a: number, b: number): number => {\r\n\t\t\treturn b - a;\r\n\t\t});\r\n\r\n\t\t// Remove losing cursors\r\n\t\tfor (const losingCursor of losingCursors) {\r\n\t\t\tselectionsAfter.splice(losingCursor, 1);\r\n\t\t}\r\n\r\n\t\treturn selectionsAfter;\r\n\t}\r\n\r\n\tprivate static _arrayIsEmpty(commands: (editorCommon.ICommand | null)[]): boolean {\r\n\t\tfor (let i = 0, len = commands.length; i < len; i++) {\r\n\t\t\tif (commands[i]) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\tprivate static _getEditOperations(ctx: IExecContext, commands: (editorCommon.ICommand | null)[]): ICommandsData {\r\n\t\tlet operations: IIdentifiedSingleEditOperation[] = [];\r\n\t\tlet hadTrackedEditOperation: boolean = false;\r\n\r\n\t\tfor (let i = 0, len = commands.length; i < len; i++) {\r\n\t\t\tconst command = commands[i];\r\n\t\t\tif (command) {\r\n\t\t\t\tconst r = this._getEditOperationsFromCommand(ctx, i, command);\r\n\t\t\t\toperations = operations.concat(r.operations);\r\n\t\t\t\thadTrackedEditOperation = hadTrackedEditOperation || r.hadTrackedEditOperation;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn {\r\n\t\t\toperations: operations,\r\n\t\t\thadTrackedEditOperation: hadTrackedEditOperation\r\n\t\t};\r\n\t}\r\n\r\n\tprivate static _getEditOperationsFromCommand(ctx: IExecContext, majorIdentifier: number, command: editorCommon.ICommand): ICommandData {\r\n\t\t// This method acts as a transaction, if the command fails\r\n\t\t// everything it has done is ignored\r\n\t\tlet operations: IIdentifiedSingleEditOperation[] = [];\r\n\t\tlet operationMinor = 0;\r\n\r\n\t\tconst addEditOperation = (range: IRange, text: string | null, forceMoveMarkers: boolean = false) => {\r\n\t\t\tif (Range.isEmpty(range) && text === '') {\r\n\t\t\t\t// This command wants to add a no-op => no thank you\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\toperations.push({\r\n\t\t\t\tidentifier: {\r\n\t\t\t\t\tmajor: majorIdentifier,\r\n\t\t\t\t\tminor: operationMinor++\r\n\t\t\t\t},\r\n\t\t\t\trange: range,\r\n\t\t\t\ttext: text,\r\n\t\t\t\tforceMoveMarkers: forceMoveMarkers,\r\n\t\t\t\tisAutoWhitespaceEdit: command.insertsAutoWhitespace\r\n\t\t\t});\r\n\t\t};\r\n\r\n\t\tlet hadTrackedEditOperation = false;\r\n\t\tconst addTrackedEditOperation = (selection: IRange, text: string | null, forceMoveMarkers?: boolean) => {\r\n\t\t\thadTrackedEditOperation = true;\r\n\t\t\taddEditOperation(selection, text, forceMoveMarkers);\r\n\t\t};\r\n\r\n\t\tconst trackSelection = (_selection: ISelection, trackPreviousOnEmpty?: boolean) => {\r\n\t\t\tconst selection = Selection.liftSelection(_selection);\r\n\t\t\tlet stickiness: TrackedRangeStickiness;\r\n\t\t\tif (selection.isEmpty()) {\r\n\t\t\t\tif (typeof trackPreviousOnEmpty === 'boolean') {\r\n\t\t\t\t\tif (trackPreviousOnEmpty) {\r\n\t\t\t\t\t\tstickiness = TrackedRangeStickiness.GrowsOnlyWhenTypingBefore;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tstickiness = TrackedRangeStickiness.GrowsOnlyWhenTypingAfter;\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// Try to lock it with surrounding text\r\n\t\t\t\t\tconst maxLineColumn = ctx.model.getLineMaxColumn(selection.startLineNumber);\r\n\t\t\t\t\tif (selection.startColumn === maxLineColumn) {\r\n\t\t\t\t\t\tstickiness = TrackedRangeStickiness.GrowsOnlyWhenTypingBefore;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tstickiness = TrackedRangeStickiness.GrowsOnlyWhenTypingAfter;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tstickiness = TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges;\r\n\t\t\t}\r\n\r\n\t\t\tconst l = ctx.trackedRanges.length;\r\n\t\t\tconst id = ctx.model._setTrackedRange(null, selection, stickiness);\r\n\t\t\tctx.trackedRanges[l] = id;\r\n\t\t\tctx.trackedRangesDirection[l] = selection.getDirection();\r\n\t\t\treturn l.toString();\r\n\t\t};\r\n\r\n\t\tconst editOperationBuilder: editorCommon.IEditOperationBuilder = {\r\n\t\t\taddEditOperation: addEditOperation,\r\n\t\t\taddTrackedEditOperation: addTrackedEditOperation,\r\n\t\t\ttrackSelection: trackSelection\r\n\t\t};\r\n\r\n\t\ttry {\r\n\t\t\tcommand.getEditOperations(ctx.model, editOperationBuilder);\r\n\t\t} catch (e) {\r\n\t\t\t// TODO@Alex use notification service if this should be user facing\r\n\t\t\t// e.friendlyMessage = nls.localize('corrupt.commands', \"Unexpected exception while executing command.\");\r\n\t\t\tonUnexpectedError(e);\r\n\t\t\treturn {\r\n\t\t\t\toperations: [],\r\n\t\t\t\thadTrackedEditOperation: false\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\toperations: operations,\r\n\t\t\thadTrackedEditOperation: hadTrackedEditOperation\r\n\t\t};\r\n\t}\r\n\r\n\tprivate static _getLoserCursorMap(operations: IIdentifiedSingleEditOperation[]): { [index: string]: boolean; } {\r\n\t\t// This is destructive on the array\r\n\t\toperations = operations.slice(0);\r\n\r\n\t\t// Sort operations with last one first\r\n\t\toperations.sort((a: IIdentifiedSingleEditOperation, b: IIdentifiedSingleEditOperation): number => {\r\n\t\t\t// Note the minus!\r\n\t\t\treturn -(Range.compareRangesUsingEnds(a.range, b.range));\r\n\t\t});\r\n\r\n\t\t// Operations can not overlap!\r\n\t\tlet loserCursorsMap: { [index: string]: boolean; } = {};\r\n\r\n\t\tfor (let i = 1; i < operations.length; i++) {\r\n\t\t\tconst previousOp = operations[i - 1];\r\n\t\t\tconst currentOp = operations[i];\r\n\r\n\t\t\tif (Range.getStartPosition(previousOp.range).isBefore(Range.getEndPosition(currentOp.range))) {\r\n\r\n\t\t\t\tlet loserMajor: number;\r\n\r\n\t\t\t\tif (previousOp.identifier!.major > currentOp.identifier!.major) {\r\n\t\t\t\t\t// previousOp loses the battle\r\n\t\t\t\t\tloserMajor = previousOp.identifier!.major;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tloserMajor = currentOp.identifier!.major;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tloserCursorsMap[loserMajor.toString()] = true;\r\n\r\n\t\t\t\tfor (let j = 0; j < operations.length; j++) {\r\n\t\t\t\t\tif (operations[j].identifier!.major === loserMajor) {\r\n\t\t\t\t\t\toperations.splice(j, 1);\r\n\t\t\t\t\t\tif (j < i) {\r\n\t\t\t\t\t\t\ti--;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tj--;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (i > 0) {\r\n\t\t\t\t\ti--;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn loserCursorsMap;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { IViewLineTokens, LineTokens } from 'vs/editor/common/core/lineTokens';\r\nimport { TokenizationResult2 } from 'vs/editor/common/core/token';\r\nimport { IState, LanguageId } from 'vs/editor/common/modes';\r\nimport { NULL_STATE, nullTokenize2 } from 'vs/editor/common/modes/nullMode';\r\n\r\nexport interface IReducedTokenizationSupport {\r\n\tgetInitialState(): IState;\r\n\ttokenize2(line: string, hasEOL: boolean, state: IState, offsetDelta: number): TokenizationResult2;\r\n}\r\n\r\nconst fallback: IReducedTokenizationSupport = {\r\n\tgetInitialState: () => NULL_STATE,\r\n\ttokenize2: (buffer: string, hasEOL: boolean, state: IState, deltaOffset: number) => nullTokenize2(LanguageId.Null, buffer, state, deltaOffset)\r\n};\r\n\r\nexport function tokenizeToString(text: string, tokenizationSupport: IReducedTokenizationSupport = fallback): string {\r\n\treturn _tokenizeToString(text, tokenizationSupport || fallback);\r\n}\r\n\r\nexport function tokenizeLineToHTML(text: string, viewLineTokens: IViewLineTokens, colorMap: string[], startOffset: number, endOffset: number, tabSize: number, useNbsp: boolean): string {\r\n\tlet result = `
    `;\r\n\tlet charIndex = startOffset;\r\n\tlet tabsCharDelta = 0;\r\n\r\n\tfor (let tokenIndex = 0, tokenCount = viewLineTokens.getCount(); tokenIndex < tokenCount; tokenIndex++) {\r\n\t\tconst tokenEndIndex = viewLineTokens.getEndOffset(tokenIndex);\r\n\r\n\t\tif (tokenEndIndex <= startOffset) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tlet partContent = '';\r\n\r\n\t\tfor (; charIndex < tokenEndIndex && charIndex < endOffset; charIndex++) {\r\n\t\t\tconst charCode = text.charCodeAt(charIndex);\r\n\r\n\t\t\tswitch (charCode) {\r\n\t\t\t\tcase CharCode.Tab:\r\n\t\t\t\t\tlet insertSpacesCount = tabSize - (charIndex + tabsCharDelta) % tabSize;\r\n\t\t\t\t\ttabsCharDelta += insertSpacesCount - 1;\r\n\t\t\t\t\twhile (insertSpacesCount > 0) {\r\n\t\t\t\t\t\tpartContent += useNbsp ? ' ' : ' ';\r\n\t\t\t\t\t\tinsertSpacesCount--;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase CharCode.LessThan:\r\n\t\t\t\t\tpartContent += '<';\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase CharCode.GreaterThan:\r\n\t\t\t\t\tpartContent += '>';\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase CharCode.Ampersand:\r\n\t\t\t\t\tpartContent += '&';\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase CharCode.Null:\r\n\t\t\t\t\tpartContent += '�';\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase CharCode.UTF8_BOM:\r\n\t\t\t\tcase CharCode.LINE_SEPARATOR:\r\n\t\t\t\tcase CharCode.PARAGRAPH_SEPARATOR:\r\n\t\t\t\tcase CharCode.NEXT_LINE:\r\n\t\t\t\t\tpartContent += '\\ufffd';\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase CharCode.CarriageReturn:\r\n\t\t\t\t\t// zero width space, because carriage return would introduce a line break\r\n\t\t\t\t\tpartContent += '​';\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase CharCode.Space:\r\n\t\t\t\t\tpartContent += useNbsp ? ' ' : ' ';\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tdefault:\r\n\t\t\t\t\tpartContent += String.fromCharCode(charCode);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tresult += `${partContent}`;\r\n\r\n\t\tif (tokenEndIndex > endOffset || charIndex >= endOffset) {\r\n\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n\r\n\tresult += `
    `;\r\n\treturn result;\r\n}\r\n\r\nfunction _tokenizeToString(text: string, tokenizationSupport: IReducedTokenizationSupport): string {\r\n\tlet result = `
    `;\r\n\tlet lines = strings.splitLines(text);\r\n\tlet currentState = tokenizationSupport.getInitialState();\r\n\tfor (let i = 0, len = lines.length; i < len; i++) {\r\n\t\tlet line = lines[i];\r\n\r\n\t\tif (i > 0) {\r\n\t\t\tresult += `
    `;\r\n\t\t}\r\n\r\n\t\tlet tokenizationResult = tokenizationSupport.tokenize2(line, true, currentState, 0);\r\n\t\tLineTokens.convertToEndOffset(tokenizationResult.tokens, line.length);\r\n\t\tlet lineTokens = new LineTokens(tokenizationResult.tokens, line);\r\n\t\tlet viewLineTokens = lineTokens.inflate();\r\n\r\n\t\tlet startOffset = 0;\r\n\t\tfor (let j = 0, lenJ = viewLineTokens.getCount(); j < lenJ; j++) {\r\n\t\t\tconst type = viewLineTokens.getClassName(j);\r\n\t\t\tconst endIndex = viewLineTokens.getEndOffset(j);\r\n\t\t\tresult += `${strings.escape(line.substring(startOffset, endIndex))}`;\r\n\t\t\tstartOffset = endIndex;\r\n\t\t}\r\n\r\n\t\tcurrentState = tokenizationResult.endState;\r\n\t}\r\n\r\n\tresult += `
    `;\r\n\treturn result;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IReference } from 'vs/base/common/lifecycle';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { IEditorModel } from 'vs/platform/editor/common/editor';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\n\r\nexport const ITextModelService = createDecorator('textModelService');\r\n\r\nexport interface ITextModelService {\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\t/**\r\n\t * Provided a resource URI, it will return a model reference\r\n\t * which should be disposed once not needed anymore.\r\n\t */\r\n\tcreateModelReference(resource: URI): Promise>;\r\n}\r\n\r\nexport interface ITextEditorModel extends IEditorModel {\r\n\r\n\t/**\r\n\t * Provides access to the underlying `ITextModel`.\r\n\t */\r\n\treadonly textEditorModel: ITextModel | null;\r\n}\r\n\r\nexport interface IResolvedTextEditorModel extends ITextEditorModel {\r\n\r\n\t/**\r\n\t * Same as ITextEditorModel#textEditorModel, but never null.\r\n\t */\r\n\treadonly textEditorModel: ITextModel;\r\n}\r\n","\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { IPosition } from 'vs/editor/common/core/position';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\n\r\nexport const ITextResourceConfigurationService = createDecorator('textResourceConfigurationService');\r\n\r\nexport interface ITextResourceConfigurationChangeEvent {\r\n\r\n\t/**\r\n\t * All affected keys. Also includes language overrides and keys changed under language overrides.\r\n\t */\r\n\treadonly affectedKeys: string[];\r\n\r\n\t/**\r\n\t * Returns `true` if the given section has changed for the given resource.\r\n\t *\r\n\t * Example: To check if the configuration section has changed for a given resource use `e.affectsConfiguration(resource, section)`.\r\n\t *\r\n\t * @param resource Resource for which the configuration has to be checked.\r\n\t * @param section Section of the configuration\r\n\t */\r\n\taffectsConfiguration(resource: URI, section: string): boolean;\r\n}\r\n\r\nexport interface ITextResourceConfigurationService {\r\n\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\t/**\r\n\t * Fetches the value of the section for the given resource by applying language overrides.\r\n\t * Value can be of native type or an object keyed off the section name.\r\n\t *\r\n\t * @param resource - Resource for which the configuration has to be fetched.\r\n\t * @param position - Position in the resource for which configuration has to be fetched.\r\n\t * @param section - Section of the configuraion.\r\n\t *\r\n\t */\r\n\tgetValue(resource: URI | undefined, section?: string): T;\r\n\tgetValue(resource: URI | undefined, position?: IPosition, section?: string): T;\r\n\r\n}\r\n\r\nexport const ITextResourcePropertiesService = createDecorator('textResourcePropertiesService');\r\n\r\nexport interface ITextResourcePropertiesService {\r\n\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\t/**\r\n\t * Returns the End of Line characters for the given resource\r\n\t */\r\n\tgetEOL(resource: URI, language?: string): string;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { RGBA8 } from 'vs/editor/common/core/rgba';\r\nimport { ColorId, TokenizationRegistry } from 'vs/editor/common/modes';\r\n\r\nexport class MinimapTokensColorTracker {\r\n\tprivate static _INSTANCE: MinimapTokensColorTracker | null = null;\r\n\tpublic static getInstance(): MinimapTokensColorTracker {\r\n\t\tif (!this._INSTANCE) {\r\n\t\t\tthis._INSTANCE = new MinimapTokensColorTracker();\r\n\t\t}\r\n\t\treturn this._INSTANCE;\r\n\t}\r\n\r\n\tprivate _colors!: RGBA8[];\r\n\tprivate _backgroundIsLight!: boolean;\r\n\r\n\tprivate readonly _onDidChange = new Emitter();\r\n\tpublic readonly onDidChange: Event = this._onDidChange.event;\r\n\r\n\tprivate constructor() {\r\n\t\tthis._updateColorMap();\r\n\t\tTokenizationRegistry.onDidChange(e => {\r\n\t\t\tif (e.changedColorMap) {\r\n\t\t\t\tthis._updateColorMap();\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _updateColorMap(): void {\r\n\t\tconst colorMap = TokenizationRegistry.getColorMap();\r\n\t\tif (!colorMap) {\r\n\t\t\tthis._colors = [RGBA8.Empty];\r\n\t\t\tthis._backgroundIsLight = true;\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._colors = [RGBA8.Empty];\r\n\t\tfor (let colorId = 1; colorId < colorMap.length; colorId++) {\r\n\t\t\tconst source = colorMap[colorId].rgba;\r\n\t\t\t// Use a VM friendly data-type\r\n\t\t\tthis._colors[colorId] = new RGBA8(source.r, source.g, source.b, Math.round(source.a * 255));\r\n\t\t}\r\n\t\tlet backgroundLuminosity = colorMap[ColorId.DefaultBackground].getRelativeLuminance();\r\n\t\tthis._backgroundIsLight = backgroundLuminosity >= 0.5;\r\n\t\tthis._onDidChange.fire(undefined);\r\n\t}\r\n\r\n\tpublic getColor(colorId: ColorId): RGBA8 {\r\n\t\tif (colorId < 1 || colorId >= this._colors.length) {\r\n\t\t\t// background color (basically invisible)\r\n\t\t\tcolorId = ColorId.DefaultBackground;\r\n\t\t}\r\n\t\treturn this._colors[colorId];\r\n\t}\r\n\r\n\tpublic backgroundIsLight(): boolean {\r\n\t\treturn this._backgroundIsLight;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as arrays from 'vs/base/common/arrays';\r\nimport { WrappingIndent } from 'vs/editor/common/config/editorOptions';\r\nimport { LineTokens } from 'vs/editor/common/core/lineTokens';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { IRange, Range } from 'vs/editor/common/core/range';\r\nimport { EndOfLinePreference, IActiveIndentGuideInfo, IModelDecoration, IModelDeltaDecoration, ITextModel } from 'vs/editor/common/model';\r\nimport { ModelDecorationOptions, ModelDecorationOverviewRulerOptions } from 'vs/editor/common/model/textModel';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { PrefixSumIndexOfResult } from 'vs/editor/common/viewModel/prefixSumComputer';\r\nimport { ICoordinatesConverter, ILineBreaksComputer, IOverviewRulerDecorations, LineBreakData, ViewLineData } from 'vs/editor/common/viewModel/viewModel';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { FontInfo } from 'vs/editor/common/config/fontInfo';\r\nimport { EditorTheme } from 'vs/editor/common/view/viewContext';\r\n\r\nexport interface ILineBreaksComputerFactory {\r\n\tcreateLineBreaksComputer(fontInfo: FontInfo, tabSize: number, wrappingColumn: number, wrappingIndent: WrappingIndent): ILineBreaksComputer;\r\n}\r\n\r\nexport interface ISimpleModel {\r\n\tgetLineTokens(lineNumber: number): LineTokens;\r\n\tgetLineContent(lineNumber: number): string;\r\n\tgetLineLength(lineNumber: number): number;\r\n\tgetLineMinColumn(lineNumber: number): number;\r\n\tgetLineMaxColumn(lineNumber: number): number;\r\n\tgetValueInRange(range: IRange, eol?: EndOfLinePreference): string;\r\n}\r\n\r\nexport interface ISplitLine {\r\n\tisVisible(): boolean;\r\n\tsetVisible(isVisible: boolean): ISplitLine;\r\n\r\n\tgetLineBreakData(): LineBreakData | null;\r\n\tgetViewLineCount(): number;\r\n\tgetViewLineContent(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): string;\r\n\tgetViewLineLength(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): number;\r\n\tgetViewLineMinColumn(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): number;\r\n\tgetViewLineMaxColumn(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): number;\r\n\tgetViewLineData(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): ViewLineData;\r\n\tgetViewLinesData(model: ISimpleModel, modelLineNumber: number, fromOuputLineIndex: number, toOutputLineIndex: number, globalStartIndex: number, needed: boolean[], result: Array): void;\r\n\r\n\tgetModelColumnOfViewPosition(outputLineIndex: number, outputColumn: number): number;\r\n\tgetViewPositionOfModelPosition(deltaLineNumber: number, inputColumn: number): Position;\r\n\tgetViewLineNumberOfModelPosition(deltaLineNumber: number, inputColumn: number): number;\r\n}\r\n\r\nexport interface IViewModelLinesCollection extends IDisposable {\r\n\tcreateCoordinatesConverter(): ICoordinatesConverter;\r\n\r\n\tsetWrappingSettings(fontInfo: FontInfo, wrappingStrategy: 'simple' | 'advanced', wrappingColumn: number, wrappingIndent: WrappingIndent): boolean;\r\n\tsetTabSize(newTabSize: number): boolean;\r\n\tgetHiddenAreas(): Range[];\r\n\tsetHiddenAreas(_ranges: Range[]): boolean;\r\n\r\n\tcreateLineBreaksComputer(): ILineBreaksComputer;\r\n\tonModelFlushed(): void;\r\n\tonModelLinesDeleted(versionId: number, fromLineNumber: number, toLineNumber: number): viewEvents.ViewLinesDeletedEvent | null;\r\n\tonModelLinesInserted(versionId: number, fromLineNumber: number, toLineNumber: number, lineBreaks: (LineBreakData | null)[]): viewEvents.ViewLinesInsertedEvent | null;\r\n\tonModelLineChanged(versionId: number, lineNumber: number, lineBreakData: LineBreakData | null): [boolean, viewEvents.ViewLinesChangedEvent | null, viewEvents.ViewLinesInsertedEvent | null, viewEvents.ViewLinesDeletedEvent | null];\r\n\tacceptVersionId(versionId: number): void;\r\n\r\n\tgetViewLineCount(): number;\r\n\tgetActiveIndentGuide(viewLineNumber: number, minLineNumber: number, maxLineNumber: number): IActiveIndentGuideInfo;\r\n\tgetViewLinesIndentGuides(viewStartLineNumber: number, viewEndLineNumber: number): number[];\r\n\tgetViewLineContent(viewLineNumber: number): string;\r\n\tgetViewLineLength(viewLineNumber: number): number;\r\n\tgetViewLineMinColumn(viewLineNumber: number): number;\r\n\tgetViewLineMaxColumn(viewLineNumber: number): number;\r\n\tgetViewLineData(viewLineNumber: number): ViewLineData;\r\n\tgetViewLinesData(viewStartLineNumber: number, viewEndLineNumber: number, needed: boolean[]): Array;\r\n\r\n\tgetAllOverviewRulerDecorations(ownerId: number, filterOutValidation: boolean, theme: EditorTheme): IOverviewRulerDecorations;\r\n\tgetDecorationsInRange(range: Range, ownerId: number, filterOutValidation: boolean): IModelDecoration[];\r\n}\r\n\r\nexport class CoordinatesConverter implements ICoordinatesConverter {\r\n\r\n\tprivate readonly _lines: SplitLinesCollection;\r\n\r\n\tconstructor(lines: SplitLinesCollection) {\r\n\t\tthis._lines = lines;\r\n\t}\r\n\r\n\t// View -> Model conversion and related methods\r\n\r\n\tpublic convertViewPositionToModelPosition(viewPosition: Position): Position {\r\n\t\treturn this._lines.convertViewPositionToModelPosition(viewPosition.lineNumber, viewPosition.column);\r\n\t}\r\n\r\n\tpublic convertViewRangeToModelRange(viewRange: Range): Range {\r\n\t\treturn this._lines.convertViewRangeToModelRange(viewRange);\r\n\t}\r\n\r\n\tpublic validateViewPosition(viewPosition: Position, expectedModelPosition: Position): Position {\r\n\t\treturn this._lines.validateViewPosition(viewPosition.lineNumber, viewPosition.column, expectedModelPosition);\r\n\t}\r\n\r\n\tpublic validateViewRange(viewRange: Range, expectedModelRange: Range): Range {\r\n\t\treturn this._lines.validateViewRange(viewRange, expectedModelRange);\r\n\t}\r\n\r\n\t// Model -> View conversion and related methods\r\n\r\n\tpublic convertModelPositionToViewPosition(modelPosition: Position): Position {\r\n\t\treturn this._lines.convertModelPositionToViewPosition(modelPosition.lineNumber, modelPosition.column);\r\n\t}\r\n\r\n\tpublic convertModelRangeToViewRange(modelRange: Range): Range {\r\n\t\treturn this._lines.convertModelRangeToViewRange(modelRange);\r\n\t}\r\n\r\n\tpublic modelPositionIsVisible(modelPosition: Position): boolean {\r\n\t\treturn this._lines.modelPositionIsVisible(modelPosition.lineNumber, modelPosition.column);\r\n\t}\r\n\r\n\tpublic getModelLineViewLineCount(modelLineNumber: number): number {\r\n\t\treturn this._lines.getModelLineViewLineCount(modelLineNumber);\r\n\t}\r\n}\r\n\r\nconst enum IndentGuideRepeatOption {\r\n\tBlockNone = 0,\r\n\tBlockSubsequent = 1,\r\n\tBlockAll = 2\r\n}\r\n\r\nclass LineNumberMapper {\r\n\r\n\tprivate _counts: number[];\r\n\tprivate _isValid: boolean;\r\n\tprivate _validEndIndex: number;\r\n\r\n\tprivate _modelToView: number[];\r\n\tprivate _viewToModel: number[];\r\n\r\n\tconstructor(viewLineCounts: number[]) {\r\n\t\tthis._counts = viewLineCounts;\r\n\t\tthis._isValid = false;\r\n\t\tthis._validEndIndex = -1;\r\n\t\tthis._modelToView = [];\r\n\t\tthis._viewToModel = [];\r\n\t}\r\n\r\n\tprivate _invalidate(index: number): void {\r\n\t\tthis._isValid = false;\r\n\t\tthis._validEndIndex = Math.min(this._validEndIndex, index - 1);\r\n\t}\r\n\r\n\tprivate _ensureValid(): void {\r\n\t\tif (this._isValid) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tfor (let i = this._validEndIndex + 1, len = this._counts.length; i < len; i++) {\r\n\t\t\tconst viewLineCount = this._counts[i];\r\n\t\t\tconst viewLinesAbove = (i > 0 ? this._modelToView[i - 1] : 0);\r\n\r\n\t\t\tthis._modelToView[i] = viewLinesAbove + viewLineCount;\r\n\t\t\tfor (let j = 0; j < viewLineCount; j++) {\r\n\t\t\t\tthis._viewToModel[viewLinesAbove + j] = i;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// trim things\r\n\t\tthis._modelToView.length = this._counts.length;\r\n\t\tthis._viewToModel.length = this._modelToView[this._modelToView.length - 1];\r\n\r\n\t\t// mark as valid\r\n\t\tthis._isValid = true;\r\n\t\tthis._validEndIndex = this._counts.length - 1;\r\n\t}\r\n\r\n\tpublic changeValue(index: number, value: number): void {\r\n\t\tif (this._counts[index] === value) {\r\n\t\t\t// no change\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._counts[index] = value;\r\n\t\tthis._invalidate(index);\r\n\t}\r\n\r\n\tpublic removeValues(start: number, deleteCount: number): void {\r\n\t\tthis._counts.splice(start, deleteCount);\r\n\t\tthis._invalidate(start);\r\n\t}\r\n\r\n\tpublic insertValues(insertIndex: number, insertArr: number[]): void {\r\n\t\tthis._counts = arrays.arrayInsert(this._counts, insertIndex, insertArr);\r\n\t\tthis._invalidate(insertIndex);\r\n\t}\r\n\r\n\tpublic getTotalValue(): number {\r\n\t\tthis._ensureValid();\r\n\t\treturn this._viewToModel.length;\r\n\t}\r\n\r\n\tpublic getAccumulatedValue(index: number): number {\r\n\t\tthis._ensureValid();\r\n\t\treturn this._modelToView[index];\r\n\t}\r\n\r\n\tpublic getIndexOf(accumulatedValue: number): PrefixSumIndexOfResult {\r\n\t\tthis._ensureValid();\r\n\t\tconst modelLineIndex = this._viewToModel[accumulatedValue];\r\n\t\tconst viewLinesAbove = (modelLineIndex > 0 ? this._modelToView[modelLineIndex - 1] : 0);\r\n\t\treturn new PrefixSumIndexOfResult(modelLineIndex, accumulatedValue - viewLinesAbove);\r\n\t}\r\n}\r\n\r\nexport class SplitLinesCollection implements IViewModelLinesCollection {\r\n\r\n\tprivate readonly model: ITextModel;\r\n\tprivate _validModelVersionId: number;\r\n\r\n\tprivate readonly _domLineBreaksComputerFactory: ILineBreaksComputerFactory;\r\n\tprivate readonly _monospaceLineBreaksComputerFactory: ILineBreaksComputerFactory;\r\n\r\n\tprivate fontInfo: FontInfo;\r\n\tprivate tabSize: number;\r\n\tprivate wrappingColumn: number;\r\n\tprivate wrappingIndent: WrappingIndent;\r\n\tprivate wrappingStrategy: 'simple' | 'advanced';\r\n\tprivate lines!: ISplitLine[];\r\n\r\n\tprivate prefixSumComputer!: LineNumberMapper;\r\n\r\n\tprivate hiddenAreasIds!: string[];\r\n\r\n\tconstructor(\r\n\t\tmodel: ITextModel,\r\n\t\tdomLineBreaksComputerFactory: ILineBreaksComputerFactory,\r\n\t\tmonospaceLineBreaksComputerFactory: ILineBreaksComputerFactory,\r\n\t\tfontInfo: FontInfo,\r\n\t\ttabSize: number,\r\n\t\twrappingStrategy: 'simple' | 'advanced',\r\n\t\twrappingColumn: number,\r\n\t\twrappingIndent: WrappingIndent,\r\n\t) {\r\n\t\tthis.model = model;\r\n\t\tthis._validModelVersionId = -1;\r\n\t\tthis._domLineBreaksComputerFactory = domLineBreaksComputerFactory;\r\n\t\tthis._monospaceLineBreaksComputerFactory = monospaceLineBreaksComputerFactory;\r\n\t\tthis.fontInfo = fontInfo;\r\n\t\tthis.tabSize = tabSize;\r\n\t\tthis.wrappingStrategy = wrappingStrategy;\r\n\t\tthis.wrappingColumn = wrappingColumn;\r\n\t\tthis.wrappingIndent = wrappingIndent;\r\n\r\n\t\tthis._constructLines(/*resetHiddenAreas*/true, null);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis.hiddenAreasIds = this.model.deltaDecorations(this.hiddenAreasIds, []);\r\n\t}\r\n\r\n\tpublic createCoordinatesConverter(): ICoordinatesConverter {\r\n\t\treturn new CoordinatesConverter(this);\r\n\t}\r\n\r\n\tprivate _constructLines(resetHiddenAreas: boolean, previousLineBreaks: ((LineBreakData | null)[]) | null): void {\r\n\t\tthis.lines = [];\r\n\r\n\t\tif (resetHiddenAreas) {\r\n\t\t\tthis.hiddenAreasIds = [];\r\n\t\t}\r\n\r\n\t\tlet linesContent = this.model.getLinesContent();\r\n\t\tconst lineCount = linesContent.length;\r\n\t\tconst lineBreaksComputer = this.createLineBreaksComputer();\r\n\t\tfor (let i = 0; i < lineCount; i++) {\r\n\t\t\tlineBreaksComputer.addRequest(linesContent[i], previousLineBreaks ? previousLineBreaks[i] : null);\r\n\t\t}\r\n\t\tconst linesBreaks = lineBreaksComputer.finalize();\r\n\r\n\t\tlet values: number[] = [];\r\n\r\n\t\tlet hiddenAreas = this.hiddenAreasIds.map((areaId) => this.model.getDecorationRange(areaId)!).sort(Range.compareRangesUsingStarts);\r\n\t\tlet hiddenAreaStart = 1, hiddenAreaEnd = 0;\r\n\t\tlet hiddenAreaIdx = -1;\r\n\t\tlet nextLineNumberToUpdateHiddenArea = (hiddenAreaIdx + 1 < hiddenAreas.length) ? hiddenAreaEnd + 1 : lineCount + 2;\r\n\r\n\t\tfor (let i = 0; i < lineCount; i++) {\r\n\t\t\tlet lineNumber = i + 1;\r\n\r\n\t\t\tif (lineNumber === nextLineNumberToUpdateHiddenArea) {\r\n\t\t\t\thiddenAreaIdx++;\r\n\t\t\t\thiddenAreaStart = hiddenAreas[hiddenAreaIdx]!.startLineNumber;\r\n\t\t\t\thiddenAreaEnd = hiddenAreas[hiddenAreaIdx]!.endLineNumber;\r\n\t\t\t\tnextLineNumberToUpdateHiddenArea = (hiddenAreaIdx + 1 < hiddenAreas.length) ? hiddenAreaEnd + 1 : lineCount + 2;\r\n\t\t\t}\r\n\r\n\t\t\tlet isInHiddenArea = (lineNumber >= hiddenAreaStart && lineNumber <= hiddenAreaEnd);\r\n\t\t\tlet line = createSplitLine(linesBreaks[i], !isInHiddenArea);\r\n\t\t\tvalues[i] = line.getViewLineCount();\r\n\t\t\tthis.lines[i] = line;\r\n\t\t}\r\n\r\n\t\tthis._validModelVersionId = this.model.getVersionId();\r\n\r\n\t\tthis.prefixSumComputer = new LineNumberMapper(values);\r\n\t}\r\n\r\n\tpublic getHiddenAreas(): Range[] {\r\n\t\treturn this.hiddenAreasIds.map((decId) => {\r\n\t\t\treturn this.model.getDecorationRange(decId)!;\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _reduceRanges(_ranges: Range[]): Range[] {\r\n\t\tif (_ranges.length === 0) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\t\tlet ranges = _ranges.map(r => this.model.validateRange(r)).sort(Range.compareRangesUsingStarts);\r\n\r\n\t\tlet result: Range[] = [];\r\n\t\tlet currentRangeStart = ranges[0].startLineNumber;\r\n\t\tlet currentRangeEnd = ranges[0].endLineNumber;\r\n\r\n\t\tfor (let i = 1, len = ranges.length; i < len; i++) {\r\n\t\t\tlet range = ranges[i];\r\n\r\n\t\t\tif (range.startLineNumber > currentRangeEnd + 1) {\r\n\t\t\t\tresult.push(new Range(currentRangeStart, 1, currentRangeEnd, 1));\r\n\t\t\t\tcurrentRangeStart = range.startLineNumber;\r\n\t\t\t\tcurrentRangeEnd = range.endLineNumber;\r\n\t\t\t} else if (range.endLineNumber > currentRangeEnd) {\r\n\t\t\t\tcurrentRangeEnd = range.endLineNumber;\r\n\t\t\t}\r\n\t\t}\r\n\t\tresult.push(new Range(currentRangeStart, 1, currentRangeEnd, 1));\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic setHiddenAreas(_ranges: Range[]): boolean {\r\n\r\n\t\tlet newRanges = this._reduceRanges(_ranges);\r\n\r\n\t\t// BEGIN TODO@Martin: Please stop calling this method on each model change!\r\n\t\tlet oldRanges = this.hiddenAreasIds.map((areaId) => this.model.getDecorationRange(areaId)!).sort(Range.compareRangesUsingStarts);\r\n\r\n\t\tif (newRanges.length === oldRanges.length) {\r\n\t\t\tlet hasDifference = false;\r\n\t\t\tfor (let i = 0; i < newRanges.length; i++) {\r\n\t\t\t\tif (!newRanges[i].equalsRange(oldRanges[i])) {\r\n\t\t\t\t\thasDifference = true;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (!hasDifference) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\t\t// END TODO@Martin: Please stop calling this method on each model change!\r\n\r\n\t\tlet newDecorations: IModelDeltaDecoration[] = [];\r\n\t\tfor (const newRange of newRanges) {\r\n\t\t\tnewDecorations.push({\r\n\t\t\t\trange: newRange,\r\n\t\t\t\toptions: ModelDecorationOptions.EMPTY\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tthis.hiddenAreasIds = this.model.deltaDecorations(this.hiddenAreasIds, newDecorations);\r\n\r\n\t\tlet hiddenAreas = newRanges;\r\n\t\tlet hiddenAreaStart = 1, hiddenAreaEnd = 0;\r\n\t\tlet hiddenAreaIdx = -1;\r\n\t\tlet nextLineNumberToUpdateHiddenArea = (hiddenAreaIdx + 1 < hiddenAreas.length) ? hiddenAreaEnd + 1 : this.lines.length + 2;\r\n\r\n\t\tlet hasVisibleLine = false;\r\n\t\tfor (let i = 0; i < this.lines.length; i++) {\r\n\t\t\tlet lineNumber = i + 1;\r\n\r\n\t\t\tif (lineNumber === nextLineNumberToUpdateHiddenArea) {\r\n\t\t\t\thiddenAreaIdx++;\r\n\t\t\t\thiddenAreaStart = hiddenAreas[hiddenAreaIdx].startLineNumber;\r\n\t\t\t\thiddenAreaEnd = hiddenAreas[hiddenAreaIdx].endLineNumber;\r\n\t\t\t\tnextLineNumberToUpdateHiddenArea = (hiddenAreaIdx + 1 < hiddenAreas.length) ? hiddenAreaEnd + 1 : this.lines.length + 2;\r\n\t\t\t}\r\n\r\n\t\t\tlet lineChanged = false;\r\n\t\t\tif (lineNumber >= hiddenAreaStart && lineNumber <= hiddenAreaEnd) {\r\n\t\t\t\t// Line should be hidden\r\n\t\t\t\tif (this.lines[i].isVisible()) {\r\n\t\t\t\t\tthis.lines[i] = this.lines[i].setVisible(false);\r\n\t\t\t\t\tlineChanged = true;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\thasVisibleLine = true;\r\n\t\t\t\t// Line should be visible\r\n\t\t\t\tif (!this.lines[i].isVisible()) {\r\n\t\t\t\t\tthis.lines[i] = this.lines[i].setVisible(true);\r\n\t\t\t\t\tlineChanged = true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (lineChanged) {\r\n\t\t\t\tlet newOutputLineCount = this.lines[i].getViewLineCount();\r\n\t\t\t\tthis.prefixSumComputer.changeValue(i, newOutputLineCount);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!hasVisibleLine) {\r\n\t\t\t// Cannot have everything be hidden => reveal everything!\r\n\t\t\tthis.setHiddenAreas([]);\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic modelPositionIsVisible(modelLineNumber: number, _modelColumn: number): boolean {\r\n\t\tif (modelLineNumber < 1 || modelLineNumber > this.lines.length) {\r\n\t\t\t// invalid arguments\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn this.lines[modelLineNumber - 1].isVisible();\r\n\t}\r\n\r\n\tpublic getModelLineViewLineCount(modelLineNumber: number): number {\r\n\t\tif (modelLineNumber < 1 || modelLineNumber > this.lines.length) {\r\n\t\t\t// invalid arguments\r\n\t\t\treturn 1;\r\n\t\t}\r\n\t\treturn this.lines[modelLineNumber - 1].getViewLineCount();\r\n\t}\r\n\r\n\tpublic setTabSize(newTabSize: number): boolean {\r\n\t\tif (this.tabSize === newTabSize) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tthis.tabSize = newTabSize;\r\n\r\n\t\tthis._constructLines(/*resetHiddenAreas*/false, null);\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic setWrappingSettings(fontInfo: FontInfo, wrappingStrategy: 'simple' | 'advanced', wrappingColumn: number, wrappingIndent: WrappingIndent): boolean {\r\n\t\tconst equalFontInfo = this.fontInfo.equals(fontInfo);\r\n\t\tconst equalWrappingStrategy = (this.wrappingStrategy === wrappingStrategy);\r\n\t\tconst equalWrappingColumn = (this.wrappingColumn === wrappingColumn);\r\n\t\tconst equalWrappingIndent = (this.wrappingIndent === wrappingIndent);\r\n\t\tif (equalFontInfo && equalWrappingStrategy && equalWrappingColumn && equalWrappingIndent) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tconst onlyWrappingColumnChanged = (equalFontInfo && equalWrappingStrategy && !equalWrappingColumn && equalWrappingIndent);\r\n\r\n\t\tthis.fontInfo = fontInfo;\r\n\t\tthis.wrappingStrategy = wrappingStrategy;\r\n\t\tthis.wrappingColumn = wrappingColumn;\r\n\t\tthis.wrappingIndent = wrappingIndent;\r\n\r\n\t\tlet previousLineBreaks: ((LineBreakData | null)[]) | null = null;\r\n\t\tif (onlyWrappingColumnChanged) {\r\n\t\t\tpreviousLineBreaks = [];\r\n\t\t\tfor (let i = 0, len = this.lines.length; i < len; i++) {\r\n\t\t\t\tpreviousLineBreaks[i] = this.lines[i].getLineBreakData();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._constructLines(/*resetHiddenAreas*/false, previousLineBreaks);\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic createLineBreaksComputer(): ILineBreaksComputer {\r\n\t\tconst lineBreaksComputerFactory = (\r\n\t\t\tthis.wrappingStrategy === 'advanced'\r\n\t\t\t\t? this._domLineBreaksComputerFactory\r\n\t\t\t\t: this._monospaceLineBreaksComputerFactory\r\n\t\t);\r\n\t\treturn lineBreaksComputerFactory.createLineBreaksComputer(this.fontInfo, this.tabSize, this.wrappingColumn, this.wrappingIndent);\r\n\t}\r\n\r\n\tpublic onModelFlushed(): void {\r\n\t\tthis._constructLines(/*resetHiddenAreas*/true, null);\r\n\t}\r\n\r\n\tpublic onModelLinesDeleted(versionId: number, fromLineNumber: number, toLineNumber: number): viewEvents.ViewLinesDeletedEvent | null {\r\n\t\tif (versionId <= this._validModelVersionId) {\r\n\t\t\t// Here we check for versionId in case the lines were reconstructed in the meantime.\r\n\t\t\t// We don't want to apply stale change events on top of a newer read model state.\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet outputFromLineNumber = (fromLineNumber === 1 ? 1 : this.prefixSumComputer.getAccumulatedValue(fromLineNumber - 2) + 1);\r\n\t\tlet outputToLineNumber = this.prefixSumComputer.getAccumulatedValue(toLineNumber - 1);\r\n\r\n\t\tthis.lines.splice(fromLineNumber - 1, toLineNumber - fromLineNumber + 1);\r\n\t\tthis.prefixSumComputer.removeValues(fromLineNumber - 1, toLineNumber - fromLineNumber + 1);\r\n\r\n\t\treturn new viewEvents.ViewLinesDeletedEvent(outputFromLineNumber, outputToLineNumber);\r\n\t}\r\n\r\n\tpublic onModelLinesInserted(versionId: number, fromLineNumber: number, _toLineNumber: number, lineBreaks: (LineBreakData | null)[]): viewEvents.ViewLinesInsertedEvent | null {\r\n\t\tif (versionId <= this._validModelVersionId) {\r\n\t\t\t// Here we check for versionId in case the lines were reconstructed in the meantime.\r\n\t\t\t// We don't want to apply stale change events on top of a newer read model state.\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\t// cannot use this.getHiddenAreas() because those decorations have already seen the effect of this model change\r\n\t\tconst isInHiddenArea = (fromLineNumber > 2 && !this.lines[fromLineNumber - 2].isVisible());\r\n\r\n\t\tlet outputFromLineNumber = (fromLineNumber === 1 ? 1 : this.prefixSumComputer.getAccumulatedValue(fromLineNumber - 2) + 1);\r\n\r\n\t\tlet totalOutputLineCount = 0;\r\n\t\tlet insertLines: ISplitLine[] = [];\r\n\t\tlet insertPrefixSumValues: number[] = [];\r\n\r\n\t\tfor (let i = 0, len = lineBreaks.length; i < len; i++) {\r\n\t\t\tlet line = createSplitLine(lineBreaks[i], !isInHiddenArea);\r\n\t\t\tinsertLines.push(line);\r\n\r\n\t\t\tlet outputLineCount = line.getViewLineCount();\r\n\t\t\ttotalOutputLineCount += outputLineCount;\r\n\t\t\tinsertPrefixSumValues[i] = outputLineCount;\r\n\t\t}\r\n\r\n\t\t// TODO@Alex: use arrays.arrayInsert\r\n\t\tthis.lines = this.lines.slice(0, fromLineNumber - 1).concat(insertLines).concat(this.lines.slice(fromLineNumber - 1));\r\n\r\n\t\tthis.prefixSumComputer.insertValues(fromLineNumber - 1, insertPrefixSumValues);\r\n\r\n\t\treturn new viewEvents.ViewLinesInsertedEvent(outputFromLineNumber, outputFromLineNumber + totalOutputLineCount - 1);\r\n\t}\r\n\r\n\tpublic onModelLineChanged(versionId: number, lineNumber: number, lineBreakData: LineBreakData | null): [boolean, viewEvents.ViewLinesChangedEvent | null, viewEvents.ViewLinesInsertedEvent | null, viewEvents.ViewLinesDeletedEvent | null] {\r\n\t\tif (versionId <= this._validModelVersionId) {\r\n\t\t\t// Here we check for versionId in case the lines were reconstructed in the meantime.\r\n\t\t\t// We don't want to apply stale change events on top of a newer read model state.\r\n\t\t\treturn [false, null, null, null];\r\n\t\t}\r\n\r\n\t\tlet lineIndex = lineNumber - 1;\r\n\r\n\t\tlet oldOutputLineCount = this.lines[lineIndex].getViewLineCount();\r\n\t\tlet isVisible = this.lines[lineIndex].isVisible();\r\n\t\tlet line = createSplitLine(lineBreakData, isVisible);\r\n\t\tthis.lines[lineIndex] = line;\r\n\t\tlet newOutputLineCount = this.lines[lineIndex].getViewLineCount();\r\n\r\n\t\tlet lineMappingChanged = false;\r\n\t\tlet changeFrom = 0;\r\n\t\tlet changeTo = -1;\r\n\t\tlet insertFrom = 0;\r\n\t\tlet insertTo = -1;\r\n\t\tlet deleteFrom = 0;\r\n\t\tlet deleteTo = -1;\r\n\r\n\t\tif (oldOutputLineCount > newOutputLineCount) {\r\n\t\t\tchangeFrom = (lineNumber === 1 ? 1 : this.prefixSumComputer.getAccumulatedValue(lineNumber - 2) + 1);\r\n\t\t\tchangeTo = changeFrom + newOutputLineCount - 1;\r\n\t\t\tdeleteFrom = changeTo + 1;\r\n\t\t\tdeleteTo = deleteFrom + (oldOutputLineCount - newOutputLineCount) - 1;\r\n\t\t\tlineMappingChanged = true;\r\n\t\t} else if (oldOutputLineCount < newOutputLineCount) {\r\n\t\t\tchangeFrom = (lineNumber === 1 ? 1 : this.prefixSumComputer.getAccumulatedValue(lineNumber - 2) + 1);\r\n\t\t\tchangeTo = changeFrom + oldOutputLineCount - 1;\r\n\t\t\tinsertFrom = changeTo + 1;\r\n\t\t\tinsertTo = insertFrom + (newOutputLineCount - oldOutputLineCount) - 1;\r\n\t\t\tlineMappingChanged = true;\r\n\t\t} else {\r\n\t\t\tchangeFrom = (lineNumber === 1 ? 1 : this.prefixSumComputer.getAccumulatedValue(lineNumber - 2) + 1);\r\n\t\t\tchangeTo = changeFrom + newOutputLineCount - 1;\r\n\t\t}\r\n\r\n\t\tthis.prefixSumComputer.changeValue(lineIndex, newOutputLineCount);\r\n\r\n\t\tconst viewLinesChangedEvent = (changeFrom <= changeTo ? new viewEvents.ViewLinesChangedEvent(changeFrom, changeTo) : null);\r\n\t\tconst viewLinesInsertedEvent = (insertFrom <= insertTo ? new viewEvents.ViewLinesInsertedEvent(insertFrom, insertTo) : null);\r\n\t\tconst viewLinesDeletedEvent = (deleteFrom <= deleteTo ? new viewEvents.ViewLinesDeletedEvent(deleteFrom, deleteTo) : null);\r\n\r\n\t\treturn [lineMappingChanged, viewLinesChangedEvent, viewLinesInsertedEvent, viewLinesDeletedEvent];\r\n\t}\r\n\r\n\tpublic acceptVersionId(versionId: number): void {\r\n\t\tthis._validModelVersionId = versionId;\r\n\t\tif (this.lines.length === 1 && !this.lines[0].isVisible()) {\r\n\t\t\t// At least one line must be visible => reset hidden areas\r\n\t\t\tthis.setHiddenAreas([]);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getViewLineCount(): number {\r\n\t\treturn this.prefixSumComputer.getTotalValue();\r\n\t}\r\n\r\n\tprivate _toValidViewLineNumber(viewLineNumber: number): number {\r\n\t\tif (viewLineNumber < 1) {\r\n\t\t\treturn 1;\r\n\t\t}\r\n\t\tconst viewLineCount = this.getViewLineCount();\r\n\t\tif (viewLineNumber > viewLineCount) {\r\n\t\t\treturn viewLineCount;\r\n\t\t}\r\n\t\treturn viewLineNumber | 0;\r\n\t}\r\n\r\n\tpublic getActiveIndentGuide(viewLineNumber: number, minLineNumber: number, maxLineNumber: number): IActiveIndentGuideInfo {\r\n\t\tviewLineNumber = this._toValidViewLineNumber(viewLineNumber);\r\n\t\tminLineNumber = this._toValidViewLineNumber(minLineNumber);\r\n\t\tmaxLineNumber = this._toValidViewLineNumber(maxLineNumber);\r\n\r\n\t\tconst modelPosition = this.convertViewPositionToModelPosition(viewLineNumber, this.getViewLineMinColumn(viewLineNumber));\r\n\t\tconst modelMinPosition = this.convertViewPositionToModelPosition(minLineNumber, this.getViewLineMinColumn(minLineNumber));\r\n\t\tconst modelMaxPosition = this.convertViewPositionToModelPosition(maxLineNumber, this.getViewLineMinColumn(maxLineNumber));\r\n\t\tconst result = this.model.getActiveIndentGuide(modelPosition.lineNumber, modelMinPosition.lineNumber, modelMaxPosition.lineNumber);\r\n\r\n\t\tconst viewStartPosition = this.convertModelPositionToViewPosition(result.startLineNumber, 1);\r\n\t\tconst viewEndPosition = this.convertModelPositionToViewPosition(result.endLineNumber, this.model.getLineMaxColumn(result.endLineNumber));\r\n\t\treturn {\r\n\t\t\tstartLineNumber: viewStartPosition.lineNumber,\r\n\t\t\tendLineNumber: viewEndPosition.lineNumber,\r\n\t\t\tindent: result.indent\r\n\t\t};\r\n\t}\r\n\r\n\tpublic getViewLinesIndentGuides(viewStartLineNumber: number, viewEndLineNumber: number): number[] {\r\n\t\tviewStartLineNumber = this._toValidViewLineNumber(viewStartLineNumber);\r\n\t\tviewEndLineNumber = this._toValidViewLineNumber(viewEndLineNumber);\r\n\r\n\t\tconst modelStart = this.convertViewPositionToModelPosition(viewStartLineNumber, this.getViewLineMinColumn(viewStartLineNumber));\r\n\t\tconst modelEnd = this.convertViewPositionToModelPosition(viewEndLineNumber, this.getViewLineMaxColumn(viewEndLineNumber));\r\n\r\n\t\tlet result: number[] = [];\r\n\t\tlet resultRepeatCount: number[] = [];\r\n\t\tlet resultRepeatOption: IndentGuideRepeatOption[] = [];\r\n\t\tconst modelStartLineIndex = modelStart.lineNumber - 1;\r\n\t\tconst modelEndLineIndex = modelEnd.lineNumber - 1;\r\n\r\n\t\tlet reqStart: Position | null = null;\r\n\t\tfor (let modelLineIndex = modelStartLineIndex; modelLineIndex <= modelEndLineIndex; modelLineIndex++) {\r\n\t\t\tconst line = this.lines[modelLineIndex];\r\n\t\t\tif (line.isVisible()) {\r\n\t\t\t\tlet viewLineStartIndex = line.getViewLineNumberOfModelPosition(0, modelLineIndex === modelStartLineIndex ? modelStart.column : 1);\r\n\t\t\t\tlet viewLineEndIndex = line.getViewLineNumberOfModelPosition(0, this.model.getLineMaxColumn(modelLineIndex + 1));\r\n\t\t\t\tlet count = viewLineEndIndex - viewLineStartIndex + 1;\r\n\t\t\t\tlet option = IndentGuideRepeatOption.BlockNone;\r\n\t\t\t\tif (count > 1 && line.getViewLineMinColumn(this.model, modelLineIndex + 1, viewLineEndIndex) === 1) {\r\n\t\t\t\t\t// wrapped lines should block indent guides\r\n\t\t\t\t\toption = (viewLineStartIndex === 0 ? IndentGuideRepeatOption.BlockSubsequent : IndentGuideRepeatOption.BlockAll);\r\n\t\t\t\t}\r\n\t\t\t\tresultRepeatCount.push(count);\r\n\t\t\t\tresultRepeatOption.push(option);\r\n\t\t\t\t// merge into previous request\r\n\t\t\t\tif (reqStart === null) {\r\n\t\t\t\t\treqStart = new Position(modelLineIndex + 1, 0);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\t// hit invisible line => flush request\r\n\t\t\t\tif (reqStart !== null) {\r\n\t\t\t\t\tresult = result.concat(this.model.getLinesIndentGuides(reqStart.lineNumber, modelLineIndex));\r\n\t\t\t\t\treqStart = null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (reqStart !== null) {\r\n\t\t\tresult = result.concat(this.model.getLinesIndentGuides(reqStart.lineNumber, modelEnd.lineNumber));\r\n\t\t\treqStart = null;\r\n\t\t}\r\n\r\n\t\tconst viewLineCount = viewEndLineNumber - viewStartLineNumber + 1;\r\n\t\tlet viewIndents = new Array(viewLineCount);\r\n\t\tlet currIndex = 0;\r\n\t\tfor (let i = 0, len = result.length; i < len; i++) {\r\n\t\t\tlet value = result[i];\r\n\t\t\tlet count = Math.min(viewLineCount - currIndex, resultRepeatCount[i]);\r\n\t\t\tlet option = resultRepeatOption[i];\r\n\t\t\tlet blockAtIndex: number;\r\n\t\t\tif (option === IndentGuideRepeatOption.BlockAll) {\r\n\t\t\t\tblockAtIndex = 0;\r\n\t\t\t} else if (option === IndentGuideRepeatOption.BlockSubsequent) {\r\n\t\t\t\tblockAtIndex = 1;\r\n\t\t\t} else {\r\n\t\t\t\tblockAtIndex = count;\r\n\t\t\t}\r\n\t\t\tfor (let j = 0; j < count; j++) {\r\n\t\t\t\tif (j === blockAtIndex) {\r\n\t\t\t\t\tvalue = 0;\r\n\t\t\t\t}\r\n\t\t\t\tviewIndents[currIndex++] = value;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn viewIndents;\r\n\t}\r\n\r\n\tpublic getViewLineContent(viewLineNumber: number): string {\r\n\t\tviewLineNumber = this._toValidViewLineNumber(viewLineNumber);\r\n\t\tlet r = this.prefixSumComputer.getIndexOf(viewLineNumber - 1);\r\n\t\tlet lineIndex = r.index;\r\n\t\tlet remainder = r.remainder;\r\n\r\n\t\treturn this.lines[lineIndex].getViewLineContent(this.model, lineIndex + 1, remainder);\r\n\t}\r\n\r\n\tpublic getViewLineLength(viewLineNumber: number): number {\r\n\t\tviewLineNumber = this._toValidViewLineNumber(viewLineNumber);\r\n\t\tlet r = this.prefixSumComputer.getIndexOf(viewLineNumber - 1);\r\n\t\tlet lineIndex = r.index;\r\n\t\tlet remainder = r.remainder;\r\n\r\n\t\treturn this.lines[lineIndex].getViewLineLength(this.model, lineIndex + 1, remainder);\r\n\t}\r\n\r\n\tpublic getViewLineMinColumn(viewLineNumber: number): number {\r\n\t\tviewLineNumber = this._toValidViewLineNumber(viewLineNumber);\r\n\t\tlet r = this.prefixSumComputer.getIndexOf(viewLineNumber - 1);\r\n\t\tlet lineIndex = r.index;\r\n\t\tlet remainder = r.remainder;\r\n\r\n\t\treturn this.lines[lineIndex].getViewLineMinColumn(this.model, lineIndex + 1, remainder);\r\n\t}\r\n\r\n\tpublic getViewLineMaxColumn(viewLineNumber: number): number {\r\n\t\tviewLineNumber = this._toValidViewLineNumber(viewLineNumber);\r\n\t\tlet r = this.prefixSumComputer.getIndexOf(viewLineNumber - 1);\r\n\t\tlet lineIndex = r.index;\r\n\t\tlet remainder = r.remainder;\r\n\r\n\t\treturn this.lines[lineIndex].getViewLineMaxColumn(this.model, lineIndex + 1, remainder);\r\n\t}\r\n\r\n\tpublic getViewLineData(viewLineNumber: number): ViewLineData {\r\n\t\tviewLineNumber = this._toValidViewLineNumber(viewLineNumber);\r\n\t\tlet r = this.prefixSumComputer.getIndexOf(viewLineNumber - 1);\r\n\t\tlet lineIndex = r.index;\r\n\t\tlet remainder = r.remainder;\r\n\r\n\t\treturn this.lines[lineIndex].getViewLineData(this.model, lineIndex + 1, remainder);\r\n\t}\r\n\r\n\tpublic getViewLinesData(viewStartLineNumber: number, viewEndLineNumber: number, needed: boolean[]): ViewLineData[] {\r\n\r\n\t\tviewStartLineNumber = this._toValidViewLineNumber(viewStartLineNumber);\r\n\t\tviewEndLineNumber = this._toValidViewLineNumber(viewEndLineNumber);\r\n\r\n\t\tlet start = this.prefixSumComputer.getIndexOf(viewStartLineNumber - 1);\r\n\t\tlet viewLineNumber = viewStartLineNumber;\r\n\t\tlet startModelLineIndex = start.index;\r\n\t\tlet startRemainder = start.remainder;\r\n\r\n\t\tlet result: ViewLineData[] = [];\r\n\t\tfor (let modelLineIndex = startModelLineIndex, len = this.model.getLineCount(); modelLineIndex < len; modelLineIndex++) {\r\n\t\t\tlet line = this.lines[modelLineIndex];\r\n\t\t\tif (!line.isVisible()) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tlet fromViewLineIndex = (modelLineIndex === startModelLineIndex ? startRemainder : 0);\r\n\t\t\tlet remainingViewLineCount = line.getViewLineCount() - fromViewLineIndex;\r\n\r\n\t\t\tlet lastLine = false;\r\n\t\t\tif (viewLineNumber + remainingViewLineCount > viewEndLineNumber) {\r\n\t\t\t\tlastLine = true;\r\n\t\t\t\tremainingViewLineCount = viewEndLineNumber - viewLineNumber + 1;\r\n\t\t\t}\r\n\t\t\tlet toViewLineIndex = fromViewLineIndex + remainingViewLineCount;\r\n\r\n\t\t\tline.getViewLinesData(this.model, modelLineIndex + 1, fromViewLineIndex, toViewLineIndex, viewLineNumber - viewStartLineNumber, needed, result);\r\n\r\n\t\t\tviewLineNumber += remainingViewLineCount;\r\n\r\n\t\t\tif (lastLine) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic validateViewPosition(viewLineNumber: number, viewColumn: number, expectedModelPosition: Position): Position {\r\n\t\tviewLineNumber = this._toValidViewLineNumber(viewLineNumber);\r\n\r\n\t\tlet r = this.prefixSumComputer.getIndexOf(viewLineNumber - 1);\r\n\t\tlet lineIndex = r.index;\r\n\t\tlet remainder = r.remainder;\r\n\r\n\t\tlet line = this.lines[lineIndex];\r\n\r\n\t\tlet minColumn = line.getViewLineMinColumn(this.model, lineIndex + 1, remainder);\r\n\t\tlet maxColumn = line.getViewLineMaxColumn(this.model, lineIndex + 1, remainder);\r\n\t\tif (viewColumn < minColumn) {\r\n\t\t\tviewColumn = minColumn;\r\n\t\t}\r\n\t\tif (viewColumn > maxColumn) {\r\n\t\t\tviewColumn = maxColumn;\r\n\t\t}\r\n\r\n\t\tlet computedModelColumn = line.getModelColumnOfViewPosition(remainder, viewColumn);\r\n\t\tlet computedModelPosition = this.model.validatePosition(new Position(lineIndex + 1, computedModelColumn));\r\n\r\n\t\tif (computedModelPosition.equals(expectedModelPosition)) {\r\n\t\t\treturn new Position(viewLineNumber, viewColumn);\r\n\t\t}\r\n\r\n\t\treturn this.convertModelPositionToViewPosition(expectedModelPosition.lineNumber, expectedModelPosition.column);\r\n\t}\r\n\r\n\tpublic validateViewRange(viewRange: Range, expectedModelRange: Range): Range {\r\n\t\tconst validViewStart = this.validateViewPosition(viewRange.startLineNumber, viewRange.startColumn, expectedModelRange.getStartPosition());\r\n\t\tconst validViewEnd = this.validateViewPosition(viewRange.endLineNumber, viewRange.endColumn, expectedModelRange.getEndPosition());\r\n\t\treturn new Range(validViewStart.lineNumber, validViewStart.column, validViewEnd.lineNumber, validViewEnd.column);\r\n\t}\r\n\r\n\tpublic convertViewPositionToModelPosition(viewLineNumber: number, viewColumn: number): Position {\r\n\t\tviewLineNumber = this._toValidViewLineNumber(viewLineNumber);\r\n\r\n\t\tlet r = this.prefixSumComputer.getIndexOf(viewLineNumber - 1);\r\n\t\tlet lineIndex = r.index;\r\n\t\tlet remainder = r.remainder;\r\n\r\n\t\tlet inputColumn = this.lines[lineIndex].getModelColumnOfViewPosition(remainder, viewColumn);\r\n\t\t// console.log('out -> in ' + viewLineNumber + ',' + viewColumn + ' ===> ' + (lineIndex+1) + ',' + inputColumn);\r\n\t\treturn this.model.validatePosition(new Position(lineIndex + 1, inputColumn));\r\n\t}\r\n\r\n\tpublic convertViewRangeToModelRange(viewRange: Range): Range {\r\n\t\tconst start = this.convertViewPositionToModelPosition(viewRange.startLineNumber, viewRange.startColumn);\r\n\t\tconst end = this.convertViewPositionToModelPosition(viewRange.endLineNumber, viewRange.endColumn);\r\n\t\treturn new Range(start.lineNumber, start.column, end.lineNumber, end.column);\r\n\t}\r\n\r\n\tpublic convertModelPositionToViewPosition(_modelLineNumber: number, _modelColumn: number): Position {\r\n\r\n\t\tconst validPosition = this.model.validatePosition(new Position(_modelLineNumber, _modelColumn));\r\n\t\tconst inputLineNumber = validPosition.lineNumber;\r\n\t\tconst inputColumn = validPosition.column;\r\n\r\n\t\tlet lineIndex = inputLineNumber - 1, lineIndexChanged = false;\r\n\t\twhile (lineIndex > 0 && !this.lines[lineIndex].isVisible()) {\r\n\t\t\tlineIndex--;\r\n\t\t\tlineIndexChanged = true;\r\n\t\t}\r\n\t\tif (lineIndex === 0 && !this.lines[lineIndex].isVisible()) {\r\n\t\t\t// Could not reach a real line\r\n\t\t\t// console.log('in -> out ' + inputLineNumber + ',' + inputColumn + ' ===> ' + 1 + ',' + 1);\r\n\t\t\treturn new Position(1, 1);\r\n\t\t}\r\n\t\tconst deltaLineNumber = 1 + (lineIndex === 0 ? 0 : this.prefixSumComputer.getAccumulatedValue(lineIndex - 1));\r\n\r\n\t\tlet r: Position;\r\n\t\tif (lineIndexChanged) {\r\n\t\t\tr = this.lines[lineIndex].getViewPositionOfModelPosition(deltaLineNumber, this.model.getLineMaxColumn(lineIndex + 1));\r\n\t\t} else {\r\n\t\t\tr = this.lines[inputLineNumber - 1].getViewPositionOfModelPosition(deltaLineNumber, inputColumn);\r\n\t\t}\r\n\r\n\t\t// console.log('in -> out ' + inputLineNumber + ',' + inputColumn + ' ===> ' + r.lineNumber + ',' + r);\r\n\t\treturn r;\r\n\t}\r\n\r\n\tpublic convertModelRangeToViewRange(modelRange: Range): Range {\r\n\t\tlet start = this.convertModelPositionToViewPosition(modelRange.startLineNumber, modelRange.startColumn);\r\n\t\tlet end = this.convertModelPositionToViewPosition(modelRange.endLineNumber, modelRange.endColumn);\r\n\t\tif (modelRange.startLineNumber === modelRange.endLineNumber && start.lineNumber !== end.lineNumber) {\r\n\t\t\t// This is a single line range that ends up taking more lines due to wrapping\r\n\t\t\tif (end.column === this.getViewLineMinColumn(end.lineNumber)) {\r\n\t\t\t\t// the end column lands on the first column of the next line\r\n\t\t\t\treturn new Range(start.lineNumber, start.column, end.lineNumber - 1, this.getViewLineMaxColumn(end.lineNumber - 1));\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn new Range(start.lineNumber, start.column, end.lineNumber, end.column);\r\n\t}\r\n\r\n\tprivate _getViewLineNumberForModelPosition(inputLineNumber: number, inputColumn: number): number {\r\n\t\tlet lineIndex = inputLineNumber - 1;\r\n\t\tif (this.lines[lineIndex].isVisible()) {\r\n\t\t\t// this model line is visible\r\n\t\t\tconst deltaLineNumber = 1 + (lineIndex === 0 ? 0 : this.prefixSumComputer.getAccumulatedValue(lineIndex - 1));\r\n\t\t\treturn this.lines[lineIndex].getViewLineNumberOfModelPosition(deltaLineNumber, inputColumn);\r\n\t\t}\r\n\r\n\t\t// this model line is not visible\r\n\t\twhile (lineIndex > 0 && !this.lines[lineIndex].isVisible()) {\r\n\t\t\tlineIndex--;\r\n\t\t}\r\n\t\tif (lineIndex === 0 && !this.lines[lineIndex].isVisible()) {\r\n\t\t\t// Could not reach a real line\r\n\t\t\treturn 1;\r\n\t\t}\r\n\t\tconst deltaLineNumber = 1 + (lineIndex === 0 ? 0 : this.prefixSumComputer.getAccumulatedValue(lineIndex - 1));\r\n\t\treturn this.lines[lineIndex].getViewLineNumberOfModelPosition(deltaLineNumber, this.model.getLineMaxColumn(lineIndex + 1));\r\n\t}\r\n\r\n\tpublic getAllOverviewRulerDecorations(ownerId: number, filterOutValidation: boolean, theme: EditorTheme): IOverviewRulerDecorations {\r\n\t\tconst decorations = this.model.getOverviewRulerDecorations(ownerId, filterOutValidation);\r\n\t\tconst result = new OverviewRulerDecorations();\r\n\t\tfor (const decoration of decorations) {\r\n\t\t\tconst opts = decoration.options.overviewRuler;\r\n\t\t\tconst lane = opts ? opts.position : 0;\r\n\t\t\tif (lane === 0) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tconst color = opts.getColor(theme);\r\n\t\t\tconst viewStartLineNumber = this._getViewLineNumberForModelPosition(decoration.range.startLineNumber, decoration.range.startColumn);\r\n\t\t\tconst viewEndLineNumber = this._getViewLineNumberForModelPosition(decoration.range.endLineNumber, decoration.range.endColumn);\r\n\r\n\t\t\tresult.accept(color, viewStartLineNumber, viewEndLineNumber, lane);\r\n\t\t}\r\n\t\treturn result.result;\r\n\t}\r\n\r\n\tpublic getDecorationsInRange(range: Range, ownerId: number, filterOutValidation: boolean): IModelDecoration[] {\r\n\t\tconst modelStart = this.convertViewPositionToModelPosition(range.startLineNumber, range.startColumn);\r\n\t\tconst modelEnd = this.convertViewPositionToModelPosition(range.endLineNumber, range.endColumn);\r\n\r\n\t\tif (modelEnd.lineNumber - modelStart.lineNumber <= range.endLineNumber - range.startLineNumber) {\r\n\t\t\t// most likely there are no hidden lines => fast path\r\n\t\t\t// fetch decorations from column 1 to cover the case of wrapped lines that have whole line decorations at column 1\r\n\t\t\treturn this.model.getDecorationsInRange(new Range(modelStart.lineNumber, 1, modelEnd.lineNumber, modelEnd.column), ownerId, filterOutValidation);\r\n\t\t}\r\n\r\n\t\tlet result: IModelDecoration[] = [];\r\n\t\tconst modelStartLineIndex = modelStart.lineNumber - 1;\r\n\t\tconst modelEndLineIndex = modelEnd.lineNumber - 1;\r\n\r\n\t\tlet reqStart: Position | null = null;\r\n\t\tfor (let modelLineIndex = modelStartLineIndex; modelLineIndex <= modelEndLineIndex; modelLineIndex++) {\r\n\t\t\tconst line = this.lines[modelLineIndex];\r\n\t\t\tif (line.isVisible()) {\r\n\t\t\t\t// merge into previous request\r\n\t\t\t\tif (reqStart === null) {\r\n\t\t\t\t\treqStart = new Position(modelLineIndex + 1, modelLineIndex === modelStartLineIndex ? modelStart.column : 1);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\t// hit invisible line => flush request\r\n\t\t\t\tif (reqStart !== null) {\r\n\t\t\t\t\tconst maxLineColumn = this.model.getLineMaxColumn(modelLineIndex);\r\n\t\t\t\t\tresult = result.concat(this.model.getDecorationsInRange(new Range(reqStart.lineNumber, reqStart.column, modelLineIndex, maxLineColumn), ownerId, filterOutValidation));\r\n\t\t\t\t\treqStart = null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (reqStart !== null) {\r\n\t\t\tresult = result.concat(this.model.getDecorationsInRange(new Range(reqStart.lineNumber, reqStart.column, modelEnd.lineNumber, modelEnd.column), ownerId, filterOutValidation));\r\n\t\t\treqStart = null;\r\n\t\t}\r\n\r\n\t\tresult.sort((a, b) => {\r\n\t\t\tconst res = Range.compareRangesUsingStarts(a.range, b.range);\r\n\t\t\tif (res === 0) {\r\n\t\t\t\tif (a.id < b.id) {\r\n\t\t\t\t\treturn -1;\r\n\t\t\t\t}\r\n\t\t\t\tif (a.id > b.id) {\r\n\t\t\t\t\treturn 1;\r\n\t\t\t\t}\r\n\t\t\t\treturn 0;\r\n\t\t\t}\r\n\t\t\treturn res;\r\n\t\t});\r\n\r\n\t\t// Eliminate duplicate decorations that might have intersected our visible ranges multiple times\r\n\t\tlet finalResult: IModelDecoration[] = [], finalResultLen = 0;\r\n\t\tlet prevDecId: string | null = null;\r\n\t\tfor (const dec of result) {\r\n\t\t\tconst decId = dec.id;\r\n\t\t\tif (prevDecId === decId) {\r\n\t\t\t\t// skip\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tprevDecId = decId;\r\n\t\t\tfinalResult[finalResultLen++] = dec;\r\n\t\t}\r\n\r\n\t\treturn finalResult;\r\n\t}\r\n}\r\n\r\nclass VisibleIdentitySplitLine implements ISplitLine {\r\n\r\n\tpublic static readonly INSTANCE = new VisibleIdentitySplitLine();\r\n\r\n\tprivate constructor() { }\r\n\r\n\tpublic isVisible(): boolean {\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic setVisible(isVisible: boolean): ISplitLine {\r\n\t\tif (isVisible) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\treturn InvisibleIdentitySplitLine.INSTANCE;\r\n\t}\r\n\r\n\tpublic getLineBreakData(): LineBreakData | null {\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic getViewLineCount(): number {\r\n\t\treturn 1;\r\n\t}\r\n\r\n\tpublic getViewLineContent(model: ISimpleModel, modelLineNumber: number, _outputLineIndex: number): string {\r\n\t\treturn model.getLineContent(modelLineNumber);\r\n\t}\r\n\r\n\tpublic getViewLineLength(model: ISimpleModel, modelLineNumber: number, _outputLineIndex: number): number {\r\n\t\treturn model.getLineLength(modelLineNumber);\r\n\t}\r\n\r\n\tpublic getViewLineMinColumn(model: ISimpleModel, modelLineNumber: number, _outputLineIndex: number): number {\r\n\t\treturn model.getLineMinColumn(modelLineNumber);\r\n\t}\r\n\r\n\tpublic getViewLineMaxColumn(model: ISimpleModel, modelLineNumber: number, _outputLineIndex: number): number {\r\n\t\treturn model.getLineMaxColumn(modelLineNumber);\r\n\t}\r\n\r\n\tpublic getViewLineData(model: ISimpleModel, modelLineNumber: number, _outputLineIndex: number): ViewLineData {\r\n\t\tlet lineTokens = model.getLineTokens(modelLineNumber);\r\n\t\tlet lineContent = lineTokens.getLineContent();\r\n\t\treturn new ViewLineData(\r\n\t\t\tlineContent,\r\n\t\t\tfalse,\r\n\t\t\t1,\r\n\t\t\tlineContent.length + 1,\r\n\t\t\t0,\r\n\t\t\tlineTokens.inflate()\r\n\t\t);\r\n\t}\r\n\r\n\tpublic getViewLinesData(model: ISimpleModel, modelLineNumber: number, _fromOuputLineIndex: number, _toOutputLineIndex: number, globalStartIndex: number, needed: boolean[], result: Array): void {\r\n\t\tif (!needed[globalStartIndex]) {\r\n\t\t\tresult[globalStartIndex] = null;\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tresult[globalStartIndex] = this.getViewLineData(model, modelLineNumber, 0);\r\n\t}\r\n\r\n\tpublic getModelColumnOfViewPosition(_outputLineIndex: number, outputColumn: number): number {\r\n\t\treturn outputColumn;\r\n\t}\r\n\r\n\tpublic getViewPositionOfModelPosition(deltaLineNumber: number, inputColumn: number): Position {\r\n\t\treturn new Position(deltaLineNumber, inputColumn);\r\n\t}\r\n\r\n\tpublic getViewLineNumberOfModelPosition(deltaLineNumber: number, _inputColumn: number): number {\r\n\t\treturn deltaLineNumber;\r\n\t}\r\n}\r\n\r\nclass InvisibleIdentitySplitLine implements ISplitLine {\r\n\r\n\tpublic static readonly INSTANCE = new InvisibleIdentitySplitLine();\r\n\r\n\tprivate constructor() { }\r\n\r\n\tpublic isVisible(): boolean {\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic setVisible(isVisible: boolean): ISplitLine {\r\n\t\tif (!isVisible) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\treturn VisibleIdentitySplitLine.INSTANCE;\r\n\t}\r\n\r\n\tpublic getLineBreakData(): LineBreakData | null {\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic getViewLineCount(): number {\r\n\t\treturn 0;\r\n\t}\r\n\r\n\tpublic getViewLineContent(_model: ISimpleModel, _modelLineNumber: number, _outputLineIndex: number): string {\r\n\t\tthrow new Error('Not supported');\r\n\t}\r\n\r\n\tpublic getViewLineLength(_model: ISimpleModel, _modelLineNumber: number, _outputLineIndex: number): number {\r\n\t\tthrow new Error('Not supported');\r\n\t}\r\n\r\n\tpublic getViewLineMinColumn(_model: ISimpleModel, _modelLineNumber: number, _outputLineIndex: number): number {\r\n\t\tthrow new Error('Not supported');\r\n\t}\r\n\r\n\tpublic getViewLineMaxColumn(_model: ISimpleModel, _modelLineNumber: number, _outputLineIndex: number): number {\r\n\t\tthrow new Error('Not supported');\r\n\t}\r\n\r\n\tpublic getViewLineData(_model: ISimpleModel, _modelLineNumber: number, _outputLineIndex: number): ViewLineData {\r\n\t\tthrow new Error('Not supported');\r\n\t}\r\n\r\n\tpublic getViewLinesData(_model: ISimpleModel, _modelLineNumber: number, _fromOuputLineIndex: number, _toOutputLineIndex: number, _globalStartIndex: number, _needed: boolean[], _result: ViewLineData[]): void {\r\n\t\tthrow new Error('Not supported');\r\n\t}\r\n\r\n\tpublic getModelColumnOfViewPosition(_outputLineIndex: number, _outputColumn: number): number {\r\n\t\tthrow new Error('Not supported');\r\n\t}\r\n\r\n\tpublic getViewPositionOfModelPosition(_deltaLineNumber: number, _inputColumn: number): Position {\r\n\t\tthrow new Error('Not supported');\r\n\t}\r\n\r\n\tpublic getViewLineNumberOfModelPosition(_deltaLineNumber: number, _inputColumn: number): number {\r\n\t\tthrow new Error('Not supported');\r\n\t}\r\n}\r\n\r\nexport class SplitLine implements ISplitLine {\r\n\r\n\tprivate readonly _lineBreakData: LineBreakData;\r\n\tprivate _isVisible: boolean;\r\n\r\n\tconstructor(lineBreakData: LineBreakData, isVisible: boolean) {\r\n\t\tthis._lineBreakData = lineBreakData;\r\n\t\tthis._isVisible = isVisible;\r\n\t}\r\n\r\n\tpublic isVisible(): boolean {\r\n\t\treturn this._isVisible;\r\n\t}\r\n\r\n\tpublic setVisible(isVisible: boolean): ISplitLine {\r\n\t\tthis._isVisible = isVisible;\r\n\t\treturn this;\r\n\t}\r\n\r\n\tpublic getLineBreakData(): LineBreakData | null {\r\n\t\treturn this._lineBreakData;\r\n\t}\r\n\r\n\tpublic getViewLineCount(): number {\r\n\t\tif (!this._isVisible) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t\treturn this._lineBreakData.breakOffsets.length;\r\n\t}\r\n\r\n\tprivate getInputStartOffsetOfOutputLineIndex(outputLineIndex: number): number {\r\n\t\treturn LineBreakData.getInputOffsetOfOutputPosition(this._lineBreakData.breakOffsets, outputLineIndex, 0);\r\n\t}\r\n\r\n\tprivate getInputEndOffsetOfOutputLineIndex(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): number {\r\n\t\tif (outputLineIndex + 1 === this._lineBreakData.breakOffsets.length) {\r\n\t\t\treturn model.getLineMaxColumn(modelLineNumber) - 1;\r\n\t\t}\r\n\t\treturn LineBreakData.getInputOffsetOfOutputPosition(this._lineBreakData.breakOffsets, outputLineIndex + 1, 0);\r\n\t}\r\n\r\n\tpublic getViewLineContent(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): string {\r\n\t\tif (!this._isVisible) {\r\n\t\t\tthrow new Error('Not supported');\r\n\t\t}\r\n\t\tlet startOffset = this.getInputStartOffsetOfOutputLineIndex(outputLineIndex);\r\n\t\tlet endOffset = this.getInputEndOffsetOfOutputLineIndex(model, modelLineNumber, outputLineIndex);\r\n\t\tlet r = model.getValueInRange({\r\n\t\t\tstartLineNumber: modelLineNumber,\r\n\t\t\tstartColumn: startOffset + 1,\r\n\t\t\tendLineNumber: modelLineNumber,\r\n\t\t\tendColumn: endOffset + 1\r\n\t\t});\r\n\r\n\t\tif (outputLineIndex > 0) {\r\n\t\t\tr = spaces(this._lineBreakData.wrappedTextIndentLength) + r;\r\n\t\t}\r\n\r\n\t\treturn r;\r\n\t}\r\n\r\n\tpublic getViewLineLength(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): number {\r\n\t\tif (!this._isVisible) {\r\n\t\t\tthrow new Error('Not supported');\r\n\t\t}\r\n\t\tlet startOffset = this.getInputStartOffsetOfOutputLineIndex(outputLineIndex);\r\n\t\tlet endOffset = this.getInputEndOffsetOfOutputLineIndex(model, modelLineNumber, outputLineIndex);\r\n\t\tlet r = endOffset - startOffset;\r\n\r\n\t\tif (outputLineIndex > 0) {\r\n\t\t\tr = this._lineBreakData.wrappedTextIndentLength + r;\r\n\t\t}\r\n\r\n\t\treturn r;\r\n\t}\r\n\r\n\tpublic getViewLineMinColumn(_model: ITextModel, _modelLineNumber: number, outputLineIndex: number): number {\r\n\t\tif (!this._isVisible) {\r\n\t\t\tthrow new Error('Not supported');\r\n\t\t}\r\n\t\tif (outputLineIndex > 0) {\r\n\t\t\treturn this._lineBreakData.wrappedTextIndentLength + 1;\r\n\t\t}\r\n\t\treturn 1;\r\n\t}\r\n\r\n\tpublic getViewLineMaxColumn(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): number {\r\n\t\tif (!this._isVisible) {\r\n\t\t\tthrow new Error('Not supported');\r\n\t\t}\r\n\t\treturn this.getViewLineContent(model, modelLineNumber, outputLineIndex).length + 1;\r\n\t}\r\n\r\n\tpublic getViewLineData(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): ViewLineData {\r\n\t\tif (!this._isVisible) {\r\n\t\t\tthrow new Error('Not supported');\r\n\t\t}\r\n\r\n\t\tlet startOffset = this.getInputStartOffsetOfOutputLineIndex(outputLineIndex);\r\n\t\tlet endOffset = this.getInputEndOffsetOfOutputLineIndex(model, modelLineNumber, outputLineIndex);\r\n\r\n\t\tlet lineContent = model.getValueInRange({\r\n\t\t\tstartLineNumber: modelLineNumber,\r\n\t\t\tstartColumn: startOffset + 1,\r\n\t\t\tendLineNumber: modelLineNumber,\r\n\t\t\tendColumn: endOffset + 1\r\n\t\t});\r\n\r\n\t\tif (outputLineIndex > 0) {\r\n\t\t\tlineContent = spaces(this._lineBreakData.wrappedTextIndentLength) + lineContent;\r\n\t\t}\r\n\r\n\t\tlet minColumn = (outputLineIndex > 0 ? this._lineBreakData.wrappedTextIndentLength + 1 : 1);\r\n\t\tlet maxColumn = lineContent.length + 1;\r\n\r\n\t\tlet continuesWithWrappedLine = (outputLineIndex + 1 < this.getViewLineCount());\r\n\r\n\t\tlet deltaStartIndex = 0;\r\n\t\tif (outputLineIndex > 0) {\r\n\t\t\tdeltaStartIndex = this._lineBreakData.wrappedTextIndentLength;\r\n\t\t}\r\n\t\tlet lineTokens = model.getLineTokens(modelLineNumber);\r\n\r\n\t\tconst startVisibleColumn = (outputLineIndex === 0 ? 0 : this._lineBreakData.breakOffsetsVisibleColumn[outputLineIndex - 1]);\r\n\r\n\t\treturn new ViewLineData(\r\n\t\t\tlineContent,\r\n\t\t\tcontinuesWithWrappedLine,\r\n\t\t\tminColumn,\r\n\t\t\tmaxColumn,\r\n\t\t\tstartVisibleColumn,\r\n\t\t\tlineTokens.sliceAndInflate(startOffset, endOffset, deltaStartIndex)\r\n\t\t);\r\n\t}\r\n\r\n\tpublic getViewLinesData(model: ITextModel, modelLineNumber: number, fromOuputLineIndex: number, toOutputLineIndex: number, globalStartIndex: number, needed: boolean[], result: Array): void {\r\n\t\tif (!this._isVisible) {\r\n\t\t\tthrow new Error('Not supported');\r\n\t\t}\r\n\r\n\t\tfor (let outputLineIndex = fromOuputLineIndex; outputLineIndex < toOutputLineIndex; outputLineIndex++) {\r\n\t\t\tlet globalIndex = globalStartIndex + outputLineIndex - fromOuputLineIndex;\r\n\t\t\tif (!needed[globalIndex]) {\r\n\t\t\t\tresult[globalIndex] = null;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tresult[globalIndex] = this.getViewLineData(model, modelLineNumber, outputLineIndex);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getModelColumnOfViewPosition(outputLineIndex: number, outputColumn: number): number {\r\n\t\tif (!this._isVisible) {\r\n\t\t\tthrow new Error('Not supported');\r\n\t\t}\r\n\t\tlet adjustedColumn = outputColumn - 1;\r\n\t\tif (outputLineIndex > 0) {\r\n\t\t\tif (adjustedColumn < this._lineBreakData.wrappedTextIndentLength) {\r\n\t\t\t\tadjustedColumn = 0;\r\n\t\t\t} else {\r\n\t\t\t\tadjustedColumn -= this._lineBreakData.wrappedTextIndentLength;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn LineBreakData.getInputOffsetOfOutputPosition(this._lineBreakData.breakOffsets, outputLineIndex, adjustedColumn) + 1;\r\n\t}\r\n\r\n\tpublic getViewPositionOfModelPosition(deltaLineNumber: number, inputColumn: number): Position {\r\n\t\tif (!this._isVisible) {\r\n\t\t\tthrow new Error('Not supported');\r\n\t\t}\r\n\t\tlet r = LineBreakData.getOutputPositionOfInputOffset(this._lineBreakData.breakOffsets, inputColumn - 1);\r\n\t\tlet outputLineIndex = r.outputLineIndex;\r\n\t\tlet outputColumn = r.outputOffset + 1;\r\n\r\n\t\tif (outputLineIndex > 0) {\r\n\t\t\toutputColumn += this._lineBreakData.wrappedTextIndentLength;\r\n\t\t}\r\n\r\n\t\t//\t\tconsole.log('in -> out ' + deltaLineNumber + ',' + inputColumn + ' ===> ' + (deltaLineNumber+outputLineIndex) + ',' + outputColumn);\r\n\t\treturn new Position(deltaLineNumber + outputLineIndex, outputColumn);\r\n\t}\r\n\r\n\tpublic getViewLineNumberOfModelPosition(deltaLineNumber: number, inputColumn: number): number {\r\n\t\tif (!this._isVisible) {\r\n\t\t\tthrow new Error('Not supported');\r\n\t\t}\r\n\t\tconst r = LineBreakData.getOutputPositionOfInputOffset(this._lineBreakData.breakOffsets, inputColumn - 1);\r\n\t\treturn (deltaLineNumber + r.outputLineIndex);\r\n\t}\r\n}\r\n\r\nlet _spaces: string[] = [''];\r\nfunction spaces(count: number): string {\r\n\tif (count >= _spaces.length) {\r\n\t\tfor (let i = 1; i <= count; i++) {\r\n\t\t\t_spaces[i] = _makeSpaces(i);\r\n\t\t}\r\n\t}\r\n\treturn _spaces[count];\r\n}\r\nfunction _makeSpaces(count: number): string {\r\n\treturn new Array(count + 1).join(' ');\r\n}\r\n\r\nfunction createSplitLine(lineBreakData: LineBreakData | null, isVisible: boolean): ISplitLine {\r\n\tif (lineBreakData === null) {\r\n\t\t// No mapping needed\r\n\t\tif (isVisible) {\r\n\t\t\treturn VisibleIdentitySplitLine.INSTANCE;\r\n\t\t}\r\n\t\treturn InvisibleIdentitySplitLine.INSTANCE;\r\n\t} else {\r\n\t\treturn new SplitLine(lineBreakData, isVisible);\r\n\t}\r\n}\r\n\r\nexport class IdentityCoordinatesConverter implements ICoordinatesConverter {\r\n\r\n\tprivate readonly _lines: IdentityLinesCollection;\r\n\r\n\tconstructor(lines: IdentityLinesCollection) {\r\n\t\tthis._lines = lines;\r\n\t}\r\n\r\n\tprivate _validPosition(pos: Position): Position {\r\n\t\treturn this._lines.model.validatePosition(pos);\r\n\t}\r\n\r\n\tprivate _validRange(range: Range): Range {\r\n\t\treturn this._lines.model.validateRange(range);\r\n\t}\r\n\r\n\t// View -> Model conversion and related methods\r\n\r\n\tpublic convertViewPositionToModelPosition(viewPosition: Position): Position {\r\n\t\treturn this._validPosition(viewPosition);\r\n\t}\r\n\r\n\tpublic convertViewRangeToModelRange(viewRange: Range): Range {\r\n\t\treturn this._validRange(viewRange);\r\n\t}\r\n\r\n\tpublic validateViewPosition(_viewPosition: Position, expectedModelPosition: Position): Position {\r\n\t\treturn this._validPosition(expectedModelPosition);\r\n\t}\r\n\r\n\tpublic validateViewRange(_viewRange: Range, expectedModelRange: Range): Range {\r\n\t\treturn this._validRange(expectedModelRange);\r\n\t}\r\n\r\n\t// Model -> View conversion and related methods\r\n\r\n\tpublic convertModelPositionToViewPosition(modelPosition: Position): Position {\r\n\t\treturn this._validPosition(modelPosition);\r\n\t}\r\n\r\n\tpublic convertModelRangeToViewRange(modelRange: Range): Range {\r\n\t\treturn this._validRange(modelRange);\r\n\t}\r\n\r\n\tpublic modelPositionIsVisible(modelPosition: Position): boolean {\r\n\t\tconst lineCount = this._lines.model.getLineCount();\r\n\t\tif (modelPosition.lineNumber < 1 || modelPosition.lineNumber > lineCount) {\r\n\t\t\t// invalid arguments\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic getModelLineViewLineCount(modelLineNumber: number): number {\r\n\t\treturn 1;\r\n\t}\r\n}\r\n\r\nexport class IdentityLinesCollection implements IViewModelLinesCollection {\r\n\r\n\tpublic readonly model: ITextModel;\r\n\r\n\tconstructor(model: ITextModel) {\r\n\t\tthis.model = model;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t}\r\n\r\n\tpublic createCoordinatesConverter(): ICoordinatesConverter {\r\n\t\treturn new IdentityCoordinatesConverter(this);\r\n\t}\r\n\r\n\tpublic getHiddenAreas(): Range[] {\r\n\t\treturn [];\r\n\t}\r\n\r\n\tpublic setHiddenAreas(_ranges: Range[]): boolean {\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic setTabSize(_newTabSize: number): boolean {\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic setWrappingSettings(_fontInfo: FontInfo, _wrappingStrategy: 'simple' | 'advanced', _wrappingColumn: number, _wrappingIndent: WrappingIndent): boolean {\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic createLineBreaksComputer(): ILineBreaksComputer {\r\n\t\tlet result: null[] = [];\r\n\t\treturn {\r\n\t\t\taddRequest: (lineText: string, previousLineBreakData: LineBreakData | null) => {\r\n\t\t\t\tresult.push(null);\r\n\t\t\t},\r\n\t\t\tfinalize: () => {\r\n\t\t\t\treturn result;\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\tpublic onModelFlushed(): void {\r\n\t}\r\n\r\n\tpublic onModelLinesDeleted(_versionId: number, fromLineNumber: number, toLineNumber: number): viewEvents.ViewLinesDeletedEvent | null {\r\n\t\treturn new viewEvents.ViewLinesDeletedEvent(fromLineNumber, toLineNumber);\r\n\t}\r\n\r\n\tpublic onModelLinesInserted(_versionId: number, fromLineNumber: number, toLineNumber: number, lineBreaks: (LineBreakData | null)[]): viewEvents.ViewLinesInsertedEvent | null {\r\n\t\treturn new viewEvents.ViewLinesInsertedEvent(fromLineNumber, toLineNumber);\r\n\t}\r\n\r\n\tpublic onModelLineChanged(_versionId: number, lineNumber: number, lineBreakData: LineBreakData | null): [boolean, viewEvents.ViewLinesChangedEvent | null, viewEvents.ViewLinesInsertedEvent | null, viewEvents.ViewLinesDeletedEvent | null] {\r\n\t\treturn [false, new viewEvents.ViewLinesChangedEvent(lineNumber, lineNumber), null, null];\r\n\t}\r\n\r\n\tpublic acceptVersionId(_versionId: number): void {\r\n\t}\r\n\r\n\tpublic getViewLineCount(): number {\r\n\t\treturn this.model.getLineCount();\r\n\t}\r\n\r\n\tpublic getActiveIndentGuide(viewLineNumber: number, _minLineNumber: number, _maxLineNumber: number): IActiveIndentGuideInfo {\r\n\t\treturn {\r\n\t\t\tstartLineNumber: viewLineNumber,\r\n\t\t\tendLineNumber: viewLineNumber,\r\n\t\t\tindent: 0\r\n\t\t};\r\n\t}\r\n\r\n\tpublic getViewLinesIndentGuides(viewStartLineNumber: number, viewEndLineNumber: number): number[] {\r\n\t\tconst viewLineCount = viewEndLineNumber - viewStartLineNumber + 1;\r\n\t\tlet result = new Array(viewLineCount);\r\n\t\tfor (let i = 0; i < viewLineCount; i++) {\r\n\t\t\tresult[i] = 0;\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic getViewLineContent(viewLineNumber: number): string {\r\n\t\treturn this.model.getLineContent(viewLineNumber);\r\n\t}\r\n\r\n\tpublic getViewLineLength(viewLineNumber: number): number {\r\n\t\treturn this.model.getLineLength(viewLineNumber);\r\n\t}\r\n\r\n\tpublic getViewLineMinColumn(viewLineNumber: number): number {\r\n\t\treturn this.model.getLineMinColumn(viewLineNumber);\r\n\t}\r\n\r\n\tpublic getViewLineMaxColumn(viewLineNumber: number): number {\r\n\t\treturn this.model.getLineMaxColumn(viewLineNumber);\r\n\t}\r\n\r\n\tpublic getViewLineData(viewLineNumber: number): ViewLineData {\r\n\t\tlet lineTokens = this.model.getLineTokens(viewLineNumber);\r\n\t\tlet lineContent = lineTokens.getLineContent();\r\n\t\treturn new ViewLineData(\r\n\t\t\tlineContent,\r\n\t\t\tfalse,\r\n\t\t\t1,\r\n\t\t\tlineContent.length + 1,\r\n\t\t\t0,\r\n\t\t\tlineTokens.inflate()\r\n\t\t);\r\n\t}\r\n\r\n\tpublic getViewLinesData(viewStartLineNumber: number, viewEndLineNumber: number, needed: boolean[]): Array {\r\n\t\tconst lineCount = this.model.getLineCount();\r\n\t\tviewStartLineNumber = Math.min(Math.max(1, viewStartLineNumber), lineCount);\r\n\t\tviewEndLineNumber = Math.min(Math.max(1, viewEndLineNumber), lineCount);\r\n\r\n\t\tlet result: Array = [];\r\n\t\tfor (let lineNumber = viewStartLineNumber; lineNumber <= viewEndLineNumber; lineNumber++) {\r\n\t\t\tlet idx = lineNumber - viewStartLineNumber;\r\n\t\t\tif (!needed[idx]) {\r\n\t\t\t\tresult[idx] = null;\r\n\t\t\t}\r\n\t\t\tresult[idx] = this.getViewLineData(lineNumber);\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic getAllOverviewRulerDecorations(ownerId: number, filterOutValidation: boolean, theme: EditorTheme): IOverviewRulerDecorations {\r\n\t\tconst decorations = this.model.getOverviewRulerDecorations(ownerId, filterOutValidation);\r\n\t\tconst result = new OverviewRulerDecorations();\r\n\t\tfor (const decoration of decorations) {\r\n\t\t\tconst opts = decoration.options.overviewRuler;\r\n\t\t\tconst lane = opts ? opts.position : 0;\r\n\t\t\tif (lane === 0) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tconst color = opts.getColor(theme);\r\n\t\t\tconst viewStartLineNumber = decoration.range.startLineNumber;\r\n\t\t\tconst viewEndLineNumber = decoration.range.endLineNumber;\r\n\r\n\t\t\tresult.accept(color, viewStartLineNumber, viewEndLineNumber, lane);\r\n\t\t}\r\n\t\treturn result.result;\r\n\t}\r\n\r\n\tpublic getDecorationsInRange(range: Range, ownerId: number, filterOutValidation: boolean): IModelDecoration[] {\r\n\t\treturn this.model.getDecorationsInRange(range, ownerId, filterOutValidation);\r\n\t}\r\n}\r\n\r\nclass OverviewRulerDecorations {\r\n\r\n\treadonly result: IOverviewRulerDecorations = Object.create(null);\r\n\r\n\tpublic accept(color: string, startLineNumber: number, endLineNumber: number, lane: number): void {\r\n\t\tlet prev = this.result[color];\r\n\r\n\t\tif (prev) {\r\n\t\t\tconst prevLane = prev[prev.length - 3];\r\n\t\t\tconst prevEndLineNumber = prev[prev.length - 1];\r\n\t\t\tif (prevLane === lane && prevEndLineNumber + 1 >= startLineNumber) {\r\n\t\t\t\t// merge into prev\r\n\t\t\t\tif (endLineNumber > prevEndLineNumber) {\r\n\t\t\t\t\tprev[prev.length - 1] = endLineNumber;\r\n\t\t\t\t}\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\t// push\r\n\t\t\tprev.push(lane, startLineNumber, endLineNumber);\r\n\t\t} else {\r\n\t\t\tthis.result[color] = [lane, startLineNumber, endLineNumber];\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Color } from 'vs/base/common/color';\r\nimport { Event } from 'vs/base/common/event';\r\nimport { IDisposable, Disposable } from 'vs/base/common/lifecycle';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { ConfigurationChangedEvent, EDITOR_FONT_DEFAULTS, EditorOption, filterValidationDecorations } from 'vs/editor/common/config/editorOptions';\r\nimport { IPosition, Position } from 'vs/editor/common/core/position';\r\nimport { ISelection, Selection } from 'vs/editor/common/core/selection';\r\nimport { IRange, Range } from 'vs/editor/common/core/range';\r\nimport { IConfiguration, IViewState, ScrollType, ICursorState, ICommand, INewScrollPosition } from 'vs/editor/common/editorCommon';\r\nimport { EndOfLinePreference, IActiveIndentGuideInfo, ITextModel, TrackedRangeStickiness, TextModelResolvedOptions, IIdentifiedSingleEditOperation, ICursorStateComputer } from 'vs/editor/common/model';\r\nimport { ModelDecorationOverviewRulerOptions, ModelDecorationMinimapOptions } from 'vs/editor/common/model/textModel';\r\nimport * as textModelEvents from 'vs/editor/common/model/textModelEvents';\r\nimport { ColorId, LanguageId, TokenizationRegistry } from 'vs/editor/common/modes';\r\nimport { tokenizeLineToHTML } from 'vs/editor/common/modes/textToHtmlTokenizer';\r\nimport { MinimapTokensColorTracker } from 'vs/editor/common/viewModel/minimapTokensColorTracker';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { ViewLayout } from 'vs/editor/common/viewLayout/viewLayout';\r\nimport { IViewModelLinesCollection, IdentityLinesCollection, SplitLinesCollection, ILineBreaksComputerFactory } from 'vs/editor/common/viewModel/splitLinesCollection';\r\nimport { ICoordinatesConverter, ILineBreaksComputer, IOverviewRulerDecorations, IViewModel, MinimapLinesRenderingData, ViewLineData, ViewLineRenderingData, ViewModelDecoration } from 'vs/editor/common/viewModel/viewModel';\r\nimport { ViewModelDecorations } from 'vs/editor/common/viewModel/viewModelDecorations';\r\nimport { RunOnceScheduler } from 'vs/base/common/async';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport { EditorTheme } from 'vs/editor/common/view/viewContext';\r\nimport { Cursor } from 'vs/editor/common/controller/cursor';\r\nimport { PartialCursorState, CursorState, IColumnSelectData, EditOperationType, CursorConfiguration } from 'vs/editor/common/controller/cursorCommon';\r\nimport { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents';\r\nimport { IWhitespaceChangeAccessor } from 'vs/editor/common/viewLayout/linesLayout';\r\nimport { ViewModelEventDispatcher, OutgoingViewModelEvent, FocusChangedEvent, ScrollChangedEvent, ViewZonesChangedEvent, ViewModelEventsCollector, ReadOnlyEditAttemptEvent } from 'vs/editor/common/viewModel/viewModelEventDispatcher';\r\nimport { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler';\r\n\r\nconst USE_IDENTITY_LINES_COLLECTION = true;\r\n\r\nexport class ViewModel extends Disposable implements IViewModel {\r\n\r\n\tprivate readonly _editorId: number;\r\n\tprivate readonly _configuration: IConfiguration;\r\n\tpublic readonly model: ITextModel;\r\n\tprivate readonly _eventDispatcher: ViewModelEventDispatcher;\r\n\tpublic readonly onEvent: Event;\r\n\tpublic cursorConfig: CursorConfiguration;\r\n\tprivate readonly _tokenizeViewportSoon: RunOnceScheduler;\r\n\tprivate readonly _updateConfigurationViewLineCount: RunOnceScheduler;\r\n\tprivate _hasFocus: boolean;\r\n\tprivate _viewportStartLine: number;\r\n\tprivate _viewportStartLineTrackedRange: string | null;\r\n\tprivate _viewportStartLineDelta: number;\r\n\tprivate readonly _lines: IViewModelLinesCollection;\r\n\tpublic readonly coordinatesConverter: ICoordinatesConverter;\r\n\tpublic readonly viewLayout: ViewLayout;\r\n\tprivate readonly _cursor: Cursor;\r\n\tprivate readonly _decorations: ViewModelDecorations;\r\n\r\n\tconstructor(\r\n\t\teditorId: number,\r\n\t\tconfiguration: IConfiguration,\r\n\t\tmodel: ITextModel,\r\n\t\tdomLineBreaksComputerFactory: ILineBreaksComputerFactory,\r\n\t\tmonospaceLineBreaksComputerFactory: ILineBreaksComputerFactory,\r\n\t\tscheduleAtNextAnimationFrame: (callback: () => void) => IDisposable\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\tthis._editorId = editorId;\r\n\t\tthis._configuration = configuration;\r\n\t\tthis.model = model;\r\n\t\tthis._eventDispatcher = new ViewModelEventDispatcher();\r\n\t\tthis.onEvent = this._eventDispatcher.onEvent;\r\n\t\tthis.cursorConfig = new CursorConfiguration(this.model.getLanguageIdentifier(), this.model.getOptions(), this._configuration);\r\n\t\tthis._tokenizeViewportSoon = this._register(new RunOnceScheduler(() => this.tokenizeViewport(), 50));\r\n\t\tthis._updateConfigurationViewLineCount = this._register(new RunOnceScheduler(() => this._updateConfigurationViewLineCountNow(), 0));\r\n\t\tthis._hasFocus = false;\r\n\t\tthis._viewportStartLine = -1;\r\n\t\tthis._viewportStartLineTrackedRange = null;\r\n\t\tthis._viewportStartLineDelta = 0;\r\n\r\n\t\tif (USE_IDENTITY_LINES_COLLECTION && this.model.isTooLargeForTokenization()) {\r\n\r\n\t\t\tthis._lines = new IdentityLinesCollection(this.model);\r\n\r\n\t\t} else {\r\n\t\t\tconst options = this._configuration.options;\r\n\t\t\tconst fontInfo = options.get(EditorOption.fontInfo);\r\n\t\t\tconst wrappingStrategy = options.get(EditorOption.wrappingStrategy);\r\n\t\t\tconst wrappingInfo = options.get(EditorOption.wrappingInfo);\r\n\t\t\tconst wrappingIndent = options.get(EditorOption.wrappingIndent);\r\n\r\n\t\t\tthis._lines = new SplitLinesCollection(\r\n\t\t\t\tthis.model,\r\n\t\t\t\tdomLineBreaksComputerFactory,\r\n\t\t\t\tmonospaceLineBreaksComputerFactory,\r\n\t\t\t\tfontInfo,\r\n\t\t\t\tthis.model.getOptions().tabSize,\r\n\t\t\t\twrappingStrategy,\r\n\t\t\t\twrappingInfo.wrappingColumn,\r\n\t\t\t\twrappingIndent\r\n\t\t\t);\r\n\t\t}\r\n\r\n\t\tthis.coordinatesConverter = this._lines.createCoordinatesConverter();\r\n\r\n\t\tthis._cursor = this._register(new Cursor(model, this, this.coordinatesConverter, this.cursorConfig));\r\n\r\n\t\tthis.viewLayout = this._register(new ViewLayout(this._configuration, this.getLineCount(), scheduleAtNextAnimationFrame));\r\n\r\n\t\tthis._register(this.viewLayout.onDidScroll((e) => {\r\n\t\t\tif (e.scrollTopChanged) {\r\n\t\t\t\tthis._tokenizeViewportSoon.schedule();\r\n\t\t\t}\r\n\t\t\tthis._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewScrollChangedEvent(e));\r\n\t\t\tthis._eventDispatcher.emitOutgoingEvent(new ScrollChangedEvent(\r\n\t\t\t\te.oldScrollWidth, e.oldScrollLeft, e.oldScrollHeight, e.oldScrollTop,\r\n\t\t\t\te.scrollWidth, e.scrollLeft, e.scrollHeight, e.scrollTop\r\n\t\t\t));\r\n\t\t}));\r\n\r\n\t\tthis._register(this.viewLayout.onDidContentSizeChange((e) => {\r\n\t\t\tthis._eventDispatcher.emitOutgoingEvent(e);\r\n\t\t}));\r\n\r\n\t\tthis._decorations = new ViewModelDecorations(this._editorId, this.model, this._configuration, this._lines, this.coordinatesConverter);\r\n\r\n\t\tthis._registerModelEvents();\r\n\r\n\t\tthis._register(this._configuration.onDidChangeFast((e) => {\r\n\t\t\ttry {\r\n\t\t\t\tconst eventsCollector = this._eventDispatcher.beginEmitViewEvents();\r\n\t\t\t\tthis._onConfigurationChanged(eventsCollector, e);\r\n\t\t\t} finally {\r\n\t\t\t\tthis._eventDispatcher.endEmitViewEvents();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._register(MinimapTokensColorTracker.getInstance().onDidChange(() => {\r\n\t\t\tthis._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewTokensColorsChangedEvent());\r\n\t\t}));\r\n\r\n\t\tthis._updateConfigurationViewLineCountNow();\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\t// First remove listeners, as disposing the lines might end up sending\r\n\t\t// model decoration changed events ... and we no longer care about them ...\r\n\t\tsuper.dispose();\r\n\t\tthis._decorations.dispose();\r\n\t\tthis._lines.dispose();\r\n\t\tthis.invalidateMinimapColorCache();\r\n\t\tthis._viewportStartLineTrackedRange = this.model._setTrackedRange(this._viewportStartLineTrackedRange, null, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges);\r\n\t\tthis._eventDispatcher.dispose();\r\n\t}\r\n\r\n\tpublic createLineBreaksComputer(): ILineBreaksComputer {\r\n\t\treturn this._lines.createLineBreaksComputer();\r\n\t}\r\n\r\n\tpublic addViewEventHandler(eventHandler: ViewEventHandler): void {\r\n\t\tthis._eventDispatcher.addViewEventHandler(eventHandler);\r\n\t}\r\n\r\n\tpublic removeViewEventHandler(eventHandler: ViewEventHandler): void {\r\n\t\tthis._eventDispatcher.removeViewEventHandler(eventHandler);\r\n\t}\r\n\r\n\tprivate _updateConfigurationViewLineCountNow(): void {\r\n\t\tthis._configuration.setViewLineCount(this._lines.getViewLineCount());\r\n\t}\r\n\r\n\tpublic tokenizeViewport(): void {\r\n\t\tconst linesViewportData = this.viewLayout.getLinesViewportData();\r\n\t\tconst startPosition = this.coordinatesConverter.convertViewPositionToModelPosition(new Position(linesViewportData.startLineNumber, 1));\r\n\t\tconst endPosition = this.coordinatesConverter.convertViewPositionToModelPosition(new Position(linesViewportData.endLineNumber, 1));\r\n\t\tthis.model.tokenizeViewport(startPosition.lineNumber, endPosition.lineNumber);\r\n\t}\r\n\r\n\tpublic setHasFocus(hasFocus: boolean): void {\r\n\t\tthis._hasFocus = hasFocus;\r\n\t\tthis._cursor.setHasFocus(hasFocus);\r\n\t\tthis._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewFocusChangedEvent(hasFocus));\r\n\t\tthis._eventDispatcher.emitOutgoingEvent(new FocusChangedEvent(!hasFocus, hasFocus));\r\n\t}\r\n\r\n\tpublic onCompositionStart(): void {\r\n\t\tthis._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewCompositionStartEvent());\r\n\t}\r\n\r\n\tpublic onCompositionEnd(): void {\r\n\t\tthis._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewCompositionEndEvent());\r\n\t}\r\n\r\n\tpublic onDidColorThemeChange(): void {\r\n\t\tthis._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewThemeChangedEvent());\r\n\t}\r\n\r\n\tprivate _onConfigurationChanged(eventsCollector: ViewModelEventsCollector, e: ConfigurationChangedEvent): void {\r\n\r\n\t\t// We might need to restore the current centered view range, so save it (if available)\r\n\t\tlet previousViewportStartModelPosition: Position | null = null;\r\n\t\tif (this._viewportStartLine !== -1) {\r\n\t\t\tlet previousViewportStartViewPosition = new Position(this._viewportStartLine, this.getLineMinColumn(this._viewportStartLine));\r\n\t\t\tpreviousViewportStartModelPosition = this.coordinatesConverter.convertViewPositionToModelPosition(previousViewportStartViewPosition);\r\n\t\t}\r\n\t\tlet restorePreviousViewportStart = false;\r\n\r\n\t\tconst options = this._configuration.options;\r\n\t\tconst fontInfo = options.get(EditorOption.fontInfo);\r\n\t\tconst wrappingStrategy = options.get(EditorOption.wrappingStrategy);\r\n\t\tconst wrappingInfo = options.get(EditorOption.wrappingInfo);\r\n\t\tconst wrappingIndent = options.get(EditorOption.wrappingIndent);\r\n\r\n\t\tif (this._lines.setWrappingSettings(fontInfo, wrappingStrategy, wrappingInfo.wrappingColumn, wrappingIndent)) {\r\n\t\t\teventsCollector.emitViewEvent(new viewEvents.ViewFlushedEvent());\r\n\t\t\teventsCollector.emitViewEvent(new viewEvents.ViewLineMappingChangedEvent());\r\n\t\t\teventsCollector.emitViewEvent(new viewEvents.ViewDecorationsChangedEvent(null));\r\n\t\t\tthis._cursor.onLineMappingChanged(eventsCollector);\r\n\t\t\tthis._decorations.onLineMappingChanged();\r\n\t\t\tthis.viewLayout.onFlushed(this.getLineCount());\r\n\r\n\t\t\tif (this.viewLayout.getCurrentScrollTop() !== 0) {\r\n\t\t\t\t// Never change the scroll position from 0 to something else...\r\n\t\t\t\trestorePreviousViewportStart = true;\r\n\t\t\t}\r\n\r\n\t\t\tthis._updateConfigurationViewLineCount.schedule();\r\n\t\t}\r\n\r\n\t\tif (e.hasChanged(EditorOption.readOnly)) {\r\n\t\t\t// Must read again all decorations due to readOnly filtering\r\n\t\t\tthis._decorations.reset();\r\n\t\t\teventsCollector.emitViewEvent(new viewEvents.ViewDecorationsChangedEvent(null));\r\n\t\t}\r\n\r\n\t\teventsCollector.emitViewEvent(new viewEvents.ViewConfigurationChangedEvent(e));\r\n\t\tthis.viewLayout.onConfigurationChanged(e);\r\n\r\n\t\tif (restorePreviousViewportStart && previousViewportStartModelPosition) {\r\n\t\t\tconst viewPosition = this.coordinatesConverter.convertModelPositionToViewPosition(previousViewportStartModelPosition);\r\n\t\t\tconst viewPositionTop = this.viewLayout.getVerticalOffsetForLineNumber(viewPosition.lineNumber);\r\n\t\t\tthis.viewLayout.setScrollPosition({ scrollTop: viewPositionTop + this._viewportStartLineDelta }, ScrollType.Immediate);\r\n\t\t}\r\n\r\n\t\tif (CursorConfiguration.shouldRecreate(e)) {\r\n\t\t\tthis.cursorConfig = new CursorConfiguration(this.model.getLanguageIdentifier(), this.model.getOptions(), this._configuration);\r\n\t\t\tthis._cursor.updateConfiguration(this.cursorConfig);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _registerModelEvents(): void {\r\n\r\n\t\tthis._register(this.model.onDidChangeRawContentFast((e) => {\r\n\t\t\ttry {\r\n\t\t\t\tconst eventsCollector = this._eventDispatcher.beginEmitViewEvents();\r\n\r\n\t\t\t\tlet hadOtherModelChange = false;\r\n\t\t\t\tlet hadModelLineChangeThatChangedLineMapping = false;\r\n\r\n\t\t\t\tconst changes = e.changes;\r\n\t\t\t\tconst versionId = e.versionId;\r\n\r\n\t\t\t\t// Do a first pass to compute line mappings, and a second pass to actually interpret them\r\n\t\t\t\tconst lineBreaksComputer = this._lines.createLineBreaksComputer();\r\n\t\t\t\tfor (const change of changes) {\r\n\t\t\t\t\tswitch (change.changeType) {\r\n\t\t\t\t\t\tcase textModelEvents.RawContentChangedType.LinesInserted: {\r\n\t\t\t\t\t\t\tfor (const line of change.detail) {\r\n\t\t\t\t\t\t\t\tlineBreaksComputer.addRequest(line, null);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tcase textModelEvents.RawContentChangedType.LineChanged: {\r\n\t\t\t\t\t\t\tlineBreaksComputer.addRequest(change.detail, null);\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tconst lineBreaks = lineBreaksComputer.finalize();\r\n\t\t\t\tlet lineBreaksOffset = 0;\r\n\r\n\t\t\t\tfor (const change of changes) {\r\n\r\n\t\t\t\t\tswitch (change.changeType) {\r\n\t\t\t\t\t\tcase textModelEvents.RawContentChangedType.Flush: {\r\n\t\t\t\t\t\t\tthis._lines.onModelFlushed();\r\n\t\t\t\t\t\t\teventsCollector.emitViewEvent(new viewEvents.ViewFlushedEvent());\r\n\t\t\t\t\t\t\tthis._decorations.reset();\r\n\t\t\t\t\t\t\tthis.viewLayout.onFlushed(this.getLineCount());\r\n\t\t\t\t\t\t\thadOtherModelChange = true;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tcase textModelEvents.RawContentChangedType.LinesDeleted: {\r\n\t\t\t\t\t\t\tconst linesDeletedEvent = this._lines.onModelLinesDeleted(versionId, change.fromLineNumber, change.toLineNumber);\r\n\t\t\t\t\t\t\tif (linesDeletedEvent !== null) {\r\n\t\t\t\t\t\t\t\teventsCollector.emitViewEvent(linesDeletedEvent);\r\n\t\t\t\t\t\t\t\tthis.viewLayout.onLinesDeleted(linesDeletedEvent.fromLineNumber, linesDeletedEvent.toLineNumber);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\thadOtherModelChange = true;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tcase textModelEvents.RawContentChangedType.LinesInserted: {\r\n\t\t\t\t\t\t\tconst insertedLineBreaks = lineBreaks.slice(lineBreaksOffset, lineBreaksOffset + change.detail.length);\r\n\t\t\t\t\t\t\tlineBreaksOffset += change.detail.length;\r\n\r\n\t\t\t\t\t\t\tconst linesInsertedEvent = this._lines.onModelLinesInserted(versionId, change.fromLineNumber, change.toLineNumber, insertedLineBreaks);\r\n\t\t\t\t\t\t\tif (linesInsertedEvent !== null) {\r\n\t\t\t\t\t\t\t\teventsCollector.emitViewEvent(linesInsertedEvent);\r\n\t\t\t\t\t\t\t\tthis.viewLayout.onLinesInserted(linesInsertedEvent.fromLineNumber, linesInsertedEvent.toLineNumber);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\thadOtherModelChange = true;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tcase textModelEvents.RawContentChangedType.LineChanged: {\r\n\t\t\t\t\t\t\tconst changedLineBreakData = lineBreaks[lineBreaksOffset];\r\n\t\t\t\t\t\t\tlineBreaksOffset++;\r\n\r\n\t\t\t\t\t\t\tconst [lineMappingChanged, linesChangedEvent, linesInsertedEvent, linesDeletedEvent] = this._lines.onModelLineChanged(versionId, change.lineNumber, changedLineBreakData);\r\n\t\t\t\t\t\t\thadModelLineChangeThatChangedLineMapping = lineMappingChanged;\r\n\t\t\t\t\t\t\tif (linesChangedEvent) {\r\n\t\t\t\t\t\t\t\teventsCollector.emitViewEvent(linesChangedEvent);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tif (linesInsertedEvent) {\r\n\t\t\t\t\t\t\t\teventsCollector.emitViewEvent(linesInsertedEvent);\r\n\t\t\t\t\t\t\t\tthis.viewLayout.onLinesInserted(linesInsertedEvent.fromLineNumber, linesInsertedEvent.toLineNumber);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tif (linesDeletedEvent) {\r\n\t\t\t\t\t\t\t\teventsCollector.emitViewEvent(linesDeletedEvent);\r\n\t\t\t\t\t\t\t\tthis.viewLayout.onLinesDeleted(linesDeletedEvent.fromLineNumber, linesDeletedEvent.toLineNumber);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tcase textModelEvents.RawContentChangedType.EOLChanged: {\r\n\t\t\t\t\t\t\t// Nothing to do. The new version will be accepted below\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tthis._lines.acceptVersionId(versionId);\r\n\t\t\t\tthis.viewLayout.onHeightMaybeChanged();\r\n\r\n\t\t\t\tif (!hadOtherModelChange && hadModelLineChangeThatChangedLineMapping) {\r\n\t\t\t\t\teventsCollector.emitViewEvent(new viewEvents.ViewLineMappingChangedEvent());\r\n\t\t\t\t\teventsCollector.emitViewEvent(new viewEvents.ViewDecorationsChangedEvent(null));\r\n\t\t\t\t\tthis._cursor.onLineMappingChanged(eventsCollector);\r\n\t\t\t\t\tthis._decorations.onLineMappingChanged();\r\n\t\t\t\t}\r\n\t\t\t} finally {\r\n\t\t\t\tthis._eventDispatcher.endEmitViewEvents();\r\n\t\t\t}\r\n\r\n\t\t\t// Update the configuration and reset the centered view line\r\n\t\t\tthis._viewportStartLine = -1;\r\n\t\t\tthis._configuration.setMaxLineNumber(this.model.getLineCount());\r\n\t\t\tthis._updateConfigurationViewLineCountNow();\r\n\r\n\t\t\t// Recover viewport\r\n\t\t\tif (!this._hasFocus && this.model.getAttachedEditorCount() >= 2 && this._viewportStartLineTrackedRange) {\r\n\t\t\t\tconst modelRange = this.model._getTrackedRange(this._viewportStartLineTrackedRange);\r\n\t\t\t\tif (modelRange) {\r\n\t\t\t\t\tconst viewPosition = this.coordinatesConverter.convertModelPositionToViewPosition(modelRange.getStartPosition());\r\n\t\t\t\t\tconst viewPositionTop = this.viewLayout.getVerticalOffsetForLineNumber(viewPosition.lineNumber);\r\n\t\t\t\t\tthis.viewLayout.setScrollPosition({ scrollTop: viewPositionTop + this._viewportStartLineDelta }, ScrollType.Immediate);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\ttry {\r\n\t\t\t\tconst eventsCollector = this._eventDispatcher.beginEmitViewEvents();\r\n\t\t\t\tthis._cursor.onModelContentChanged(eventsCollector, e);\r\n\t\t\t} finally {\r\n\t\t\t\tthis._eventDispatcher.endEmitViewEvents();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._register(this.model.onDidChangeTokens((e) => {\r\n\t\t\tlet viewRanges: { fromLineNumber: number; toLineNumber: number; }[] = [];\r\n\t\t\tfor (let j = 0, lenJ = e.ranges.length; j < lenJ; j++) {\r\n\t\t\t\tconst modelRange = e.ranges[j];\r\n\t\t\t\tconst viewStartLineNumber = this.coordinatesConverter.convertModelPositionToViewPosition(new Position(modelRange.fromLineNumber, 1)).lineNumber;\r\n\t\t\t\tconst viewEndLineNumber = this.coordinatesConverter.convertModelPositionToViewPosition(new Position(modelRange.toLineNumber, this.model.getLineMaxColumn(modelRange.toLineNumber))).lineNumber;\r\n\t\t\t\tviewRanges[j] = {\r\n\t\t\t\t\tfromLineNumber: viewStartLineNumber,\r\n\t\t\t\t\ttoLineNumber: viewEndLineNumber\r\n\t\t\t\t};\r\n\t\t\t}\r\n\t\t\tthis._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewTokensChangedEvent(viewRanges));\r\n\r\n\t\t\tif (e.tokenizationSupportChanged) {\r\n\t\t\t\tthis._tokenizeViewportSoon.schedule();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._register(this.model.onDidChangeLanguageConfiguration((e) => {\r\n\t\t\tthis._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewLanguageConfigurationEvent());\r\n\t\t\tthis.cursorConfig = new CursorConfiguration(this.model.getLanguageIdentifier(), this.model.getOptions(), this._configuration);\r\n\t\t\tthis._cursor.updateConfiguration(this.cursorConfig);\r\n\t\t}));\r\n\r\n\t\tthis._register(this.model.onDidChangeLanguage((e) => {\r\n\t\t\tthis.cursorConfig = new CursorConfiguration(this.model.getLanguageIdentifier(), this.model.getOptions(), this._configuration);\r\n\t\t\tthis._cursor.updateConfiguration(this.cursorConfig);\r\n\t\t}));\r\n\r\n\t\tthis._register(this.model.onDidChangeOptions((e) => {\r\n\t\t\t// A tab size change causes a line mapping changed event => all view parts will repaint OK, no further event needed here\r\n\t\t\tif (this._lines.setTabSize(this.model.getOptions().tabSize)) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tconst eventsCollector = this._eventDispatcher.beginEmitViewEvents();\r\n\t\t\t\t\teventsCollector.emitViewEvent(new viewEvents.ViewFlushedEvent());\r\n\t\t\t\t\teventsCollector.emitViewEvent(new viewEvents.ViewLineMappingChangedEvent());\r\n\t\t\t\t\teventsCollector.emitViewEvent(new viewEvents.ViewDecorationsChangedEvent(null));\r\n\t\t\t\t\tthis._cursor.onLineMappingChanged(eventsCollector);\r\n\t\t\t\t\tthis._decorations.onLineMappingChanged();\r\n\t\t\t\t\tthis.viewLayout.onFlushed(this.getLineCount());\r\n\t\t\t\t} finally {\r\n\t\t\t\t\tthis._eventDispatcher.endEmitViewEvents();\r\n\t\t\t\t}\r\n\t\t\t\tthis._updateConfigurationViewLineCount.schedule();\r\n\t\t\t}\r\n\r\n\t\t\tthis.cursorConfig = new CursorConfiguration(this.model.getLanguageIdentifier(), this.model.getOptions(), this._configuration);\r\n\t\t\tthis._cursor.updateConfiguration(this.cursorConfig);\r\n\t\t}));\r\n\r\n\t\tthis._register(this.model.onDidChangeDecorations((e) => {\r\n\t\t\tthis._decorations.onModelDecorationsChanged();\r\n\t\t\tthis._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewDecorationsChangedEvent(e));\r\n\t\t}));\r\n\t}\r\n\r\n\tpublic setHiddenAreas(ranges: Range[]): void {\r\n\t\ttry {\r\n\t\t\tconst eventsCollector = this._eventDispatcher.beginEmitViewEvents();\r\n\t\t\tlet lineMappingChanged = this._lines.setHiddenAreas(ranges);\r\n\t\t\tif (lineMappingChanged) {\r\n\t\t\t\teventsCollector.emitViewEvent(new viewEvents.ViewFlushedEvent());\r\n\t\t\t\teventsCollector.emitViewEvent(new viewEvents.ViewLineMappingChangedEvent());\r\n\t\t\t\teventsCollector.emitViewEvent(new viewEvents.ViewDecorationsChangedEvent(null));\r\n\t\t\t\tthis._cursor.onLineMappingChanged(eventsCollector);\r\n\t\t\t\tthis._decorations.onLineMappingChanged();\r\n\t\t\t\tthis.viewLayout.onFlushed(this.getLineCount());\r\n\t\t\t\tthis.viewLayout.onHeightMaybeChanged();\r\n\t\t\t}\r\n\t\t} finally {\r\n\t\t\tthis._eventDispatcher.endEmitViewEvents();\r\n\t\t}\r\n\t\tthis._updateConfigurationViewLineCount.schedule();\r\n\t}\r\n\r\n\tpublic getVisibleRangesPlusViewportAboveBelow(): Range[] {\r\n\t\tconst layoutInfo = this._configuration.options.get(EditorOption.layoutInfo);\r\n\t\tconst lineHeight = this._configuration.options.get(EditorOption.lineHeight);\r\n\t\tconst linesAround = Math.max(20, Math.round(layoutInfo.height / lineHeight));\r\n\t\tconst partialData = this.viewLayout.getLinesViewportData();\r\n\t\tconst startViewLineNumber = Math.max(1, partialData.completelyVisibleStartLineNumber - linesAround);\r\n\t\tconst endViewLineNumber = Math.min(this.getLineCount(), partialData.completelyVisibleEndLineNumber + linesAround);\r\n\r\n\t\treturn this._toModelVisibleRanges(new Range(\r\n\t\t\tstartViewLineNumber, this.getLineMinColumn(startViewLineNumber),\r\n\t\t\tendViewLineNumber, this.getLineMaxColumn(endViewLineNumber)\r\n\t\t));\r\n\t}\r\n\r\n\tpublic getVisibleRanges(): Range[] {\r\n\t\tconst visibleViewRange = this.getCompletelyVisibleViewRange();\r\n\t\treturn this._toModelVisibleRanges(visibleViewRange);\r\n\t}\r\n\r\n\tprivate _toModelVisibleRanges(visibleViewRange: Range): Range[] {\r\n\t\tconst visibleRange = this.coordinatesConverter.convertViewRangeToModelRange(visibleViewRange);\r\n\t\tconst hiddenAreas = this._lines.getHiddenAreas();\r\n\r\n\t\tif (hiddenAreas.length === 0) {\r\n\t\t\treturn [visibleRange];\r\n\t\t}\r\n\r\n\t\tlet result: Range[] = [], resultLen = 0;\r\n\t\tlet startLineNumber = visibleRange.startLineNumber;\r\n\t\tlet startColumn = visibleRange.startColumn;\r\n\t\tlet endLineNumber = visibleRange.endLineNumber;\r\n\t\tlet endColumn = visibleRange.endColumn;\r\n\t\tfor (let i = 0, len = hiddenAreas.length; i < len; i++) {\r\n\t\t\tconst hiddenStartLineNumber = hiddenAreas[i].startLineNumber;\r\n\t\t\tconst hiddenEndLineNumber = hiddenAreas[i].endLineNumber;\r\n\r\n\t\t\tif (hiddenEndLineNumber < startLineNumber) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (hiddenStartLineNumber > endLineNumber) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (startLineNumber < hiddenStartLineNumber) {\r\n\t\t\t\tresult[resultLen++] = new Range(\r\n\t\t\t\t\tstartLineNumber, startColumn,\r\n\t\t\t\t\thiddenStartLineNumber - 1, this.model.getLineMaxColumn(hiddenStartLineNumber - 1)\r\n\t\t\t\t);\r\n\t\t\t}\r\n\t\t\tstartLineNumber = hiddenEndLineNumber + 1;\r\n\t\t\tstartColumn = 1;\r\n\t\t}\r\n\r\n\t\tif (startLineNumber < endLineNumber || (startLineNumber === endLineNumber && startColumn < endColumn)) {\r\n\t\t\tresult[resultLen++] = new Range(\r\n\t\t\t\tstartLineNumber, startColumn,\r\n\t\t\t\tendLineNumber, endColumn\r\n\t\t\t);\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic getCompletelyVisibleViewRange(): Range {\r\n\t\tconst partialData = this.viewLayout.getLinesViewportData();\r\n\t\tconst startViewLineNumber = partialData.completelyVisibleStartLineNumber;\r\n\t\tconst endViewLineNumber = partialData.completelyVisibleEndLineNumber;\r\n\r\n\t\treturn new Range(\r\n\t\t\tstartViewLineNumber, this.getLineMinColumn(startViewLineNumber),\r\n\t\t\tendViewLineNumber, this.getLineMaxColumn(endViewLineNumber)\r\n\t\t);\r\n\t}\r\n\r\n\tpublic getCompletelyVisibleViewRangeAtScrollTop(scrollTop: number): Range {\r\n\t\tconst partialData = this.viewLayout.getLinesViewportDataAtScrollTop(scrollTop);\r\n\t\tconst startViewLineNumber = partialData.completelyVisibleStartLineNumber;\r\n\t\tconst endViewLineNumber = partialData.completelyVisibleEndLineNumber;\r\n\r\n\t\treturn new Range(\r\n\t\t\tstartViewLineNumber, this.getLineMinColumn(startViewLineNumber),\r\n\t\t\tendViewLineNumber, this.getLineMaxColumn(endViewLineNumber)\r\n\t\t);\r\n\t}\r\n\r\n\tpublic saveState(): IViewState {\r\n\t\tconst compatViewState = this.viewLayout.saveState();\r\n\r\n\t\tconst scrollTop = compatViewState.scrollTop;\r\n\t\tconst firstViewLineNumber = this.viewLayout.getLineNumberAtVerticalOffset(scrollTop);\r\n\t\tconst firstPosition = this.coordinatesConverter.convertViewPositionToModelPosition(new Position(firstViewLineNumber, this.getLineMinColumn(firstViewLineNumber)));\r\n\t\tconst firstPositionDeltaTop = this.viewLayout.getVerticalOffsetForLineNumber(firstViewLineNumber) - scrollTop;\r\n\r\n\t\treturn {\r\n\t\t\tscrollLeft: compatViewState.scrollLeft,\r\n\t\t\tfirstPosition: firstPosition,\r\n\t\t\tfirstPositionDeltaTop: firstPositionDeltaTop\r\n\t\t};\r\n\t}\r\n\r\n\tpublic reduceRestoreState(state: IViewState): { scrollLeft: number; scrollTop: number; } {\r\n\t\tif (typeof state.firstPosition === 'undefined') {\r\n\t\t\t// This is a view state serialized by an older version\r\n\t\t\treturn this._reduceRestoreStateCompatibility(state);\r\n\t\t}\r\n\r\n\t\tconst modelPosition = this.model.validatePosition(state.firstPosition);\r\n\t\tconst viewPosition = this.coordinatesConverter.convertModelPositionToViewPosition(modelPosition);\r\n\t\tconst scrollTop = this.viewLayout.getVerticalOffsetForLineNumber(viewPosition.lineNumber) - state.firstPositionDeltaTop;\r\n\t\treturn {\r\n\t\t\tscrollLeft: state.scrollLeft,\r\n\t\t\tscrollTop: scrollTop\r\n\t\t};\r\n\t}\r\n\r\n\tprivate _reduceRestoreStateCompatibility(state: IViewState): { scrollLeft: number; scrollTop: number; } {\r\n\t\treturn {\r\n\t\t\tscrollLeft: state.scrollLeft,\r\n\t\t\tscrollTop: state.scrollTopWithoutViewZones!\r\n\t\t};\r\n\t}\r\n\r\n\tprivate getTabSize(): number {\r\n\t\treturn this.model.getOptions().tabSize;\r\n\t}\r\n\r\n\tpublic getTextModelOptions(): TextModelResolvedOptions {\r\n\t\treturn this.model.getOptions();\r\n\t}\r\n\r\n\tpublic getLineCount(): number {\r\n\t\treturn this._lines.getViewLineCount();\r\n\t}\r\n\r\n\t/**\r\n\t * Gives a hint that a lot of requests are about to come in for these line numbers.\r\n\t */\r\n\tpublic setViewport(startLineNumber: number, endLineNumber: number, centeredLineNumber: number): void {\r\n\t\tthis._viewportStartLine = startLineNumber;\r\n\t\tlet position = this.coordinatesConverter.convertViewPositionToModelPosition(new Position(startLineNumber, this.getLineMinColumn(startLineNumber)));\r\n\t\tthis._viewportStartLineTrackedRange = this.model._setTrackedRange(this._viewportStartLineTrackedRange, new Range(position.lineNumber, position.column, position.lineNumber, position.column), TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges);\r\n\t\tconst viewportStartLineTop = this.viewLayout.getVerticalOffsetForLineNumber(startLineNumber);\r\n\t\tconst scrollTop = this.viewLayout.getCurrentScrollTop();\r\n\t\tthis._viewportStartLineDelta = scrollTop - viewportStartLineTop;\r\n\t}\r\n\r\n\tpublic getActiveIndentGuide(lineNumber: number, minLineNumber: number, maxLineNumber: number): IActiveIndentGuideInfo {\r\n\t\treturn this._lines.getActiveIndentGuide(lineNumber, minLineNumber, maxLineNumber);\r\n\t}\r\n\r\n\tpublic getLinesIndentGuides(startLineNumber: number, endLineNumber: number): number[] {\r\n\t\treturn this._lines.getViewLinesIndentGuides(startLineNumber, endLineNumber);\r\n\t}\r\n\r\n\tpublic getLineContent(lineNumber: number): string {\r\n\t\treturn this._lines.getViewLineContent(lineNumber);\r\n\t}\r\n\r\n\tpublic getLineLength(lineNumber: number): number {\r\n\t\treturn this._lines.getViewLineLength(lineNumber);\r\n\t}\r\n\r\n\tpublic getLineMinColumn(lineNumber: number): number {\r\n\t\treturn this._lines.getViewLineMinColumn(lineNumber);\r\n\t}\r\n\r\n\tpublic getLineMaxColumn(lineNumber: number): number {\r\n\t\treturn this._lines.getViewLineMaxColumn(lineNumber);\r\n\t}\r\n\r\n\tpublic getLineFirstNonWhitespaceColumn(lineNumber: number): number {\r\n\t\tconst result = strings.firstNonWhitespaceIndex(this.getLineContent(lineNumber));\r\n\t\tif (result === -1) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t\treturn result + 1;\r\n\t}\r\n\r\n\tpublic getLineLastNonWhitespaceColumn(lineNumber: number): number {\r\n\t\tconst result = strings.lastNonWhitespaceIndex(this.getLineContent(lineNumber));\r\n\t\tif (result === -1) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t\treturn result + 2;\r\n\t}\r\n\r\n\tpublic getDecorationsInViewport(visibleRange: Range): ViewModelDecoration[] {\r\n\t\treturn this._decorations.getDecorationsViewportData(visibleRange).decorations;\r\n\t}\r\n\r\n\tpublic getViewLineRenderingData(visibleRange: Range, lineNumber: number): ViewLineRenderingData {\r\n\t\tlet mightContainRTL = this.model.mightContainRTL();\r\n\t\tlet mightContainNonBasicASCII = this.model.mightContainNonBasicASCII();\r\n\t\tlet tabSize = this.getTabSize();\r\n\t\tlet lineData = this._lines.getViewLineData(lineNumber);\r\n\t\tlet allInlineDecorations = this._decorations.getDecorationsViewportData(visibleRange).inlineDecorations;\r\n\t\tlet inlineDecorations = allInlineDecorations[lineNumber - visibleRange.startLineNumber];\r\n\r\n\t\treturn new ViewLineRenderingData(\r\n\t\t\tlineData.minColumn,\r\n\t\t\tlineData.maxColumn,\r\n\t\t\tlineData.content,\r\n\t\t\tlineData.continuesWithWrappedLine,\r\n\t\t\tmightContainRTL,\r\n\t\t\tmightContainNonBasicASCII,\r\n\t\t\tlineData.tokens,\r\n\t\t\tinlineDecorations,\r\n\t\t\ttabSize,\r\n\t\t\tlineData.startVisibleColumn\r\n\t\t);\r\n\t}\r\n\r\n\tpublic getViewLineData(lineNumber: number): ViewLineData {\r\n\t\treturn this._lines.getViewLineData(lineNumber);\r\n\t}\r\n\r\n\tpublic getMinimapLinesRenderingData(startLineNumber: number, endLineNumber: number, needed: boolean[]): MinimapLinesRenderingData {\r\n\t\tlet result = this._lines.getViewLinesData(startLineNumber, endLineNumber, needed);\r\n\t\treturn new MinimapLinesRenderingData(\r\n\t\t\tthis.getTabSize(),\r\n\t\t\tresult\r\n\t\t);\r\n\t}\r\n\r\n\tpublic getAllOverviewRulerDecorations(theme: EditorTheme): IOverviewRulerDecorations {\r\n\t\treturn this._lines.getAllOverviewRulerDecorations(this._editorId, filterValidationDecorations(this._configuration.options), theme);\r\n\t}\r\n\r\n\tpublic invalidateOverviewRulerColorCache(): void {\r\n\t\tconst decorations = this.model.getOverviewRulerDecorations();\r\n\t\tfor (const decoration of decorations) {\r\n\t\t\tconst opts = decoration.options.overviewRuler;\r\n\t\t\tif (opts) {\r\n\t\t\t\topts.invalidateCachedColor();\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic invalidateMinimapColorCache(): void {\r\n\t\tconst decorations = this.model.getAllDecorations();\r\n\t\tfor (const decoration of decorations) {\r\n\t\t\tconst opts = decoration.options.minimap;\r\n\t\t\tif (opts) {\r\n\t\t\t\topts.invalidateCachedColor();\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getValueInRange(range: Range, eol: EndOfLinePreference): string {\r\n\t\tconst modelRange = this.coordinatesConverter.convertViewRangeToModelRange(range);\r\n\t\treturn this.model.getValueInRange(modelRange, eol);\r\n\t}\r\n\r\n\tpublic getModelLineMaxColumn(modelLineNumber: number): number {\r\n\t\treturn this.model.getLineMaxColumn(modelLineNumber);\r\n\t}\r\n\r\n\tpublic validateModelPosition(position: IPosition): Position {\r\n\t\treturn this.model.validatePosition(position);\r\n\t}\r\n\r\n\tpublic validateModelRange(range: IRange): Range {\r\n\t\treturn this.model.validateRange(range);\r\n\t}\r\n\r\n\tpublic deduceModelPositionRelativeToViewPosition(viewAnchorPosition: Position, deltaOffset: number, lineFeedCnt: number): Position {\r\n\t\tconst modelAnchor = this.coordinatesConverter.convertViewPositionToModelPosition(viewAnchorPosition);\r\n\t\tif (this.model.getEOL().length === 2) {\r\n\t\t\t// This model uses CRLF, so the delta must take that into account\r\n\t\t\tif (deltaOffset < 0) {\r\n\t\t\t\tdeltaOffset -= lineFeedCnt;\r\n\t\t\t} else {\r\n\t\t\t\tdeltaOffset += lineFeedCnt;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst modelAnchorOffset = this.model.getOffsetAt(modelAnchor);\r\n\t\tconst resultOffset = modelAnchorOffset + deltaOffset;\r\n\t\treturn this.model.getPositionAt(resultOffset);\r\n\t}\r\n\r\n\tpublic getEOL(): string {\r\n\t\treturn this.model.getEOL();\r\n\t}\r\n\r\n\tpublic getPlainTextToCopy(modelRanges: Range[], emptySelectionClipboard: boolean, forceCRLF: boolean): string | string[] {\r\n\t\tconst newLineCharacter = forceCRLF ? '\\r\\n' : this.model.getEOL();\r\n\r\n\t\tmodelRanges = modelRanges.slice(0);\r\n\t\tmodelRanges.sort(Range.compareRangesUsingStarts);\r\n\r\n\t\tlet hasEmptyRange = false;\r\n\t\tlet hasNonEmptyRange = false;\r\n\t\tfor (const range of modelRanges) {\r\n\t\t\tif (range.isEmpty()) {\r\n\t\t\t\thasEmptyRange = true;\r\n\t\t\t} else {\r\n\t\t\t\thasNonEmptyRange = true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!hasNonEmptyRange) {\r\n\t\t\t// all ranges are empty\r\n\t\t\tif (!emptySelectionClipboard) {\r\n\t\t\t\treturn '';\r\n\t\t\t}\r\n\r\n\t\t\tconst modelLineNumbers = modelRanges.map((r) => r.startLineNumber);\r\n\r\n\t\t\tlet result = '';\r\n\t\t\tfor (let i = 0; i < modelLineNumbers.length; i++) {\r\n\t\t\t\tif (i > 0 && modelLineNumbers[i - 1] === modelLineNumbers[i]) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\tresult += this.model.getLineContent(modelLineNumbers[i]) + newLineCharacter;\r\n\t\t\t}\r\n\t\t\treturn result;\r\n\t\t}\r\n\r\n\t\tif (hasEmptyRange && emptySelectionClipboard) {\r\n\t\t\t// mixed empty selections and non-empty selections\r\n\t\t\tlet result: string[] = [];\r\n\t\t\tlet prevModelLineNumber = 0;\r\n\t\t\tfor (const modelRange of modelRanges) {\r\n\t\t\t\tconst modelLineNumber = modelRange.startLineNumber;\r\n\t\t\t\tif (modelRange.isEmpty()) {\r\n\t\t\t\t\tif (modelLineNumber !== prevModelLineNumber) {\r\n\t\t\t\t\t\tresult.push(this.model.getLineContent(modelLineNumber));\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tresult.push(this.model.getValueInRange(modelRange, forceCRLF ? EndOfLinePreference.CRLF : EndOfLinePreference.TextDefined));\r\n\t\t\t\t}\r\n\t\t\t\tprevModelLineNumber = modelLineNumber;\r\n\t\t\t}\r\n\t\t\treturn result.length === 1 ? result[0] : result;\r\n\t\t}\r\n\r\n\t\tlet result: string[] = [];\r\n\t\tfor (const modelRange of modelRanges) {\r\n\t\t\tif (!modelRange.isEmpty()) {\r\n\t\t\t\tresult.push(this.model.getValueInRange(modelRange, forceCRLF ? EndOfLinePreference.CRLF : EndOfLinePreference.TextDefined));\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn result.length === 1 ? result[0] : result;\r\n\t}\r\n\r\n\tpublic getRichTextToCopy(modelRanges: Range[], emptySelectionClipboard: boolean): { html: string, mode: string } | null {\r\n\t\tconst languageId = this.model.getLanguageIdentifier();\r\n\t\tif (languageId.id === LanguageId.PlainText) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (modelRanges.length !== 1) {\r\n\t\t\t// no multiple selection support at this time\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet range = modelRanges[0];\r\n\t\tif (range.isEmpty()) {\r\n\t\t\tif (!emptySelectionClipboard) {\r\n\t\t\t\t// nothing to copy\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t\tconst lineNumber = range.startLineNumber;\r\n\t\t\trange = new Range(lineNumber, this.model.getLineMinColumn(lineNumber), lineNumber, this.model.getLineMaxColumn(lineNumber));\r\n\t\t}\r\n\r\n\t\tconst fontInfo = this._configuration.options.get(EditorOption.fontInfo);\r\n\t\tconst colorMap = this._getColorMap();\r\n\t\tconst fontFamily = fontInfo.fontFamily === EDITOR_FONT_DEFAULTS.fontFamily ? fontInfo.fontFamily : `'${fontInfo.fontFamily}', ${EDITOR_FONT_DEFAULTS.fontFamily}`;\r\n\r\n\t\treturn {\r\n\t\t\tmode: languageId.language,\r\n\t\t\thtml: (\r\n\t\t\t\t`
    `\r\n\t\t\t\t+ this._getHTMLToCopy(range, colorMap)\r\n\t\t\t\t+ '
    '\r\n\t\t\t)\r\n\t\t};\r\n\t}\r\n\r\n\tprivate _getHTMLToCopy(modelRange: Range, colorMap: string[]): string {\r\n\t\tconst startLineNumber = modelRange.startLineNumber;\r\n\t\tconst startColumn = modelRange.startColumn;\r\n\t\tconst endLineNumber = modelRange.endLineNumber;\r\n\t\tconst endColumn = modelRange.endColumn;\r\n\r\n\t\tconst tabSize = this.getTabSize();\r\n\r\n\t\tlet result = '';\r\n\r\n\t\tfor (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {\r\n\t\t\tconst lineTokens = this.model.getLineTokens(lineNumber);\r\n\t\t\tconst lineContent = lineTokens.getLineContent();\r\n\t\t\tconst startOffset = (lineNumber === startLineNumber ? startColumn - 1 : 0);\r\n\t\t\tconst endOffset = (lineNumber === endLineNumber ? endColumn - 1 : lineContent.length);\r\n\r\n\t\t\tif (lineContent === '') {\r\n\t\t\t\tresult += '
    ';\r\n\t\t\t} else {\r\n\t\t\t\tresult += tokenizeLineToHTML(lineContent, lineTokens.inflate(), colorMap, startOffset, endOffset, tabSize, platform.isWindows);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate _getColorMap(): string[] {\r\n\t\tlet colorMap = TokenizationRegistry.getColorMap();\r\n\t\tlet result: string[] = ['#000000'];\r\n\t\tif (colorMap) {\r\n\t\t\tfor (let i = 1, len = colorMap.length; i < len; i++) {\r\n\t\t\t\tresult[i] = Color.Format.CSS.formatHex(colorMap[i]);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\t//#region model\r\n\r\n\tpublic pushStackElement(): void {\r\n\t\tthis.model.pushStackElement();\r\n\t}\r\n\r\n\t//#endregion\r\n\r\n\t//#region cursor operations\r\n\r\n\tpublic getPrimaryCursorState(): CursorState {\r\n\t\treturn this._cursor.getPrimaryCursorState();\r\n\t}\r\n\tpublic getLastAddedCursorIndex(): number {\r\n\t\treturn this._cursor.getLastAddedCursorIndex();\r\n\t}\r\n\tpublic getCursorStates(): CursorState[] {\r\n\t\treturn this._cursor.getCursorStates();\r\n\t}\r\n\tpublic setCursorStates(source: string | null | undefined, reason: CursorChangeReason, states: PartialCursorState[] | null): void {\r\n\t\tthis._withViewEventsCollector(eventsCollector => this._cursor.setStates(eventsCollector, source, reason, states));\r\n\t}\r\n\tpublic getCursorColumnSelectData(): IColumnSelectData {\r\n\t\treturn this._cursor.getCursorColumnSelectData();\r\n\t}\r\n\tpublic setCursorColumnSelectData(columnSelectData: IColumnSelectData): void {\r\n\t\tthis._cursor.setCursorColumnSelectData(columnSelectData);\r\n\t}\r\n\tpublic getPrevEditOperationType(): EditOperationType {\r\n\t\treturn this._cursor.getPrevEditOperationType();\r\n\t}\r\n\tpublic setPrevEditOperationType(type: EditOperationType): void {\r\n\t\tthis._cursor.setPrevEditOperationType(type);\r\n\t}\r\n\tpublic getSelection(): Selection {\r\n\t\treturn this._cursor.getSelection();\r\n\t}\r\n\tpublic getSelections(): Selection[] {\r\n\t\treturn this._cursor.getSelections();\r\n\t}\r\n\tpublic getPosition(): Position {\r\n\t\treturn this._cursor.getPrimaryCursorState().modelState.position;\r\n\t}\r\n\tpublic setSelections(source: string | null | undefined, selections: readonly ISelection[], reason = CursorChangeReason.NotSet): void {\r\n\t\tthis._withViewEventsCollector(eventsCollector => this._cursor.setSelections(eventsCollector, source, selections, reason));\r\n\t}\r\n\tpublic saveCursorState(): ICursorState[] {\r\n\t\treturn this._cursor.saveState();\r\n\t}\r\n\tpublic restoreCursorState(states: ICursorState[]): void {\r\n\t\tthis._withViewEventsCollector(eventsCollector => this._cursor.restoreState(eventsCollector, states));\r\n\t}\r\n\r\n\tprivate _executeCursorEdit(callback: (eventsCollector: ViewModelEventsCollector) => void): void {\r\n\t\tif (this._cursor.context.cursorConfig.readOnly) {\r\n\t\t\t// we cannot edit when read only...\r\n\t\t\tthis._eventDispatcher.emitOutgoingEvent(new ReadOnlyEditAttemptEvent());\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._withViewEventsCollector(callback);\r\n\t}\r\n\tpublic executeEdits(source: string | null | undefined, edits: IIdentifiedSingleEditOperation[], cursorStateComputer: ICursorStateComputer): void {\r\n\t\tthis._executeCursorEdit(eventsCollector => this._cursor.executeEdits(eventsCollector, source, edits, cursorStateComputer));\r\n\t}\r\n\tpublic startComposition(): void {\r\n\t\tthis._cursor.setIsDoingComposition(true);\r\n\t\tthis._executeCursorEdit(eventsCollector => this._cursor.startComposition(eventsCollector));\r\n\t}\r\n\tpublic endComposition(source?: string | null | undefined): void {\r\n\t\tthis._cursor.setIsDoingComposition(false);\r\n\t\tthis._executeCursorEdit(eventsCollector => this._cursor.endComposition(eventsCollector, source));\r\n\t}\r\n\tpublic type(text: string, source?: string | null | undefined): void {\r\n\t\tthis._executeCursorEdit(eventsCollector => this._cursor.type(eventsCollector, text, source));\r\n\t}\r\n\tpublic replacePreviousChar(text: string, replaceCharCnt: number, source?: string | null | undefined): void {\r\n\t\tthis._executeCursorEdit(eventsCollector => this._cursor.replacePreviousChar(eventsCollector, text, replaceCharCnt, source));\r\n\t}\r\n\tpublic paste(text: string, pasteOnNewLine: boolean, multicursorText?: string[] | null | undefined, source?: string | null | undefined): void {\r\n\t\tthis._executeCursorEdit(eventsCollector => this._cursor.paste(eventsCollector, text, pasteOnNewLine, multicursorText, source));\r\n\t}\r\n\tpublic cut(source?: string | null | undefined): void {\r\n\t\tthis._executeCursorEdit(eventsCollector => this._cursor.cut(eventsCollector, source));\r\n\t}\r\n\tpublic executeCommand(command: ICommand, source?: string | null | undefined): void {\r\n\t\tthis._executeCursorEdit(eventsCollector => this._cursor.executeCommand(eventsCollector, command, source));\r\n\t}\r\n\tpublic executeCommands(commands: ICommand[], source?: string | null | undefined): void {\r\n\t\tthis._executeCursorEdit(eventsCollector => this._cursor.executeCommands(eventsCollector, commands, source));\r\n\t}\r\n\tpublic revealPrimaryCursor(source: string | null | undefined, revealHorizontal: boolean): void {\r\n\t\tthis._withViewEventsCollector(eventsCollector => this._cursor.revealPrimary(eventsCollector, source, revealHorizontal, ScrollType.Smooth));\r\n\t}\r\n\tpublic revealTopMostCursor(source: string | null | undefined): void {\r\n\t\tconst viewPosition = this._cursor.getTopMostViewPosition();\r\n\t\tconst viewRange = new Range(viewPosition.lineNumber, viewPosition.column, viewPosition.lineNumber, viewPosition.column);\r\n\t\tthis._withViewEventsCollector(eventsCollector => eventsCollector.emitViewEvent(new viewEvents.ViewRevealRangeRequestEvent(source, viewRange, null, viewEvents.VerticalRevealType.Simple, true, ScrollType.Smooth)));\r\n\t}\r\n\tpublic revealBottomMostCursor(source: string | null | undefined): void {\r\n\t\tconst viewPosition = this._cursor.getBottomMostViewPosition();\r\n\t\tconst viewRange = new Range(viewPosition.lineNumber, viewPosition.column, viewPosition.lineNumber, viewPosition.column);\r\n\t\tthis._withViewEventsCollector(eventsCollector => eventsCollector.emitViewEvent(new viewEvents.ViewRevealRangeRequestEvent(source, viewRange, null, viewEvents.VerticalRevealType.Simple, true, ScrollType.Smooth)));\r\n\t}\r\n\tpublic revealRange(source: string | null | undefined, revealHorizontal: boolean, viewRange: Range, verticalType: viewEvents.VerticalRevealType, scrollType: ScrollType): void {\r\n\t\tthis._withViewEventsCollector(eventsCollector => eventsCollector.emitViewEvent(new viewEvents.ViewRevealRangeRequestEvent(source, viewRange, null, verticalType, revealHorizontal, scrollType)));\r\n\t}\r\n\r\n\t//#endregion\r\n\r\n\t//#region viewLayout\r\n\tpublic getVerticalOffsetForLineNumber(viewLineNumber: number): number {\r\n\t\treturn this.viewLayout.getVerticalOffsetForLineNumber(viewLineNumber);\r\n\t}\r\n\tpublic getScrollTop(): number {\r\n\t\treturn this.viewLayout.getCurrentScrollTop();\r\n\t}\r\n\tpublic setScrollTop(newScrollTop: number, scrollType: ScrollType): void {\r\n\t\tthis.viewLayout.setScrollPosition({ scrollTop: newScrollTop }, scrollType);\r\n\t}\r\n\tpublic setScrollPosition(position: INewScrollPosition, type: ScrollType): void {\r\n\t\tthis.viewLayout.setScrollPosition(position, type);\r\n\t}\r\n\tpublic deltaScrollNow(deltaScrollLeft: number, deltaScrollTop: number): void {\r\n\t\tthis.viewLayout.deltaScrollNow(deltaScrollLeft, deltaScrollTop);\r\n\t}\r\n\tpublic changeWhitespace(callback: (accessor: IWhitespaceChangeAccessor) => void): void {\r\n\t\tconst hadAChange = this.viewLayout.changeWhitespace(callback);\r\n\t\tif (hadAChange) {\r\n\t\t\tthis._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewZonesChangedEvent());\r\n\t\t\tthis._eventDispatcher.emitOutgoingEvent(new ViewZonesChangedEvent());\r\n\t\t}\r\n\t}\r\n\tpublic setMaxLineWidth(maxLineWidth: number): void {\r\n\t\tthis.viewLayout.setMaxLineWidth(maxLineWidth);\r\n\t}\r\n\t//#endregion\r\n\r\n\tprivate _withViewEventsCollector(callback: (eventsCollector: ViewModelEventsCollector) => void): void {\r\n\t\ttry {\r\n\t\t\tconst eventsCollector = this._eventDispatcher.beginEmitViewEvents();\r\n\t\t\tcallback(eventsCollector);\r\n\t\t} finally {\r\n\t\t\tthis._eventDispatcher.endEmitViewEvents();\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { equals } from 'vs/base/common/arrays';\r\nimport { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\r\nimport { onUnexpectedExternalError } from 'vs/base/common/errors';\r\nimport { LRUCache } from 'vs/base/common/map';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { DocumentSymbol, DocumentSymbolProvider, DocumentSymbolProviderRegistry } from 'vs/editor/common/modes';\r\nimport { Iterable } from 'vs/base/common/iterator';\r\nimport { LanguageFeatureRequestDelays } from 'vs/editor/common/modes/languageFeatureRegistry';\r\nimport { URI } from 'vs/base/common/uri';\r\n\r\nexport abstract class TreeElement {\r\n\r\n\tabstract id: string;\r\n\tabstract children: Map;\r\n\tabstract parent: TreeElement | undefined;\r\n\r\n\tremove(): void {\r\n\t\tif (this.parent) {\r\n\t\t\tthis.parent.children.delete(this.id);\r\n\t\t}\r\n\t}\r\n\r\n\tstatic findId(candidate: DocumentSymbol | string, container: TreeElement): string {\r\n\t\t// complex id-computation which contains the origin/extension,\r\n\t\t// the parent path, and some dedupe logic when names collide\r\n\t\tlet candidateId: string;\r\n\t\tif (typeof candidate === 'string') {\r\n\t\t\tcandidateId = `${container.id}/${candidate}`;\r\n\t\t} else {\r\n\t\t\tcandidateId = `${container.id}/${candidate.name}`;\r\n\t\t\tif (container.children.get(candidateId) !== undefined) {\r\n\t\t\t\tcandidateId = `${container.id}/${candidate.name}_${candidate.range.startLineNumber}_${candidate.range.startColumn}`;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet id = candidateId;\r\n\t\tfor (let i = 0; container.children.get(id) !== undefined; i++) {\r\n\t\t\tid = `${candidateId}_${i}`;\r\n\t\t}\r\n\r\n\t\treturn id;\r\n\t}\r\n\r\n\tstatic empty(element: TreeElement): boolean {\r\n\t\treturn element.children.size === 0;\r\n\t}\r\n}\r\n\r\nexport class OutlineElement extends TreeElement {\r\n\r\n\tchildren = new Map();\r\n\r\n\tconstructor(\r\n\t\treadonly id: string,\r\n\t\tpublic parent: TreeElement | undefined,\r\n\t\treadonly symbol: DocumentSymbol\r\n\t) {\r\n\t\tsuper();\r\n\t}\r\n}\r\n\r\nexport class OutlineGroup extends TreeElement {\r\n\r\n\tchildren = new Map();\r\n\r\n\tconstructor(\r\n\t\treadonly id: string,\r\n\t\tpublic parent: TreeElement | undefined,\r\n\t\treadonly label: string,\r\n\t\treadonly order: number,\r\n\t) {\r\n\t\tsuper();\r\n\t}\r\n}\r\n\r\nexport class OutlineModel extends TreeElement {\r\n\r\n\tprivate static readonly _requestDurations = new LanguageFeatureRequestDelays(DocumentSymbolProviderRegistry, 350);\r\n\tprivate static readonly _requests = new LRUCache, model: OutlineModel | undefined }>(9, 0.75);\r\n\tprivate static readonly _keys = new class {\r\n\r\n\t\tprivate _counter = 1;\r\n\t\tprivate _data = new WeakMap();\r\n\r\n\t\tfor(textModel: ITextModel, version: boolean): string {\r\n\t\t\treturn `${textModel.id}/${version ? textModel.getVersionId() : ''}/${this._hash(DocumentSymbolProviderRegistry.all(textModel))}`;\r\n\t\t}\r\n\r\n\t\tprivate _hash(providers: DocumentSymbolProvider[]): string {\r\n\t\t\tlet result = '';\r\n\t\t\tfor (const provider of providers) {\r\n\t\t\t\tlet n = this._data.get(provider);\r\n\t\t\t\tif (typeof n === 'undefined') {\r\n\t\t\t\t\tn = this._counter++;\r\n\t\t\t\t\tthis._data.set(provider, n);\r\n\t\t\t\t}\r\n\t\t\t\tresult += n;\r\n\t\t\t}\r\n\t\t\treturn result;\r\n\t\t}\r\n\t};\r\n\r\n\r\n\tstatic create(textModel: ITextModel, token: CancellationToken): Promise {\r\n\r\n\t\tlet key = this._keys.for(textModel, true);\r\n\t\tlet data = OutlineModel._requests.get(key);\r\n\r\n\t\tif (!data) {\r\n\t\t\tlet source = new CancellationTokenSource();\r\n\t\t\tdata = {\r\n\t\t\t\tpromiseCnt: 0,\r\n\t\t\t\tsource,\r\n\t\t\t\tpromise: OutlineModel._create(textModel, source.token),\r\n\t\t\t\tmodel: undefined,\r\n\t\t\t};\r\n\t\t\tOutlineModel._requests.set(key, data);\r\n\r\n\t\t\t// keep moving average of request durations\r\n\t\t\tconst now = Date.now();\r\n\t\t\tdata.promise.then(() => {\r\n\t\t\t\tthis._requestDurations.update(textModel, Date.now() - now);\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tif (data!.model) {\r\n\t\t\t// resolved -> return data\r\n\t\t\treturn Promise.resolve(data.model!);\r\n\t\t}\r\n\r\n\t\t// increase usage counter\r\n\t\tdata!.promiseCnt += 1;\r\n\r\n\t\ttoken.onCancellationRequested(() => {\r\n\t\t\t// last -> cancel provider request, remove cached promise\r\n\t\t\tif (--data!.promiseCnt === 0) {\r\n\t\t\t\tdata!.source.cancel();\r\n\t\t\t\tOutlineModel._requests.delete(key);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\treturn new Promise((resolve, reject) => {\r\n\t\t\tdata!.promise.then(model => {\r\n\t\t\t\tdata!.model = model;\r\n\t\t\t\tresolve(model);\r\n\t\t\t}, err => {\r\n\t\t\t\tOutlineModel._requests.delete(key);\r\n\t\t\t\treject(err);\r\n\t\t\t});\r\n\t\t});\r\n\t}\r\n\r\n\tprivate static _create(textModel: ITextModel, token: CancellationToken): Promise {\r\n\r\n\t\tconst cts = new CancellationTokenSource(token);\r\n\t\tconst result = new OutlineModel(textModel.uri);\r\n\t\tconst provider = DocumentSymbolProviderRegistry.ordered(textModel);\r\n\t\tconst promises = provider.map((provider, index) => {\r\n\r\n\t\t\tlet id = TreeElement.findId(`provider_${index}`, result);\r\n\t\t\tlet group = new OutlineGroup(id, result, provider.displayName ?? 'Unknown Outline Provider', index);\r\n\r\n\t\t\treturn Promise.resolve(provider.provideDocumentSymbols(textModel, cts.token)).then(result => {\r\n\t\t\t\tfor (const info of result || []) {\r\n\t\t\t\t\tOutlineModel._makeOutlineElement(info, group);\r\n\t\t\t\t}\r\n\t\t\t\treturn group;\r\n\t\t\t}, err => {\r\n\t\t\t\tonUnexpectedExternalError(err);\r\n\t\t\t\treturn group;\r\n\t\t\t}).then(group => {\r\n\t\t\t\tif (!TreeElement.empty(group)) {\r\n\t\t\t\t\tresult._groups.set(id, group);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tgroup.remove();\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t});\r\n\r\n\t\tconst listener = DocumentSymbolProviderRegistry.onDidChange(() => {\r\n\t\t\tconst newProvider = DocumentSymbolProviderRegistry.ordered(textModel);\r\n\t\t\tif (!equals(newProvider, provider)) {\r\n\t\t\t\tcts.cancel();\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\treturn Promise.all(promises).then(() => {\r\n\t\t\tif (cts.token.isCancellationRequested && !token.isCancellationRequested) {\r\n\t\t\t\treturn OutlineModel._create(textModel, token);\r\n\t\t\t} else {\r\n\t\t\t\treturn result._compact();\r\n\t\t\t}\r\n\t\t}).finally(() => {\r\n\t\t\tlistener.dispose();\r\n\t\t});\r\n\t}\r\n\r\n\tprivate static _makeOutlineElement(info: DocumentSymbol, container: OutlineGroup | OutlineElement): void {\r\n\t\tlet id = TreeElement.findId(info, container);\r\n\t\tlet res = new OutlineElement(id, container, info);\r\n\t\tif (info.children) {\r\n\t\t\tfor (const childInfo of info.children) {\r\n\t\t\t\tOutlineModel._makeOutlineElement(childInfo, res);\r\n\t\t\t}\r\n\t\t}\r\n\t\tcontainer.children.set(res.id, res);\r\n\t}\r\n\r\n\treadonly id = 'root';\r\n\treadonly parent = undefined;\r\n\r\n\tprotected _groups = new Map();\r\n\tchildren = new Map();\r\n\r\n\tprotected constructor(readonly uri: URI) {\r\n\t\tsuper();\r\n\r\n\t\tthis.id = 'root';\r\n\t\tthis.parent = undefined;\r\n\t}\r\n\r\n\tprivate _compact(): this {\r\n\t\tlet count = 0;\r\n\t\tfor (const [key, group] of this._groups) {\r\n\t\t\tif (group.children.size === 0) { // empty\r\n\t\t\t\tthis._groups.delete(key);\r\n\t\t\t} else {\r\n\t\t\t\tcount += 1;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (count !== 1) {\r\n\t\t\t//\r\n\t\t\tthis.children = this._groups;\r\n\t\t} else {\r\n\t\t\t// adopt all elements of the first group\r\n\t\t\tlet group = Iterable.first(this._groups.values())!;\r\n\t\t\tfor (let [, child] of group.children) {\r\n\t\t\t\tchild.parent = this;\r\n\t\t\t\tthis.children.set(child.id, child);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this;\r\n\t}\r\n\r\n\tgetTopLevelSymbols(): DocumentSymbol[] {\r\n\t\tconst roots: DocumentSymbol[] = [];\r\n\t\tfor (const child of this.children.values()) {\r\n\t\t\tif (child instanceof OutlineElement) {\r\n\t\t\t\troots.push(child.symbol);\r\n\t\t\t} else {\r\n\t\t\t\troots.push(...Iterable.map(child.children.values(), child => child.symbol));\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn roots.sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range));\r\n\t}\r\n\r\n\tasListOfDocumentSymbols(): DocumentSymbol[] {\r\n\t\tconst roots = this.getTopLevelSymbols();\r\n\t\tconst bucket: DocumentSymbol[] = [];\r\n\t\tOutlineModel._flattenDocumentSymbols(bucket, roots, '');\r\n\t\treturn bucket.sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range));\r\n\t}\r\n\r\n\tprivate static _flattenDocumentSymbols(bucket: DocumentSymbol[], entries: DocumentSymbol[], overrideContainerLabel: string): void {\r\n\t\tfor (const entry of entries) {\r\n\t\t\tbucket.push({\r\n\t\t\t\tkind: entry.kind,\r\n\t\t\t\ttags: entry.tags,\r\n\t\t\t\tname: entry.name,\r\n\t\t\t\tdetail: entry.detail,\r\n\t\t\t\tcontainerName: entry.containerName || overrideContainerLabel,\r\n\t\t\t\trange: entry.range,\r\n\t\t\t\tselectionRange: entry.selectionRange,\r\n\t\t\t\tchildren: undefined, // we flatten it...\r\n\t\t\t});\r\n\r\n\t\t\t// Recurse over children\r\n\t\t\tif (entry.children) {\r\n\t\t\t\tOutlineModel._flattenDocumentSymbols(bucket, entry.children, entry.name);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { FoldingMarkers } from 'vs/editor/common/modes/languageConfiguration';\r\nimport { FoldingRegions, MAX_LINE_NUMBER } from 'vs/editor/contrib/folding/foldingRanges';\r\nimport { TextModel } from 'vs/editor/common/model/textModel';\r\nimport { RangeProvider } from './folding';\r\nimport { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\n\r\nconst MAX_FOLDING_REGIONS_FOR_INDENT_LIMIT = 5000;\r\n\r\nexport const ID_INDENT_PROVIDER = 'indent';\r\n\r\nexport class IndentRangeProvider implements RangeProvider {\r\n\treadonly id = ID_INDENT_PROVIDER;\r\n\r\n\tconstructor(private readonly editorModel: ITextModel) {\r\n\t}\r\n\r\n\tdispose() {\r\n\t}\r\n\r\n\tcompute(cancelationToken: CancellationToken): Promise {\r\n\t\tlet foldingRules = LanguageConfigurationRegistry.getFoldingRules(this.editorModel.getLanguageIdentifier().id);\r\n\t\tlet offSide = foldingRules && !!foldingRules.offSide;\r\n\t\tlet markers = foldingRules && foldingRules.markers;\r\n\t\treturn Promise.resolve(computeRanges(this.editorModel, offSide, markers));\r\n\t}\r\n}\r\n\r\n// public only for testing\r\nexport class RangesCollector {\r\n\tprivate readonly _startIndexes: number[];\r\n\tprivate readonly _endIndexes: number[];\r\n\tprivate readonly _indentOccurrences: number[];\r\n\tprivate _length: number;\r\n\tprivate readonly _foldingRangesLimit: number;\r\n\r\n\tconstructor(foldingRangesLimit: number) {\r\n\t\tthis._startIndexes = [];\r\n\t\tthis._endIndexes = [];\r\n\t\tthis._indentOccurrences = [];\r\n\t\tthis._length = 0;\r\n\t\tthis._foldingRangesLimit = foldingRangesLimit;\r\n\t}\r\n\r\n\tpublic insertFirst(startLineNumber: number, endLineNumber: number, indent: number) {\r\n\t\tif (startLineNumber > MAX_LINE_NUMBER || endLineNumber > MAX_LINE_NUMBER) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tlet index = this._length;\r\n\t\tthis._startIndexes[index] = startLineNumber;\r\n\t\tthis._endIndexes[index] = endLineNumber;\r\n\t\tthis._length++;\r\n\t\tif (indent < 1000) {\r\n\t\t\tthis._indentOccurrences[indent] = (this._indentOccurrences[indent] || 0) + 1;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic toIndentRanges(model: ITextModel) {\r\n\t\tif (this._length <= this._foldingRangesLimit) {\r\n\t\t\t// reverse and create arrays of the exact length\r\n\t\t\tlet startIndexes = new Uint32Array(this._length);\r\n\t\t\tlet endIndexes = new Uint32Array(this._length);\r\n\t\t\tfor (let i = this._length - 1, k = 0; i >= 0; i--, k++) {\r\n\t\t\t\tstartIndexes[k] = this._startIndexes[i];\r\n\t\t\t\tendIndexes[k] = this._endIndexes[i];\r\n\t\t\t}\r\n\t\t\treturn new FoldingRegions(startIndexes, endIndexes);\r\n\t\t} else {\r\n\t\t\tlet entries = 0;\r\n\t\t\tlet maxIndent = this._indentOccurrences.length;\r\n\t\t\tfor (let i = 0; i < this._indentOccurrences.length; i++) {\r\n\t\t\t\tlet n = this._indentOccurrences[i];\r\n\t\t\t\tif (n) {\r\n\t\t\t\t\tif (n + entries > this._foldingRangesLimit) {\r\n\t\t\t\t\t\tmaxIndent = i;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tentries += n;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tconst tabSize = model.getOptions().tabSize;\r\n\t\t\t// reverse and create arrays of the exact length\r\n\t\t\tlet startIndexes = new Uint32Array(this._foldingRangesLimit);\r\n\t\t\tlet endIndexes = new Uint32Array(this._foldingRangesLimit);\r\n\t\t\tfor (let i = this._length - 1, k = 0; i >= 0; i--) {\r\n\t\t\t\tlet startIndex = this._startIndexes[i];\r\n\t\t\t\tlet lineContent = model.getLineContent(startIndex);\r\n\t\t\t\tlet indent = TextModel.computeIndentLevel(lineContent, tabSize);\r\n\t\t\t\tif (indent < maxIndent || (indent === maxIndent && entries++ < this._foldingRangesLimit)) {\r\n\t\t\t\t\tstartIndexes[k] = startIndex;\r\n\t\t\t\t\tendIndexes[k] = this._endIndexes[i];\r\n\t\t\t\t\tk++;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn new FoldingRegions(startIndexes, endIndexes);\r\n\t\t}\r\n\r\n\t}\r\n}\r\n\r\n\r\ninterface PreviousRegion {\r\n\tindent: number; // indent or -2 if a marker\r\n\tendAbove: number; // end line number for the region above\r\n\tline: number; // start line of the region. Only used for marker regions.\r\n}\r\n\r\nexport function computeRanges(model: ITextModel, offSide: boolean, markers?: FoldingMarkers, foldingRangesLimit = MAX_FOLDING_REGIONS_FOR_INDENT_LIMIT): FoldingRegions {\r\n\tconst tabSize = model.getOptions().tabSize;\r\n\tlet result = new RangesCollector(foldingRangesLimit);\r\n\r\n\tlet pattern: RegExp | undefined = undefined;\r\n\tif (markers) {\r\n\t\tpattern = new RegExp(`(${markers.start.source})|(?:${markers.end.source})`);\r\n\t}\r\n\r\n\tlet previousRegions: PreviousRegion[] = [];\r\n\tlet line = model.getLineCount() + 1;\r\n\tpreviousRegions.push({ indent: -1, endAbove: line, line }); // sentinel, to make sure there's at least one entry\r\n\r\n\tfor (let line = model.getLineCount(); line > 0; line--) {\r\n\t\tlet lineContent = model.getLineContent(line);\r\n\t\tlet indent = TextModel.computeIndentLevel(lineContent, tabSize);\r\n\t\tlet previous = previousRegions[previousRegions.length - 1];\r\n\t\tif (indent === -1) {\r\n\t\t\tif (offSide) {\r\n\t\t\t\t// for offSide languages, empty lines are associated to the previous block\r\n\t\t\t\t// note: the next block is already written to the results, so this only\r\n\t\t\t\t// impacts the end position of the block before\r\n\t\t\t\tprevious.endAbove = line;\r\n\t\t\t}\r\n\t\t\tcontinue; // only whitespace\r\n\t\t}\r\n\t\tlet m;\r\n\t\tif (pattern && (m = lineContent.match(pattern))) {\r\n\t\t\t// folding pattern match\r\n\t\t\tif (m[1]) { // start pattern match\r\n\t\t\t\t// discard all regions until the folding pattern\r\n\t\t\t\tlet i = previousRegions.length - 1;\r\n\t\t\t\twhile (i > 0 && previousRegions[i].indent !== -2) {\r\n\t\t\t\t\ti--;\r\n\t\t\t\t}\r\n\t\t\t\tif (i > 0) {\r\n\t\t\t\t\tpreviousRegions.length = i + 1;\r\n\t\t\t\t\tprevious = previousRegions[i];\r\n\r\n\t\t\t\t\t// new folding range from pattern, includes the end line\r\n\t\t\t\t\tresult.insertFirst(line, previous.line, indent);\r\n\t\t\t\t\tprevious.line = line;\r\n\t\t\t\t\tprevious.indent = indent;\r\n\t\t\t\t\tprevious.endAbove = line;\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// no end marker found, treat line as a regular line\r\n\t\t\t\t}\r\n\t\t\t} else { // end pattern match\r\n\t\t\t\tpreviousRegions.push({ indent: -2, endAbove: line, line });\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (previous.indent > indent) {\r\n\t\t\t// discard all regions with larger indent\r\n\t\t\tdo {\r\n\t\t\t\tpreviousRegions.pop();\r\n\t\t\t\tprevious = previousRegions[previousRegions.length - 1];\r\n\t\t\t} while (previous.indent > indent);\r\n\r\n\t\t\t// new folding range\r\n\t\t\tlet endLineNumber = previous.endAbove - 1;\r\n\t\t\tif (endLineNumber - line >= 1) { // needs at east size 1\r\n\t\t\t\tresult.insertFirst(line, endLineNumber, indent);\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (previous.indent === indent) {\r\n\t\t\tprevious.endAbove = line;\r\n\t\t} else { // previous.indent < indent\r\n\t\t\t// new region with a bigger indent\r\n\t\t\tpreviousRegions.push({ indent, endAbove: line, line });\r\n\t\t}\r\n\t}\r\n\treturn result.toIndentRanges(model);\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { ShiftCommand } from 'vs/editor/common/commands/shiftCommand';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { ICommand, ICursorStateComputerData, IEditOperationBuilder } from 'vs/editor/common/editorCommon';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { CompleteEnterAction, IndentAction } from 'vs/editor/common/modes/languageConfiguration';\r\nimport { IIndentConverter, LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';\r\nimport { IndentConsts } from 'vs/editor/common/modes/supports/indentRules';\r\nimport * as indentUtils from 'vs/editor/contrib/indentation/indentUtils';\r\nimport { EditorAutoIndentStrategy } from 'vs/editor/common/config/editorOptions';\r\n\r\nexport class MoveLinesCommand implements ICommand {\r\n\r\n\tprivate readonly _selection: Selection;\r\n\tprivate readonly _isMovingDown: boolean;\r\n\tprivate readonly _autoIndent: EditorAutoIndentStrategy;\r\n\r\n\tprivate _selectionId: string | null;\r\n\tprivate _moveEndPositionDown?: boolean;\r\n\tprivate _moveEndLineSelectionShrink: boolean;\r\n\r\n\tconstructor(selection: Selection, isMovingDown: boolean, autoIndent: EditorAutoIndentStrategy) {\r\n\t\tthis._selection = selection;\r\n\t\tthis._isMovingDown = isMovingDown;\r\n\t\tthis._autoIndent = autoIndent;\r\n\t\tthis._selectionId = null;\r\n\t\tthis._moveEndLineSelectionShrink = false;\r\n\t}\r\n\r\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\r\n\r\n\t\tlet modelLineCount = model.getLineCount();\r\n\r\n\t\tif (this._isMovingDown && this._selection.endLineNumber === modelLineCount) {\r\n\t\t\tthis._selectionId = builder.trackSelection(this._selection);\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (!this._isMovingDown && this._selection.startLineNumber === 1) {\r\n\t\t\tthis._selectionId = builder.trackSelection(this._selection);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._moveEndPositionDown = false;\r\n\t\tlet s = this._selection;\r\n\r\n\t\tif (s.startLineNumber < s.endLineNumber && s.endColumn === 1) {\r\n\t\t\tthis._moveEndPositionDown = true;\r\n\t\t\ts = s.setEndPosition(s.endLineNumber - 1, model.getLineMaxColumn(s.endLineNumber - 1));\r\n\t\t}\r\n\r\n\t\tconst { tabSize, indentSize, insertSpaces } = model.getOptions();\r\n\t\tlet indentConverter = this.buildIndentConverter(tabSize, indentSize, insertSpaces);\r\n\t\tlet virtualModel = {\r\n\t\t\tgetLineTokens: (lineNumber: number) => {\r\n\t\t\t\treturn model.getLineTokens(lineNumber);\r\n\t\t\t},\r\n\t\t\tgetLanguageIdentifier: () => {\r\n\t\t\t\treturn model.getLanguageIdentifier();\r\n\t\t\t},\r\n\t\t\tgetLanguageIdAtPosition: (lineNumber: number, column: number) => {\r\n\t\t\t\treturn model.getLanguageIdAtPosition(lineNumber, column);\r\n\t\t\t},\r\n\t\t\tgetLineContent: null as unknown as (lineNumber: number) => string,\r\n\t\t};\r\n\r\n\t\tif (s.startLineNumber === s.endLineNumber && model.getLineMaxColumn(s.startLineNumber) === 1) {\r\n\t\t\t// Current line is empty\r\n\t\t\tlet lineNumber = s.startLineNumber;\r\n\t\t\tlet otherLineNumber = (this._isMovingDown ? lineNumber + 1 : lineNumber - 1);\r\n\r\n\t\t\tif (model.getLineMaxColumn(otherLineNumber) === 1) {\r\n\t\t\t\t// Other line number is empty too, so no editing is needed\r\n\t\t\t\t// Add a no-op to force running by the model\r\n\t\t\t\tbuilder.addEditOperation(new Range(1, 1, 1, 1), null);\r\n\t\t\t} else {\r\n\t\t\t\t// Type content from other line number on line number\r\n\t\t\t\tbuilder.addEditOperation(new Range(lineNumber, 1, lineNumber, 1), model.getLineContent(otherLineNumber));\r\n\r\n\t\t\t\t// Remove content from other line number\r\n\t\t\t\tbuilder.addEditOperation(new Range(otherLineNumber, 1, otherLineNumber, model.getLineMaxColumn(otherLineNumber)), null);\r\n\t\t\t}\r\n\t\t\t// Track selection at the other line number\r\n\t\t\ts = new Selection(otherLineNumber, 1, otherLineNumber, 1);\r\n\r\n\t\t} else {\r\n\r\n\t\t\tlet movingLineNumber: number;\r\n\t\t\tlet movingLineText: string;\r\n\r\n\t\t\tif (this._isMovingDown) {\r\n\t\t\t\tmovingLineNumber = s.endLineNumber + 1;\r\n\t\t\t\tmovingLineText = model.getLineContent(movingLineNumber);\r\n\t\t\t\t// Delete line that needs to be moved\r\n\t\t\t\tbuilder.addEditOperation(new Range(movingLineNumber - 1, model.getLineMaxColumn(movingLineNumber - 1), movingLineNumber, model.getLineMaxColumn(movingLineNumber)), null);\r\n\r\n\t\t\t\tlet insertingText = movingLineText;\r\n\r\n\t\t\t\tif (this.shouldAutoIndent(model, s)) {\r\n\t\t\t\t\tlet movingLineMatchResult = this.matchEnterRule(model, indentConverter, tabSize, movingLineNumber, s.startLineNumber - 1);\r\n\t\t\t\t\t// if s.startLineNumber - 1 matches onEnter rule, we still honor that.\r\n\t\t\t\t\tif (movingLineMatchResult !== null) {\r\n\t\t\t\t\t\tlet oldIndentation = strings.getLeadingWhitespace(model.getLineContent(movingLineNumber));\r\n\t\t\t\t\t\tlet newSpaceCnt = movingLineMatchResult + indentUtils.getSpaceCnt(oldIndentation, tabSize);\r\n\t\t\t\t\t\tlet newIndentation = indentUtils.generateIndent(newSpaceCnt, tabSize, insertSpaces);\r\n\t\t\t\t\t\tinsertingText = newIndentation + this.trimLeft(movingLineText);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t// no enter rule matches, let's check indentatin rules then.\r\n\t\t\t\t\t\tvirtualModel.getLineContent = (lineNumber: number) => {\r\n\t\t\t\t\t\t\tif (lineNumber === s.startLineNumber) {\r\n\t\t\t\t\t\t\t\treturn model.getLineContent(movingLineNumber);\r\n\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\treturn model.getLineContent(lineNumber);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t};\r\n\t\t\t\t\t\tlet indentOfMovingLine = LanguageConfigurationRegistry.getGoodIndentForLine(this._autoIndent, virtualModel, model.getLanguageIdAtPosition(\r\n\t\t\t\t\t\t\tmovingLineNumber, 1), s.startLineNumber, indentConverter);\r\n\t\t\t\t\t\tif (indentOfMovingLine !== null) {\r\n\t\t\t\t\t\t\tlet oldIndentation = strings.getLeadingWhitespace(model.getLineContent(movingLineNumber));\r\n\t\t\t\t\t\t\tlet newSpaceCnt = indentUtils.getSpaceCnt(indentOfMovingLine, tabSize);\r\n\t\t\t\t\t\t\tlet oldSpaceCnt = indentUtils.getSpaceCnt(oldIndentation, tabSize);\r\n\t\t\t\t\t\t\tif (newSpaceCnt !== oldSpaceCnt) {\r\n\t\t\t\t\t\t\t\tlet newIndentation = indentUtils.generateIndent(newSpaceCnt, tabSize, insertSpaces);\r\n\t\t\t\t\t\t\t\tinsertingText = newIndentation + this.trimLeft(movingLineText);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t// add edit operations for moving line first to make sure it's executed after we make indentation change\r\n\t\t\t\t\t// to s.startLineNumber\r\n\t\t\t\t\tbuilder.addEditOperation(new Range(s.startLineNumber, 1, s.startLineNumber, 1), insertingText + '\\n');\r\n\r\n\t\t\t\t\tlet ret = this.matchEnterRuleMovingDown(model, indentConverter, tabSize, s.startLineNumber, movingLineNumber, insertingText);\r\n\r\n\t\t\t\t\t// check if the line being moved before matches onEnter rules, if so let's adjust the indentation by onEnter rules.\r\n\t\t\t\t\tif (ret !== null) {\r\n\t\t\t\t\t\tif (ret !== 0) {\r\n\t\t\t\t\t\t\tthis.getIndentEditsOfMovingBlock(model, builder, s, tabSize, insertSpaces, ret);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t// it doesn't match onEnter rules, let's check indentation rules then.\r\n\t\t\t\t\t\tvirtualModel.getLineContent = (lineNumber: number) => {\r\n\t\t\t\t\t\t\tif (lineNumber === s.startLineNumber) {\r\n\t\t\t\t\t\t\t\treturn insertingText;\r\n\t\t\t\t\t\t\t} else if (lineNumber >= s.startLineNumber + 1 && lineNumber <= s.endLineNumber + 1) {\r\n\t\t\t\t\t\t\t\treturn model.getLineContent(lineNumber - 1);\r\n\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\treturn model.getLineContent(lineNumber);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t};\r\n\r\n\t\t\t\t\t\tlet newIndentatOfMovingBlock = LanguageConfigurationRegistry.getGoodIndentForLine(this._autoIndent, virtualModel, model.getLanguageIdAtPosition(\r\n\t\t\t\t\t\t\tmovingLineNumber, 1), s.startLineNumber + 1, indentConverter);\r\n\r\n\t\t\t\t\t\tif (newIndentatOfMovingBlock !== null) {\r\n\t\t\t\t\t\t\tconst oldIndentation = strings.getLeadingWhitespace(model.getLineContent(s.startLineNumber));\r\n\t\t\t\t\t\t\tconst newSpaceCnt = indentUtils.getSpaceCnt(newIndentatOfMovingBlock, tabSize);\r\n\t\t\t\t\t\t\tconst oldSpaceCnt = indentUtils.getSpaceCnt(oldIndentation, tabSize);\r\n\t\t\t\t\t\t\tif (newSpaceCnt !== oldSpaceCnt) {\r\n\t\t\t\t\t\t\t\tconst spaceCntOffset = newSpaceCnt - oldSpaceCnt;\r\n\r\n\t\t\t\t\t\t\t\tthis.getIndentEditsOfMovingBlock(model, builder, s, tabSize, insertSpaces, spaceCntOffset);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// Insert line that needs to be moved before\r\n\t\t\t\t\tbuilder.addEditOperation(new Range(s.startLineNumber, 1, s.startLineNumber, 1), insertingText + '\\n');\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tmovingLineNumber = s.startLineNumber - 1;\r\n\t\t\t\tmovingLineText = model.getLineContent(movingLineNumber);\r\n\r\n\t\t\t\t// Delete line that needs to be moved\r\n\t\t\t\tbuilder.addEditOperation(new Range(movingLineNumber, 1, movingLineNumber + 1, 1), null);\r\n\r\n\t\t\t\t// Insert line that needs to be moved after\r\n\t\t\t\tbuilder.addEditOperation(new Range(s.endLineNumber, model.getLineMaxColumn(s.endLineNumber), s.endLineNumber, model.getLineMaxColumn(s.endLineNumber)), '\\n' + movingLineText);\r\n\r\n\t\t\t\tif (this.shouldAutoIndent(model, s)) {\r\n\t\t\t\t\tvirtualModel.getLineContent = (lineNumber: number) => {\r\n\t\t\t\t\t\tif (lineNumber === movingLineNumber) {\r\n\t\t\t\t\t\t\treturn model.getLineContent(s.startLineNumber);\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\treturn model.getLineContent(lineNumber);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t};\r\n\r\n\t\t\t\t\tlet ret = this.matchEnterRule(model, indentConverter, tabSize, s.startLineNumber, s.startLineNumber - 2);\r\n\t\t\t\t\t// check if s.startLineNumber - 2 matches onEnter rules, if so adjust the moving block by onEnter rules.\r\n\t\t\t\t\tif (ret !== null) {\r\n\t\t\t\t\t\tif (ret !== 0) {\r\n\t\t\t\t\t\t\tthis.getIndentEditsOfMovingBlock(model, builder, s, tabSize, insertSpaces, ret);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t// it doesn't match any onEnter rule, let's check indentation rules then.\r\n\t\t\t\t\t\tlet indentOfFirstLine = LanguageConfigurationRegistry.getGoodIndentForLine(this._autoIndent, virtualModel, model.getLanguageIdAtPosition(s.startLineNumber, 1), movingLineNumber, indentConverter);\r\n\t\t\t\t\t\tif (indentOfFirstLine !== null) {\r\n\t\t\t\t\t\t\t// adjust the indentation of the moving block\r\n\t\t\t\t\t\t\tlet oldIndent = strings.getLeadingWhitespace(model.getLineContent(s.startLineNumber));\r\n\t\t\t\t\t\t\tlet newSpaceCnt = indentUtils.getSpaceCnt(indentOfFirstLine, tabSize);\r\n\t\t\t\t\t\t\tlet oldSpaceCnt = indentUtils.getSpaceCnt(oldIndent, tabSize);\r\n\t\t\t\t\t\t\tif (newSpaceCnt !== oldSpaceCnt) {\r\n\t\t\t\t\t\t\t\tlet spaceCntOffset = newSpaceCnt - oldSpaceCnt;\r\n\r\n\t\t\t\t\t\t\t\tthis.getIndentEditsOfMovingBlock(model, builder, s, tabSize, insertSpaces, spaceCntOffset);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._selectionId = builder.trackSelection(s);\r\n\t}\r\n\r\n\tprivate buildIndentConverter(tabSize: number, indentSize: number, insertSpaces: boolean): IIndentConverter {\r\n\t\treturn {\r\n\t\t\tshiftIndent: (indentation) => {\r\n\t\t\t\treturn ShiftCommand.shiftIndent(indentation, indentation.length + 1, tabSize, indentSize, insertSpaces);\r\n\t\t\t},\r\n\t\t\tunshiftIndent: (indentation) => {\r\n\t\t\t\treturn ShiftCommand.unshiftIndent(indentation, indentation.length + 1, tabSize, indentSize, insertSpaces);\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\tprivate parseEnterResult(model: ITextModel, indentConverter: IIndentConverter, tabSize: number, line: number, enter: CompleteEnterAction | null) {\r\n\t\tif (enter) {\r\n\t\t\tlet enterPrefix = enter.indentation;\r\n\r\n\t\t\tif (enter.indentAction === IndentAction.None) {\r\n\t\t\t\tenterPrefix = enter.indentation + enter.appendText;\r\n\t\t\t} else if (enter.indentAction === IndentAction.Indent) {\r\n\t\t\t\tenterPrefix = enter.indentation + enter.appendText;\r\n\t\t\t} else if (enter.indentAction === IndentAction.IndentOutdent) {\r\n\t\t\t\tenterPrefix = enter.indentation;\r\n\t\t\t} else if (enter.indentAction === IndentAction.Outdent) {\r\n\t\t\t\tenterPrefix = indentConverter.unshiftIndent(enter.indentation) + enter.appendText;\r\n\t\t\t}\r\n\t\t\tlet movingLineText = model.getLineContent(line);\r\n\t\t\tif (this.trimLeft(movingLineText).indexOf(this.trimLeft(enterPrefix)) >= 0) {\r\n\t\t\t\tlet oldIndentation = strings.getLeadingWhitespace(model.getLineContent(line));\r\n\t\t\t\tlet newIndentation = strings.getLeadingWhitespace(enterPrefix);\r\n\t\t\t\tlet indentMetadataOfMovelingLine = LanguageConfigurationRegistry.getIndentMetadata(model, line);\r\n\t\t\t\tif (indentMetadataOfMovelingLine !== null && indentMetadataOfMovelingLine & IndentConsts.DECREASE_MASK) {\r\n\t\t\t\t\tnewIndentation = indentConverter.unshiftIndent(newIndentation);\r\n\t\t\t\t}\r\n\t\t\t\tlet newSpaceCnt = indentUtils.getSpaceCnt(newIndentation, tabSize);\r\n\t\t\t\tlet oldSpaceCnt = indentUtils.getSpaceCnt(oldIndentation, tabSize);\r\n\t\t\t\treturn newSpaceCnt - oldSpaceCnt;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\t/**\r\n\t *\r\n\t * @param model\r\n\t * @param indentConverter\r\n\t * @param tabSize\r\n\t * @param line the line moving down\r\n\t * @param futureAboveLineNumber the line which will be at the `line` position\r\n\t * @param futureAboveLineText\r\n\t */\r\n\tprivate matchEnterRuleMovingDown(model: ITextModel, indentConverter: IIndentConverter, tabSize: number, line: number, futureAboveLineNumber: number, futureAboveLineText: string) {\r\n\t\tif (strings.lastNonWhitespaceIndex(futureAboveLineText) >= 0) {\r\n\t\t\t// break\r\n\t\t\tlet maxColumn = model.getLineMaxColumn(futureAboveLineNumber);\r\n\t\t\tlet enter = LanguageConfigurationRegistry.getEnterAction(this._autoIndent, model, new Range(futureAboveLineNumber, maxColumn, futureAboveLineNumber, maxColumn));\r\n\t\t\treturn this.parseEnterResult(model, indentConverter, tabSize, line, enter);\r\n\t\t} else {\r\n\t\t\t// go upwards, starting from `line - 1`\r\n\t\t\tlet validPrecedingLine = line - 1;\r\n\t\t\twhile (validPrecedingLine >= 1) {\r\n\t\t\t\tlet lineContent = model.getLineContent(validPrecedingLine);\r\n\t\t\t\tlet nonWhitespaceIdx = strings.lastNonWhitespaceIndex(lineContent);\r\n\r\n\t\t\t\tif (nonWhitespaceIdx >= 0) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvalidPrecedingLine--;\r\n\t\t\t}\r\n\r\n\t\t\tif (validPrecedingLine < 1 || line > model.getLineCount()) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\r\n\t\t\tlet maxColumn = model.getLineMaxColumn(validPrecedingLine);\r\n\t\t\tlet enter = LanguageConfigurationRegistry.getEnterAction(this._autoIndent, model, new Range(validPrecedingLine, maxColumn, validPrecedingLine, maxColumn));\r\n\t\t\treturn this.parseEnterResult(model, indentConverter, tabSize, line, enter);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate matchEnterRule(model: ITextModel, indentConverter: IIndentConverter, tabSize: number, line: number, oneLineAbove: number, previousLineText?: string) {\r\n\t\tlet validPrecedingLine = oneLineAbove;\r\n\t\twhile (validPrecedingLine >= 1) {\r\n\t\t\t// ship empty lines as empty lines just inherit indentation\r\n\t\t\tlet lineContent;\r\n\t\t\tif (validPrecedingLine === oneLineAbove && previousLineText !== undefined) {\r\n\t\t\t\tlineContent = previousLineText;\r\n\t\t\t} else {\r\n\t\t\t\tlineContent = model.getLineContent(validPrecedingLine);\r\n\t\t\t}\r\n\r\n\t\t\tlet nonWhitespaceIdx = strings.lastNonWhitespaceIndex(lineContent);\r\n\t\t\tif (nonWhitespaceIdx >= 0) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tvalidPrecedingLine--;\r\n\t\t}\r\n\r\n\t\tif (validPrecedingLine < 1 || line > model.getLineCount()) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet maxColumn = model.getLineMaxColumn(validPrecedingLine);\r\n\t\tlet enter = LanguageConfigurationRegistry.getEnterAction(this._autoIndent, model, new Range(validPrecedingLine, maxColumn, validPrecedingLine, maxColumn));\r\n\t\treturn this.parseEnterResult(model, indentConverter, tabSize, line, enter);\r\n\t}\r\n\r\n\tprivate trimLeft(str: string) {\r\n\t\treturn str.replace(/^\\s+/, '');\r\n\t}\r\n\r\n\tprivate shouldAutoIndent(model: ITextModel, selection: Selection) {\r\n\t\tif (this._autoIndent < EditorAutoIndentStrategy.Full) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\t// if it's not easy to tokenize, we stop auto indent.\r\n\t\tif (!model.isCheapToTokenize(selection.startLineNumber)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tlet languageAtSelectionStart = model.getLanguageIdAtPosition(selection.startLineNumber, 1);\r\n\t\tlet languageAtSelectionEnd = model.getLanguageIdAtPosition(selection.endLineNumber, 1);\r\n\r\n\t\tif (languageAtSelectionStart !== languageAtSelectionEnd) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tif (LanguageConfigurationRegistry.getIndentRulesSupport(languageAtSelectionStart) === null) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tprivate getIndentEditsOfMovingBlock(model: ITextModel, builder: IEditOperationBuilder, s: Selection, tabSize: number, insertSpaces: boolean, offset: number) {\r\n\t\tfor (let i = s.startLineNumber; i <= s.endLineNumber; i++) {\r\n\t\t\tlet lineContent = model.getLineContent(i);\r\n\t\t\tlet originalIndent = strings.getLeadingWhitespace(lineContent);\r\n\t\t\tlet originalSpacesCnt = indentUtils.getSpaceCnt(originalIndent, tabSize);\r\n\t\t\tlet newSpacesCnt = originalSpacesCnt + offset;\r\n\t\t\tlet newIndent = indentUtils.generateIndent(newSpacesCnt, tabSize, insertSpaces);\r\n\r\n\t\t\tif (newIndent !== originalIndent) {\r\n\t\t\t\tbuilder.addEditOperation(new Range(i, 1, i, originalIndent.length + 1), newIndent);\r\n\r\n\t\t\t\tif (i === s.endLineNumber && s.endColumn <= originalIndent.length + 1 && newIndent === '') {\r\n\t\t\t\t\t// as users select part of the original indent white spaces\r\n\t\t\t\t\t// when we adjust the indentation of endLine, we should adjust the cursor position as well.\r\n\t\t\t\t\tthis._moveEndLineSelectionShrink = true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t}\r\n\t}\r\n\r\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\r\n\t\tlet result = helper.getTrackedSelection(this._selectionId!);\r\n\r\n\t\tif (this._moveEndPositionDown) {\r\n\t\t\tresult = result.setEndPosition(result.endLineNumber + 1, 1);\r\n\t\t}\r\n\r\n\t\tif (this._moveEndLineSelectionShrink && result.startLineNumber < result.endLineNumber) {\r\n\t\t\tresult = result.setEndPosition(result.endLineNumber, 2);\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./zoneWidget';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { IHorizontalSashLayoutProvider, ISashEvent, Orientation, Sash, SashState } from 'vs/base/browser/ui/sash/sash';\r\nimport { Color, RGBA } from 'vs/base/common/color';\r\nimport { IdGenerator } from 'vs/base/common/idGenerator';\r\nimport { DisposableStore } from 'vs/base/common/lifecycle';\r\nimport * as objects from 'vs/base/common/objects';\r\nimport { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, IViewZone, IViewZoneChangeAccessor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorLayoutInfo, EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { IPosition, Position } from 'vs/editor/common/core/position';\r\nimport { IRange, Range } from 'vs/editor/common/core/range';\r\nimport { ScrollType } from 'vs/editor/common/editorCommon';\r\nimport { TrackedRangeStickiness } from 'vs/editor/common/model';\r\nimport { ModelDecorationOptions } from 'vs/editor/common/model/textModel';\r\n\r\nexport interface IOptions {\r\n\tshowFrame?: boolean;\r\n\tshowArrow?: boolean;\r\n\tframeWidth?: number;\r\n\tclassName?: string;\r\n\tisAccessible?: boolean;\r\n\tisResizeable?: boolean;\r\n\tframeColor?: Color;\r\n\tarrowColor?: Color;\r\n\tkeepEditorSelection?: boolean;\r\n}\r\n\r\nexport interface IStyles {\r\n\tframeColor?: Color | null;\r\n\tarrowColor?: Color | null;\r\n}\r\n\r\nconst defaultColor = new Color(new RGBA(0, 122, 204));\r\n\r\nconst defaultOptions: IOptions = {\r\n\tshowArrow: true,\r\n\tshowFrame: true,\r\n\tclassName: '',\r\n\tframeColor: defaultColor,\r\n\tarrowColor: defaultColor,\r\n\tkeepEditorSelection: false\r\n};\r\n\r\nconst WIDGET_ID = 'vs.editor.contrib.zoneWidget';\r\n\r\nexport class ViewZoneDelegate implements IViewZone {\r\n\r\n\tdomNode: HTMLElement;\r\n\tid: string = ''; // A valid zone id should be greater than 0\r\n\tafterLineNumber: number;\r\n\tafterColumn: number;\r\n\theightInLines: number;\r\n\r\n\tprivate readonly _onDomNodeTop: (top: number) => void;\r\n\tprivate readonly _onComputedHeight: (height: number) => void;\r\n\r\n\tconstructor(domNode: HTMLElement, afterLineNumber: number, afterColumn: number, heightInLines: number,\r\n\t\tonDomNodeTop: (top: number) => void,\r\n\t\tonComputedHeight: (height: number) => void\r\n\t) {\r\n\t\tthis.domNode = domNode;\r\n\t\tthis.afterLineNumber = afterLineNumber;\r\n\t\tthis.afterColumn = afterColumn;\r\n\t\tthis.heightInLines = heightInLines;\r\n\t\tthis._onDomNodeTop = onDomNodeTop;\r\n\t\tthis._onComputedHeight = onComputedHeight;\r\n\t}\r\n\r\n\tonDomNodeTop(top: number): void {\r\n\t\tthis._onDomNodeTop(top);\r\n\t}\r\n\r\n\tonComputedHeight(height: number): void {\r\n\t\tthis._onComputedHeight(height);\r\n\t}\r\n}\r\n\r\nexport class OverlayWidgetDelegate implements IOverlayWidget {\r\n\r\n\tprivate readonly _id: string;\r\n\tprivate readonly _domNode: HTMLElement;\r\n\r\n\tconstructor(id: string, domNode: HTMLElement) {\r\n\t\tthis._id = id;\r\n\t\tthis._domNode = domNode;\r\n\t}\r\n\r\n\tgetId(): string {\r\n\t\treturn this._id;\r\n\t}\r\n\r\n\tgetDomNode(): HTMLElement {\r\n\t\treturn this._domNode;\r\n\t}\r\n\r\n\tgetPosition(): IOverlayWidgetPosition | null {\r\n\t\treturn null;\r\n\t}\r\n}\r\n\r\nclass Arrow {\r\n\r\n\tprivate static readonly _IdGenerator = new IdGenerator('.arrow-decoration-');\r\n\r\n\tprivate readonly _ruleName = Arrow._IdGenerator.nextId();\r\n\tprivate _decorations: string[] = [];\r\n\tprivate _color: string | null = null;\r\n\tprivate _height: number = -1;\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _editor: ICodeEditor\r\n\t) {\r\n\t\t//\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis.hide();\r\n\t\tdom.removeCSSRulesContainingSelector(this._ruleName);\r\n\t}\r\n\r\n\tset color(value: string) {\r\n\t\tif (this._color !== value) {\r\n\t\t\tthis._color = value;\r\n\t\t\tthis._updateStyle();\r\n\t\t}\r\n\t}\r\n\r\n\tset height(value: number) {\r\n\t\tif (this._height !== value) {\r\n\t\t\tthis._height = value;\r\n\t\t\tthis._updateStyle();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _updateStyle(): void {\r\n\t\tdom.removeCSSRulesContainingSelector(this._ruleName);\r\n\t\tdom.createCSSRule(\r\n\t\t\t`.monaco-editor ${this._ruleName}`,\r\n\t\t\t`border-style: solid; border-color: transparent; border-bottom-color: ${this._color}; border-width: ${this._height}px; bottom: -${this._height}px; margin-left: -${this._height}px; `\r\n\t\t);\r\n\t}\r\n\r\n\tshow(where: IPosition): void {\r\n\t\tthis._decorations = this._editor.deltaDecorations(\r\n\t\t\tthis._decorations,\r\n\t\t\t[{ range: Range.fromPositions(where), options: { className: this._ruleName, stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges } }]\r\n\t\t);\r\n\t}\r\n\r\n\thide(): void {\r\n\t\tthis._editor.deltaDecorations(this._decorations, []);\r\n\t}\r\n}\r\n\r\nexport abstract class ZoneWidget implements IHorizontalSashLayoutProvider {\r\n\r\n\tprivate _arrow: Arrow | null = null;\r\n\tprivate _overlayWidget: OverlayWidgetDelegate | null = null;\r\n\tprivate _resizeSash: Sash | null = null;\r\n\tprivate _positionMarkerId: string[] = [];\r\n\r\n\tprotected _viewZone: ViewZoneDelegate | null = null;\r\n\tprotected readonly _disposables = new DisposableStore();\r\n\r\n\tcontainer: HTMLElement | null = null;\r\n\tdomNode: HTMLElement;\r\n\teditor: ICodeEditor;\r\n\toptions: IOptions;\r\n\r\n\r\n\tconstructor(editor: ICodeEditor, options: IOptions = {}) {\r\n\t\tthis.editor = editor;\r\n\t\tthis.options = objects.deepClone(options);\r\n\t\tobjects.mixin(this.options, defaultOptions, false);\r\n\t\tthis.domNode = document.createElement('div');\r\n\t\tif (!this.options.isAccessible) {\r\n\t\t\tthis.domNode.setAttribute('aria-hidden', 'true');\r\n\t\t\tthis.domNode.setAttribute('role', 'presentation');\r\n\t\t}\r\n\r\n\t\tthis._disposables.add(this.editor.onDidLayoutChange((info: EditorLayoutInfo) => {\r\n\t\t\tconst width = this._getWidth(info);\r\n\t\t\tthis.domNode.style.width = width + 'px';\r\n\t\t\tthis.domNode.style.left = this._getLeft(info) + 'px';\r\n\t\t\tthis._onWidth(width);\r\n\t\t}));\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tif (this._overlayWidget) {\r\n\t\t\tthis.editor.removeOverlayWidget(this._overlayWidget);\r\n\t\t\tthis._overlayWidget = null;\r\n\t\t}\r\n\r\n\t\tif (this._viewZone) {\r\n\t\t\tthis.editor.changeViewZones(accessor => {\r\n\t\t\t\tif (this._viewZone) {\r\n\t\t\t\t\taccessor.removeZone(this._viewZone.id);\r\n\t\t\t\t}\r\n\t\t\t\tthis._viewZone = null;\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tthis.editor.deltaDecorations(this._positionMarkerId, []);\r\n\t\tthis._positionMarkerId = [];\r\n\r\n\t\tthis._disposables.dispose();\r\n\t}\r\n\r\n\tcreate(): void {\r\n\r\n\t\tthis.domNode.classList.add('zone-widget');\r\n\t\tif (this.options.className) {\r\n\t\t\tthis.domNode.classList.add(this.options.className);\r\n\t\t}\r\n\r\n\t\tthis.container = document.createElement('div');\r\n\t\tthis.container.classList.add('zone-widget-container');\r\n\t\tthis.domNode.appendChild(this.container);\r\n\t\tif (this.options.showArrow) {\r\n\t\t\tthis._arrow = new Arrow(this.editor);\r\n\t\t\tthis._disposables.add(this._arrow);\r\n\t\t}\r\n\t\tthis._fillContainer(this.container);\r\n\t\tthis._initSash();\r\n\t\tthis._applyStyles();\r\n\t}\r\n\r\n\tstyle(styles: IStyles): void {\r\n\t\tif (styles.frameColor) {\r\n\t\t\tthis.options.frameColor = styles.frameColor;\r\n\t\t}\r\n\t\tif (styles.arrowColor) {\r\n\t\t\tthis.options.arrowColor = styles.arrowColor;\r\n\t\t}\r\n\t\tthis._applyStyles();\r\n\t}\r\n\r\n\tprotected _applyStyles(): void {\r\n\t\tif (this.container && this.options.frameColor) {\r\n\t\t\tlet frameColor = this.options.frameColor.toString();\r\n\t\t\tthis.container.style.borderTopColor = frameColor;\r\n\t\t\tthis.container.style.borderBottomColor = frameColor;\r\n\t\t}\r\n\t\tif (this._arrow && this.options.arrowColor) {\r\n\t\t\tlet arrowColor = this.options.arrowColor.toString();\r\n\t\t\tthis._arrow.color = arrowColor;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _getWidth(info: EditorLayoutInfo): number {\r\n\t\treturn info.width - info.minimap.minimapWidth - info.verticalScrollbarWidth;\r\n\t}\r\n\r\n\tprivate _getLeft(info: EditorLayoutInfo): number {\r\n\t\t// If minimap is to the left, we move beyond it\r\n\t\tif (info.minimap.minimapWidth > 0 && info.minimap.minimapLeft === 0) {\r\n\t\t\treturn info.minimap.minimapWidth;\r\n\t\t}\r\n\t\treturn 0;\r\n\t}\r\n\r\n\tprivate _onViewZoneTop(top: number): void {\r\n\t\tthis.domNode.style.top = top + 'px';\r\n\t}\r\n\r\n\tprivate _onViewZoneHeight(height: number): void {\r\n\t\tthis.domNode.style.height = `${height}px`;\r\n\r\n\t\tif (this.container) {\r\n\t\t\tlet containerHeight = height - this._decoratingElementsHeight();\r\n\t\t\tthis.container.style.height = `${containerHeight}px`;\r\n\t\t\tconst layoutInfo = this.editor.getLayoutInfo();\r\n\t\t\tthis._doLayout(containerHeight, this._getWidth(layoutInfo));\r\n\t\t}\r\n\r\n\t\tif (this._resizeSash) {\r\n\t\t\tthis._resizeSash.layout();\r\n\t\t}\r\n\t}\r\n\r\n\tget position(): Position | undefined {\r\n\t\tconst [id] = this._positionMarkerId;\r\n\t\tif (!id) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\r\n\t\tconst model = this.editor.getModel();\r\n\t\tif (!model) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\r\n\t\tconst range = model.getDecorationRange(id);\r\n\t\tif (!range) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\t\treturn range.getStartPosition();\r\n\t}\r\n\r\n\tprotected _isShowing: boolean = false;\r\n\r\n\tshow(rangeOrPos: IRange | IPosition, heightInLines: number): void {\r\n\t\tconst range = Range.isIRange(rangeOrPos) ? Range.lift(rangeOrPos) : Range.fromPositions(rangeOrPos);\r\n\t\tthis._isShowing = true;\r\n\t\tthis._showImpl(range, heightInLines);\r\n\t\tthis._isShowing = false;\r\n\t\tthis._positionMarkerId = this.editor.deltaDecorations(this._positionMarkerId, [{ range, options: ModelDecorationOptions.EMPTY }]);\r\n\t}\r\n\r\n\thide(): void {\r\n\t\tif (this._viewZone) {\r\n\t\t\tthis.editor.changeViewZones(accessor => {\r\n\t\t\t\tif (this._viewZone) {\r\n\t\t\t\t\taccessor.removeZone(this._viewZone.id);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t\tthis._viewZone = null;\r\n\t\t}\r\n\t\tif (this._overlayWidget) {\r\n\t\t\tthis.editor.removeOverlayWidget(this._overlayWidget);\r\n\t\t\tthis._overlayWidget = null;\r\n\t\t}\r\n\t\tif (this._arrow) {\r\n\t\t\tthis._arrow.hide();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _decoratingElementsHeight(): number {\r\n\t\tlet lineHeight = this.editor.getOption(EditorOption.lineHeight);\r\n\t\tlet result = 0;\r\n\r\n\t\tif (this.options.showArrow) {\r\n\t\t\tlet arrowHeight = Math.round(lineHeight / 3);\r\n\t\t\tresult += 2 * arrowHeight;\r\n\t\t}\r\n\r\n\t\tif (this.options.showFrame) {\r\n\t\t\tlet frameThickness = Math.round(lineHeight / 9);\r\n\t\t\tresult += 2 * frameThickness;\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate _showImpl(where: Range, heightInLines: number): void {\r\n\t\tconst position = where.getStartPosition();\r\n\t\tconst layoutInfo = this.editor.getLayoutInfo();\r\n\t\tconst width = this._getWidth(layoutInfo);\r\n\t\tthis.domNode.style.width = `${width}px`;\r\n\t\tthis.domNode.style.left = this._getLeft(layoutInfo) + 'px';\r\n\r\n\t\t// Render the widget as zone (rendering) and widget (lifecycle)\r\n\t\tconst viewZoneDomNode = document.createElement('div');\r\n\t\tviewZoneDomNode.style.overflow = 'hidden';\r\n\t\tconst lineHeight = this.editor.getOption(EditorOption.lineHeight);\r\n\r\n\t\t// adjust heightInLines to viewport\r\n\t\tconst maxHeightInLines = Math.max(12, (this.editor.getLayoutInfo().height / lineHeight) * 0.8);\r\n\t\theightInLines = Math.min(heightInLines, maxHeightInLines);\r\n\r\n\t\tlet arrowHeight = 0;\r\n\t\tlet frameThickness = 0;\r\n\r\n\t\t// Render the arrow one 1/3 of an editor line height\r\n\t\tif (this._arrow && this.options.showArrow) {\r\n\t\t\tarrowHeight = Math.round(lineHeight / 3);\r\n\t\t\tthis._arrow.height = arrowHeight;\r\n\t\t\tthis._arrow.show(position);\r\n\t\t}\r\n\r\n\t\t// Render the frame as 1/9 of an editor line height\r\n\t\tif (this.options.showFrame) {\r\n\t\t\tframeThickness = Math.round(lineHeight / 9);\r\n\t\t}\r\n\r\n\t\t// insert zone widget\r\n\t\tthis.editor.changeViewZones((accessor: IViewZoneChangeAccessor) => {\r\n\t\t\tif (this._viewZone) {\r\n\t\t\t\taccessor.removeZone(this._viewZone.id);\r\n\t\t\t}\r\n\t\t\tif (this._overlayWidget) {\r\n\t\t\t\tthis.editor.removeOverlayWidget(this._overlayWidget);\r\n\t\t\t\tthis._overlayWidget = null;\r\n\t\t\t}\r\n\t\t\tthis.domNode.style.top = '-1000px';\r\n\t\t\tthis._viewZone = new ViewZoneDelegate(\r\n\t\t\t\tviewZoneDomNode,\r\n\t\t\t\tposition.lineNumber,\r\n\t\t\t\tposition.column,\r\n\t\t\t\theightInLines,\r\n\t\t\t\t(top: number) => this._onViewZoneTop(top),\r\n\t\t\t\t(height: number) => this._onViewZoneHeight(height)\r\n\t\t\t);\r\n\t\t\tthis._viewZone.id = accessor.addZone(this._viewZone);\r\n\t\t\tthis._overlayWidget = new OverlayWidgetDelegate(WIDGET_ID + this._viewZone.id, this.domNode);\r\n\t\t\tthis.editor.addOverlayWidget(this._overlayWidget);\r\n\t\t});\r\n\r\n\t\tif (this.container && this.options.showFrame) {\r\n\t\t\tconst width = this.options.frameWidth ? this.options.frameWidth : frameThickness;\r\n\t\t\tthis.container.style.borderTopWidth = width + 'px';\r\n\t\t\tthis.container.style.borderBottomWidth = width + 'px';\r\n\t\t}\r\n\r\n\t\tlet containerHeight = heightInLines * lineHeight - this._decoratingElementsHeight();\r\n\r\n\t\tif (this.container) {\r\n\t\t\tthis.container.style.top = arrowHeight + 'px';\r\n\t\t\tthis.container.style.height = containerHeight + 'px';\r\n\t\t\tthis.container.style.overflow = 'hidden';\r\n\t\t}\r\n\r\n\t\tthis._doLayout(containerHeight, width);\r\n\r\n\t\tif (!this.options.keepEditorSelection) {\r\n\t\t\tthis.editor.setSelection(where);\r\n\t\t}\r\n\r\n\t\tconst model = this.editor.getModel();\r\n\t\tif (model) {\r\n\t\t\tconst revealLine = where.endLineNumber + 1;\r\n\t\t\tif (revealLine <= model.getLineCount()) {\r\n\t\t\t\t// reveal line below the zone widget\r\n\t\t\t\tthis.revealLine(revealLine, false);\r\n\t\t\t} else {\r\n\t\t\t\t// reveal last line atop\r\n\t\t\t\tthis.revealLine(model.getLineCount(), true);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprotected revealLine(lineNumber: number, isLastLine: boolean) {\r\n\t\tif (isLastLine) {\r\n\t\t\tthis.editor.revealLineInCenter(lineNumber, ScrollType.Smooth);\r\n\t\t} else {\r\n\t\t\tthis.editor.revealLine(lineNumber, ScrollType.Smooth);\r\n\t\t}\r\n\t}\r\n\r\n\tprotected setCssClass(className: string, classToReplace?: string): void {\r\n\t\tif (!this.container) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (classToReplace) {\r\n\t\t\tthis.container.classList.remove(classToReplace);\r\n\t\t}\r\n\r\n\t\tthis.container.classList.add(className);\r\n\r\n\t}\r\n\r\n\tprotected abstract _fillContainer(container: HTMLElement): void;\r\n\r\n\tprotected _onWidth(widthInPixel: number): void {\r\n\t\t// implement in subclass\r\n\t}\r\n\r\n\tprotected _doLayout(heightInPixel: number, widthInPixel: number): void {\r\n\t\t// implement in subclass\r\n\t}\r\n\r\n\tprotected _relayout(newHeightInLines: number): void {\r\n\t\tif (this._viewZone && this._viewZone.heightInLines !== newHeightInLines) {\r\n\t\t\tthis.editor.changeViewZones(accessor => {\r\n\t\t\t\tif (this._viewZone) {\r\n\t\t\t\t\tthis._viewZone.heightInLines = newHeightInLines;\r\n\t\t\t\t\taccessor.layoutZone(this._viewZone.id);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\t// --- sash\r\n\r\n\tprivate _initSash(): void {\r\n\t\tif (this._resizeSash) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._resizeSash = this._disposables.add(new Sash(this.domNode, this, { orientation: Orientation.HORIZONTAL }));\r\n\r\n\t\tif (!this.options.isResizeable) {\r\n\t\t\tthis._resizeSash.hide();\r\n\t\t\tthis._resizeSash.state = SashState.Disabled;\r\n\t\t}\r\n\r\n\t\tlet data: { startY: number; heightInLines: number; } | undefined;\r\n\t\tthis._disposables.add(this._resizeSash.onDidStart((e: ISashEvent) => {\r\n\t\t\tif (this._viewZone) {\r\n\t\t\t\tdata = {\r\n\t\t\t\t\tstartY: e.startY,\r\n\t\t\t\t\theightInLines: this._viewZone.heightInLines,\r\n\t\t\t\t};\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._disposables.add(this._resizeSash.onDidEnd(() => {\r\n\t\t\tdata = undefined;\r\n\t\t}));\r\n\r\n\t\tthis._disposables.add(this._resizeSash.onDidChange((evt: ISashEvent) => {\r\n\t\t\tif (data) {\r\n\t\t\t\tlet lineDelta = (evt.currentY - data.startY) / this.editor.getOption(EditorOption.lineHeight);\r\n\t\t\t\tlet roundedLineDelta = lineDelta < 0 ? Math.ceil(lineDelta) : Math.floor(lineDelta);\r\n\t\t\t\tlet newHeightInLines = data.heightInLines + roundedLineDelta;\r\n\r\n\t\t\t\tif (newHeightInLines > 5 && newHeightInLines < 35) {\r\n\t\t\t\t\tthis._relayout(newHeightInLines);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\tgetHorizontalSashLeft() {\r\n\t\treturn 0;\r\n\t}\r\n\r\n\tgetHorizontalSashTop() {\r\n\t\treturn (this.domNode.style.height === null ? 0 : parseInt(this.domNode.style.height)) - (this._decoratingElementsHeight() / 2);\r\n\t}\r\n\r\n\tgetHorizontalSashWidth() {\r\n\t\tconst layoutInfo = this.editor.getLayoutInfo();\r\n\t\treturn layoutInfo.width - layoutInfo.minimap.minimapWidth;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\n/**\r\n * Create a syntax highighter with a fully declarative JSON style lexer description\r\n * using regular expressions.\r\n */\r\n\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { Token, TokenizationResult, TokenizationResult2 } from 'vs/editor/common/core/token';\r\nimport * as modes from 'vs/editor/common/modes';\r\nimport { NULL_MODE_ID, NULL_STATE } from 'vs/editor/common/modes/nullMode';\r\nimport { TokenTheme } from 'vs/editor/common/modes/supports/tokenization';\r\nimport { IModeService } from 'vs/editor/common/services/modeService';\r\nimport * as monarchCommon from 'vs/editor/standalone/common/monarch/monarchCommon';\r\nimport { IStandaloneThemeService } from 'vs/editor/standalone/common/standaloneThemeService';\r\n\r\nconst CACHE_STACK_DEPTH = 5;\r\n\r\n/**\r\n * Reuse the same stack elements up to a certain depth.\r\n */\r\nclass MonarchStackElementFactory {\r\n\r\n\tprivate static readonly _INSTANCE = new MonarchStackElementFactory(CACHE_STACK_DEPTH);\r\n\tpublic static create(parent: MonarchStackElement | null, state: string): MonarchStackElement {\r\n\t\treturn this._INSTANCE.create(parent, state);\r\n\t}\r\n\r\n\tprivate readonly _maxCacheDepth: number;\r\n\tprivate readonly _entries: { [stackElementId: string]: MonarchStackElement; };\r\n\r\n\tconstructor(maxCacheDepth: number) {\r\n\t\tthis._maxCacheDepth = maxCacheDepth;\r\n\t\tthis._entries = Object.create(null);\r\n\t}\r\n\r\n\tpublic create(parent: MonarchStackElement | null, state: string): MonarchStackElement {\r\n\t\tif (parent !== null && parent.depth >= this._maxCacheDepth) {\r\n\t\t\t// no caching above a certain depth\r\n\t\t\treturn new MonarchStackElement(parent, state);\r\n\t\t}\r\n\t\tlet stackElementId = MonarchStackElement.getStackElementId(parent);\r\n\t\tif (stackElementId.length > 0) {\r\n\t\t\tstackElementId += '|';\r\n\t\t}\r\n\t\tstackElementId += state;\r\n\r\n\t\tlet result = this._entries[stackElementId];\r\n\t\tif (result) {\r\n\t\t\treturn result;\r\n\t\t}\r\n\t\tresult = new MonarchStackElement(parent, state);\r\n\t\tthis._entries[stackElementId] = result;\r\n\t\treturn result;\r\n\t}\r\n}\r\n\r\nclass MonarchStackElement {\r\n\r\n\tpublic readonly parent: MonarchStackElement | null;\r\n\tpublic readonly state: string;\r\n\tpublic readonly depth: number;\r\n\r\n\tconstructor(parent: MonarchStackElement | null, state: string) {\r\n\t\tthis.parent = parent;\r\n\t\tthis.state = state;\r\n\t\tthis.depth = (this.parent ? this.parent.depth : 0) + 1;\r\n\t}\r\n\r\n\tpublic static getStackElementId(element: MonarchStackElement | null): string {\r\n\t\tlet result = '';\r\n\t\twhile (element !== null) {\r\n\t\t\tif (result.length > 0) {\r\n\t\t\t\tresult += '|';\r\n\t\t\t}\r\n\t\t\tresult += element.state;\r\n\t\t\telement = element.parent;\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _equals(a: MonarchStackElement | null, b: MonarchStackElement | null): boolean {\r\n\t\twhile (a !== null && b !== null) {\r\n\t\t\tif (a === b) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t\tif (a.state !== b.state) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t\ta = a.parent;\r\n\t\t\tb = b.parent;\r\n\t\t}\r\n\t\tif (a === null && b === null) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic equals(other: MonarchStackElement): boolean {\r\n\t\treturn MonarchStackElement._equals(this, other);\r\n\t}\r\n\r\n\tpublic push(state: string): MonarchStackElement {\r\n\t\treturn MonarchStackElementFactory.create(this, state);\r\n\t}\r\n\r\n\tpublic pop(): MonarchStackElement | null {\r\n\t\treturn this.parent;\r\n\t}\r\n\r\n\tpublic popall(): MonarchStackElement {\r\n\t\tlet result: MonarchStackElement = this;\r\n\t\twhile (result.parent) {\r\n\t\t\tresult = result.parent;\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic switchTo(state: string): MonarchStackElement {\r\n\t\treturn MonarchStackElementFactory.create(this.parent, state);\r\n\t}\r\n}\r\n\r\nclass EmbeddedModeData {\r\n\tpublic readonly modeId: string;\r\n\tpublic readonly state: modes.IState;\r\n\r\n\tconstructor(modeId: string, state: modes.IState) {\r\n\t\tthis.modeId = modeId;\r\n\t\tthis.state = state;\r\n\t}\r\n\r\n\tpublic equals(other: EmbeddedModeData): boolean {\r\n\t\treturn (\r\n\t\t\tthis.modeId === other.modeId\r\n\t\t\t&& this.state.equals(other.state)\r\n\t\t);\r\n\t}\r\n\r\n\tpublic clone(): EmbeddedModeData {\r\n\t\tlet stateClone = this.state.clone();\r\n\t\t// save an object\r\n\t\tif (stateClone === this.state) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\treturn new EmbeddedModeData(this.modeId, this.state);\r\n\t}\r\n}\r\n\r\n/**\r\n * Reuse the same line states up to a certain depth.\r\n */\r\nclass MonarchLineStateFactory {\r\n\r\n\tprivate static readonly _INSTANCE = new MonarchLineStateFactory(CACHE_STACK_DEPTH);\r\n\tpublic static create(stack: MonarchStackElement, embeddedModeData: EmbeddedModeData | null): MonarchLineState {\r\n\t\treturn this._INSTANCE.create(stack, embeddedModeData);\r\n\t}\r\n\r\n\tprivate readonly _maxCacheDepth: number;\r\n\tprivate readonly _entries: { [stackElementId: string]: MonarchLineState; };\r\n\r\n\tconstructor(maxCacheDepth: number) {\r\n\t\tthis._maxCacheDepth = maxCacheDepth;\r\n\t\tthis._entries = Object.create(null);\r\n\t}\r\n\r\n\tpublic create(stack: MonarchStackElement, embeddedModeData: EmbeddedModeData | null): MonarchLineState {\r\n\t\tif (embeddedModeData !== null) {\r\n\t\t\t// no caching when embedding\r\n\t\t\treturn new MonarchLineState(stack, embeddedModeData);\r\n\t\t}\r\n\t\tif (stack !== null && stack.depth >= this._maxCacheDepth) {\r\n\t\t\t// no caching above a certain depth\r\n\t\t\treturn new MonarchLineState(stack, embeddedModeData);\r\n\t\t}\r\n\t\tlet stackElementId = MonarchStackElement.getStackElementId(stack);\r\n\r\n\t\tlet result = this._entries[stackElementId];\r\n\t\tif (result) {\r\n\t\t\treturn result;\r\n\t\t}\r\n\t\tresult = new MonarchLineState(stack, null);\r\n\t\tthis._entries[stackElementId] = result;\r\n\t\treturn result;\r\n\t}\r\n}\r\n\r\nclass MonarchLineState implements modes.IState {\r\n\r\n\tpublic readonly stack: MonarchStackElement;\r\n\tpublic readonly embeddedModeData: EmbeddedModeData | null;\r\n\r\n\tconstructor(\r\n\t\tstack: MonarchStackElement,\r\n\t\tembeddedModeData: EmbeddedModeData | null\r\n\t) {\r\n\t\tthis.stack = stack;\r\n\t\tthis.embeddedModeData = embeddedModeData;\r\n\t}\r\n\r\n\tpublic clone(): modes.IState {\r\n\t\tlet embeddedModeDataClone = this.embeddedModeData ? this.embeddedModeData.clone() : null;\r\n\t\t// save an object\r\n\t\tif (embeddedModeDataClone === this.embeddedModeData) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\treturn MonarchLineStateFactory.create(this.stack, this.embeddedModeData);\r\n\t}\r\n\r\n\tpublic equals(other: modes.IState): boolean {\r\n\t\tif (!(other instanceof MonarchLineState)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (!this.stack.equals(other.stack)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (this.embeddedModeData === null && other.embeddedModeData === null) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (this.embeddedModeData === null || other.embeddedModeData === null) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn this.embeddedModeData.equals(other.embeddedModeData);\r\n\t}\r\n}\r\n\r\ninterface IMonarchTokensCollector {\r\n\tenterMode(startOffset: number, modeId: string): void;\r\n\temit(startOffset: number, type: string): void;\r\n\tnestedModeTokenize(embeddedModeLine: string, hasEOL: boolean, embeddedModeData: EmbeddedModeData, offsetDelta: number): modes.IState;\r\n}\r\n\r\nclass MonarchClassicTokensCollector implements IMonarchTokensCollector {\r\n\r\n\tprivate _tokens: Token[];\r\n\tprivate _language: string | null;\r\n\tprivate _lastTokenType: string | null;\r\n\tprivate _lastTokenLanguage: string | null;\r\n\r\n\tconstructor() {\r\n\t\tthis._tokens = [];\r\n\t\tthis._language = null;\r\n\t\tthis._lastTokenType = null;\r\n\t\tthis._lastTokenLanguage = null;\r\n\t}\r\n\r\n\tpublic enterMode(startOffset: number, modeId: string): void {\r\n\t\tthis._language = modeId;\r\n\t}\r\n\r\n\tpublic emit(startOffset: number, type: string): void {\r\n\t\tif (this._lastTokenType === type && this._lastTokenLanguage === this._language) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._lastTokenType = type;\r\n\t\tthis._lastTokenLanguage = this._language;\r\n\t\tthis._tokens.push(new Token(startOffset, type, this._language!));\r\n\t}\r\n\r\n\tpublic nestedModeTokenize(embeddedModeLine: string, hasEOL: boolean, embeddedModeData: EmbeddedModeData, offsetDelta: number): modes.IState {\r\n\t\tconst nestedModeId = embeddedModeData.modeId;\r\n\t\tconst embeddedModeState = embeddedModeData.state;\r\n\r\n\t\tconst nestedModeTokenizationSupport = modes.TokenizationRegistry.get(nestedModeId);\r\n\t\tif (!nestedModeTokenizationSupport) {\r\n\t\t\tthis.enterMode(offsetDelta, nestedModeId);\r\n\t\t\tthis.emit(offsetDelta, '');\r\n\t\t\treturn embeddedModeState;\r\n\t\t}\r\n\r\n\t\tlet nestedResult = nestedModeTokenizationSupport.tokenize(embeddedModeLine, hasEOL, embeddedModeState, offsetDelta);\r\n\t\tthis._tokens = this._tokens.concat(nestedResult.tokens);\r\n\t\tthis._lastTokenType = null;\r\n\t\tthis._lastTokenLanguage = null;\r\n\t\tthis._language = null;\r\n\t\treturn nestedResult.endState;\r\n\t}\r\n\r\n\tpublic finalize(endState: MonarchLineState): TokenizationResult {\r\n\t\treturn new TokenizationResult(this._tokens, endState);\r\n\t}\r\n}\r\n\r\nclass MonarchModernTokensCollector implements IMonarchTokensCollector {\r\n\r\n\tprivate readonly _modeService: IModeService;\r\n\tprivate readonly _theme: TokenTheme;\r\n\tprivate _prependTokens: Uint32Array | null;\r\n\tprivate _tokens: number[];\r\n\tprivate _currentLanguageId: modes.LanguageId;\r\n\tprivate _lastTokenMetadata: number;\r\n\r\n\tconstructor(modeService: IModeService, theme: TokenTheme) {\r\n\t\tthis._modeService = modeService;\r\n\t\tthis._theme = theme;\r\n\t\tthis._prependTokens = null;\r\n\t\tthis._tokens = [];\r\n\t\tthis._currentLanguageId = modes.LanguageId.Null;\r\n\t\tthis._lastTokenMetadata = 0;\r\n\t}\r\n\r\n\tpublic enterMode(startOffset: number, modeId: string): void {\r\n\t\tthis._currentLanguageId = this._modeService.getLanguageIdentifier(modeId)!.id;\r\n\t}\r\n\r\n\tpublic emit(startOffset: number, type: string): void {\r\n\t\tlet metadata = this._theme.match(this._currentLanguageId, type);\r\n\t\tif (this._lastTokenMetadata === metadata) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._lastTokenMetadata = metadata;\r\n\t\tthis._tokens.push(startOffset);\r\n\t\tthis._tokens.push(metadata);\r\n\t}\r\n\r\n\tprivate static _merge(a: Uint32Array | null, b: number[], c: Uint32Array | null): Uint32Array {\r\n\t\tlet aLen = (a !== null ? a.length : 0);\r\n\t\tlet bLen = b.length;\r\n\t\tlet cLen = (c !== null ? c.length : 0);\r\n\r\n\t\tif (aLen === 0 && bLen === 0 && cLen === 0) {\r\n\t\t\treturn new Uint32Array(0);\r\n\t\t}\r\n\t\tif (aLen === 0 && bLen === 0) {\r\n\t\t\treturn c!;\r\n\t\t}\r\n\t\tif (bLen === 0 && cLen === 0) {\r\n\t\t\treturn a!;\r\n\t\t}\r\n\r\n\t\tlet result = new Uint32Array(aLen + bLen + cLen);\r\n\t\tif (a !== null) {\r\n\t\t\tresult.set(a);\r\n\t\t}\r\n\t\tfor (let i = 0; i < bLen; i++) {\r\n\t\t\tresult[aLen + i] = b[i];\r\n\t\t}\r\n\t\tif (c !== null) {\r\n\t\t\tresult.set(c, aLen + bLen);\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic nestedModeTokenize(embeddedModeLine: string, hasEOL: boolean, embeddedModeData: EmbeddedModeData, offsetDelta: number): modes.IState {\r\n\t\tconst nestedModeId = embeddedModeData.modeId;\r\n\t\tconst embeddedModeState = embeddedModeData.state;\r\n\r\n\t\tconst nestedModeTokenizationSupport = modes.TokenizationRegistry.get(nestedModeId);\r\n\t\tif (!nestedModeTokenizationSupport) {\r\n\t\t\tthis.enterMode(offsetDelta, nestedModeId);\r\n\t\t\tthis.emit(offsetDelta, '');\r\n\t\t\treturn embeddedModeState;\r\n\t\t}\r\n\r\n\t\tlet nestedResult = nestedModeTokenizationSupport.tokenize2(embeddedModeLine, hasEOL, embeddedModeState, offsetDelta);\r\n\t\tthis._prependTokens = MonarchModernTokensCollector._merge(this._prependTokens, this._tokens, nestedResult.tokens);\r\n\t\tthis._tokens = [];\r\n\t\tthis._currentLanguageId = 0;\r\n\t\tthis._lastTokenMetadata = 0;\r\n\t\treturn nestedResult.endState;\r\n\t}\r\n\r\n\tpublic finalize(endState: MonarchLineState): TokenizationResult2 {\r\n\t\treturn new TokenizationResult2(\r\n\t\t\tMonarchModernTokensCollector._merge(this._prependTokens, this._tokens, null),\r\n\t\t\tendState\r\n\t\t);\r\n\t}\r\n}\r\n\r\nexport type ILoadStatus = { loaded: true; } | { loaded: false; promise: Promise; };\r\n\r\nexport class MonarchTokenizer implements modes.ITokenizationSupport {\r\n\r\n\tprivate readonly _modeService: IModeService;\r\n\tprivate readonly _standaloneThemeService: IStandaloneThemeService;\r\n\tprivate readonly _modeId: string;\r\n\tprivate readonly _lexer: monarchCommon.ILexer;\r\n\tprivate readonly _embeddedModes: { [modeId: string]: boolean; };\r\n\tpublic embeddedLoaded: Promise;\r\n\tprivate readonly _tokenizationRegistryListener: IDisposable;\r\n\r\n\tconstructor(modeService: IModeService, standaloneThemeService: IStandaloneThemeService, modeId: string, lexer: monarchCommon.ILexer) {\r\n\t\tthis._modeService = modeService;\r\n\t\tthis._standaloneThemeService = standaloneThemeService;\r\n\t\tthis._modeId = modeId;\r\n\t\tthis._lexer = lexer;\r\n\t\tthis._embeddedModes = Object.create(null);\r\n\t\tthis.embeddedLoaded = Promise.resolve(undefined);\r\n\r\n\t\t// Set up listening for embedded modes\r\n\t\tlet emitting = false;\r\n\t\tthis._tokenizationRegistryListener = modes.TokenizationRegistry.onDidChange((e) => {\r\n\t\t\tif (emitting) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tlet isOneOfMyEmbeddedModes = false;\r\n\t\t\tfor (let i = 0, len = e.changedLanguages.length; i < len; i++) {\r\n\t\t\t\tlet language = e.changedLanguages[i];\r\n\t\t\t\tif (this._embeddedModes[language]) {\r\n\t\t\t\t\tisOneOfMyEmbeddedModes = true;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (isOneOfMyEmbeddedModes) {\r\n\t\t\t\temitting = true;\r\n\t\t\t\tmodes.TokenizationRegistry.fire([this._modeId]);\r\n\t\t\t\temitting = false;\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._tokenizationRegistryListener.dispose();\r\n\t}\r\n\r\n\tpublic getLoadStatus(): ILoadStatus {\r\n\t\tlet promises: Thenable[] = [];\r\n\t\tfor (let nestedModeId in this._embeddedModes) {\r\n\t\t\tconst tokenizationSupport = modes.TokenizationRegistry.get(nestedModeId);\r\n\t\t\tif (tokenizationSupport) {\r\n\t\t\t\t// The nested mode is already loaded\r\n\t\t\t\tif (tokenizationSupport instanceof MonarchTokenizer) {\r\n\t\t\t\t\tconst nestedModeStatus = tokenizationSupport.getLoadStatus();\r\n\t\t\t\t\tif (nestedModeStatus.loaded === false) {\r\n\t\t\t\t\t\tpromises.push(nestedModeStatus.promise);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tconst tokenizationSupportPromise = modes.TokenizationRegistry.getPromise(nestedModeId);\r\n\t\t\tif (tokenizationSupportPromise) {\r\n\t\t\t\t// The nested mode is in the process of being loaded\r\n\t\t\t\tpromises.push(tokenizationSupportPromise);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (promises.length === 0) {\r\n\t\t\treturn {\r\n\t\t\t\tloaded: true\r\n\t\t\t};\r\n\t\t}\r\n\t\treturn {\r\n\t\t\tloaded: false,\r\n\t\t\tpromise: Promise.all(promises).then(_ => undefined)\r\n\t\t};\r\n\t}\r\n\r\n\tpublic getInitialState(): modes.IState {\r\n\t\tlet rootState = MonarchStackElementFactory.create(null, this._lexer.start!);\r\n\t\treturn MonarchLineStateFactory.create(rootState, null);\r\n\t}\r\n\r\n\tpublic tokenize(line: string, hasEOL: boolean, lineState: modes.IState, offsetDelta: number): TokenizationResult {\r\n\t\tlet tokensCollector = new MonarchClassicTokensCollector();\r\n\t\tlet endLineState = this._tokenize(line, hasEOL, lineState, offsetDelta, tokensCollector);\r\n\t\treturn tokensCollector.finalize(endLineState);\r\n\t}\r\n\r\n\tpublic tokenize2(line: string, hasEOL: boolean, lineState: modes.IState, offsetDelta: number): TokenizationResult2 {\r\n\t\tlet tokensCollector = new MonarchModernTokensCollector(this._modeService, this._standaloneThemeService.getColorTheme().tokenTheme);\r\n\t\tlet endLineState = this._tokenize(line, hasEOL, lineState, offsetDelta, tokensCollector);\r\n\t\treturn tokensCollector.finalize(endLineState);\r\n\t}\r\n\r\n\tprivate _tokenize(line: string, hasEOL: boolean, lineState: MonarchLineState, offsetDelta: number, collector: IMonarchTokensCollector): MonarchLineState {\r\n\t\tif (lineState.embeddedModeData) {\r\n\t\t\treturn this._nestedTokenize(line, hasEOL, lineState, offsetDelta, collector);\r\n\t\t} else {\r\n\t\t\treturn this._myTokenize(line, hasEOL, lineState, offsetDelta, collector);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _findLeavingNestedModeOffset(line: string, state: MonarchLineState): number {\r\n\t\tlet rules: monarchCommon.IRule[] | null = this._lexer.tokenizer[state.stack.state];\r\n\t\tif (!rules) {\r\n\t\t\trules = monarchCommon.findRules(this._lexer, state.stack.state); // do parent matching\r\n\t\t\tif (!rules) {\r\n\t\t\t\tthrow monarchCommon.createError(this._lexer, 'tokenizer state is not defined: ' + state.stack.state);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet popOffset = -1;\r\n\t\tlet hasEmbeddedPopRule = false;\r\n\r\n\t\tfor (const rule of rules) {\r\n\t\t\tif (!monarchCommon.isIAction(rule.action) || rule.action.nextEmbedded !== '@pop') {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\thasEmbeddedPopRule = true;\r\n\r\n\t\t\tlet regex = rule.regex;\r\n\t\t\tlet regexSource = rule.regex.source;\r\n\t\t\tif (regexSource.substr(0, 4) === '^(?:' && regexSource.substr(regexSource.length - 1, 1) === ')') {\r\n\t\t\t\tlet flags = (regex.ignoreCase ? 'i' : '') + (regex.unicode ? 'u' : '');\r\n\t\t\t\tregex = new RegExp(regexSource.substr(4, regexSource.length - 5), flags);\r\n\t\t\t}\r\n\r\n\t\t\tlet result = line.search(regex);\r\n\t\t\tif (result === -1 || (result !== 0 && rule.matchOnlyAtLineStart)) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (popOffset === -1 || result < popOffset) {\r\n\t\t\t\tpopOffset = result;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!hasEmbeddedPopRule) {\r\n\t\t\tthrow monarchCommon.createError(this._lexer, 'no rule containing nextEmbedded: \"@pop\" in tokenizer embedded state: ' + state.stack.state);\r\n\t\t}\r\n\r\n\t\treturn popOffset;\r\n\t}\r\n\r\n\tprivate _nestedTokenize(line: string, hasEOL: boolean, lineState: MonarchLineState, offsetDelta: number, tokensCollector: IMonarchTokensCollector): MonarchLineState {\r\n\r\n\t\tlet popOffset = this._findLeavingNestedModeOffset(line, lineState);\r\n\r\n\t\tif (popOffset === -1) {\r\n\t\t\t// tokenization will not leave nested mode\r\n\t\t\tlet nestedEndState = tokensCollector.nestedModeTokenize(line, hasEOL, lineState.embeddedModeData!, offsetDelta);\r\n\t\t\treturn MonarchLineStateFactory.create(lineState.stack, new EmbeddedModeData(lineState.embeddedModeData!.modeId, nestedEndState));\r\n\t\t}\r\n\r\n\t\tlet nestedModeLine = line.substring(0, popOffset);\r\n\t\tif (nestedModeLine.length > 0) {\r\n\t\t\t// tokenize with the nested mode\r\n\t\t\ttokensCollector.nestedModeTokenize(nestedModeLine, false, lineState.embeddedModeData!, offsetDelta);\r\n\t\t}\r\n\r\n\t\tlet restOfTheLine = line.substring(popOffset);\r\n\t\treturn this._myTokenize(restOfTheLine, hasEOL, lineState, offsetDelta + popOffset, tokensCollector);\r\n\t}\r\n\r\n\tprivate _safeRuleName(rule: monarchCommon.IRule | null): string {\r\n\t\tif (rule) {\r\n\t\t\treturn rule.name;\r\n\t\t}\r\n\t\treturn '(unknown)';\r\n\t}\r\n\r\n\tprivate _myTokenize(lineWithoutLF: string, hasEOL: boolean, lineState: MonarchLineState, offsetDelta: number, tokensCollector: IMonarchTokensCollector): MonarchLineState {\r\n\t\ttokensCollector.enterMode(offsetDelta, this._modeId);\r\n\r\n\t\tconst lineWithoutLFLength = lineWithoutLF.length;\r\n\t\tconst line = (hasEOL && this._lexer.includeLF ? lineWithoutLF + '\\n' : lineWithoutLF);\r\n\t\tconst lineLength = line.length;\r\n\r\n\t\tlet embeddedModeData = lineState.embeddedModeData;\r\n\t\tlet stack = lineState.stack;\r\n\t\tlet pos = 0;\r\n\r\n\t\t// regular expression group matching\r\n\t\t// these never need cloning or equality since they are only used within a line match\r\n\t\tinterface GroupMatching {\r\n\t\t\tmatches: string[];\r\n\t\t\trule: monarchCommon.IRule | null;\r\n\t\t\tgroups: { action: monarchCommon.FuzzyAction; matched: string; }[];\r\n\t\t}\r\n\t\tlet groupMatching: GroupMatching | null = null;\r\n\r\n\t\t// See https://github.com/microsoft/monaco-editor/issues/1235\r\n\t\t// Evaluate rules at least once for an empty line\r\n\t\tlet forceEvaluation = true;\r\n\r\n\t\twhile (forceEvaluation || pos < lineLength) {\r\n\r\n\t\t\tconst pos0 = pos;\r\n\t\t\tconst stackLen0 = stack.depth;\r\n\t\t\tconst groupLen0 = groupMatching ? groupMatching.groups.length : 0;\r\n\t\t\tconst state = stack.state;\r\n\r\n\t\t\tlet matches: string[] | null = null;\r\n\t\t\tlet matched: string | null = null;\r\n\t\t\tlet action: monarchCommon.FuzzyAction | monarchCommon.FuzzyAction[] | null = null;\r\n\t\t\tlet rule: monarchCommon.IRule | null = null;\r\n\r\n\t\t\tlet enteringEmbeddedMode: string | null = null;\r\n\r\n\t\t\t// check if we need to process group matches first\r\n\t\t\tif (groupMatching) {\r\n\t\t\t\tmatches = groupMatching.matches;\r\n\t\t\t\tconst groupEntry = groupMatching.groups.shift()!;\r\n\t\t\t\tmatched = groupEntry.matched;\r\n\t\t\t\taction = groupEntry.action;\r\n\t\t\t\trule = groupMatching.rule;\r\n\r\n\t\t\t\t// cleanup if necessary\r\n\t\t\t\tif (groupMatching.groups.length === 0) {\r\n\t\t\t\t\tgroupMatching = null;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\t// otherwise we match on the token stream\r\n\r\n\t\t\t\tif (!forceEvaluation && pos >= lineLength) {\r\n\t\t\t\t\t// nothing to do\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tforceEvaluation = false;\r\n\r\n\t\t\t\t// get the rules for this state\r\n\t\t\t\tlet rules: monarchCommon.IRule[] | null = this._lexer.tokenizer[state];\r\n\t\t\t\tif (!rules) {\r\n\t\t\t\t\trules = monarchCommon.findRules(this._lexer, state); // do parent matching\r\n\t\t\t\t\tif (!rules) {\r\n\t\t\t\t\t\tthrow monarchCommon.createError(this._lexer, 'tokenizer state is not defined: ' + state);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// try each rule until we match\r\n\t\t\t\tlet restOfLine = line.substr(pos);\r\n\t\t\t\tfor (const rule of rules) {\r\n\t\t\t\t\tif (pos === 0 || !rule.matchOnlyAtLineStart) {\r\n\t\t\t\t\t\tmatches = restOfLine.match(rule.regex);\r\n\t\t\t\t\t\tif (matches) {\r\n\t\t\t\t\t\t\tmatched = matches[0];\r\n\t\t\t\t\t\t\taction = rule.action;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// We matched 'rule' with 'matches' and 'action'\r\n\t\t\tif (!matches) {\r\n\t\t\t\tmatches = [''];\r\n\t\t\t\tmatched = '';\r\n\t\t\t}\r\n\r\n\t\t\tif (!action) {\r\n\t\t\t\t// bad: we didn't match anything, and there is no action to take\r\n\t\t\t\t// we need to advance the stream or we get progress trouble\r\n\t\t\t\tif (pos < lineLength) {\r\n\t\t\t\t\tmatches = [line.charAt(pos)];\r\n\t\t\t\t\tmatched = matches[0];\r\n\t\t\t\t}\r\n\t\t\t\taction = this._lexer.defaultToken;\r\n\t\t\t}\r\n\r\n\t\t\tif (matched === null) {\r\n\t\t\t\t// should never happen, needed for strict null checking\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\t// advance stream\r\n\t\t\tpos += matched.length;\r\n\r\n\t\t\t// maybe call action function (used for 'cases')\r\n\t\t\twhile (monarchCommon.isFuzzyAction(action) && monarchCommon.isIAction(action) && action.test) {\r\n\t\t\t\taction = action.test(matched, matches, state, pos === lineLength);\r\n\t\t\t}\r\n\r\n\t\t\tlet result: monarchCommon.FuzzyAction | monarchCommon.FuzzyAction[] | null = null;\r\n\t\t\t// set the result: either a string or an array of actions\r\n\t\t\tif (typeof action === 'string' || Array.isArray(action)) {\r\n\t\t\t\tresult = action;\r\n\t\t\t} else if (action.group) {\r\n\t\t\t\tresult = action.group;\r\n\t\t\t} else if (action.token !== null && action.token !== undefined) {\r\n\r\n\t\t\t\t// do $n replacements?\r\n\t\t\t\tif (action.tokenSubst) {\r\n\t\t\t\t\tresult = monarchCommon.substituteMatches(this._lexer, action.token, matched, matches, state);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tresult = action.token;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// enter embedded mode?\r\n\t\t\t\tif (action.nextEmbedded) {\r\n\t\t\t\t\tif (action.nextEmbedded === '@pop') {\r\n\t\t\t\t\t\tif (!embeddedModeData) {\r\n\t\t\t\t\t\t\tthrow monarchCommon.createError(this._lexer, 'cannot pop embedded mode if not inside one');\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tembeddedModeData = null;\r\n\t\t\t\t\t} else if (embeddedModeData) {\r\n\t\t\t\t\t\tthrow monarchCommon.createError(this._lexer, 'cannot enter embedded mode from within an embedded mode');\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tenteringEmbeddedMode = monarchCommon.substituteMatches(this._lexer, action.nextEmbedded, matched, matches, state);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// state transformations\r\n\t\t\t\tif (action.goBack) { // back up the stream..\r\n\t\t\t\t\tpos = Math.max(0, pos - action.goBack);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (action.switchTo && typeof action.switchTo === 'string') {\r\n\t\t\t\t\tlet nextState = monarchCommon.substituteMatches(this._lexer, action.switchTo, matched, matches, state); // switch state without a push...\r\n\t\t\t\t\tif (nextState[0] === '@') {\r\n\t\t\t\t\t\tnextState = nextState.substr(1); // peel off starting '@'\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (!monarchCommon.findRules(this._lexer, nextState)) {\r\n\t\t\t\t\t\tthrow monarchCommon.createError(this._lexer, 'trying to switch to a state \\'' + nextState + '\\' that is undefined in rule: ' + this._safeRuleName(rule));\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tstack = stack.switchTo(nextState);\r\n\t\t\t\t\t}\r\n\t\t\t\t} else if (action.transform && typeof action.transform === 'function') {\r\n\t\t\t\t\tthrow monarchCommon.createError(this._lexer, 'action.transform not supported');\r\n\t\t\t\t} else if (action.next) {\r\n\t\t\t\t\tif (action.next === '@push') {\r\n\t\t\t\t\t\tif (stack.depth >= this._lexer.maxStack) {\r\n\t\t\t\t\t\t\tthrow monarchCommon.createError(this._lexer, 'maximum tokenizer stack size reached: [' +\r\n\t\t\t\t\t\t\t\tstack.state + ',' + stack.parent!.state + ',...]');\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tstack = stack.push(state);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} else if (action.next === '@pop') {\r\n\t\t\t\t\t\tif (stack.depth <= 1) {\r\n\t\t\t\t\t\t\tthrow monarchCommon.createError(this._lexer, 'trying to pop an empty stack in rule: ' + this._safeRuleName(rule));\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tstack = stack.pop()!;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} else if (action.next === '@popall') {\r\n\t\t\t\t\t\tstack = stack.popall();\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tlet nextState = monarchCommon.substituteMatches(this._lexer, action.next, matched, matches, state);\r\n\t\t\t\t\t\tif (nextState[0] === '@') {\r\n\t\t\t\t\t\t\tnextState = nextState.substr(1); // peel off starting '@'\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif (!monarchCommon.findRules(this._lexer, nextState)) {\r\n\t\t\t\t\t\t\tthrow monarchCommon.createError(this._lexer, 'trying to set a next state \\'' + nextState + '\\' that is undefined in rule: ' + this._safeRuleName(rule));\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tstack = stack.push(nextState);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (action.log && typeof (action.log) === 'string') {\r\n\t\t\t\t\tmonarchCommon.log(this._lexer, this._lexer.languageId + ': ' + monarchCommon.substituteMatches(this._lexer, action.log, matched, matches, state));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// check result\r\n\t\t\tif (result === null) {\r\n\t\t\t\tthrow monarchCommon.createError(this._lexer, 'lexer rule has no well-defined action in rule: ' + this._safeRuleName(rule));\r\n\t\t\t}\r\n\r\n\t\t\tconst computeNewStateForEmbeddedMode = (enteringEmbeddedMode: string) => {\r\n\t\t\t\t// substitute language alias to known modes to support syntax highlighting\r\n\t\t\t\tlet enteringEmbeddedModeId = this._modeService.getModeIdForLanguageName(enteringEmbeddedMode);\r\n\t\t\t\tif (enteringEmbeddedModeId) {\r\n\t\t\t\t\tenteringEmbeddedMode = enteringEmbeddedModeId;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst embeddedModeData = this._getNestedEmbeddedModeData(enteringEmbeddedMode);\r\n\r\n\t\t\t\tif (pos < lineLength) {\r\n\t\t\t\t\t// there is content from the embedded mode on this line\r\n\t\t\t\t\tconst restOfLine = lineWithoutLF.substr(pos);\r\n\t\t\t\t\treturn this._nestedTokenize(restOfLine, hasEOL, MonarchLineStateFactory.create(stack, embeddedModeData), offsetDelta + pos, tokensCollector);\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn MonarchLineStateFactory.create(stack, embeddedModeData);\r\n\t\t\t\t}\r\n\t\t\t};\r\n\r\n\t\t\t// is the result a group match?\r\n\t\t\tif (Array.isArray(result)) {\r\n\t\t\t\tif (groupMatching && groupMatching.groups.length > 0) {\r\n\t\t\t\t\tthrow monarchCommon.createError(this._lexer, 'groups cannot be nested: ' + this._safeRuleName(rule));\r\n\t\t\t\t}\r\n\t\t\t\tif (matches.length !== result.length + 1) {\r\n\t\t\t\t\tthrow monarchCommon.createError(this._lexer, 'matched number of groups does not match the number of actions in rule: ' + this._safeRuleName(rule));\r\n\t\t\t\t}\r\n\t\t\t\tlet totalLen = 0;\r\n\t\t\t\tfor (let i = 1; i < matches.length; i++) {\r\n\t\t\t\t\ttotalLen += matches[i].length;\r\n\t\t\t\t}\r\n\t\t\t\tif (totalLen !== matched.length) {\r\n\t\t\t\t\tthrow monarchCommon.createError(this._lexer, 'with groups, all characters should be matched in consecutive groups in rule: ' + this._safeRuleName(rule));\r\n\t\t\t\t}\r\n\r\n\t\t\t\tgroupMatching = {\r\n\t\t\t\t\trule: rule,\r\n\t\t\t\t\tmatches: matches,\r\n\t\t\t\t\tgroups: []\r\n\t\t\t\t};\r\n\t\t\t\tfor (let i = 0; i < result.length; i++) {\r\n\t\t\t\t\tgroupMatching.groups[i] = {\r\n\t\t\t\t\t\taction: result[i],\r\n\t\t\t\t\t\tmatched: matches[i + 1]\r\n\t\t\t\t\t};\r\n\t\t\t\t}\r\n\r\n\t\t\t\tpos -= matched.length;\r\n\t\t\t\t// call recursively to initiate first result match\r\n\t\t\t\tcontinue;\r\n\t\t\t} else {\r\n\t\t\t\t// regular result\r\n\r\n\t\t\t\t// check for '@rematch'\r\n\t\t\t\tif (result === '@rematch') {\r\n\t\t\t\t\tpos -= matched.length;\r\n\t\t\t\t\tmatched = ''; // better set the next state too..\r\n\t\t\t\t\tmatches = null;\r\n\t\t\t\t\tresult = '';\r\n\r\n\t\t\t\t\t// Even though `@rematch` was specified, if `nextEmbedded` also specified,\r\n\t\t\t\t\t// a state transition should occur.\r\n\t\t\t\t\tif (enteringEmbeddedMode !== null) {\r\n\t\t\t\t\t\treturn computeNewStateForEmbeddedMode(enteringEmbeddedMode);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// check progress\r\n\t\t\t\tif (matched.length === 0) {\r\n\t\t\t\t\tif (lineLength === 0 || stackLen0 !== stack.depth || state !== stack.state || (!groupMatching ? 0 : groupMatching.groups.length) !== groupLen0) {\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tthrow monarchCommon.createError(this._lexer, 'no progress in tokenizer in rule: ' + this._safeRuleName(rule));\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// return the result (and check for brace matching)\r\n\t\t\t\t// todo: for efficiency we could pre-sanitize tokenPostfix and substitutions\r\n\t\t\t\tlet tokenType: string | null = null;\r\n\t\t\t\tif (monarchCommon.isString(result) && result.indexOf('@brackets') === 0) {\r\n\t\t\t\t\tlet rest = result.substr('@brackets'.length);\r\n\t\t\t\t\tlet bracket = findBracket(this._lexer, matched);\r\n\t\t\t\t\tif (!bracket) {\r\n\t\t\t\t\t\tthrow monarchCommon.createError(this._lexer, '@brackets token returned but no bracket defined as: ' + matched);\r\n\t\t\t\t\t}\r\n\t\t\t\t\ttokenType = monarchCommon.sanitize(bracket.token + rest);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tlet token = (result === '' ? '' : result + this._lexer.tokenPostfix);\r\n\t\t\t\t\ttokenType = monarchCommon.sanitize(token);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (pos0 < lineWithoutLFLength) {\r\n\t\t\t\t\ttokensCollector.emit(pos0 + offsetDelta, tokenType);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (enteringEmbeddedMode !== null) {\r\n\t\t\t\treturn computeNewStateForEmbeddedMode(enteringEmbeddedMode);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn MonarchLineStateFactory.create(stack, embeddedModeData);\r\n\t}\r\n\r\n\tprivate _getNestedEmbeddedModeData(mimetypeOrModeId: string): EmbeddedModeData {\r\n\t\tlet nestedModeId = this._locateMode(mimetypeOrModeId);\r\n\t\tif (nestedModeId) {\r\n\t\t\tlet tokenizationSupport = modes.TokenizationRegistry.get(nestedModeId);\r\n\t\t\tif (tokenizationSupport) {\r\n\t\t\t\treturn new EmbeddedModeData(nestedModeId, tokenizationSupport.getInitialState());\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn new EmbeddedModeData(nestedModeId || NULL_MODE_ID, NULL_STATE);\r\n\t}\r\n\r\n\tprivate _locateMode(mimetypeOrModeId: string): string | null {\r\n\t\tif (!mimetypeOrModeId || !this._modeService.isRegisteredMode(mimetypeOrModeId)) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (mimetypeOrModeId === this._modeId) {\r\n\t\t\t// embedding myself...\r\n\t\t\treturn mimetypeOrModeId;\r\n\t\t}\r\n\r\n\t\tlet modeId = this._modeService.getModeId(mimetypeOrModeId);\r\n\r\n\t\tif (modeId) {\r\n\t\t\t// Fire mode loading event\r\n\t\t\tthis._modeService.triggerMode(modeId);\r\n\t\t\tthis._embeddedModes[modeId] = true;\r\n\t\t}\r\n\r\n\t\treturn modeId;\r\n\t}\r\n\r\n}\r\n\r\n/**\r\n * Searches for a bracket in the 'brackets' attribute that matches the input.\r\n */\r\nfunction findBracket(lexer: monarchCommon.ILexer, matched: string) {\r\n\tif (!matched) {\r\n\t\treturn null;\r\n\t}\r\n\tmatched = monarchCommon.fixCase(lexer, matched);\r\n\r\n\tlet brackets = lexer.brackets;\r\n\tfor (const bracket of brackets) {\r\n\t\tif (bracket.open === matched) {\r\n\t\t\treturn { token: bracket.token, bracketType: monarchCommon.MonarchBracket.Open };\r\n\t\t}\r\n\t\telse if (bracket.close === matched) {\r\n\t\t\treturn { token: bracket.token, bracketType: monarchCommon.MonarchBracket.Close };\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n}\r\n\r\nexport function createTokenizationSupport(modeService: IModeService, standaloneThemeService: IStandaloneThemeService, modeId: string, lexer: monarchCommon.ILexer): modes.ITokenizationSupport {\r\n\treturn new MonarchTokenizer(modeService, standaloneThemeService, modeId, lexer);\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { TimeoutTimer } from 'vs/base/common/async';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { IViewLineTokens, LineTokens } from 'vs/editor/common/core/lineTokens';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { ColorId, FontStyle, ITokenizationSupport, MetadataConsts, TokenizationRegistry } from 'vs/editor/common/modes';\r\nimport { IModeService } from 'vs/editor/common/services/modeService';\r\nimport { RenderLineInput, renderViewLine2 as renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer';\r\nimport { ViewLineRenderingData } from 'vs/editor/common/viewModel/viewModel';\r\nimport { IStandaloneThemeService } from 'vs/editor/standalone/common/standaloneThemeService';\r\nimport { MonarchTokenizer } from 'vs/editor/standalone/common/monarch/monarchLexer';\r\n\r\nconst ttPolicy = window.trustedTypes?.createPolicy('standaloneColorizer', { createHTML: value => value });\r\n\r\nexport interface IColorizerOptions {\r\n\ttabSize?: number;\r\n}\r\n\r\nexport interface IColorizerElementOptions extends IColorizerOptions {\r\n\ttheme?: string;\r\n\tmimeType?: string;\r\n}\r\n\r\nexport class Colorizer {\r\n\r\n\tpublic static colorizeElement(themeService: IStandaloneThemeService, modeService: IModeService, domNode: HTMLElement, options: IColorizerElementOptions): Promise {\r\n\t\toptions = options || {};\r\n\t\tlet theme = options.theme || 'vs';\r\n\t\tlet mimeType = options.mimeType || domNode.getAttribute('lang') || domNode.getAttribute('data-lang');\r\n\t\tif (!mimeType) {\r\n\t\t\tconsole.error('Mode not detected');\r\n\t\t\treturn Promise.resolve();\r\n\t\t}\r\n\r\n\t\tthemeService.setTheme(theme);\r\n\r\n\t\tlet text = domNode.firstChild ? domNode.firstChild.nodeValue : '';\r\n\t\tdomNode.className += ' ' + theme;\r\n\t\tlet render = (str: string) => {\r\n\t\t\tconst trustedhtml = ttPolicy?.createHTML(str) ?? str;\r\n\t\t\tdomNode.innerHTML = trustedhtml as string;\r\n\t\t};\r\n\t\treturn this.colorize(modeService, text || '', mimeType, options).then(render, (err) => console.error(err));\r\n\t}\r\n\r\n\tpublic static colorize(modeService: IModeService, text: string, mimeType: string, options: IColorizerOptions | null | undefined): Promise {\r\n\t\tlet tabSize = 4;\r\n\t\tif (options && typeof options.tabSize === 'number') {\r\n\t\t\ttabSize = options.tabSize;\r\n\t\t}\r\n\r\n\t\tif (strings.startsWithUTF8BOM(text)) {\r\n\t\t\ttext = text.substr(1);\r\n\t\t}\r\n\t\tlet lines = strings.splitLines(text);\r\n\t\tlet language = modeService.getModeId(mimeType);\r\n\t\tif (!language) {\r\n\t\t\treturn Promise.resolve(_fakeColorize(lines, tabSize));\r\n\t\t}\r\n\r\n\t\t// Send out the event to create the mode\r\n\t\tmodeService.triggerMode(language);\r\n\r\n\t\tconst tokenizationSupport = TokenizationRegistry.get(language);\r\n\t\tif (tokenizationSupport) {\r\n\t\t\treturn _colorize(lines, tabSize, tokenizationSupport);\r\n\t\t}\r\n\r\n\t\tconst tokenizationSupportPromise = TokenizationRegistry.getPromise(language);\r\n\t\tif (tokenizationSupportPromise) {\r\n\t\t\t// A tokenizer will be registered soon\r\n\t\t\treturn new Promise((resolve, reject) => {\r\n\t\t\t\ttokenizationSupportPromise.then(tokenizationSupport => {\r\n\t\t\t\t\t_colorize(lines, tabSize, tokenizationSupport).then(resolve, reject);\r\n\t\t\t\t}, reject);\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\treturn new Promise((resolve, reject) => {\r\n\t\t\tlet listener: IDisposable | null = null;\r\n\t\t\tlet timeout: TimeoutTimer | null = null;\r\n\r\n\t\t\tconst execute = () => {\r\n\t\t\t\tif (listener) {\r\n\t\t\t\t\tlistener.dispose();\r\n\t\t\t\t\tlistener = null;\r\n\t\t\t\t}\r\n\t\t\t\tif (timeout) {\r\n\t\t\t\t\ttimeout.dispose();\r\n\t\t\t\t\ttimeout = null;\r\n\t\t\t\t}\r\n\t\t\t\tconst tokenizationSupport = TokenizationRegistry.get(language!);\r\n\t\t\t\tif (tokenizationSupport) {\r\n\t\t\t\t\t_colorize(lines, tabSize, tokenizationSupport).then(resolve, reject);\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\tresolve(_fakeColorize(lines, tabSize));\r\n\t\t\t};\r\n\r\n\t\t\t// wait 500ms for mode to load, then give up\r\n\t\t\ttimeout = new TimeoutTimer();\r\n\t\t\ttimeout.cancelAndSet(execute, 500);\r\n\t\t\tlistener = TokenizationRegistry.onDidChange((e) => {\r\n\t\t\t\tif (e.changedLanguages.indexOf(language!) >= 0) {\r\n\t\t\t\t\texecute();\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t});\r\n\t}\r\n\r\n\tpublic static colorizeLine(line: string, mightContainNonBasicASCII: boolean, mightContainRTL: boolean, tokens: IViewLineTokens, tabSize: number = 4): string {\r\n\t\tconst isBasicASCII = ViewLineRenderingData.isBasicASCII(line, mightContainNonBasicASCII);\r\n\t\tconst containsRTL = ViewLineRenderingData.containsRTL(line, isBasicASCII, mightContainRTL);\r\n\t\tlet renderResult = renderViewLine(new RenderLineInput(\r\n\t\t\tfalse,\r\n\t\t\ttrue,\r\n\t\t\tline,\r\n\t\t\tfalse,\r\n\t\t\tisBasicASCII,\r\n\t\t\tcontainsRTL,\r\n\t\t\t0,\r\n\t\t\ttokens,\r\n\t\t\t[],\r\n\t\t\ttabSize,\r\n\t\t\t0,\r\n\t\t\t0,\r\n\t\t\t0,\r\n\t\t\t0,\r\n\t\t\t-1,\r\n\t\t\t'none',\r\n\t\t\tfalse,\r\n\t\t\tfalse,\r\n\t\t\tnull\r\n\t\t));\r\n\t\treturn renderResult.html;\r\n\t}\r\n\r\n\tpublic static colorizeModelLine(model: ITextModel, lineNumber: number, tabSize: number = 4): string {\r\n\t\tlet content = model.getLineContent(lineNumber);\r\n\t\tmodel.forceTokenization(lineNumber);\r\n\t\tlet tokens = model.getLineTokens(lineNumber);\r\n\t\tlet inflatedTokens = tokens.inflate();\r\n\t\treturn this.colorizeLine(content, model.mightContainNonBasicASCII(), model.mightContainRTL(), inflatedTokens, tabSize);\r\n\t}\r\n}\r\n\r\nfunction _colorize(lines: string[], tabSize: number, tokenizationSupport: ITokenizationSupport): Promise {\r\n\treturn new Promise((c, e) => {\r\n\t\tconst execute = () => {\r\n\t\t\tconst result = _actualColorize(lines, tabSize, tokenizationSupport);\r\n\t\t\tif (tokenizationSupport instanceof MonarchTokenizer) {\r\n\t\t\t\tconst status = tokenizationSupport.getLoadStatus();\r\n\t\t\t\tif (status.loaded === false) {\r\n\t\t\t\t\tstatus.promise.then(execute, e);\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tc(result);\r\n\t\t};\r\n\t\texecute();\r\n\t});\r\n}\r\n\r\nfunction _fakeColorize(lines: string[], tabSize: number): string {\r\n\tlet html: string[] = [];\r\n\r\n\tconst defaultMetadata = (\r\n\t\t(FontStyle.None << MetadataConsts.FONT_STYLE_OFFSET)\r\n\t\t| (ColorId.DefaultForeground << MetadataConsts.FOREGROUND_OFFSET)\r\n\t\t| (ColorId.DefaultBackground << MetadataConsts.BACKGROUND_OFFSET)\r\n\t) >>> 0;\r\n\r\n\tconst tokens = new Uint32Array(2);\r\n\ttokens[0] = 0;\r\n\ttokens[1] = defaultMetadata;\r\n\r\n\tfor (let i = 0, length = lines.length; i < length; i++) {\r\n\t\tlet line = lines[i];\r\n\r\n\t\ttokens[0] = line.length;\r\n\t\tconst lineTokens = new LineTokens(tokens, line);\r\n\r\n\t\tconst isBasicASCII = ViewLineRenderingData.isBasicASCII(line, /* check for basic ASCII */true);\r\n\t\tconst containsRTL = ViewLineRenderingData.containsRTL(line, isBasicASCII, /* check for RTL */true);\r\n\t\tlet renderResult = renderViewLine(new RenderLineInput(\r\n\t\t\tfalse,\r\n\t\t\ttrue,\r\n\t\t\tline,\r\n\t\t\tfalse,\r\n\t\t\tisBasicASCII,\r\n\t\t\tcontainsRTL,\r\n\t\t\t0,\r\n\t\t\tlineTokens,\r\n\t\t\t[],\r\n\t\t\ttabSize,\r\n\t\t\t0,\r\n\t\t\t0,\r\n\t\t\t0,\r\n\t\t\t0,\r\n\t\t\t-1,\r\n\t\t\t'none',\r\n\t\t\tfalse,\r\n\t\t\tfalse,\r\n\t\t\tnull\r\n\t\t));\r\n\r\n\t\thtml = html.concat(renderResult.html);\r\n\t\thtml.push('
    ');\r\n\t}\r\n\r\n\treturn html.join('');\r\n}\r\n\r\nfunction _actualColorize(lines: string[], tabSize: number, tokenizationSupport: ITokenizationSupport): string {\r\n\tlet html: string[] = [];\r\n\tlet state = tokenizationSupport.getInitialState();\r\n\r\n\tfor (let i = 0, length = lines.length; i < length; i++) {\r\n\t\tlet line = lines[i];\r\n\t\tlet tokenizeResult = tokenizationSupport.tokenize2(line, true, state, 0);\r\n\t\tLineTokens.convertToEndOffset(tokenizeResult.tokens, line.length);\r\n\t\tlet lineTokens = new LineTokens(tokenizeResult.tokens, line);\r\n\t\tconst isBasicASCII = ViewLineRenderingData.isBasicASCII(line, /* check for basic ASCII */true);\r\n\t\tconst containsRTL = ViewLineRenderingData.containsRTL(line, isBasicASCII, /* check for RTL */true);\r\n\t\tlet renderResult = renderViewLine(new RenderLineInput(\r\n\t\t\tfalse,\r\n\t\t\ttrue,\r\n\t\t\tline,\r\n\t\t\tfalse,\r\n\t\t\tisBasicASCII,\r\n\t\t\tcontainsRTL,\r\n\t\t\t0,\r\n\t\t\tlineTokens.inflate(),\r\n\t\t\t[],\r\n\t\t\ttabSize,\r\n\t\t\t0,\r\n\t\t\t0,\r\n\t\t\t0,\r\n\t\t\t0,\r\n\t\t\t-1,\r\n\t\t\t'none',\r\n\t\t\tfalse,\r\n\t\t\tfalse,\r\n\t\t\tnull\r\n\t\t));\r\n\r\n\t\thtml = html.concat(renderResult.html);\r\n\t\thtml.push('
    ');\r\n\r\n\t\tstate = tokenizeResult.endState;\r\n\t}\r\n\r\n\treturn html.join('');\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Color } from 'vs/base/common/color';\r\nimport { ITokenThemeRule, TokenTheme } from 'vs/editor/common/modes/supports/tokenization';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService';\r\n\r\nexport const IStandaloneThemeService = createDecorator('themeService');\r\n\r\nexport type BuiltinTheme = 'vs' | 'vs-dark' | 'hc-black';\r\nexport type IColors = { [colorId: string]: string; };\r\n\r\nexport interface IStandaloneThemeData {\r\n\tbase: BuiltinTheme;\r\n\tinherit: boolean;\r\n\trules: ITokenThemeRule[];\r\n\tencodedTokensColors?: string[];\r\n\tcolors: IColors;\r\n}\r\n\r\nexport interface IStandaloneTheme extends IColorTheme {\r\n\ttokenTheme: TokenTheme;\r\n\tthemeName: string;\r\n}\r\n\r\nexport interface IStandaloneThemeService extends IThemeService {\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\tsetTheme(themeName: string): string;\r\n\r\n\tdefineTheme(themeName: string, themeData: IStandaloneThemeData): void;\r\n\r\n\tgetColorTheme(): IStandaloneTheme;\r\n\r\n\tsetColorMapOverride(colorMapOverride: Color[] | null): void;\r\n\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\n\r\nexport const IClipboardService = createDecorator('clipboardService');\r\n\r\nexport interface IClipboardService {\r\n\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\t/**\r\n\t * Writes text to the system clipboard.\r\n\t */\r\n\twriteText(text: string, type?: string): Promise;\r\n\r\n\t/**\r\n\t * Reads the content of the clipboard in plain text\r\n\t */\r\n\treadText(type?: string): Promise;\r\n\r\n\t/**\r\n\t * Reads text from the system find pasteboard.\r\n\t */\r\n\treadFindText(): Promise;\r\n\r\n\t/**\r\n\t * Writes text to the system find pasteboard.\r\n\t */\r\n\twriteFindText(text: string): Promise;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IDisposable, toDisposable } from 'vs/base/common/lifecycle';\r\nimport { TypeConstraint, validateConstraints } from 'vs/base/common/types';\r\nimport { ServicesAccessor, createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { Event, Emitter } from 'vs/base/common/event';\r\nimport { LinkedList } from 'vs/base/common/linkedList';\r\nimport { IJSONSchema } from 'vs/base/common/jsonSchema';\r\nimport { Iterable } from 'vs/base/common/iterator';\r\n\r\nexport const ICommandService = createDecorator('commandService');\r\n\r\nexport interface ICommandEvent {\r\n\tcommandId: string;\r\n\targs: any[];\r\n}\r\n\r\nexport interface ICommandService {\r\n\treadonly _serviceBrand: undefined;\r\n\texecuteCommand(commandId: string, ...args: any[]): Promise;\r\n}\r\n\r\nexport type ICommandsMap = Map;\r\n\r\nexport interface ICommandHandler {\r\n\t(accessor: ServicesAccessor, ...args: any[]): void;\r\n}\r\n\r\nexport interface ICommand {\r\n\tid: string;\r\n\thandler: ICommandHandler;\r\n\tdescription?: ICommandHandlerDescription | null;\r\n}\r\n\r\nexport interface ICommandHandlerDescription {\r\n\treadonly description: string;\r\n\treadonly args: ReadonlyArray<{\r\n\t\treadonly name: string;\r\n\t\treadonly description?: string;\r\n\t\treadonly constraint?: TypeConstraint;\r\n\t\treadonly schema?: IJSONSchema;\r\n\t}>;\r\n}\r\n\r\nexport interface ICommandRegistry {\r\n\tregisterCommand(id: string, command: ICommandHandler): IDisposable;\r\n\tregisterCommand(command: ICommand): IDisposable;\r\n\tregisterCommandAlias(oldId: string, newId: string): IDisposable;\r\n\tgetCommand(id: string): ICommand | undefined;\r\n}\r\n\r\nexport const CommandsRegistry: ICommandRegistry = new class implements ICommandRegistry {\r\n\r\n\tprivate readonly _commands = new Map>();\r\n\r\n\tprivate readonly _onDidRegisterCommand = new Emitter();\r\n\treadonly onDidRegisterCommand: Event = this._onDidRegisterCommand.event;\r\n\r\n\tregisterCommand(idOrCommand: string | ICommand, handler?: ICommandHandler): IDisposable {\r\n\r\n\t\tif (!idOrCommand) {\r\n\t\t\tthrow new Error(`invalid command`);\r\n\t\t}\r\n\r\n\t\tif (typeof idOrCommand === 'string') {\r\n\t\t\tif (!handler) {\r\n\t\t\t\tthrow new Error(`invalid command`);\r\n\t\t\t}\r\n\t\t\treturn this.registerCommand({ id: idOrCommand, handler });\r\n\t\t}\r\n\r\n\t\t// add argument validation if rich command metadata is provided\r\n\t\tif (idOrCommand.description) {\r\n\t\t\tconst constraints: Array = [];\r\n\t\t\tfor (let arg of idOrCommand.description.args) {\r\n\t\t\t\tconstraints.push(arg.constraint);\r\n\t\t\t}\r\n\t\t\tconst actualHandler = idOrCommand.handler;\r\n\t\t\tidOrCommand.handler = function (accessor, ...args: any[]) {\r\n\t\t\t\tvalidateConstraints(args, constraints);\r\n\t\t\t\treturn actualHandler(accessor, ...args);\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\t// find a place to store the command\r\n\t\tconst { id } = idOrCommand;\r\n\r\n\t\tlet commands = this._commands.get(id);\r\n\t\tif (!commands) {\r\n\t\t\tcommands = new LinkedList();\r\n\t\t\tthis._commands.set(id, commands);\r\n\t\t}\r\n\r\n\t\tlet removeFn = commands.unshift(idOrCommand);\r\n\r\n\t\tlet ret = toDisposable(() => {\r\n\t\t\tremoveFn();\r\n\t\t\tconst command = this._commands.get(id);\r\n\t\t\tif (command?.isEmpty()) {\r\n\t\t\t\tthis._commands.delete(id);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\t// tell the world about this command\r\n\t\tthis._onDidRegisterCommand.fire(id);\r\n\r\n\t\treturn ret;\r\n\t}\r\n\r\n\tregisterCommandAlias(oldId: string, newId: string): IDisposable {\r\n\t\treturn CommandsRegistry.registerCommand(oldId, (accessor, ...args) => accessor.get(ICommandService).executeCommand(newId, ...args));\r\n\t}\r\n\r\n\tgetCommand(id: string): ICommand | undefined {\r\n\t\tconst list = this._commands.get(id);\r\n\t\tif (!list || list.isEmpty()) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\t\treturn Iterable.first(list);\r\n\t}\r\n\r\n\tgetCommands(): ICommandsMap {\r\n\t\tconst result = new Map();\r\n\t\tfor (const key of this._commands.keys()) {\r\n\t\t\tconst command = this.getCommand(key);\r\n\t\t\tif (command) {\r\n\t\t\t\tresult.set(key, command);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n};\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { onUnexpectedExternalError } from 'vs/base/common/errors';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { DocumentSemanticTokensProviderRegistry, DocumentSemanticTokensProvider, SemanticTokens, SemanticTokensEdits, SemanticTokensLegend, DocumentRangeSemanticTokensProviderRegistry, DocumentRangeSemanticTokensProvider } from 'vs/editor/common/modes';\r\nimport { IModelService } from 'vs/editor/common/services/modelService';\r\nimport { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';\r\nimport { assertType } from 'vs/base/common/types';\r\nimport { VSBuffer } from 'vs/base/common/buffer';\r\nimport { encodeSemanticTokensDto } from 'vs/editor/common/services/semanticTokensDto';\r\nimport { Range } from 'vs/editor/common/core/range';\r\n\r\nexport function isSemanticTokens(v: SemanticTokens | SemanticTokensEdits): v is SemanticTokens {\r\n\treturn v && !!((v).data);\r\n}\r\n\r\nexport function isSemanticTokensEdits(v: SemanticTokens | SemanticTokensEdits): v is SemanticTokensEdits {\r\n\treturn v && Array.isArray((v).edits);\r\n}\r\n\r\nexport interface IDocumentSemanticTokensResult {\r\n\tprovider: DocumentSemanticTokensProvider;\r\n\trequest: Promise;\r\n}\r\n\r\nexport function getDocumentSemanticTokens(model: ITextModel, lastResultId: string | null, token: CancellationToken): IDocumentSemanticTokensResult | null {\r\n\tconst provider = _getDocumentSemanticTokensProvider(model);\r\n\tif (!provider) {\r\n\t\treturn null;\r\n\t}\r\n\treturn {\r\n\t\tprovider: provider,\r\n\t\trequest: Promise.resolve(provider.provideDocumentSemanticTokens(model, lastResultId, token))\r\n\t};\r\n}\r\n\r\nfunction _getDocumentSemanticTokensProvider(model: ITextModel): DocumentSemanticTokensProvider | null {\r\n\tconst result = DocumentSemanticTokensProviderRegistry.ordered(model);\r\n\treturn (result.length > 0 ? result[0] : null);\r\n}\r\n\r\nexport function getDocumentRangeSemanticTokensProvider(model: ITextModel): DocumentRangeSemanticTokensProvider | null {\r\n\tconst result = DocumentRangeSemanticTokensProviderRegistry.ordered(model);\r\n\treturn (result.length > 0 ? result[0] : null);\r\n}\r\n\r\nCommandsRegistry.registerCommand('_provideDocumentSemanticTokensLegend', async (accessor, ...args): Promise => {\r\n\tconst [uri] = args;\r\n\tassertType(uri instanceof URI);\r\n\r\n\tconst model = accessor.get(IModelService).getModel(uri);\r\n\tif (!model) {\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tconst provider = _getDocumentSemanticTokensProvider(model);\r\n\tif (!provider) {\r\n\t\t// there is no provider => fall back to a document range semantic tokens provider\r\n\t\treturn accessor.get(ICommandService).executeCommand('_provideDocumentRangeSemanticTokensLegend', uri);\r\n\t}\r\n\r\n\treturn provider.getLegend();\r\n});\r\n\r\nCommandsRegistry.registerCommand('_provideDocumentSemanticTokens', async (accessor, ...args): Promise => {\r\n\tconst [uri] = args;\r\n\tassertType(uri instanceof URI);\r\n\r\n\tconst model = accessor.get(IModelService).getModel(uri);\r\n\tif (!model) {\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tconst r = getDocumentSemanticTokens(model, null, CancellationToken.None);\r\n\tif (!r) {\r\n\t\t// there is no provider => fall back to a document range semantic tokens provider\r\n\t\treturn accessor.get(ICommandService).executeCommand('_provideDocumentRangeSemanticTokens', uri, model.getFullModelRange());\r\n\t}\r\n\r\n\tconst { provider, request } = r;\r\n\r\n\tlet result: SemanticTokens | SemanticTokensEdits | null | undefined;\r\n\ttry {\r\n\t\tresult = await request;\r\n\t} catch (err) {\r\n\t\tonUnexpectedExternalError(err);\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tif (!result || !isSemanticTokens(result)) {\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tconst buff = encodeSemanticTokensDto({\r\n\t\tid: 0,\r\n\t\ttype: 'full',\r\n\t\tdata: result.data\r\n\t});\r\n\tif (result.resultId) {\r\n\t\tprovider.releaseDocumentSemanticTokens(result.resultId);\r\n\t}\r\n\treturn buff;\r\n});\r\n\r\nCommandsRegistry.registerCommand('_provideDocumentRangeSemanticTokensLegend', async (accessor, ...args): Promise => {\r\n\tconst [uri] = args;\r\n\tassertType(uri instanceof URI);\r\n\r\n\tconst model = accessor.get(IModelService).getModel(uri);\r\n\tif (!model) {\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tconst provider = getDocumentRangeSemanticTokensProvider(model);\r\n\tif (!provider) {\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\treturn provider.getLegend();\r\n});\r\n\r\nCommandsRegistry.registerCommand('_provideDocumentRangeSemanticTokens', async (accessor, ...args): Promise => {\r\n\tconst [uri, range] = args;\r\n\tassertType(uri instanceof URI);\r\n\tassertType(Range.isIRange(range));\r\n\r\n\tconst model = accessor.get(IModelService).getModel(uri);\r\n\tif (!model) {\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tconst provider = getDocumentRangeSemanticTokensProvider(model);\r\n\tif (!provider) {\r\n\t\t// there is no provider\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tlet result: SemanticTokens | null | undefined;\r\n\ttry {\r\n\t\tresult = await provider.provideDocumentRangeSemanticTokens(model, Range.lift(range), CancellationToken.None);\r\n\t} catch (err) {\r\n\t\tonUnexpectedExternalError(err);\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tif (!result || !isSemanticTokens(result)) {\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\treturn encodeSemanticTokensDto({\r\n\t\tid: 0,\r\n\t\ttype: 'full',\r\n\t\tdata: result.data\r\n\t});\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { mergeSort } from 'vs/base/common/arrays';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { illegalArgument, onUnexpectedExternalError } from 'vs/base/common/errors';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { CodeLensProvider, CodeLensProviderRegistry, CodeLens, CodeLensList } from 'vs/editor/common/modes';\r\nimport { IModelService } from 'vs/editor/common/services/modelService';\r\nimport { DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { CommandsRegistry } from 'vs/platform/commands/common/commands';\r\nimport { assertType } from 'vs/base/common/types';\r\n\r\nexport interface CodeLensItem {\r\n\tsymbol: CodeLens;\r\n\tprovider: CodeLensProvider;\r\n}\r\n\r\nexport class CodeLensModel {\r\n\r\n\tlenses: CodeLensItem[] = [];\r\n\r\n\tprivate readonly _disposables = new DisposableStore();\r\n\r\n\tdispose(): void {\r\n\t\tthis._disposables.dispose();\r\n\t}\r\n\r\n\tadd(list: CodeLensList, provider: CodeLensProvider): void {\r\n\t\tthis._disposables.add(list);\r\n\t\tfor (const symbol of list.lenses) {\r\n\t\t\tthis.lenses.push({ symbol, provider });\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport async function getCodeLensModel(model: ITextModel, token: CancellationToken): Promise {\r\n\r\n\tconst provider = CodeLensProviderRegistry.ordered(model);\r\n\tconst providerRanks = new Map();\r\n\tconst result = new CodeLensModel();\r\n\r\n\tconst promises = provider.map(async (provider, i) => {\r\n\r\n\t\tproviderRanks.set(provider, i);\r\n\r\n\t\ttry {\r\n\t\t\tconst list = await Promise.resolve(provider.provideCodeLenses(model, token));\r\n\t\t\tif (list) {\r\n\t\t\t\tresult.add(list, provider);\r\n\t\t\t}\r\n\t\t} catch (err) {\r\n\t\t\tonUnexpectedExternalError(err);\r\n\t\t}\r\n\t});\r\n\r\n\tawait Promise.all(promises);\r\n\r\n\tresult.lenses = mergeSort(result.lenses, (a, b) => {\r\n\t\t// sort by lineNumber, provider-rank, and column\r\n\t\tif (a.symbol.range.startLineNumber < b.symbol.range.startLineNumber) {\r\n\t\t\treturn -1;\r\n\t\t} else if (a.symbol.range.startLineNumber > b.symbol.range.startLineNumber) {\r\n\t\t\treturn 1;\r\n\t\t} else if ((providerRanks.get(a.provider)!) < (providerRanks.get(b.provider)!)) {\r\n\t\t\treturn -1;\r\n\t\t} else if ((providerRanks.get(a.provider)!) > (providerRanks.get(b.provider)!)) {\r\n\t\t\treturn 1;\r\n\t\t} else if (a.symbol.range.startColumn < b.symbol.range.startColumn) {\r\n\t\t\treturn -1;\r\n\t\t} else if (a.symbol.range.startColumn > b.symbol.range.startColumn) {\r\n\t\t\treturn 1;\r\n\t\t} else {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t});\r\n\treturn result;\r\n}\r\n\r\nCommandsRegistry.registerCommand('_executeCodeLensProvider', function (accessor, ...args: [URI, number | undefined | null]) {\r\n\tlet [uri, itemResolveCount] = args;\r\n\tassertType(URI.isUri(uri));\r\n\tassertType(typeof itemResolveCount === 'number' || !itemResolveCount);\r\n\r\n\tconst model = accessor.get(IModelService).getModel(uri);\r\n\tif (!model) {\r\n\t\tthrow illegalArgument();\r\n\t}\r\n\r\n\tconst result: CodeLens[] = [];\r\n\tconst disposables = new DisposableStore();\r\n\treturn getCodeLensModel(model, CancellationToken.None).then(value => {\r\n\r\n\t\tdisposables.add(value);\r\n\t\tlet resolve: Promise[] = [];\r\n\r\n\t\tfor (const item of value.lenses) {\r\n\t\t\tif (itemResolveCount === undefined || itemResolveCount === null || Boolean(item.symbol.command)) {\r\n\t\t\t\tresult.push(item.symbol);\r\n\t\t\t} else if (itemResolveCount-- > 0 && item.provider.resolveCodeLens) {\r\n\t\t\t\tresolve.push(Promise.resolve(item.provider.resolveCodeLens(model, item.symbol, CancellationToken.None)).then(symbol => result.push(symbol || item.symbol)));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn Promise.all(resolve);\r\n\r\n\t}).then(() => {\r\n\t\treturn result;\r\n\t}).finally(() => {\r\n\t\t// make sure to return results, then (on next tick)\r\n\t\t// dispose the results\r\n\t\tsetTimeout(() => disposables.dispose(), 100);\r\n\t});\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { illegalArgument } from 'vs/base/common/errors';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { IRange, Range } from 'vs/editor/common/core/range';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { ColorProviderRegistry, DocumentColorProvider, IColorInformation, IColorPresentation } from 'vs/editor/common/modes';\r\nimport { IModelService } from 'vs/editor/common/services/modelService';\r\nimport { CommandsRegistry } from 'vs/platform/commands/common/commands';\r\n\r\n\r\nexport interface IColorData {\r\n\tcolorInfo: IColorInformation;\r\n\tprovider: DocumentColorProvider;\r\n}\r\n\r\nexport function getColors(model: ITextModel, token: CancellationToken): Promise {\r\n\tconst colors: IColorData[] = [];\r\n\tconst providers = ColorProviderRegistry.ordered(model).reverse();\r\n\tconst promises = providers.map(provider => Promise.resolve(provider.provideDocumentColors(model, token)).then(result => {\r\n\t\tif (Array.isArray(result)) {\r\n\t\t\tfor (let colorInfo of result) {\r\n\t\t\t\tcolors.push({ colorInfo, provider });\r\n\t\t\t}\r\n\t\t}\r\n\t}));\r\n\r\n\treturn Promise.all(promises).then(() => colors);\r\n}\r\n\r\nexport function getColorPresentations(model: ITextModel, colorInfo: IColorInformation, provider: DocumentColorProvider, token: CancellationToken): Promise {\r\n\treturn Promise.resolve(provider.provideColorPresentations(model, colorInfo, token));\r\n}\r\n\r\nCommandsRegistry.registerCommand('_executeDocumentColorProvider', function (accessor, ...args) {\r\n\r\n\tconst [resource] = args;\r\n\tif (!(resource instanceof URI)) {\r\n\t\tthrow illegalArgument();\r\n\t}\r\n\r\n\tconst model = accessor.get(IModelService).getModel(resource);\r\n\tif (!model) {\r\n\t\tthrow illegalArgument();\r\n\t}\r\n\r\n\tconst rawCIs: { range: IRange, color: [number, number, number, number] }[] = [];\r\n\tconst providers = ColorProviderRegistry.ordered(model).reverse();\r\n\tconst promises = providers.map(provider => Promise.resolve(provider.provideDocumentColors(model, CancellationToken.None)).then(result => {\r\n\t\tif (Array.isArray(result)) {\r\n\t\t\tfor (let ci of result) {\r\n\t\t\t\trawCIs.push({ range: ci.range, color: [ci.color.red, ci.color.green, ci.color.blue, ci.color.alpha] });\r\n\t\t\t}\r\n\t\t}\r\n\t}));\r\n\r\n\treturn Promise.all(promises).then(() => rawCIs);\r\n});\r\n\r\n\r\nCommandsRegistry.registerCommand('_executeColorPresentationProvider', function (accessor, ...args) {\r\n\r\n\tconst [color, context] = args;\r\n\tconst { uri, range } = context;\r\n\tif (!(uri instanceof URI) || !Array.isArray(color) || color.length !== 4 || !Range.isIRange(range)) {\r\n\t\tthrow illegalArgument();\r\n\t}\r\n\tconst [red, green, blue, alpha] = color;\r\n\r\n\tconst model = accessor.get(IModelService).getModel(uri);\r\n\tif (!model) {\r\n\t\tthrow illegalArgument();\r\n\t}\r\n\r\n\tconst colorInfo = {\r\n\t\trange,\r\n\t\tcolor: { red, green, blue, alpha }\r\n\t};\r\n\r\n\tconst presentations: IColorPresentation[] = [];\r\n\tconst providers = ColorProviderRegistry.ordered(model).reverse();\r\n\tconst promises = providers.map(provider => Promise.resolve(provider.provideColorPresentations(model, colorInfo, CancellationToken.None)).then(result => {\r\n\t\tif (Array.isArray(result)) {\r\n\t\t\tpresentations.push(...result);\r\n\t\t}\r\n\t}));\r\n\treturn Promise.all(promises).then(() => presentations);\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { DocumentSymbol } from 'vs/editor/common/modes';\r\nimport { IModelService } from 'vs/editor/common/services/modelService';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { ITextModelService } from 'vs/editor/common/services/resolverService';\r\nimport { OutlineModel } from 'vs/editor/contrib/documentSymbols/outlineModel';\r\nimport { CommandsRegistry } from 'vs/platform/commands/common/commands';\r\nimport { assertType } from 'vs/base/common/types';\r\n\r\nexport async function getDocumentSymbols(document: ITextModel, flat: boolean, token: CancellationToken): Promise {\r\n\tconst model = await OutlineModel.create(document, token);\r\n\treturn flat\r\n\t\t? model.asListOfDocumentSymbols()\r\n\t\t: model.getTopLevelSymbols();\r\n}\r\n\r\nCommandsRegistry.registerCommand('_executeDocumentSymbolProvider', async function (accessor, ...args) {\r\n\tconst [resource] = args;\r\n\tassertType(URI.isUri(resource));\r\n\r\n\tconst model = accessor.get(IModelService).getModel(resource);\r\n\tif (model) {\r\n\t\treturn getDocumentSymbols(model, false, CancellationToken.None);\r\n\t}\r\n\r\n\tconst reference = await accessor.get(ITextModelService).createModelReference(resource);\r\n\ttry {\r\n\t\treturn await getDocumentSymbols(reference.object.textEditorModel, false, CancellationToken.None);\r\n\t} finally {\r\n\t\treference.dispose();\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { onUnexpectedExternalError } from 'vs/base/common/errors';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { IRange, Range } from 'vs/editor/common/core/range';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { ILink, LinkProvider, LinkProviderRegistry, ILinksList } from 'vs/editor/common/modes';\r\nimport { IModelService } from 'vs/editor/common/services/modelService';\r\nimport { CommandsRegistry } from 'vs/platform/commands/common/commands';\r\nimport { isDisposable, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { coalesce } from 'vs/base/common/arrays';\r\nimport { assertType } from 'vs/base/common/types';\r\n\r\nexport class Link implements ILink {\r\n\r\n\tprivate _link: ILink;\r\n\tprivate readonly _provider: LinkProvider;\r\n\r\n\tconstructor(link: ILink, provider: LinkProvider) {\r\n\t\tthis._link = link;\r\n\t\tthis._provider = provider;\r\n\t}\r\n\r\n\ttoJSON(): ILink {\r\n\t\treturn {\r\n\t\t\trange: this.range,\r\n\t\t\turl: this.url,\r\n\t\t\ttooltip: this.tooltip\r\n\t\t};\r\n\t}\r\n\r\n\tget range(): IRange {\r\n\t\treturn this._link.range;\r\n\t}\r\n\r\n\tget url(): URI | string | undefined {\r\n\t\treturn this._link.url;\r\n\t}\r\n\r\n\tget tooltip(): string | undefined {\r\n\t\treturn this._link.tooltip;\r\n\t}\r\n\r\n\tasync resolve(token: CancellationToken): Promise {\r\n\t\tif (this._link.url) {\r\n\t\t\treturn this._link.url;\r\n\t\t}\r\n\r\n\t\tif (typeof this._provider.resolveLink === 'function') {\r\n\t\t\treturn Promise.resolve(this._provider.resolveLink(this._link, token)).then(value => {\r\n\t\t\t\tthis._link = value || this._link;\r\n\t\t\t\tif (this._link.url) {\r\n\t\t\t\t\t// recurse\r\n\t\t\t\t\treturn this.resolve(token);\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn Promise.reject(new Error('missing'));\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\treturn Promise.reject(new Error('missing'));\r\n\t}\r\n}\r\n\r\nexport class LinksList {\r\n\r\n\treadonly links: Link[];\r\n\r\n\tprivate readonly _disposables = new DisposableStore();\r\n\r\n\tconstructor(tuples: [ILinksList, LinkProvider][]) {\r\n\r\n\t\tlet links: Link[] = [];\r\n\t\tfor (const [list, provider] of tuples) {\r\n\t\t\t// merge all links\r\n\t\t\tconst newLinks = list.links.map(link => new Link(link, provider));\r\n\t\t\tlinks = LinksList._union(links, newLinks);\r\n\t\t\t// register disposables\r\n\t\t\tif (isDisposable(list)) {\r\n\t\t\t\tthis._disposables.add(list);\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis.links = links;\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._disposables.dispose();\r\n\t\tthis.links.length = 0;\r\n\t}\r\n\r\n\tprivate static _union(oldLinks: Link[], newLinks: Link[]): Link[] {\r\n\t\t// reunite oldLinks with newLinks and remove duplicates\r\n\t\tlet result: Link[] = [];\r\n\t\tlet oldIndex: number;\r\n\t\tlet oldLen: number;\r\n\t\tlet newIndex: number;\r\n\t\tlet newLen: number;\r\n\r\n\t\tfor (oldIndex = 0, newIndex = 0, oldLen = oldLinks.length, newLen = newLinks.length; oldIndex < oldLen && newIndex < newLen;) {\r\n\t\t\tconst oldLink = oldLinks[oldIndex];\r\n\t\t\tconst newLink = newLinks[newIndex];\r\n\r\n\t\t\tif (Range.areIntersectingOrTouching(oldLink.range, newLink.range)) {\r\n\t\t\t\t// Remove the oldLink\r\n\t\t\t\toldIndex++;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tconst comparisonResult = Range.compareRangesUsingStarts(oldLink.range, newLink.range);\r\n\r\n\t\t\tif (comparisonResult < 0) {\r\n\t\t\t\t// oldLink is before\r\n\t\t\t\tresult.push(oldLink);\r\n\t\t\t\toldIndex++;\r\n\t\t\t} else {\r\n\t\t\t\t// newLink is before\r\n\t\t\t\tresult.push(newLink);\r\n\t\t\t\tnewIndex++;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tfor (; oldIndex < oldLen; oldIndex++) {\r\n\t\t\tresult.push(oldLinks[oldIndex]);\r\n\t\t}\r\n\t\tfor (; newIndex < newLen; newIndex++) {\r\n\t\t\tresult.push(newLinks[newIndex]);\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n}\r\n\r\nexport function getLinks(model: ITextModel, token: CancellationToken): Promise {\r\n\r\n\tconst lists: [ILinksList, LinkProvider][] = [];\r\n\r\n\t// ask all providers for links in parallel\r\n\tconst promises = LinkProviderRegistry.ordered(model).reverse().map((provider, i) => {\r\n\t\treturn Promise.resolve(provider.provideLinks(model, token)).then(result => {\r\n\t\t\tif (result) {\r\n\t\t\t\tlists[i] = [result, provider];\r\n\t\t\t}\r\n\t\t}, onUnexpectedExternalError);\r\n\t});\r\n\r\n\treturn Promise.all(promises).then(() => {\r\n\t\tconst result = new LinksList(coalesce(lists));\r\n\t\tif (!token.isCancellationRequested) {\r\n\t\t\treturn result;\r\n\t\t}\r\n\t\tresult.dispose();\r\n\t\treturn new LinksList([]);\r\n\t});\r\n}\r\n\r\n\r\nCommandsRegistry.registerCommand('_executeLinkProvider', async (accessor, ...args): Promise => {\r\n\tlet [uri, resolveCount] = args;\r\n\tassertType(uri instanceof URI);\r\n\r\n\tif (typeof resolveCount !== 'number') {\r\n\t\tresolveCount = 0;\r\n\t}\r\n\r\n\tconst model = accessor.get(IModelService).getModel(uri);\r\n\tif (!model) {\r\n\t\treturn [];\r\n\t}\r\n\tconst list = await getLinks(model, CancellationToken.None);\r\n\tif (!list) {\r\n\t\treturn [];\r\n\t}\r\n\r\n\t// resolve links\r\n\tfor (let i = 0; i < Math.min(resolveCount, list.links.length); i++) {\r\n\t\tawait list.links[i].resolve(CancellationToken.None);\r\n\t}\r\n\r\n\tconst result = list.links.slice(0);\r\n\tlist.dispose();\r\n\treturn result;\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Event } from 'vs/base/common/event';\r\nimport { isFalsyOrWhitespace } from 'vs/base/common/strings';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { userAgent, isMacintosh, isLinux, isWindows, isWeb } from 'vs/base/common/platform';\r\n\r\nlet _userAgent = userAgent || '';\r\nconst STATIC_VALUES = new Map();\r\nSTATIC_VALUES.set('false', false);\r\nSTATIC_VALUES.set('true', true);\r\nSTATIC_VALUES.set('isMac', isMacintosh);\r\nSTATIC_VALUES.set('isLinux', isLinux);\r\nSTATIC_VALUES.set('isWindows', isWindows);\r\nSTATIC_VALUES.set('isWeb', isWeb);\r\nSTATIC_VALUES.set('isMacNative', isMacintosh && !isWeb);\r\nSTATIC_VALUES.set('isEdge', _userAgent.indexOf('Edg/') >= 0);\r\nSTATIC_VALUES.set('isFirefox', _userAgent.indexOf('Firefox') >= 0);\r\nSTATIC_VALUES.set('isChrome', _userAgent.indexOf('Chrome') >= 0);\r\nSTATIC_VALUES.set('isSafari', _userAgent.indexOf('Safari') >= 0);\r\nSTATIC_VALUES.set('isIPad', _userAgent.indexOf('iPad') >= 0);\r\n\r\nconst hasOwnProperty = Object.prototype.hasOwnProperty;\r\n\r\nexport const enum ContextKeyExprType {\r\n\tFalse = 0,\r\n\tTrue = 1,\r\n\tDefined = 2,\r\n\tNot = 3,\r\n\tEquals = 4,\r\n\tNotEquals = 5,\r\n\tAnd = 6,\r\n\tRegex = 7,\r\n\tNotRegex = 8,\r\n\tOr = 9,\r\n\tIn = 10,\r\n\tNotIn = 11,\r\n\tGreater = 12,\r\n\tGreaterEquals = 13,\r\n\tSmaller = 14,\r\n\tSmallerEquals = 15,\r\n}\r\n\r\nexport interface IContextKeyExpression {\r\n\r\n}\r\n\r\nexport type ContextKeyExpression = (\r\n\tContextKeyFalseExpr | ContextKeyTrueExpr | ContextKeyDefinedExpr | ContextKeyNotExpr\r\n\t| ContextKeyEqualsExpr | ContextKeyNotEqualsExpr | ContextKeyRegexExpr\r\n\t| ContextKeyNotRegexExpr | ContextKeyAndExpr | ContextKeyOrExpr | ContextKeyInExpr\r\n\t| ContextKeyNotInExpr | ContextKeyGreaterExpr | ContextKeyGreaterEqualsExpr\r\n\t| ContextKeySmallerExpr | ContextKeySmallerEqualsExpr\r\n);\r\n\r\nexport abstract class ContextKeyExpr {\r\n\r\n\tpublic static has(key: string): ContextKeyExpression {\r\n\t\treturn ContextKeyDefinedExpr.create(key);\r\n\t}\r\n\r\n\tpublic static equals(key: string, value: any): ContextKeyExpression {\r\n\t\treturn ContextKeyEqualsExpr.create(key, value);\r\n\t}\r\n\r\n\tpublic static regex(key: string, value: RegExp): ContextKeyExpression {\r\n\t\treturn ContextKeyRegexExpr.create(key, value);\r\n\t}\r\n\r\n\tpublic static not(key: string): ContextKeyExpression {\r\n\t\treturn ContextKeyNotExpr.create(key);\r\n\t}\r\n\r\n\tpublic static and(...expr: Array): ContextKeyExpression | undefined {\r\n\t\treturn ContextKeyAndExpr.create(expr);\r\n\t}\r\n\r\n\tpublic static or(...expr: Array): ContextKeyExpression | undefined {\r\n\t\treturn ContextKeyOrExpr.create(expr);\r\n\t}\r\n\r\n\tpublic static deserialize(serialized: string | null | undefined, strict: boolean = false): ContextKeyExpression | undefined {\r\n\t\tif (!serialized) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\r\n\t\treturn this._deserializeOrExpression(serialized, strict);\r\n\t}\r\n\r\n\tprivate static _deserializeOrExpression(serialized: string, strict: boolean): ContextKeyExpression | undefined {\r\n\t\tlet pieces = serialized.split('||');\r\n\t\treturn ContextKeyOrExpr.create(pieces.map(p => this._deserializeAndExpression(p, strict)));\r\n\t}\r\n\r\n\tprivate static _deserializeAndExpression(serialized: string, strict: boolean): ContextKeyExpression | undefined {\r\n\t\tlet pieces = serialized.split('&&');\r\n\t\treturn ContextKeyAndExpr.create(pieces.map(p => this._deserializeOne(p, strict)));\r\n\t}\r\n\r\n\tprivate static _deserializeOne(serializedOne: string, strict: boolean): ContextKeyExpression {\r\n\t\tserializedOne = serializedOne.trim();\r\n\r\n\t\tif (serializedOne.indexOf('!=') >= 0) {\r\n\t\t\tlet pieces = serializedOne.split('!=');\r\n\t\t\treturn ContextKeyNotEqualsExpr.create(pieces[0].trim(), this._deserializeValue(pieces[1], strict));\r\n\t\t}\r\n\r\n\t\tif (serializedOne.indexOf('==') >= 0) {\r\n\t\t\tlet pieces = serializedOne.split('==');\r\n\t\t\treturn ContextKeyEqualsExpr.create(pieces[0].trim(), this._deserializeValue(pieces[1], strict));\r\n\t\t}\r\n\r\n\t\tif (serializedOne.indexOf('=~') >= 0) {\r\n\t\t\tlet pieces = serializedOne.split('=~');\r\n\t\t\treturn ContextKeyRegexExpr.create(pieces[0].trim(), this._deserializeRegexValue(pieces[1], strict));\r\n\t\t}\r\n\r\n\t\tif (serializedOne.indexOf(' in ') >= 0) {\r\n\t\t\tlet pieces = serializedOne.split(' in ');\r\n\t\t\treturn ContextKeyInExpr.create(pieces[0].trim(), pieces[1].trim());\r\n\t\t}\r\n\r\n\t\tif (/^[^<=>]+>=[^<=>]+$/.test(serializedOne)) {\r\n\t\t\tconst pieces = serializedOne.split('>=');\r\n\t\t\treturn ContextKeyGreaterEqualsExpr.create(pieces[0].trim(), pieces[1].trim());\r\n\t\t}\r\n\r\n\t\tif (/^[^<=>]+>[^<=>]+$/.test(serializedOne)) {\r\n\t\t\tconst pieces = serializedOne.split('>');\r\n\t\t\treturn ContextKeyGreaterExpr.create(pieces[0].trim(), pieces[1].trim());\r\n\t\t}\r\n\r\n\t\tif (/^[^<=>]+<=[^<=>]+$/.test(serializedOne)) {\r\n\t\t\tconst pieces = serializedOne.split('<=');\r\n\t\t\treturn ContextKeySmallerEqualsExpr.create(pieces[0].trim(), pieces[1].trim());\r\n\t\t}\r\n\r\n\t\tif (/^[^<=>]+<[^<=>]+$/.test(serializedOne)) {\r\n\t\t\tconst pieces = serializedOne.split('<');\r\n\t\t\treturn ContextKeySmallerExpr.create(pieces[0].trim(), pieces[1].trim());\r\n\t\t}\r\n\r\n\t\tif (/^\\!\\s*/.test(serializedOne)) {\r\n\t\t\treturn ContextKeyNotExpr.create(serializedOne.substr(1).trim());\r\n\t\t}\r\n\r\n\t\treturn ContextKeyDefinedExpr.create(serializedOne);\r\n\t}\r\n\r\n\tprivate static _deserializeValue(serializedValue: string, strict: boolean): any {\r\n\t\tserializedValue = serializedValue.trim();\r\n\r\n\t\tif (serializedValue === 'true') {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tif (serializedValue === 'false') {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tlet m = /^'([^']*)'$/.exec(serializedValue);\r\n\t\tif (m) {\r\n\t\t\treturn m[1].trim();\r\n\t\t}\r\n\r\n\t\treturn serializedValue;\r\n\t}\r\n\r\n\tprivate static _deserializeRegexValue(serializedValue: string, strict: boolean): RegExp | null {\r\n\r\n\t\tif (isFalsyOrWhitespace(serializedValue)) {\r\n\t\t\tif (strict) {\r\n\t\t\t\tthrow new Error('missing regexp-value for =~-expression');\r\n\t\t\t} else {\r\n\t\t\t\tconsole.warn('missing regexp-value for =~-expression');\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet start = serializedValue.indexOf('/');\r\n\t\tlet end = serializedValue.lastIndexOf('/');\r\n\t\tif (start === end || start < 0 /* || to < 0 */) {\r\n\t\t\tif (strict) {\r\n\t\t\t\tthrow new Error(`bad regexp-value '${serializedValue}', missing /-enclosure`);\r\n\t\t\t} else {\r\n\t\t\t\tconsole.warn(`bad regexp-value '${serializedValue}', missing /-enclosure`);\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet value = serializedValue.slice(start + 1, end);\r\n\t\tlet caseIgnoreFlag = serializedValue[end + 1] === 'i' ? 'i' : '';\r\n\t\ttry {\r\n\t\t\treturn new RegExp(value, caseIgnoreFlag);\r\n\t\t} catch (e) {\r\n\t\t\tif (strict) {\r\n\t\t\t\tthrow new Error(`bad regexp-value '${serializedValue}', parse error: ${e}`);\r\n\t\t\t} else {\r\n\t\t\t\tconsole.warn(`bad regexp-value '${serializedValue}', parse error: ${e}`);\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction cmp(a: ContextKeyExpression, b: ContextKeyExpression): number {\r\n\treturn a.cmp(b);\r\n}\r\n\r\nexport class ContextKeyFalseExpr implements IContextKeyExpression {\r\n\tpublic static INSTANCE = new ContextKeyFalseExpr();\r\n\r\n\tpublic readonly type = ContextKeyExprType.False;\r\n\r\n\tprotected constructor() {\r\n\t}\r\n\r\n\tpublic cmp(other: ContextKeyExpression): number {\r\n\t\treturn this.type - other.type;\r\n\t}\r\n\r\n\tpublic equals(other: ContextKeyExpression): boolean {\r\n\t\treturn (other.type === this.type);\r\n\t}\r\n\r\n\tpublic evaluate(context: IContext): boolean {\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic serialize(): string {\r\n\t\treturn 'false';\r\n\t}\r\n\r\n\tpublic keys(): string[] {\r\n\t\treturn [];\r\n\t}\r\n\r\n\tpublic negate(): ContextKeyExpression {\r\n\t\treturn ContextKeyTrueExpr.INSTANCE;\r\n\t}\r\n}\r\n\r\nexport class ContextKeyTrueExpr implements IContextKeyExpression {\r\n\tpublic static INSTANCE = new ContextKeyTrueExpr();\r\n\r\n\tpublic readonly type = ContextKeyExprType.True;\r\n\r\n\tprotected constructor() {\r\n\t}\r\n\r\n\tpublic cmp(other: ContextKeyExpression): number {\r\n\t\treturn this.type - other.type;\r\n\t}\r\n\r\n\tpublic equals(other: ContextKeyExpression): boolean {\r\n\t\treturn (other.type === this.type);\r\n\t}\r\n\r\n\tpublic evaluate(context: IContext): boolean {\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic serialize(): string {\r\n\t\treturn 'true';\r\n\t}\r\n\r\n\tpublic keys(): string[] {\r\n\t\treturn [];\r\n\t}\r\n\r\n\tpublic negate(): ContextKeyExpression {\r\n\t\treturn ContextKeyFalseExpr.INSTANCE;\r\n\t}\r\n}\r\n\r\nexport class ContextKeyDefinedExpr implements IContextKeyExpression {\r\n\tpublic static create(key: string): ContextKeyExpression {\r\n\t\tconst staticValue = STATIC_VALUES.get(key);\r\n\t\tif (typeof staticValue === 'boolean') {\r\n\t\t\treturn staticValue ? ContextKeyTrueExpr.INSTANCE : ContextKeyFalseExpr.INSTANCE;\r\n\t\t}\r\n\t\treturn new ContextKeyDefinedExpr(key);\r\n\t}\r\n\r\n\tpublic readonly type = ContextKeyExprType.Defined;\r\n\r\n\tprotected constructor(protected readonly key: string) {\r\n\t}\r\n\r\n\tpublic cmp(other: ContextKeyExpression): number {\r\n\t\tif (other.type !== this.type) {\r\n\t\t\treturn this.type - other.type;\r\n\t\t}\r\n\t\treturn cmp1(this.key, other.key);\r\n\t}\r\n\r\n\tpublic equals(other: ContextKeyExpression): boolean {\r\n\t\tif (other.type === this.type) {\r\n\t\t\treturn (this.key === other.key);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic evaluate(context: IContext): boolean {\r\n\t\treturn (!!context.getValue(this.key));\r\n\t}\r\n\r\n\tpublic serialize(): string {\r\n\t\treturn this.key;\r\n\t}\r\n\r\n\tpublic keys(): string[] {\r\n\t\treturn [this.key];\r\n\t}\r\n\r\n\tpublic negate(): ContextKeyExpression {\r\n\t\treturn ContextKeyNotExpr.create(this.key);\r\n\t}\r\n}\r\n\r\nexport class ContextKeyEqualsExpr implements IContextKeyExpression {\r\n\r\n\tpublic static create(key: string, value: any): ContextKeyExpression {\r\n\t\tif (typeof value === 'boolean') {\r\n\t\t\treturn (value ? ContextKeyDefinedExpr.create(key) : ContextKeyNotExpr.create(key));\r\n\t\t}\r\n\t\tconst staticValue = STATIC_VALUES.get(key);\r\n\t\tif (typeof staticValue === 'boolean') {\r\n\t\t\tconst trueValue = staticValue ? 'true' : 'false';\r\n\t\t\treturn (value === trueValue ? ContextKeyTrueExpr.INSTANCE : ContextKeyFalseExpr.INSTANCE);\r\n\t\t}\r\n\t\treturn new ContextKeyEqualsExpr(key, value);\r\n\t}\r\n\r\n\tpublic readonly type = ContextKeyExprType.Equals;\r\n\r\n\tprivate constructor(private readonly key: string, private readonly value: any) {\r\n\t}\r\n\r\n\tpublic cmp(other: ContextKeyExpression): number {\r\n\t\tif (other.type !== this.type) {\r\n\t\t\treturn this.type - other.type;\r\n\t\t}\r\n\t\treturn cmp2(this.key, this.value, other.key, other.value);\r\n\t}\r\n\r\n\tpublic equals(other: ContextKeyExpression): boolean {\r\n\t\tif (other.type === this.type) {\r\n\t\t\treturn (this.key === other.key && this.value === other.value);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic evaluate(context: IContext): boolean {\r\n\t\t// Intentional ==\r\n\t\t// eslint-disable-next-line eqeqeq\r\n\t\treturn (context.getValue(this.key) == this.value);\r\n\t}\r\n\r\n\tpublic serialize(): string {\r\n\t\treturn `${this.key} == '${this.value}'`;\r\n\t}\r\n\r\n\tpublic keys(): string[] {\r\n\t\treturn [this.key];\r\n\t}\r\n\r\n\tpublic negate(): ContextKeyExpression {\r\n\t\treturn ContextKeyNotEqualsExpr.create(this.key, this.value);\r\n\t}\r\n}\r\n\r\nexport class ContextKeyInExpr implements IContextKeyExpression {\r\n\r\n\tpublic static create(key: string, valueKey: string): ContextKeyInExpr {\r\n\t\treturn new ContextKeyInExpr(key, valueKey);\r\n\t}\r\n\r\n\tpublic readonly type = ContextKeyExprType.In;\r\n\r\n\tprivate constructor(private readonly key: string, private readonly valueKey: string) {\r\n\t}\r\n\r\n\tpublic cmp(other: ContextKeyExpression): number {\r\n\t\tif (other.type !== this.type) {\r\n\t\t\treturn this.type - other.type;\r\n\t\t}\r\n\t\treturn cmp2(this.key, this.valueKey, other.key, other.valueKey);\r\n\t}\r\n\r\n\tpublic equals(other: ContextKeyExpression): boolean {\r\n\t\tif (other.type === this.type) {\r\n\t\t\treturn (this.key === other.key && this.valueKey === other.valueKey);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic evaluate(context: IContext): boolean {\r\n\t\tconst source = context.getValue(this.valueKey);\r\n\r\n\t\tconst item = context.getValue(this.key);\r\n\r\n\t\tif (Array.isArray(source)) {\r\n\t\t\treturn (source.indexOf(item) >= 0);\r\n\t\t}\r\n\r\n\t\tif (typeof item === 'string' && typeof source === 'object' && source !== null) {\r\n\t\t\treturn hasOwnProperty.call(source, item);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic serialize(): string {\r\n\t\treturn `${this.key} in '${this.valueKey}'`;\r\n\t}\r\n\r\n\tpublic keys(): string[] {\r\n\t\treturn [this.key, this.valueKey];\r\n\t}\r\n\r\n\tpublic negate(): ContextKeyExpression {\r\n\t\treturn ContextKeyNotInExpr.create(this);\r\n\t}\r\n}\r\n\r\nexport class ContextKeyNotInExpr implements IContextKeyExpression {\r\n\r\n\tpublic static create(actual: ContextKeyInExpr): ContextKeyNotInExpr {\r\n\t\treturn new ContextKeyNotInExpr(actual);\r\n\t}\r\n\r\n\tpublic readonly type = ContextKeyExprType.NotIn;\r\n\r\n\tprivate constructor(private readonly _actual: ContextKeyInExpr) {\r\n\t\t//\r\n\t}\r\n\r\n\tpublic cmp(other: ContextKeyExpression): number {\r\n\t\tif (other.type !== this.type) {\r\n\t\t\treturn this.type - other.type;\r\n\t\t}\r\n\t\treturn this._actual.cmp(other._actual);\r\n\t}\r\n\r\n\tpublic equals(other: ContextKeyExpression): boolean {\r\n\t\tif (other.type === this.type) {\r\n\t\t\treturn this._actual.equals(other._actual);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic evaluate(context: IContext): boolean {\r\n\t\treturn !this._actual.evaluate(context);\r\n\t}\r\n\r\n\tpublic serialize(): string {\r\n\t\tthrow new Error('Method not implemented.');\r\n\t}\r\n\r\n\tpublic keys(): string[] {\r\n\t\treturn this._actual.keys();\r\n\t}\r\n\r\n\tpublic negate(): ContextKeyExpression {\r\n\t\treturn this._actual;\r\n\t}\r\n}\r\n\r\nexport class ContextKeyNotEqualsExpr implements IContextKeyExpression {\r\n\r\n\tpublic static create(key: string, value: any): ContextKeyExpression {\r\n\t\tif (typeof value === 'boolean') {\r\n\t\t\tif (value) {\r\n\t\t\t\treturn ContextKeyNotExpr.create(key);\r\n\t\t\t}\r\n\t\t\treturn ContextKeyDefinedExpr.create(key);\r\n\t\t}\r\n\t\tconst staticValue = STATIC_VALUES.get(key);\r\n\t\tif (typeof staticValue === 'boolean') {\r\n\t\t\tconst falseValue = staticValue ? 'true' : 'false';\r\n\t\t\treturn (value === falseValue ? ContextKeyFalseExpr.INSTANCE : ContextKeyTrueExpr.INSTANCE);\r\n\t\t}\r\n\t\treturn new ContextKeyNotEqualsExpr(key, value);\r\n\t}\r\n\r\n\tpublic readonly type = ContextKeyExprType.NotEquals;\r\n\r\n\tprivate constructor(private readonly key: string, private readonly value: any) {\r\n\t}\r\n\r\n\tpublic cmp(other: ContextKeyExpression): number {\r\n\t\tif (other.type !== this.type) {\r\n\t\t\treturn this.type - other.type;\r\n\t\t}\r\n\t\treturn cmp2(this.key, this.value, other.key, other.value);\r\n\t}\r\n\r\n\tpublic equals(other: ContextKeyExpression): boolean {\r\n\t\tif (other.type === this.type) {\r\n\t\t\treturn (this.key === other.key && this.value === other.value);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic evaluate(context: IContext): boolean {\r\n\t\t// Intentional !=\r\n\t\t// eslint-disable-next-line eqeqeq\r\n\t\treturn (context.getValue(this.key) != this.value);\r\n\t}\r\n\r\n\tpublic serialize(): string {\r\n\t\treturn `${this.key} != '${this.value}'`;\r\n\t}\r\n\r\n\tpublic keys(): string[] {\r\n\t\treturn [this.key];\r\n\t}\r\n\r\n\tpublic negate(): ContextKeyExpression {\r\n\t\treturn ContextKeyEqualsExpr.create(this.key, this.value);\r\n\t}\r\n}\r\n\r\nexport class ContextKeyNotExpr implements IContextKeyExpression {\r\n\r\n\tpublic static create(key: string): ContextKeyExpression {\r\n\t\tconst staticValue = STATIC_VALUES.get(key);\r\n\t\tif (typeof staticValue === 'boolean') {\r\n\t\t\treturn (staticValue ? ContextKeyFalseExpr.INSTANCE : ContextKeyTrueExpr.INSTANCE);\r\n\t\t}\r\n\t\treturn new ContextKeyNotExpr(key);\r\n\t}\r\n\r\n\tpublic readonly type = ContextKeyExprType.Not;\r\n\r\n\tprivate constructor(private readonly key: string) {\r\n\t}\r\n\r\n\tpublic cmp(other: ContextKeyExpression): number {\r\n\t\tif (other.type !== this.type) {\r\n\t\t\treturn this.type - other.type;\r\n\t\t}\r\n\t\treturn cmp1(this.key, other.key);\r\n\t}\r\n\r\n\tpublic equals(other: ContextKeyExpression): boolean {\r\n\t\tif (other.type === this.type) {\r\n\t\t\treturn (this.key === other.key);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic evaluate(context: IContext): boolean {\r\n\t\treturn (!context.getValue(this.key));\r\n\t}\r\n\r\n\tpublic serialize(): string {\r\n\t\treturn `!${this.key}`;\r\n\t}\r\n\r\n\tpublic keys(): string[] {\r\n\t\treturn [this.key];\r\n\t}\r\n\r\n\tpublic negate(): ContextKeyExpression {\r\n\t\treturn ContextKeyDefinedExpr.create(this.key);\r\n\t}\r\n}\r\n\r\nexport class ContextKeyGreaterExpr implements IContextKeyExpression {\r\n\r\n\tpublic static create(key: string, value: any): ContextKeyExpression {\r\n\t\treturn new ContextKeyGreaterExpr(key, value);\r\n\t}\r\n\r\n\tpublic readonly type = ContextKeyExprType.Greater;\r\n\r\n\tprivate constructor(\r\n\t\tprivate readonly key: string,\r\n\t\tprivate readonly value: any\r\n\t) { }\r\n\r\n\tpublic cmp(other: ContextKeyExpression): number {\r\n\t\tif (other.type !== this.type) {\r\n\t\t\treturn this.type - other.type;\r\n\t\t}\r\n\t\treturn cmp2(this.key, this.value, other.key, other.value);\r\n\t}\r\n\r\n\tpublic equals(other: ContextKeyExpression): boolean {\r\n\t\tif (other.type === this.type) {\r\n\t\t\treturn (this.key === other.key && this.value === other.value);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic evaluate(context: IContext): boolean {\r\n\t\treturn (parseFloat(context.getValue(this.key)) > parseFloat(this.value));\r\n\t}\r\n\r\n\tpublic serialize(): string {\r\n\t\treturn `${this.key} > ${this.value}`;\r\n\t}\r\n\r\n\tpublic keys(): string[] {\r\n\t\treturn [this.key];\r\n\t}\r\n\r\n\tpublic negate(): ContextKeyExpression {\r\n\t\treturn ContextKeySmallerEqualsExpr.create(this.key, this.value);\r\n\t}\r\n}\r\n\r\nexport class ContextKeyGreaterEqualsExpr implements IContextKeyExpression {\r\n\r\n\tpublic static create(key: string, value: any): ContextKeyExpression {\r\n\t\treturn new ContextKeyGreaterEqualsExpr(key, value);\r\n\t}\r\n\r\n\tpublic readonly type = ContextKeyExprType.GreaterEquals;\r\n\r\n\tprivate constructor(\r\n\t\tprivate readonly key: string,\r\n\t\tprivate readonly value: any\r\n\t) { }\r\n\r\n\tpublic cmp(other: ContextKeyExpression): number {\r\n\t\tif (other.type !== this.type) {\r\n\t\t\treturn this.type - other.type;\r\n\t\t}\r\n\t\treturn cmp2(this.key, this.value, other.key, other.value);\r\n\t}\r\n\r\n\tpublic equals(other: ContextKeyExpression): boolean {\r\n\t\tif (other.type === this.type) {\r\n\t\t\treturn (this.key === other.key && this.value === other.value);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic evaluate(context: IContext): boolean {\r\n\t\treturn (parseFloat(context.getValue(this.key)) >= parseFloat(this.value));\r\n\t}\r\n\r\n\tpublic serialize(): string {\r\n\t\treturn `${this.key} >= ${this.value}`;\r\n\t}\r\n\r\n\tpublic keys(): string[] {\r\n\t\treturn [this.key];\r\n\t}\r\n\r\n\tpublic negate(): ContextKeyExpression {\r\n\t\treturn ContextKeySmallerExpr.create(this.key, this.value);\r\n\t}\r\n}\r\n\r\nexport class ContextKeySmallerExpr implements IContextKeyExpression {\r\n\r\n\tpublic static create(key: string, value: any): ContextKeyExpression {\r\n\t\treturn new ContextKeySmallerExpr(key, value);\r\n\t}\r\n\r\n\tpublic readonly type = ContextKeyExprType.Smaller;\r\n\r\n\tprivate constructor(\r\n\t\tprivate readonly key: string,\r\n\t\tprivate readonly value: any\r\n\t) {\r\n\t}\r\n\r\n\tpublic cmp(other: ContextKeyExpression): number {\r\n\t\tif (other.type !== this.type) {\r\n\t\t\treturn this.type - other.type;\r\n\t\t}\r\n\t\treturn cmp2(this.key, this.value, other.key, other.value);\r\n\t}\r\n\r\n\tpublic equals(other: ContextKeyExpression): boolean {\r\n\t\tif (other.type === this.type) {\r\n\t\t\treturn (this.key === other.key && this.value === other.value);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic evaluate(context: IContext): boolean {\r\n\t\treturn (parseFloat(context.getValue(this.key)) < parseFloat(this.value));\r\n\t}\r\n\r\n\tpublic serialize(): string {\r\n\t\treturn `${this.key} < ${this.value}`;\r\n\t}\r\n\r\n\tpublic keys(): string[] {\r\n\t\treturn [this.key];\r\n\t}\r\n\r\n\tpublic negate(): ContextKeyExpression {\r\n\t\treturn ContextKeyGreaterEqualsExpr.create(this.key, this.value);\r\n\t}\r\n}\r\n\r\nexport class ContextKeySmallerEqualsExpr implements IContextKeyExpression {\r\n\r\n\tpublic static create(key: string, value: any): ContextKeyExpression {\r\n\t\treturn new ContextKeySmallerEqualsExpr(key, value);\r\n\t}\r\n\r\n\tpublic readonly type = ContextKeyExprType.SmallerEquals;\r\n\r\n\tprivate constructor(\r\n\t\tprivate readonly key: string,\r\n\t\tprivate readonly value: any\r\n\t) {\r\n\t}\r\n\r\n\tpublic cmp(other: ContextKeyExpression): number {\r\n\t\tif (other.type !== this.type) {\r\n\t\t\treturn this.type - other.type;\r\n\t\t}\r\n\t\treturn cmp2(this.key, this.value, other.key, other.value);\r\n\t}\r\n\r\n\tpublic equals(other: ContextKeyExpression): boolean {\r\n\t\tif (other.type === this.type) {\r\n\t\t\treturn (this.key === other.key && this.value === other.value);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic evaluate(context: IContext): boolean {\r\n\t\treturn (parseFloat(context.getValue(this.key)) <= parseFloat(this.value));\r\n\t}\r\n\r\n\tpublic serialize(): string {\r\n\t\treturn `${this.key} <= ${this.value}`;\r\n\t}\r\n\r\n\tpublic keys(): string[] {\r\n\t\treturn [this.key];\r\n\t}\r\n\r\n\tpublic negate(): ContextKeyExpression {\r\n\t\treturn ContextKeyGreaterExpr.create(this.key, this.value);\r\n\t}\r\n}\r\n\r\nexport class ContextKeyRegexExpr implements IContextKeyExpression {\r\n\r\n\tpublic static create(key: string, regexp: RegExp | null): ContextKeyRegexExpr {\r\n\t\treturn new ContextKeyRegexExpr(key, regexp);\r\n\t}\r\n\r\n\tpublic readonly type = ContextKeyExprType.Regex;\r\n\r\n\tprivate constructor(private readonly key: string, private readonly regexp: RegExp | null) {\r\n\t\t//\r\n\t}\r\n\r\n\tpublic cmp(other: ContextKeyExpression): number {\r\n\t\tif (other.type !== this.type) {\r\n\t\t\treturn this.type - other.type;\r\n\t\t}\r\n\t\tif (this.key < other.key) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\tif (this.key > other.key) {\r\n\t\t\treturn 1;\r\n\t\t}\r\n\t\tconst thisSource = this.regexp ? this.regexp.source : '';\r\n\t\tconst otherSource = other.regexp ? other.regexp.source : '';\r\n\t\tif (thisSource < otherSource) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\tif (thisSource > otherSource) {\r\n\t\t\treturn 1;\r\n\t\t}\r\n\t\treturn 0;\r\n\t}\r\n\r\n\tpublic equals(other: ContextKeyExpression): boolean {\r\n\t\tif (other.type === this.type) {\r\n\t\t\tconst thisSource = this.regexp ? this.regexp.source : '';\r\n\t\t\tconst otherSource = other.regexp ? other.regexp.source : '';\r\n\t\t\treturn (this.key === other.key && thisSource === otherSource);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic evaluate(context: IContext): boolean {\r\n\t\tlet value = context.getValue(this.key);\r\n\t\treturn this.regexp ? this.regexp.test(value) : false;\r\n\t}\r\n\r\n\tpublic serialize(): string {\r\n\t\tconst value = this.regexp\r\n\t\t\t? `/${this.regexp.source}/${this.regexp.ignoreCase ? 'i' : ''}`\r\n\t\t\t: '/invalid/';\r\n\t\treturn `${this.key} =~ ${value}`;\r\n\t}\r\n\r\n\tpublic keys(): string[] {\r\n\t\treturn [this.key];\r\n\t}\r\n\r\n\tpublic negate(): ContextKeyExpression {\r\n\t\treturn ContextKeyNotRegexExpr.create(this);\r\n\t}\r\n}\r\n\r\nexport class ContextKeyNotRegexExpr implements IContextKeyExpression {\r\n\r\n\tpublic static create(actual: ContextKeyRegexExpr): ContextKeyExpression {\r\n\t\treturn new ContextKeyNotRegexExpr(actual);\r\n\t}\r\n\r\n\tpublic readonly type = ContextKeyExprType.NotRegex;\r\n\r\n\tprivate constructor(private readonly _actual: ContextKeyRegexExpr) {\r\n\t\t//\r\n\t}\r\n\r\n\tpublic cmp(other: ContextKeyExpression): number {\r\n\t\tif (other.type !== this.type) {\r\n\t\t\treturn this.type - other.type;\r\n\t\t}\r\n\t\treturn this._actual.cmp(other._actual);\r\n\t}\r\n\r\n\tpublic equals(other: ContextKeyExpression): boolean {\r\n\t\tif (other.type === this.type) {\r\n\t\t\treturn this._actual.equals(other._actual);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic evaluate(context: IContext): boolean {\r\n\t\treturn !this._actual.evaluate(context);\r\n\t}\r\n\r\n\tpublic serialize(): string {\r\n\t\tthrow new Error('Method not implemented.');\r\n\t}\r\n\r\n\tpublic keys(): string[] {\r\n\t\treturn this._actual.keys();\r\n\t}\r\n\r\n\tpublic negate(): ContextKeyExpression {\r\n\t\treturn this._actual;\r\n\t}\r\n}\r\n\r\nexport class ContextKeyAndExpr implements IContextKeyExpression {\r\n\r\n\tpublic static create(_expr: ReadonlyArray): ContextKeyExpression | undefined {\r\n\t\treturn ContextKeyAndExpr._normalizeArr(_expr);\r\n\t}\r\n\r\n\tpublic readonly type = ContextKeyExprType.And;\r\n\r\n\tprivate constructor(public readonly expr: ContextKeyExpression[]) {\r\n\t}\r\n\r\n\tpublic cmp(other: ContextKeyExpression): number {\r\n\t\tif (other.type !== this.type) {\r\n\t\t\treturn this.type - other.type;\r\n\t\t}\r\n\t\tif (this.expr.length < other.expr.length) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\tif (this.expr.length > other.expr.length) {\r\n\t\t\treturn 1;\r\n\t\t}\r\n\t\tfor (let i = 0, len = this.expr.length; i < len; i++) {\r\n\t\t\tconst r = cmp(this.expr[i], other.expr[i]);\r\n\t\t\tif (r !== 0) {\r\n\t\t\t\treturn r;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn 0;\r\n\t}\r\n\r\n\tpublic equals(other: ContextKeyExpression): boolean {\r\n\t\tif (other.type === this.type) {\r\n\t\t\tif (this.expr.length !== other.expr.length) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t\tfor (let i = 0, len = this.expr.length; i < len; i++) {\r\n\t\t\t\tif (!this.expr[i].equals(other.expr[i])) {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic evaluate(context: IContext): boolean {\r\n\t\tfor (let i = 0, len = this.expr.length; i < len; i++) {\r\n\t\t\tif (!this.expr[i].evaluate(context)) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\tprivate static _normalizeArr(arr: ReadonlyArray): ContextKeyExpression | undefined {\r\n\t\tconst expr: ContextKeyExpression[] = [];\r\n\t\tlet hasTrue = false;\r\n\r\n\t\tfor (const e of arr) {\r\n\t\t\tif (!e) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (e.type === ContextKeyExprType.True) {\r\n\t\t\t\t// anything && true ==> anything\r\n\t\t\t\thasTrue = true;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (e.type === ContextKeyExprType.False) {\r\n\t\t\t\t// anything && false ==> false\r\n\t\t\t\treturn ContextKeyFalseExpr.INSTANCE;\r\n\t\t\t}\r\n\r\n\t\t\tif (e.type === ContextKeyExprType.And) {\r\n\t\t\t\texpr.push(...e.expr);\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\texpr.push(e);\r\n\t\t}\r\n\r\n\t\tif (expr.length === 0 && hasTrue) {\r\n\t\t\treturn ContextKeyTrueExpr.INSTANCE;\r\n\t\t}\r\n\r\n\t\tif (expr.length === 0) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\r\n\t\tif (expr.length === 1) {\r\n\t\t\treturn expr[0];\r\n\t\t}\r\n\r\n\t\texpr.sort(cmp);\r\n\r\n\t\t// We must distribute any OR expression because we don't support parens\r\n\t\t// OR extensions will be at the end (due to sorting rules)\r\n\t\twhile (expr.length > 1) {\r\n\t\t\tconst lastElement = expr[expr.length - 1];\r\n\t\t\tif (lastElement.type !== ContextKeyExprType.Or) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\t// pop the last element\r\n\t\t\texpr.pop();\r\n\r\n\t\t\t// pop the second to last element\r\n\t\t\tconst secondToLastElement = expr.pop()!;\r\n\r\n\t\t\t// distribute `lastElement` over `secondToLastElement`\r\n\t\t\tconst resultElement = ContextKeyOrExpr.create(\r\n\t\t\t\tlastElement.expr.map(el => ContextKeyAndExpr.create([el, secondToLastElement]))\r\n\t\t\t);\r\n\r\n\t\t\tif (resultElement) {\r\n\t\t\t\texpr.push(resultElement);\r\n\t\t\t\texpr.sort(cmp);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (expr.length === 1) {\r\n\t\t\treturn expr[0];\r\n\t\t}\r\n\r\n\t\treturn new ContextKeyAndExpr(expr);\r\n\t}\r\n\r\n\tpublic serialize(): string {\r\n\t\treturn this.expr.map(e => e.serialize()).join(' && ');\r\n\t}\r\n\r\n\tpublic keys(): string[] {\r\n\t\tconst result: string[] = [];\r\n\t\tfor (let expr of this.expr) {\r\n\t\t\tresult.push(...expr.keys());\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic negate(): ContextKeyExpression {\r\n\t\tlet result: ContextKeyExpression[] = [];\r\n\t\tfor (let expr of this.expr) {\r\n\t\t\tresult.push(expr.negate());\r\n\t\t}\r\n\t\treturn ContextKeyOrExpr.create(result)!;\r\n\t}\r\n}\r\n\r\nexport class ContextKeyOrExpr implements IContextKeyExpression {\r\n\r\n\tpublic static create(_expr: ReadonlyArray): ContextKeyExpression | undefined {\r\n\t\tconst expr = ContextKeyOrExpr._normalizeArr(_expr);\r\n\t\tif (expr.length === 0) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\r\n\t\tif (expr.length === 1) {\r\n\t\t\treturn expr[0];\r\n\t\t}\r\n\r\n\t\treturn new ContextKeyOrExpr(expr);\r\n\t}\r\n\r\n\tpublic readonly type = ContextKeyExprType.Or;\r\n\r\n\tprivate constructor(public readonly expr: ContextKeyExpression[]) {\r\n\t}\r\n\r\n\tpublic cmp(other: ContextKeyExpression): number {\r\n\t\tif (other.type !== this.type) {\r\n\t\t\treturn this.type - other.type;\r\n\t\t}\r\n\t\tif (this.expr.length < other.expr.length) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\tif (this.expr.length > other.expr.length) {\r\n\t\t\treturn 1;\r\n\t\t}\r\n\t\tfor (let i = 0, len = this.expr.length; i < len; i++) {\r\n\t\t\tconst r = cmp(this.expr[i], other.expr[i]);\r\n\t\t\tif (r !== 0) {\r\n\t\t\t\treturn r;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn 0;\r\n\t}\r\n\r\n\tpublic equals(other: ContextKeyExpression): boolean {\r\n\t\tif (other.type === this.type) {\r\n\t\t\tif (this.expr.length !== other.expr.length) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t\tfor (let i = 0, len = this.expr.length; i < len; i++) {\r\n\t\t\t\tif (!this.expr[i].equals(other.expr[i])) {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic evaluate(context: IContext): boolean {\r\n\t\tfor (let i = 0, len = this.expr.length; i < len; i++) {\r\n\t\t\tif (this.expr[i].evaluate(context)) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tprivate static _normalizeArr(arr: ReadonlyArray): ContextKeyExpression[] {\r\n\t\tlet expr: ContextKeyExpression[] = [];\r\n\t\tlet hasFalse = false;\r\n\r\n\t\tif (arr) {\r\n\t\t\tfor (let i = 0, len = arr.length; i < len; i++) {\r\n\t\t\t\tconst e = arr[i];\r\n\t\t\t\tif (!e) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (e.type === ContextKeyExprType.False) {\r\n\t\t\t\t\t// anything || false ==> anything\r\n\t\t\t\t\thasFalse = true;\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (e.type === ContextKeyExprType.True) {\r\n\t\t\t\t\t// anything || true ==> true\r\n\t\t\t\t\treturn [ContextKeyTrueExpr.INSTANCE];\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (e.type === ContextKeyExprType.Or) {\r\n\t\t\t\t\texpr = expr.concat(e.expr);\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\texpr.push(e);\r\n\t\t\t}\r\n\r\n\t\t\tif (expr.length === 0 && hasFalse) {\r\n\t\t\t\treturn [ContextKeyFalseExpr.INSTANCE];\r\n\t\t\t}\r\n\r\n\t\t\texpr.sort(cmp);\r\n\t\t}\r\n\r\n\t\treturn expr;\r\n\t}\r\n\r\n\tpublic serialize(): string {\r\n\t\treturn this.expr.map(e => e.serialize()).join(' || ');\r\n\t}\r\n\r\n\tpublic keys(): string[] {\r\n\t\tconst result: string[] = [];\r\n\t\tfor (let expr of this.expr) {\r\n\t\t\tresult.push(...expr.keys());\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic negate(): ContextKeyExpression {\r\n\t\tlet result: ContextKeyExpression[] = [];\r\n\t\tfor (let expr of this.expr) {\r\n\t\t\tresult.push(expr.negate());\r\n\t\t}\r\n\r\n\t\tconst terminals = (node: ContextKeyExpression) => {\r\n\t\t\tif (node.type === ContextKeyExprType.Or) {\r\n\t\t\t\treturn node.expr;\r\n\t\t\t}\r\n\t\t\treturn [node];\r\n\t\t};\r\n\r\n\t\t// We don't support parens, so here we distribute the AND over the OR terminals\r\n\t\t// We always take the first 2 AND pairs and distribute them\r\n\t\twhile (result.length > 1) {\r\n\t\t\tconst LEFT = result.shift()!;\r\n\t\t\tconst RIGHT = result.shift()!;\r\n\r\n\t\t\tconst all: ContextKeyExpression[] = [];\r\n\t\t\tfor (const left of terminals(LEFT)) {\r\n\t\t\t\tfor (const right of terminals(RIGHT)) {\r\n\t\t\t\t\tall.push(ContextKeyExpr.and(left, right)!);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tresult.unshift(ContextKeyExpr.or(...all)!);\r\n\t\t}\r\n\r\n\t\treturn result[0];\r\n\t}\r\n}\r\n\r\nexport class RawContextKey extends ContextKeyDefinedExpr {\r\n\r\n\tprivate readonly _defaultValue: T | undefined;\r\n\r\n\tconstructor(key: string, defaultValue: T | undefined) {\r\n\t\tsuper(key);\r\n\t\tthis._defaultValue = defaultValue;\r\n\t}\r\n\r\n\tpublic bindTo(target: IContextKeyService): IContextKey {\r\n\t\treturn target.createKey(this.key, this._defaultValue);\r\n\t}\r\n\r\n\tpublic getValue(target: IContextKeyService): T | undefined {\r\n\t\treturn target.getContextKeyValue(this.key);\r\n\t}\r\n\r\n\tpublic toNegated(): ContextKeyExpression {\r\n\t\treturn ContextKeyExpr.not(this.key);\r\n\t}\r\n\r\n\tpublic isEqualTo(value: any): ContextKeyExpression {\r\n\t\treturn ContextKeyExpr.equals(this.key, value);\r\n\t}\r\n}\r\n\r\nexport interface IContext {\r\n\tgetValue(key: string): T | undefined;\r\n}\r\n\r\nexport interface IContextKey {\r\n\tset(value: T): void;\r\n\treset(): void;\r\n\tget(): T | undefined;\r\n}\r\n\r\nexport interface IContextKeyServiceTarget {\r\n\tparentElement: IContextKeyServiceTarget | null;\r\n\tsetAttribute(attr: string, value: string): void;\r\n\tremoveAttribute(attr: string): void;\r\n\thasAttribute(attr: string): boolean;\r\n\tgetAttribute(attr: string): string | null;\r\n}\r\n\r\nexport const IContextKeyService = createDecorator('contextKeyService');\r\n\r\nexport interface IReadableSet {\r\n\thas(value: T): boolean;\r\n}\r\n\r\nexport interface IContextKeyChangeEvent {\r\n\taffectsSome(keys: IReadableSet): boolean;\r\n}\r\n\r\nexport interface IContextKeyService {\r\n\treadonly _serviceBrand: undefined;\r\n\tdispose(): void;\r\n\r\n\tonDidChangeContext: Event;\r\n\tbufferChangeEvents(callback: Function): void;\r\n\r\n\tcreateKey(key: string, defaultValue: T | undefined): IContextKey;\r\n\tcontextMatchesRules(rules: ContextKeyExpression | undefined): boolean;\r\n\tgetContextKeyValue(key: string): T | undefined;\r\n\r\n\tcreateScoped(target?: IContextKeyServiceTarget): IContextKeyService;\r\n\tgetContext(target: IContextKeyServiceTarget | null): IContext;\r\n}\r\n\r\nexport const SET_CONTEXT_COMMAND_ID = 'setContext';\r\n\r\nfunction cmp1(key1: string, key2: string): number {\r\n\tif (key1 < key2) {\r\n\t\treturn -1;\r\n\t}\r\n\tif (key1 > key2) {\r\n\t\treturn 1;\r\n\t}\r\n\treturn 0;\r\n}\r\n\r\nfunction cmp2(key1: string, value1: any, key2: string, value2: any): number {\r\n\tif (key1 < key2) {\r\n\t\treturn -1;\r\n\t}\r\n\tif (key1 > key2) {\r\n\t\treturn 1;\r\n\t}\r\n\tif (value1 < value2) {\r\n\t\treturn -1;\r\n\t}\r\n\tif (value1 > value2) {\r\n\t\treturn 1;\r\n\t}\r\n\treturn 0;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { RawContextKey } from 'vs/platform/contextkey/common/contextkey';\r\n\r\nexport namespace EditorContextKeys {\r\n\r\n\texport const editorSimpleInput = new RawContextKey('editorSimpleInput', false);\r\n\t/**\r\n\t * A context key that is set when the editor's text has focus (cursor is blinking).\r\n\t * Is false when focus is in simple editor widgets (repl input, scm commit input).\r\n\t */\r\n\texport const editorTextFocus = new RawContextKey('editorTextFocus', false);\r\n\t/**\r\n\t * A context key that is set when the editor's text or an editor's widget has focus.\r\n\t */\r\n\texport const focus = new RawContextKey('editorFocus', false);\r\n\r\n\t/**\r\n\t * A context key that is set when any editor input has focus (regular editor, repl input...).\r\n\t */\r\n\texport const textInputFocus = new RawContextKey('textInputFocus', false);\r\n\r\n\texport const readOnly = new RawContextKey('editorReadonly', false);\r\n\texport const inDiffEditor = new RawContextKey('inDiffEditor', false);\r\n\texport const columnSelection = new RawContextKey('editorColumnSelection', false);\r\n\texport const writable = readOnly.toNegated();\r\n\texport const hasNonEmptySelection = new RawContextKey('editorHasSelection', false);\r\n\texport const hasOnlyEmptySelection = hasNonEmptySelection.toNegated();\r\n\texport const hasMultipleSelections = new RawContextKey('editorHasMultipleSelections', false);\r\n\texport const hasSingleSelection = hasMultipleSelections.toNegated();\r\n\texport const tabMovesFocus = new RawContextKey('editorTabMovesFocus', false);\r\n\texport const tabDoesNotMoveFocus = tabMovesFocus.toNegated();\r\n\texport const isInWalkThroughSnippet = new RawContextKey('isInEmbeddedEditor', false);\r\n\texport const canUndo = new RawContextKey('canUndo', false);\r\n\texport const canRedo = new RawContextKey('canRedo', false);\r\n\r\n\texport const hoverVisible = new RawContextKey('editorHoverVisible', false);\r\n\r\n\t/**\r\n\t * A context key that is set when an editor is part of a larger editor, like notebooks or\r\n\t * (future) a diff editor\r\n\t */\r\n\texport const inCompositeEditor = new RawContextKey('inCompositeEditor', undefined);\r\n\texport const notInCompositeEditor = inCompositeEditor.toNegated();\r\n\r\n\t// -- mode context keys\r\n\texport const languageId = new RawContextKey('editorLangId', '');\r\n\texport const hasCompletionItemProvider = new RawContextKey('editorHasCompletionItemProvider', false);\r\n\texport const hasCodeActionsProvider = new RawContextKey('editorHasCodeActionsProvider', false);\r\n\texport const hasCodeLensProvider = new RawContextKey('editorHasCodeLensProvider', false);\r\n\texport const hasDefinitionProvider = new RawContextKey('editorHasDefinitionProvider', false);\r\n\texport const hasDeclarationProvider = new RawContextKey('editorHasDeclarationProvider', false);\r\n\texport const hasImplementationProvider = new RawContextKey('editorHasImplementationProvider', false);\r\n\texport const hasTypeDefinitionProvider = new RawContextKey('editorHasTypeDefinitionProvider', false);\r\n\texport const hasHoverProvider = new RawContextKey('editorHasHoverProvider', false);\r\n\texport const hasDocumentHighlightProvider = new RawContextKey('editorHasDocumentHighlightProvider', false);\r\n\texport const hasDocumentSymbolProvider = new RawContextKey('editorHasDocumentSymbolProvider', false);\r\n\texport const hasReferenceProvider = new RawContextKey('editorHasReferenceProvider', false);\r\n\texport const hasRenameProvider = new RawContextKey('editorHasRenameProvider', false);\r\n\texport const hasSignatureHelpProvider = new RawContextKey('editorHasSignatureHelpProvider', false);\r\n\texport const hasInlineHintsProvider = new RawContextKey('editorHasInlineHintsProvider', false);\r\n\r\n\t// -- mode context keys: formatting\r\n\texport const hasDocumentFormattingProvider = new RawContextKey('editorHasDocumentFormattingProvider', false);\r\n\texport const hasDocumentSelectionFormattingProvider = new RawContextKey('editorHasDocumentSelectionFormattingProvider', false);\r\n\texport const hasMultipleDocumentFormattingProvider = new RawContextKey('editorHasMultipleDocumentFormattingProvider', false);\r\n\texport const hasMultipleDocumentSelectionFormattingProvider = new RawContextKey('editorHasMultipleDocumentSelectionFormattingProvider', false);\r\n\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { onUnexpectedExternalError } from 'vs/base/common/errors';\r\nimport { IPosition, Position } from 'vs/editor/common/core/position';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport * as modes from 'vs/editor/common/modes';\r\nimport { RawContextKey } from 'vs/platform/contextkey/common/contextkey';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { CommandsRegistry } from 'vs/platform/commands/common/commands';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { assertType } from 'vs/base/common/types';\r\nimport { ITextModelService } from 'vs/editor/common/services/resolverService';\r\n\r\nexport const Context = {\r\n\tVisible: new RawContextKey('parameterHintsVisible', false),\r\n\tMultipleSignatures: new RawContextKey('parameterHintsMultipleSignatures', false),\r\n};\r\n\r\nexport async function provideSignatureHelp(\r\n\tmodel: ITextModel,\r\n\tposition: Position,\r\n\tcontext: modes.SignatureHelpContext,\r\n\ttoken: CancellationToken\r\n): Promise {\r\n\r\n\tconst supports = modes.SignatureHelpProviderRegistry.ordered(model);\r\n\r\n\tfor (const support of supports) {\r\n\t\ttry {\r\n\t\t\tconst result = await support.provideSignatureHelp(model, position, token, context);\r\n\t\t\tif (result) {\r\n\t\t\t\treturn result;\r\n\t\t\t}\r\n\t\t} catch (err) {\r\n\t\t\tonUnexpectedExternalError(err);\r\n\t\t}\r\n\t}\r\n\treturn undefined;\r\n}\r\n\r\nCommandsRegistry.registerCommand('_executeSignatureHelpProvider', async (accessor, ...args: [URI, IPosition, string?]) => {\r\n\tconst [uri, position, triggerCharacter] = args;\r\n\tassertType(URI.isUri(uri));\r\n\tassertType(Position.isIPosition(position));\r\n\tassertType(typeof triggerCharacter === 'string' || !triggerCharacter);\r\n\r\n\tconst ref = await accessor.get(ITextModelService).createModelReference(uri);\r\n\ttry {\r\n\r\n\t\tconst result = await provideSignatureHelp(ref.object.textEditorModel, Position.lift(position), {\r\n\t\t\ttriggerKind: modes.SignatureHelpTriggerKind.Invoke,\r\n\t\t\tisRetrigger: false,\r\n\t\t\ttriggerCharacter,\r\n\t\t}, CancellationToken.None);\r\n\r\n\t\tif (!result) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\r\n\t\tsetTimeout(() => result.dispose(), 0);\r\n\t\treturn result.value;\r\n\r\n\t} finally {\r\n\t\tref.dispose();\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CancelablePromise, createCancelablePromise, Delayer } from 'vs/base/common/async';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport { Emitter } from 'vs/base/common/event';\r\nimport { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';\r\nimport { CharacterSet } from 'vs/editor/common/core/characterClassifier';\r\nimport * as modes from 'vs/editor/common/modes';\r\nimport { provideSignatureHelp } from 'vs/editor/contrib/parameterHints/provideSignatureHelp';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\nexport interface TriggerContext {\r\n\treadonly triggerKind: modes.SignatureHelpTriggerKind;\r\n\treadonly triggerCharacter?: string;\r\n}\r\n\r\nnamespace ParameterHintState {\r\n\texport const enum Type {\r\n\t\tDefault,\r\n\t\tActive,\r\n\t\tPending,\r\n\t}\r\n\r\n\texport const Default = { type: Type.Default } as const;\r\n\r\n\texport class Pending {\r\n\t\treadonly type = Type.Pending;\r\n\t\tconstructor(\r\n\t\t\treadonly request: CancelablePromise,\r\n\t\t\treadonly previouslyActiveHints: modes.SignatureHelp | undefined,\r\n\t\t) { }\r\n\t}\r\n\r\n\texport class Active {\r\n\t\treadonly type = Type.Active;\r\n\t\tconstructor(\r\n\t\t\treadonly hints: modes.SignatureHelp\r\n\t\t) { }\r\n\t}\r\n\r\n\texport type State = typeof Default | Pending | Active;\r\n}\r\n\r\nexport class ParameterHintsModel extends Disposable {\r\n\r\n\tprivate static readonly DEFAULT_DELAY = 120; // ms\r\n\r\n\tprivate readonly _onChangedHints = this._register(new Emitter());\r\n\tpublic readonly onChangedHints = this._onChangedHints.event;\r\n\r\n\tprivate readonly editor: ICodeEditor;\r\n\tprivate triggerOnType = false;\r\n\tprivate _state: ParameterHintState.State = ParameterHintState.Default;\r\n\tprivate _pendingTriggers: TriggerContext[] = [];\r\n\tprivate readonly _lastSignatureHelpResult = this._register(new MutableDisposable());\r\n\tprivate triggerChars = new CharacterSet();\r\n\tprivate retriggerChars = new CharacterSet();\r\n\r\n\tprivate readonly throttledDelayer: Delayer;\r\n\tprivate triggerId = 0;\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor,\r\n\t\tdelay: number = ParameterHintsModel.DEFAULT_DELAY\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\tthis.editor = editor;\r\n\r\n\t\tthis.throttledDelayer = new Delayer(delay);\r\n\r\n\t\tthis._register(this.editor.onDidChangeConfiguration(() => this.onEditorConfigurationChange()));\r\n\t\tthis._register(this.editor.onDidChangeModel(e => this.onModelChanged()));\r\n\t\tthis._register(this.editor.onDidChangeModelLanguage(_ => this.onModelChanged()));\r\n\t\tthis._register(this.editor.onDidChangeCursorSelection(e => this.onCursorChange(e)));\r\n\t\tthis._register(this.editor.onDidChangeModelContent(e => this.onModelContentChange()));\r\n\t\tthis._register(modes.SignatureHelpProviderRegistry.onDidChange(this.onModelChanged, this));\r\n\t\tthis._register(this.editor.onDidType(text => this.onDidType(text)));\r\n\r\n\t\tthis.onEditorConfigurationChange();\r\n\t\tthis.onModelChanged();\r\n\t}\r\n\r\n\tprivate get state() { return this._state; }\r\n\tprivate set state(value: ParameterHintState.State) {\r\n\t\tif (this._state.type === ParameterHintState.Type.Pending) {\r\n\t\t\tthis._state.request.cancel();\r\n\t\t}\r\n\t\tthis._state = value;\r\n\t}\r\n\r\n\tcancel(silent: boolean = false): void {\r\n\t\tthis.state = ParameterHintState.Default;\r\n\r\n\t\tthis.throttledDelayer.cancel();\r\n\r\n\t\tif (!silent) {\r\n\t\t\tthis._onChangedHints.fire(undefined);\r\n\t\t}\r\n\t}\r\n\r\n\ttrigger(context: TriggerContext, delay?: number): void {\r\n\t\tconst model = this.editor.getModel();\r\n\t\tif (!model || !modes.SignatureHelpProviderRegistry.has(model)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst triggerId = ++this.triggerId;\r\n\r\n\t\tthis._pendingTriggers.push(context);\r\n\t\tthis.throttledDelayer.trigger(() => {\r\n\t\t\treturn this.doTrigger(triggerId);\r\n\t\t}, delay)\r\n\t\t\t.catch(onUnexpectedError);\r\n\t}\r\n\r\n\tpublic next(): void {\r\n\t\tif (this.state.type !== ParameterHintState.Type.Active) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst length = this.state.hints.signatures.length;\r\n\t\tconst activeSignature = this.state.hints.activeSignature;\r\n\t\tconst last = (activeSignature % length) === (length - 1);\r\n\t\tconst cycle = this.editor.getOption(EditorOption.parameterHints).cycle;\r\n\r\n\t\t// If there is only one signature, or we're on last signature of list\r\n\t\tif ((length < 2 || last) && !cycle) {\r\n\t\t\tthis.cancel();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.updateActiveSignature(last && cycle ? 0 : activeSignature + 1);\r\n\t}\r\n\r\n\tpublic previous(): void {\r\n\t\tif (this.state.type !== ParameterHintState.Type.Active) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst length = this.state.hints.signatures.length;\r\n\t\tconst activeSignature = this.state.hints.activeSignature;\r\n\t\tconst first = activeSignature === 0;\r\n\t\tconst cycle = this.editor.getOption(EditorOption.parameterHints).cycle;\r\n\r\n\t\t// If there is only one signature, or we're on first signature of list\r\n\t\tif ((length < 2 || first) && !cycle) {\r\n\t\t\tthis.cancel();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.updateActiveSignature(first && cycle ? length - 1 : activeSignature - 1);\r\n\t}\r\n\r\n\tprivate updateActiveSignature(activeSignature: number) {\r\n\t\tif (this.state.type !== ParameterHintState.Type.Active) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.state = new ParameterHintState.Active({ ...this.state.hints, activeSignature });\r\n\t\tthis._onChangedHints.fire(this.state.hints);\r\n\t}\r\n\r\n\tprivate async doTrigger(triggerId: number): Promise {\r\n\t\tconst isRetrigger = this.state.type === ParameterHintState.Type.Active || this.state.type === ParameterHintState.Type.Pending;\r\n\t\tconst activeSignatureHelp = this.getLastActiveHints();\r\n\t\tthis.cancel(true);\r\n\r\n\t\tif (this._pendingTriggers.length === 0) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tconst context: TriggerContext = this._pendingTriggers.reduce(mergeTriggerContexts);\r\n\t\tthis._pendingTriggers = [];\r\n\r\n\t\tconst triggerContext = {\r\n\t\t\ttriggerKind: context.triggerKind,\r\n\t\t\ttriggerCharacter: context.triggerCharacter,\r\n\t\t\tisRetrigger: isRetrigger,\r\n\t\t\tactiveSignatureHelp: activeSignatureHelp\r\n\t\t};\r\n\r\n\t\tif (!this.editor.hasModel()) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tconst model = this.editor.getModel();\r\n\t\tconst position = this.editor.getPosition();\r\n\r\n\t\tthis.state = new ParameterHintState.Pending(\r\n\t\t\tcreateCancelablePromise(token => provideSignatureHelp(model, position, triggerContext, token)),\r\n\t\t\tactiveSignatureHelp);\r\n\r\n\t\ttry {\r\n\t\t\tconst result = await this.state.request;\r\n\r\n\t\t\t// Check that we are still resolving the correct signature help\r\n\t\t\tif (triggerId !== this.triggerId) {\r\n\t\t\t\tresult?.dispose();\r\n\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\tif (!result || !result.value.signatures || result.value.signatures.length === 0) {\r\n\t\t\t\tresult?.dispose();\r\n\t\t\t\tthis._lastSignatureHelpResult.clear();\r\n\t\t\t\tthis.cancel();\r\n\t\t\t\treturn false;\r\n\t\t\t} else {\r\n\t\t\t\tthis.state = new ParameterHintState.Active(result.value);\r\n\t\t\t\tthis._lastSignatureHelpResult.value = result;\r\n\t\t\t\tthis._onChangedHints.fire(this.state.hints);\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t} catch (error) {\r\n\t\t\tif (triggerId === this.triggerId) {\r\n\t\t\t\tthis.state = ParameterHintState.Default;\r\n\t\t\t}\r\n\t\t\tonUnexpectedError(error);\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate getLastActiveHints(): modes.SignatureHelp | undefined {\r\n\t\tswitch (this.state.type) {\r\n\t\t\tcase ParameterHintState.Type.Active: return this.state.hints;\r\n\t\t\tcase ParameterHintState.Type.Pending: return this.state.previouslyActiveHints;\r\n\t\t\tdefault: return undefined;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate get isTriggered(): boolean {\r\n\t\treturn this.state.type === ParameterHintState.Type.Active\r\n\t\t\t|| this.state.type === ParameterHintState.Type.Pending\r\n\t\t\t|| this.throttledDelayer.isTriggered();\r\n\t}\r\n\r\n\tprivate onModelChanged(): void {\r\n\t\tthis.cancel();\r\n\r\n\t\t// Update trigger characters\r\n\t\tthis.triggerChars = new CharacterSet();\r\n\t\tthis.retriggerChars = new CharacterSet();\r\n\r\n\t\tconst model = this.editor.getModel();\r\n\t\tif (!model) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tfor (const support of modes.SignatureHelpProviderRegistry.ordered(model)) {\r\n\t\t\tfor (const ch of support.signatureHelpTriggerCharacters || []) {\r\n\t\t\t\tthis.triggerChars.add(ch.charCodeAt(0));\r\n\r\n\t\t\t\t// All trigger characters are also considered retrigger characters\r\n\t\t\t\tthis.retriggerChars.add(ch.charCodeAt(0));\r\n\t\t\t}\r\n\r\n\t\t\tfor (const ch of support.signatureHelpRetriggerCharacters || []) {\r\n\t\t\t\tthis.retriggerChars.add(ch.charCodeAt(0));\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate onDidType(text: string) {\r\n\t\tif (!this.triggerOnType) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst lastCharIndex = text.length - 1;\r\n\t\tconst triggerCharCode = text.charCodeAt(lastCharIndex);\r\n\r\n\t\tif (this.triggerChars.has(triggerCharCode) || this.isTriggered && this.retriggerChars.has(triggerCharCode)) {\r\n\t\t\tthis.trigger({\r\n\t\t\t\ttriggerKind: modes.SignatureHelpTriggerKind.TriggerCharacter,\r\n\t\t\t\ttriggerCharacter: text.charAt(lastCharIndex),\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tprivate onCursorChange(e: ICursorSelectionChangedEvent): void {\r\n\t\tif (e.source === 'mouse') {\r\n\t\t\tthis.cancel();\r\n\t\t} else if (this.isTriggered) {\r\n\t\t\tthis.trigger({ triggerKind: modes.SignatureHelpTriggerKind.ContentChange });\r\n\t\t}\r\n\t}\r\n\r\n\tprivate onModelContentChange(): void {\r\n\t\tif (this.isTriggered) {\r\n\t\t\tthis.trigger({ triggerKind: modes.SignatureHelpTriggerKind.ContentChange });\r\n\t\t}\r\n\t}\r\n\r\n\tprivate onEditorConfigurationChange(): void {\r\n\t\tthis.triggerOnType = this.editor.getOption(EditorOption.parameterHints).enabled;\r\n\r\n\t\tif (!this.triggerOnType) {\r\n\t\t\tthis.cancel();\r\n\t\t}\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis.cancel(true);\r\n\t\tsuper.dispose();\r\n\t}\r\n}\r\n\r\nfunction mergeTriggerContexts(previous: TriggerContext, current: TriggerContext) {\r\n\tswitch (current.triggerKind) {\r\n\t\tcase modes.SignatureHelpTriggerKind.Invoke:\r\n\t\t\t// Invoke overrides previous triggers.\r\n\t\t\treturn current;\r\n\r\n\t\tcase modes.SignatureHelpTriggerKind.ContentChange:\r\n\t\t\t// Ignore content changes triggers\r\n\t\t\treturn previous;\r\n\r\n\t\tcase modes.SignatureHelpTriggerKind.TriggerCharacter:\r\n\t\tdefault:\r\n\t\t\treturn current;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';\r\nimport { CompletionModel } from './completionModel';\r\nimport { ISelectedSuggestion } from './suggestWidget';\r\n\r\nexport class SuggestAlternatives {\r\n\r\n\tstatic readonly OtherSuggestions = new RawContextKey('hasOtherSuggestions', false);\r\n\r\n\tprivate readonly _ckOtherSuggestions: IContextKey;\r\n\r\n\tprivate _index: number = 0;\r\n\tprivate _model: CompletionModel | undefined;\r\n\tprivate _acceptNext: ((selected: ISelectedSuggestion) => any) | undefined;\r\n\tprivate _listener: IDisposable | undefined;\r\n\tprivate _ignore: boolean | undefined;\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _editor: ICodeEditor,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService\r\n\t) {\r\n\t\tthis._ckOtherSuggestions = SuggestAlternatives.OtherSuggestions.bindTo(contextKeyService);\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis.reset();\r\n\t}\r\n\r\n\treset(): void {\r\n\t\tthis._ckOtherSuggestions.reset();\r\n\t\tthis._listener?.dispose();\r\n\t\tthis._model = undefined;\r\n\t\tthis._acceptNext = undefined;\r\n\t\tthis._ignore = false;\r\n\t}\r\n\r\n\tset({ model, index }: ISelectedSuggestion, acceptNext: (selected: ISelectedSuggestion) => any): void {\r\n\r\n\t\t// no suggestions -> nothing to do\r\n\t\tif (model.items.length === 0) {\r\n\t\t\tthis.reset();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// no alternative suggestions -> nothing to do\r\n\t\tlet nextIndex = SuggestAlternatives._moveIndex(true, model, index);\r\n\t\tif (nextIndex === index) {\r\n\t\t\tthis.reset();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._acceptNext = acceptNext;\r\n\t\tthis._model = model;\r\n\t\tthis._index = index;\r\n\t\tthis._listener = this._editor.onDidChangeCursorPosition(() => {\r\n\t\t\tif (!this._ignore) {\r\n\t\t\t\tthis.reset();\r\n\t\t\t}\r\n\t\t});\r\n\t\tthis._ckOtherSuggestions.set(true);\r\n\t}\r\n\r\n\tprivate static _moveIndex(fwd: boolean, model: CompletionModel, index: number): number {\r\n\t\tlet newIndex = index;\r\n\t\twhile (true) {\r\n\t\t\tnewIndex = (newIndex + model.items.length + (fwd ? +1 : -1)) % model.items.length;\r\n\t\t\tif (newIndex === index) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tif (!model.items[newIndex].completion.additionalTextEdits) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn newIndex;\r\n\t}\r\n\r\n\tnext(): void {\r\n\t\tthis._move(true);\r\n\t}\r\n\r\n\tprev(): void {\r\n\t\tthis._move(false);\r\n\t}\r\n\r\n\tprivate _move(fwd: boolean): void {\r\n\t\tif (!this._model) {\r\n\t\t\t// nothing to reason about\r\n\t\t\treturn;\r\n\t\t}\r\n\t\ttry {\r\n\t\t\tthis._ignore = true;\r\n\t\t\tthis._index = SuggestAlternatives._moveIndex(fwd, this._model, this._index);\r\n\t\t\tthis._acceptNext!({ index: this._index, item: this._model.items[this._index], model: this._model });\r\n\t\t} finally {\r\n\t\t\tthis._ignore = false;\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IDisposable, Disposable } from 'vs/base/common/lifecycle';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\nexport class WordContextKey extends Disposable {\r\n\r\n\tstatic readonly AtEnd = new RawContextKey('atEndOfWord', false);\r\n\r\n\tprivate readonly _ckAtEnd: IContextKey;\r\n\r\n\tprivate _enabled: boolean = false;\r\n\tprivate _selectionListener?: IDisposable;\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _editor: ICodeEditor,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\r\n\t) {\r\n\t\tsuper();\r\n\t\tthis._ckAtEnd = WordContextKey.AtEnd.bindTo(contextKeyService);\r\n\t\tthis._register(this._editor.onDidChangeConfiguration(e => e.hasChanged(EditorOption.tabCompletion) && this._update()));\r\n\t\tthis._update();\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tsuper.dispose();\r\n\t\tthis._selectionListener?.dispose();\r\n\t\tthis._ckAtEnd.reset();\r\n\t}\r\n\r\n\tprivate _update(): void {\r\n\t\t// only update this when tab completions are enabled\r\n\t\tconst enabled = this._editor.getOption(EditorOption.tabCompletion) === 'on';\r\n\t\tif (this._enabled === enabled) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._enabled = enabled;\r\n\r\n\t\tif (this._enabled) {\r\n\t\t\tconst checkForWordEnd = () => {\r\n\t\t\t\tif (!this._editor.hasModel()) {\r\n\t\t\t\t\tthis._ckAtEnd.set(false);\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\tconst model = this._editor.getModel();\r\n\t\t\t\tconst selection = this._editor.getSelection();\r\n\t\t\t\tconst word = model.getWordAtPosition(selection.getStartPosition());\r\n\t\t\t\tif (!word) {\r\n\t\t\t\t\tthis._ckAtEnd.set(false);\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\tthis._ckAtEnd.set(word.endColumn === selection.getStartPosition().column);\r\n\t\t\t};\r\n\t\t\tthis._selectionListener = this._editor.onDidChangeCursorSelection(checkForWordEnd);\r\n\t\t\tcheckForWordEnd();\r\n\r\n\t\t} else if (this._selectionListener) {\r\n\t\t\tthis._ckAtEnd.reset();\r\n\t\t\tthis._selectionListener.dispose();\r\n\t\t\tthis._selectionListener = undefined;\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { Event } from 'vs/base/common/event';\r\nimport { RawContextKey } from 'vs/platform/contextkey/common/contextkey';\r\n\r\nexport const IAccessibilityService = createDecorator('accessibilityService');\r\n\r\nexport interface IAccessibilityService {\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\treadonly onDidChangeScreenReaderOptimized: Event;\r\n\tisScreenReaderOptimized(): boolean;\r\n\tgetAccessibilitySupport(): AccessibilitySupport;\r\n}\r\n\r\nexport const enum AccessibilitySupport {\r\n\t/**\r\n\t * This should be the browser case where it is not known if a screen reader is attached or no.\r\n\t */\r\n\tUnknown = 0,\r\n\r\n\tDisabled = 1,\r\n\r\n\tEnabled = 2\r\n}\r\n\r\nexport const CONTEXT_ACCESSIBILITY_MODE_ENABLED = new RawContextKey('accessibilityModeEnabled', false);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IContextMenuDelegate } from 'vs/base/browser/contextmenu';\r\nimport { AnchorAlignment, AnchorAxisAlignment, IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';\r\n\r\nexport const IContextViewService = createDecorator('contextViewService');\r\n\r\nexport interface IContextViewService extends IContextViewProvider {\r\n\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\tshowContextView(delegate: IContextViewDelegate, container?: HTMLElement, shadowRoot?: boolean): IDisposable;\r\n\thideContextView(data?: any): void;\r\n\tgetContextViewElement(): HTMLElement;\r\n}\r\n\r\nexport interface IContextViewDelegate {\r\n\r\n\tcanRelayout?: boolean; // Default: true\r\n\r\n\tgetAnchor(): HTMLElement | { x: number; y: number; width?: number; height?: number; };\r\n\trender(container: HTMLElement): IDisposable;\r\n\tonHide?(data?: any): void;\r\n\tfocus?(): void;\r\n\tanchorAlignment?: AnchorAlignment;\r\n\tanchorAxisAlignment?: AnchorAxisAlignment;\r\n}\r\n\r\nexport const IContextMenuService = createDecorator('contextMenuService');\r\n\r\nexport interface IContextMenuService {\r\n\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\tshowContextMenu(delegate: IContextMenuDelegate): void;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport Severity from 'vs/base/common/severity';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\n\r\nexport interface IConfirmation {\r\n\ttitle?: string;\r\n\tmessage: string;\r\n\tdetail?: string;\r\n\tprimaryButton?: string;\r\n\tsecondaryButton?: string;\r\n}\r\n\r\nexport interface IConfirmationResult {\r\n\r\n\t/**\r\n\t * Will be true if the dialog was confirmed with the primary button\r\n\t * pressed.\r\n\t */\r\n\tconfirmed: boolean;\r\n\r\n\t/**\r\n\t * This will only be defined if the confirmation was created\r\n\t * with the checkbox option defined.\r\n\t */\r\n\tcheckboxChecked?: boolean;\r\n}\r\n\r\nexport interface IShowResult {\r\n\r\n\t/**\r\n\t * Selected choice index. If the user refused to choose,\r\n\t * then a promise with index of `cancelId` option is returned. If there is no such\r\n\t * option then promise with index `0` is returned.\r\n\t */\r\n\tchoice: number;\r\n}\r\n\r\nexport const IDialogService = createDecorator('dialogService');\r\n\r\nexport interface IDialogOptions {\r\n\tcancelId?: number;\r\n}\r\n\r\n/**\r\n * A service to bring up modal dialogs.\r\n *\r\n * Note: use the `INotificationService.prompt()` method for a non-modal way to ask\r\n * the user for input.\r\n */\r\nexport interface IDialogService {\r\n\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\t/**\r\n\t * Ask the user for confirmation with a modal dialog.\r\n\t */\r\n\tconfirm(confirmation: IConfirmation): Promise;\r\n\r\n\t/**\r\n\t * Present a modal dialog to the user.\r\n\t *\r\n\t * @returns A promise with the selected choice index. If the user refused to choose,\r\n\t * then a promise with index of `cancelId` option is returned. If there is no such\r\n\t * option then promise with index `0` is returned.\r\n\t */\r\n\tshow(severity: Severity, message: string, buttons: string[], options?: IDialogOptions): Promise;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';\r\nimport { SyncDescriptor } from './descriptors';\r\n\r\nexport class ServiceCollection {\r\n\r\n\tprivate _entries = new Map, any>();\r\n\r\n\tconstructor(...entries: [ServiceIdentifier, any][]) {\r\n\t\tfor (let [id, service] of entries) {\r\n\t\t\tthis.set(id, service);\r\n\t\t}\r\n\t}\r\n\r\n\tset(id: ServiceIdentifier, instanceOrDescriptor: T | SyncDescriptor): T | SyncDescriptor {\r\n\t\tconst result = this._entries.get(id);\r\n\t\tthis._entries.set(id, instanceOrDescriptor);\r\n\t\treturn result;\r\n\t}\r\n\r\n\thas(id: ServiceIdentifier): boolean {\r\n\t\treturn this._entries.has(id);\r\n\t}\r\n\r\n\tget(id: ServiceIdentifier): T | SyncDescriptor {\r\n\t\treturn this._entries.get(id);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { illegalState } from 'vs/base/common/errors';\r\nimport { Graph } from 'vs/platform/instantiation/common/graph';\r\nimport { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';\r\nimport { ServiceIdentifier, IInstantiationService, ServicesAccessor, _util, optional } from 'vs/platform/instantiation/common/instantiation';\r\nimport { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';\r\nimport { IdleValue } from 'vs/base/common/async';\r\n\r\n// TRACING\r\nconst _enableTracing = false;\r\n\r\nclass CyclicDependencyError extends Error {\r\n\tconstructor(graph: Graph) {\r\n\t\tsuper('cyclic dependency between services');\r\n\t\tthis.message = graph.toString();\r\n\t}\r\n}\r\n\r\nexport class InstantiationService implements IInstantiationService {\r\n\r\n\tdeclare readonly _serviceBrand: undefined;\r\n\r\n\tprivate readonly _services: ServiceCollection;\r\n\tprivate readonly _strict: boolean;\r\n\tprivate readonly _parent?: InstantiationService;\r\n\r\n\tconstructor(services: ServiceCollection = new ServiceCollection(), strict: boolean = false, parent?: InstantiationService) {\r\n\t\tthis._services = services;\r\n\t\tthis._strict = strict;\r\n\t\tthis._parent = parent;\r\n\r\n\t\tthis._services.set(IInstantiationService, this);\r\n\t}\r\n\r\n\tcreateChild(services: ServiceCollection): IInstantiationService {\r\n\t\treturn new InstantiationService(services, this._strict, this);\r\n\t}\r\n\r\n\tinvokeFunction(fn: (accessor: ServicesAccessor, ...args: TS) => R, ...args: TS): R {\r\n\t\tlet _trace = Trace.traceInvocation(fn);\r\n\t\tlet _done = false;\r\n\t\ttry {\r\n\t\t\tconst accessor: ServicesAccessor = {\r\n\t\t\t\tget: (id: ServiceIdentifier, isOptional?: typeof optional) => {\r\n\r\n\t\t\t\t\tif (_done) {\r\n\t\t\t\t\t\tthrow illegalState('service accessor is only valid during the invocation of its target method');\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tconst result = this._getOrCreateServiceInstance(id, _trace);\r\n\t\t\t\t\tif (!result && isOptional !== optional) {\r\n\t\t\t\t\t\tthrow new Error(`[invokeFunction] unknown service '${id}'`);\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn result;\r\n\t\t\t\t}\r\n\t\t\t};\r\n\t\t\treturn fn(accessor, ...args);\r\n\t\t} finally {\r\n\t\t\t_done = true;\r\n\t\t\t_trace.stop();\r\n\t\t}\r\n\t}\r\n\r\n\tcreateInstance(ctorOrDescriptor: any | SyncDescriptor, ...rest: any[]): any {\r\n\t\tlet _trace: Trace;\r\n\t\tlet result: any;\r\n\t\tif (ctorOrDescriptor instanceof SyncDescriptor) {\r\n\t\t\t_trace = Trace.traceCreation(ctorOrDescriptor.ctor);\r\n\t\t\tresult = this._createInstance(ctorOrDescriptor.ctor, ctorOrDescriptor.staticArguments.concat(rest), _trace);\r\n\t\t} else {\r\n\t\t\t_trace = Trace.traceCreation(ctorOrDescriptor);\r\n\t\t\tresult = this._createInstance(ctorOrDescriptor, rest, _trace);\r\n\t\t}\r\n\t\t_trace.stop();\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate _createInstance(ctor: any, args: any[] = [], _trace: Trace): T {\r\n\r\n\t\t// arguments defined by service decorators\r\n\t\tlet serviceDependencies = _util.getServiceDependencies(ctor).sort((a, b) => a.index - b.index);\r\n\t\tlet serviceArgs: any[] = [];\r\n\t\tfor (const dependency of serviceDependencies) {\r\n\t\t\tlet service = this._getOrCreateServiceInstance(dependency.id, _trace);\r\n\t\t\tif (!service && this._strict && !dependency.optional) {\r\n\t\t\t\tthrow new Error(`[createInstance] ${ctor.name} depends on UNKNOWN service ${dependency.id}.`);\r\n\t\t\t}\r\n\t\t\tserviceArgs.push(service);\r\n\t\t}\r\n\r\n\t\tlet firstServiceArgPos = serviceDependencies.length > 0 ? serviceDependencies[0].index : args.length;\r\n\r\n\t\t// check for argument mismatches, adjust static args if needed\r\n\t\tif (args.length !== firstServiceArgPos) {\r\n\t\t\tconsole.warn(`[createInstance] First service dependency of ${ctor.name} at position ${firstServiceArgPos + 1} conflicts with ${args.length} static arguments`);\r\n\r\n\t\t\tlet delta = firstServiceArgPos - args.length;\r\n\t\t\tif (delta > 0) {\r\n\t\t\t\targs = args.concat(new Array(delta));\r\n\t\t\t} else {\r\n\t\t\t\targs = args.slice(0, firstServiceArgPos);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// now create the instance\r\n\t\treturn new ctor(...[...args, ...serviceArgs]);\r\n\t}\r\n\r\n\tprivate _setServiceInstance(id: ServiceIdentifier, instance: T): void {\r\n\t\tif (this._services.get(id) instanceof SyncDescriptor) {\r\n\t\t\tthis._services.set(id, instance);\r\n\t\t} else if (this._parent) {\r\n\t\t\tthis._parent._setServiceInstance(id, instance);\r\n\t\t} else {\r\n\t\t\tthrow new Error('illegalState - setting UNKNOWN service instance');\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _getServiceInstanceOrDescriptor(id: ServiceIdentifier): T | SyncDescriptor {\r\n\t\tlet instanceOrDesc = this._services.get(id);\r\n\t\tif (!instanceOrDesc && this._parent) {\r\n\t\t\treturn this._parent._getServiceInstanceOrDescriptor(id);\r\n\t\t} else {\r\n\t\t\treturn instanceOrDesc;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _getOrCreateServiceInstance(id: ServiceIdentifier, _trace: Trace): T {\r\n\t\tlet thing = this._getServiceInstanceOrDescriptor(id);\r\n\t\tif (thing instanceof SyncDescriptor) {\r\n\t\t\treturn this._safeCreateAndCacheServiceInstance(id, thing, _trace.branch(id, true));\r\n\t\t} else {\r\n\t\t\t_trace.branch(id, false);\r\n\t\t\treturn thing;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate readonly _activeInstantiations = new Set>();\r\n\r\n\r\n\tprivate _safeCreateAndCacheServiceInstance(id: ServiceIdentifier, desc: SyncDescriptor, _trace: Trace): T {\r\n\t\tif (this._activeInstantiations.has(id)) {\r\n\t\t\tthrow new Error(`illegal state - RECURSIVELY instantiating service '${id}'`);\r\n\t\t}\r\n\t\tthis._activeInstantiations.add(id);\r\n\t\ttry {\r\n\t\t\treturn this._createAndCacheServiceInstance(id, desc, _trace);\r\n\t\t} finally {\r\n\t\t\tthis._activeInstantiations.delete(id);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _createAndCacheServiceInstance(id: ServiceIdentifier, desc: SyncDescriptor, _trace: Trace): T {\r\n\r\n\t\ttype Triple = { id: ServiceIdentifier, desc: SyncDescriptor, _trace: Trace; };\r\n\t\tconst graph = new Graph(data => data.id.toString());\r\n\r\n\t\tlet cycleCount = 0;\r\n\t\tconst stack = [{ id, desc, _trace }];\r\n\t\twhile (stack.length) {\r\n\t\t\tconst item = stack.pop()!;\r\n\t\t\tgraph.lookupOrInsertNode(item);\r\n\r\n\t\t\t// a weak but working heuristic for cycle checks\r\n\t\t\tif (cycleCount++ > 1000) {\r\n\t\t\t\tthrow new CyclicDependencyError(graph);\r\n\t\t\t}\r\n\r\n\t\t\t// check all dependencies for existence and if they need to be created first\r\n\t\t\tfor (let dependency of _util.getServiceDependencies(item.desc.ctor)) {\r\n\r\n\t\t\t\tlet instanceOrDesc = this._getServiceInstanceOrDescriptor(dependency.id);\r\n\t\t\t\tif (!instanceOrDesc && !dependency.optional) {\r\n\t\t\t\t\tconsole.warn(`[createInstance] ${id} depends on ${dependency.id} which is NOT registered.`);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (instanceOrDesc instanceof SyncDescriptor) {\r\n\t\t\t\t\tconst d = { id: dependency.id, desc: instanceOrDesc, _trace: item._trace.branch(dependency.id, true) };\r\n\t\t\t\t\tgraph.insertEdge(item, d);\r\n\t\t\t\t\tstack.push(d);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\twhile (true) {\r\n\t\t\tconst roots = graph.roots();\r\n\r\n\t\t\t// if there is no more roots but still\r\n\t\t\t// nodes in the graph we have a cycle\r\n\t\t\tif (roots.length === 0) {\r\n\t\t\t\tif (!graph.isEmpty()) {\r\n\t\t\t\t\tthrow new CyclicDependencyError(graph);\r\n\t\t\t\t}\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tfor (const { data } of roots) {\r\n\t\t\t\t// Repeat the check for this still being a service sync descriptor. That's because\r\n\t\t\t\t// instantiating a dependency might have side-effect and recursively trigger instantiation\r\n\t\t\t\t// so that some dependencies are now fullfilled already.\r\n\t\t\t\tconst instanceOrDesc = this._getServiceInstanceOrDescriptor(data.id);\r\n\t\t\t\tif (instanceOrDesc instanceof SyncDescriptor) {\r\n\t\t\t\t\t// create instance and overwrite the service collections\r\n\t\t\t\t\tconst instance = this._createServiceInstanceWithOwner(data.id, data.desc.ctor, data.desc.staticArguments, data.desc.supportsDelayedInstantiation, data._trace);\r\n\t\t\t\t\tthis._setServiceInstance(data.id, instance);\r\n\t\t\t\t}\r\n\t\t\t\tgraph.removeNode(data);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this._getServiceInstanceOrDescriptor(id);\r\n\t}\r\n\r\n\tprivate _createServiceInstanceWithOwner(id: ServiceIdentifier, ctor: any, args: any[] = [], supportsDelayedInstantiation: boolean, _trace: Trace): T {\r\n\t\tif (this._services.get(id) instanceof SyncDescriptor) {\r\n\t\t\treturn this._createServiceInstance(ctor, args, supportsDelayedInstantiation, _trace);\r\n\t\t} else if (this._parent) {\r\n\t\t\treturn this._parent._createServiceInstanceWithOwner(id, ctor, args, supportsDelayedInstantiation, _trace);\r\n\t\t} else {\r\n\t\t\tthrow new Error(`illegalState - creating UNKNOWN service instance ${ctor.name}`);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _createServiceInstance(ctor: any, args: any[] = [], _supportsDelayedInstantiation: boolean, _trace: Trace): T {\r\n\t\tif (!_supportsDelayedInstantiation) {\r\n\t\t\t// eager instantiation\r\n\t\t\treturn this._createInstance(ctor, args, _trace);\r\n\r\n\t\t} else {\r\n\t\t\t// Return a proxy object that's backed by an idle value. That\r\n\t\t\t// strategy is to instantiate services in our idle time or when actually\r\n\t\t\t// needed but not when injected into a consumer\r\n\t\t\tconst idle = new IdleValue(() => this._createInstance(ctor, args, _trace));\r\n\t\t\treturn new Proxy(Object.create(null), {\r\n\t\t\t\tget(target: any, key: PropertyKey): any {\r\n\t\t\t\t\tif (key in target) {\r\n\t\t\t\t\t\treturn target[key];\r\n\t\t\t\t\t}\r\n\t\t\t\t\tlet obj = idle.value;\r\n\t\t\t\t\tlet prop = obj[key];\r\n\t\t\t\t\tif (typeof prop !== 'function') {\r\n\t\t\t\t\t\treturn prop;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tprop = prop.bind(obj);\r\n\t\t\t\t\ttarget[key] = prop;\r\n\t\t\t\t\treturn prop;\r\n\t\t\t\t},\r\n\t\t\t\tset(_target: T, p: PropertyKey, value: any): boolean {\r\n\t\t\t\t\tidle.value[p] = value;\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n}\r\n\r\n//#region -- tracing ---\r\n\r\nconst enum TraceType {\r\n\tCreation, Invocation, Branch\r\n}\r\n\r\nclass Trace {\r\n\r\n\tprivate static readonly _None = new class extends Trace {\r\n\t\tconstructor() { super(-1, null); }\r\n\t\tstop() { }\r\n\t\tbranch() { return this; }\r\n\t};\r\n\r\n\tstatic traceInvocation(ctor: any): Trace {\r\n\t\treturn !_enableTracing ? Trace._None : new Trace(TraceType.Invocation, ctor.name || (ctor.toString() as string).substring(0, 42).replace(/\\n/g, ''));\r\n\t}\r\n\r\n\tstatic traceCreation(ctor: any): Trace {\r\n\t\treturn !_enableTracing ? Trace._None : new Trace(TraceType.Creation, ctor.name);\r\n\t}\r\n\r\n\tprivate static _totals: number = 0;\r\n\tprivate readonly _start: number = Date.now();\r\n\tprivate readonly _dep: [ServiceIdentifier, boolean, Trace?][] = [];\r\n\r\n\tprivate constructor(\r\n\t\treadonly type: TraceType,\r\n\t\treadonly name: string | null\r\n\t) { }\r\n\r\n\tbranch(id: ServiceIdentifier, first: boolean): Trace {\r\n\t\tlet child = new Trace(TraceType.Branch, id.toString());\r\n\t\tthis._dep.push([id, first, child]);\r\n\t\treturn child;\r\n\t}\r\n\r\n\tstop() {\r\n\t\tlet dur = Date.now() - this._start;\r\n\t\tTrace._totals += dur;\r\n\r\n\t\tlet causedCreation = false;\r\n\r\n\t\tfunction printChild(n: number, trace: Trace) {\r\n\t\t\tlet res: string[] = [];\r\n\t\t\tlet prefix = new Array(n + 1).join('\\t');\r\n\t\t\tfor (const [id, first, child] of trace._dep) {\r\n\t\t\t\tif (first && child) {\r\n\t\t\t\t\tcausedCreation = true;\r\n\t\t\t\t\tres.push(`${prefix}CREATES -> ${id}`);\r\n\t\t\t\t\tlet nested = printChild(n + 1, child);\r\n\t\t\t\t\tif (nested) {\r\n\t\t\t\t\t\tres.push(nested);\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tres.push(`${prefix}uses -> ${id}`);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn res.join('\\n');\r\n\t\t}\r\n\r\n\t\tlet lines = [\r\n\t\t\t`${this.type === TraceType.Creation ? 'CREATE' : 'CALL'} ${this.name}`,\r\n\t\t\t`${printChild(1, this)}`,\r\n\t\t\t`DONE, took ${dur.toFixed(2)}ms (grand total ${Trace._totals.toFixed(2)}ms)`\r\n\t\t];\r\n\r\n\t\tif (dur > 2 || causedCreation) {\r\n\t\t\tconsole.log(lines.join('\\n'));\r\n\t\t}\r\n\t}\r\n}\r\n\r\n//#endregion\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { IntervalTimer } from 'vs/base/common/async';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { KeyCode, Keybinding, ResolvedKeybinding } from 'vs/base/common/keyCodes';\r\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\r\nimport { ICommandService } from 'vs/platform/commands/common/commands';\r\nimport { IContextKeyService, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IKeybindingEvent, IKeybindingService, IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding';\r\nimport { IResolveResult, KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver';\r\nimport { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';\r\nimport { INotificationService } from 'vs/platform/notification/common/notification';\r\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\r\nimport { WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions';\r\nimport { ILogService } from 'vs/platform/log/common/log';\r\n\r\ninterface CurrentChord {\r\n\tkeypress: string;\r\n\tlabel: string | null;\r\n}\r\n\r\nexport abstract class AbstractKeybindingService extends Disposable implements IKeybindingService {\r\n\tpublic _serviceBrand: undefined;\r\n\r\n\tprotected readonly _onDidUpdateKeybindings: Emitter = this._register(new Emitter());\r\n\tget onDidUpdateKeybindings(): Event {\r\n\t\treturn this._onDidUpdateKeybindings ? this._onDidUpdateKeybindings.event : Event.None; // Sinon stubbing walks properties on prototype\r\n\t}\r\n\r\n\tprivate _currentChord: CurrentChord | null;\r\n\tprivate _currentChordChecker: IntervalTimer;\r\n\tprivate _currentChordStatusMessage: IDisposable | null;\r\n\tprotected _logging: boolean;\r\n\r\n\tconstructor(\r\n\t\tprivate _contextKeyService: IContextKeyService,\r\n\t\tprotected _commandService: ICommandService,\r\n\t\tprotected _telemetryService: ITelemetryService,\r\n\t\tprivate _notificationService: INotificationService,\r\n\t\tprotected _logService: ILogService,\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\tthis._currentChord = null;\r\n\t\tthis._currentChordChecker = new IntervalTimer();\r\n\t\tthis._currentChordStatusMessage = null;\r\n\t\tthis._logging = false;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tprotected abstract _getResolver(): KeybindingResolver;\r\n\tprotected abstract _documentHasFocus(): boolean;\r\n\tpublic abstract resolveKeybinding(keybinding: Keybinding): ResolvedKeybinding[];\r\n\tpublic abstract resolveKeyboardEvent(keyboardEvent: IKeyboardEvent): ResolvedKeybinding;\r\n\r\n\tprotected _log(str: string): void {\r\n\t\tif (this._logging) {\r\n\t\t\tthis._logService.info(`[KeybindingService]: ${str}`);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getKeybindings(): readonly ResolvedKeybindingItem[] {\r\n\t\treturn this._getResolver().getKeybindings();\r\n\t}\r\n\r\n\tpublic lookupKeybinding(commandId: string): ResolvedKeybinding | undefined {\r\n\t\tconst result = this._getResolver().lookupPrimaryKeybinding(commandId);\r\n\t\tif (!result) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\t\treturn result.resolvedKeybinding;\r\n\t}\r\n\r\n\tpublic dispatchEvent(e: IKeyboardEvent, target: IContextKeyServiceTarget): boolean {\r\n\t\treturn this._dispatch(e, target);\r\n\t}\r\n\r\n\tpublic softDispatch(e: IKeyboardEvent, target: IContextKeyServiceTarget): IResolveResult | null {\r\n\t\tconst keybinding = this.resolveKeyboardEvent(e);\r\n\t\tif (keybinding.isChord()) {\r\n\t\t\tconsole.warn('Unexpected keyboard event mapped to a chord');\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tconst [firstPart,] = keybinding.getDispatchParts();\r\n\t\tif (firstPart === null) {\r\n\t\t\t// cannot be dispatched, probably only modifier keys\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst contextValue = this._contextKeyService.getContext(target);\r\n\t\tconst currentChord = this._currentChord ? this._currentChord.keypress : null;\r\n\t\treturn this._getResolver().resolve(contextValue, currentChord, firstPart);\r\n\t}\r\n\r\n\tprivate _enterChordMode(firstPart: string, keypressLabel: string | null): void {\r\n\t\tthis._currentChord = {\r\n\t\t\tkeypress: firstPart,\r\n\t\t\tlabel: keypressLabel\r\n\t\t};\r\n\t\tthis._currentChordStatusMessage = this._notificationService.status(nls.localize('first.chord', \"({0}) was pressed. Waiting for second key of chord...\", keypressLabel));\r\n\t\tconst chordEnterTime = Date.now();\r\n\t\tthis._currentChordChecker.cancelAndSet(() => {\r\n\r\n\t\t\tif (!this._documentHasFocus()) {\r\n\t\t\t\t// Focus has been lost => leave chord mode\r\n\t\t\t\tthis._leaveChordMode();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (Date.now() - chordEnterTime > 5000) {\r\n\t\t\t\t// 5 seconds elapsed => leave chord mode\r\n\t\t\t\tthis._leaveChordMode();\r\n\t\t\t}\r\n\r\n\t\t}, 500);\r\n\t}\r\n\r\n\tprivate _leaveChordMode(): void {\r\n\t\tif (this._currentChordStatusMessage) {\r\n\t\t\tthis._currentChordStatusMessage.dispose();\r\n\t\t\tthis._currentChordStatusMessage = null;\r\n\t\t}\r\n\t\tthis._currentChordChecker.cancel();\r\n\t\tthis._currentChord = null;\r\n\t}\r\n\r\n\tprotected _dispatch(e: IKeyboardEvent, target: IContextKeyServiceTarget): boolean {\r\n\t\treturn this._doDispatch(this.resolveKeyboardEvent(e), target);\r\n\t}\r\n\r\n\tprivate _doDispatch(keybinding: ResolvedKeybinding, target: IContextKeyServiceTarget): boolean {\r\n\t\tlet shouldPreventDefault = false;\r\n\r\n\t\tif (keybinding.isChord()) {\r\n\t\t\tconsole.warn('Unexpected keyboard event mapped to a chord');\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tconst [firstPart,] = keybinding.getDispatchParts();\r\n\t\tif (firstPart === null) {\r\n\t\t\tthis._log(`\\\\ Keyboard event cannot be dispatched.`);\r\n\t\t\t// cannot be dispatched, probably only modifier keys\r\n\t\t\treturn shouldPreventDefault;\r\n\t\t}\r\n\r\n\t\tconst contextValue = this._contextKeyService.getContext(target);\r\n\t\tconst currentChord = this._currentChord ? this._currentChord.keypress : null;\r\n\t\tconst keypressLabel = keybinding.getLabel();\r\n\t\tconst resolveResult = this._getResolver().resolve(contextValue, currentChord, firstPart);\r\n\r\n\t\tthis._logService.trace('KeybindingService#dispatch', keypressLabel, resolveResult?.commandId);\r\n\r\n\t\tif (resolveResult && resolveResult.enterChord) {\r\n\t\t\tshouldPreventDefault = true;\r\n\t\t\tthis._enterChordMode(firstPart, keypressLabel);\r\n\t\t\treturn shouldPreventDefault;\r\n\t\t}\r\n\r\n\t\tif (this._currentChord) {\r\n\t\t\tif (!resolveResult || !resolveResult.commandId) {\r\n\t\t\t\tthis._notificationService.status(nls.localize('missing.chord', \"The key combination ({0}, {1}) is not a command.\", this._currentChord.label, keypressLabel), { hideAfter: 10 * 1000 /* 10s */ });\r\n\t\t\t\tshouldPreventDefault = true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._leaveChordMode();\r\n\r\n\t\tif (resolveResult && resolveResult.commandId) {\r\n\t\t\tif (!resolveResult.bubble) {\r\n\t\t\t\tshouldPreventDefault = true;\r\n\t\t\t}\r\n\t\t\tif (typeof resolveResult.commandArgs === 'undefined') {\r\n\t\t\t\tthis._commandService.executeCommand(resolveResult.commandId).then(undefined, err => this._notificationService.warn(err));\r\n\t\t\t} else {\r\n\t\t\t\tthis._commandService.executeCommand(resolveResult.commandId, resolveResult.commandArgs).then(undefined, err => this._notificationService.warn(err));\r\n\t\t\t}\r\n\t\t\tthis._telemetryService.publicLog2('workbenchActionExecuted', { id: resolveResult.commandId, from: 'keybinding' });\r\n\t\t}\r\n\r\n\t\treturn shouldPreventDefault;\r\n\t}\r\n\r\n\tmightProducePrintableCharacter(event: IKeyboardEvent): boolean {\r\n\t\tif (event.ctrlKey || event.metaKey) {\r\n\t\t\t// ignore ctrl/cmd-combination but not shift/alt-combinatios\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\t// weak check for certain ranges. this is properly implemented in a subclass\r\n\t\t// with access to the KeyboardMapperFactory.\r\n\t\tif ((event.keyCode >= KeyCode.KEY_A && event.keyCode <= KeyCode.KEY_Z)\r\n\t\t\t|| (event.keyCode >= KeyCode.KEY_0 && event.keyCode <= KeyCode.KEY_9)) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { OperatingSystem } from 'vs/base/common/platform';\r\nimport { illegalArgument } from 'vs/base/common/errors';\r\nimport { Modifiers, UILabelProvider, AriaLabelProvider } from 'vs/base/common/keybindingLabels';\r\nimport { ResolvedKeybinding, ResolvedKeybindingPart } from 'vs/base/common/keyCodes';\r\n\r\nexport abstract class BaseResolvedKeybinding extends ResolvedKeybinding {\r\n\r\n\tprotected readonly _os: OperatingSystem;\r\n\tprotected readonly _parts: T[];\r\n\r\n\tconstructor(os: OperatingSystem, parts: T[]) {\r\n\t\tsuper();\r\n\t\tif (parts.length === 0) {\r\n\t\t\tthrow illegalArgument(`parts`);\r\n\t\t}\r\n\t\tthis._os = os;\r\n\t\tthis._parts = parts;\r\n\t}\r\n\r\n\tpublic getLabel(): string | null {\r\n\t\treturn UILabelProvider.toLabel(this._os, this._parts, (keybinding) => this._getLabel(keybinding));\r\n\t}\r\n\r\n\tpublic getAriaLabel(): string | null {\r\n\t\treturn AriaLabelProvider.toLabel(this._os, this._parts, (keybinding) => this._getAriaLabel(keybinding));\r\n\t}\r\n\r\n\tpublic isChord(): boolean {\r\n\t\treturn (this._parts.length > 1);\r\n\t}\r\n\r\n\tpublic getParts(): ResolvedKeybindingPart[] {\r\n\t\treturn this._parts.map((keybinding) => this._getPart(keybinding));\r\n\t}\r\n\r\n\tprivate _getPart(keybinding: T): ResolvedKeybindingPart {\r\n\t\treturn new ResolvedKeybindingPart(\r\n\t\t\tkeybinding.ctrlKey,\r\n\t\t\tkeybinding.shiftKey,\r\n\t\t\tkeybinding.altKey,\r\n\t\t\tkeybinding.metaKey,\r\n\t\t\tthis._getLabel(keybinding),\r\n\t\t\tthis._getAriaLabel(keybinding)\r\n\t\t);\r\n\t}\r\n\r\n\tpublic getDispatchParts(): (string | null)[] {\r\n\t\treturn this._parts.map((keybinding) => this._getDispatchPart(keybinding));\r\n\t}\r\n\r\n\tprotected abstract _getLabel(keybinding: T): string | null;\r\n\tprotected abstract _getAriaLabel(keybinding: T): string | null;\r\n\tprotected abstract _getDispatchPart(keybinding: T): string | null;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Event } from 'vs/base/common/event';\r\nimport { KeyCode, ResolvedKeybinding } from 'vs/base/common/keyCodes';\r\nimport { IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IResolveResult } from 'vs/platform/keybinding/common/keybindingResolver';\r\nimport { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';\r\n\r\nexport const enum KeybindingSource {\r\n\tDefault = 1,\r\n\tUser\r\n}\r\n\r\nexport interface IKeybindingEvent {\r\n\tsource: KeybindingSource;\r\n}\r\n\r\nexport interface IKeyboardEvent {\r\n\treadonly _standardKeyboardEventBrand: true;\r\n\r\n\treadonly ctrlKey: boolean;\r\n\treadonly shiftKey: boolean;\r\n\treadonly altKey: boolean;\r\n\treadonly metaKey: boolean;\r\n\treadonly keyCode: KeyCode;\r\n}\r\n\r\nexport const IKeybindingService = createDecorator('keybindingService');\r\n\r\nexport interface IKeybindingService {\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\tonDidUpdateKeybindings: Event;\r\n\r\n\t/**\r\n\t * Resolve and dispatch `keyboardEvent` and invoke the command.\r\n\t */\r\n\tdispatchEvent(e: IKeyboardEvent, target: IContextKeyServiceTarget): boolean;\r\n\r\n\t/**\r\n\t * Resolve and dispatch `keyboardEvent`, but do not invoke the command or change inner state.\r\n\t */\r\n\tsoftDispatch(keyboardEvent: IKeyboardEvent, target: IContextKeyServiceTarget): IResolveResult | null;\r\n\r\n\t/**\r\n\t * Look up the preferred (last defined) keybinding for a command.\r\n\t * @returns The preferred keybinding or null if the command is not bound.\r\n\t */\r\n\tlookupKeybinding(commandId: string): ResolvedKeybinding | undefined;\r\n\r\n\tgetKeybindings(): readonly ResolvedKeybindingItem[];\r\n\r\n\t/**\r\n\t * Will the given key event produce a character that's rendered on screen, e.g. in a\r\n\t * text box. *Note* that the results of this function can be incorrect.\r\n\t */\r\n\tmightProducePrintableCharacter(event: IKeyboardEvent): boolean;\r\n}\r\n\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IContext, ContextKeyExpression, ContextKeyExprType } from 'vs/platform/contextkey/common/contextkey';\r\nimport { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';\r\n\r\nexport interface IResolveResult {\r\n\t/** Whether the resolved keybinding is entering a chord */\r\n\tenterChord: boolean;\r\n\t/** Whether the resolved keybinding is leaving (and executing) a chord */\r\n\tleaveChord: boolean;\r\n\tcommandId: string | null;\r\n\tcommandArgs: any;\r\n\tbubble: boolean;\r\n}\r\n\r\nexport class KeybindingResolver {\r\n\tprivate readonly _log: (str: string) => void;\r\n\tprivate readonly _defaultKeybindings: ResolvedKeybindingItem[];\r\n\tprivate readonly _keybindings: ResolvedKeybindingItem[];\r\n\tprivate readonly _defaultBoundCommands: Map;\r\n\tprivate readonly _map: Map;\r\n\tprivate readonly _lookupMap: Map;\r\n\r\n\tconstructor(\r\n\t\tdefaultKeybindings: ResolvedKeybindingItem[],\r\n\t\toverrides: ResolvedKeybindingItem[],\r\n\t\tlog: (str: string) => void\r\n\t) {\r\n\t\tthis._log = log;\r\n\t\tthis._defaultKeybindings = defaultKeybindings;\r\n\r\n\t\tthis._defaultBoundCommands = new Map();\r\n\t\tfor (let i = 0, len = defaultKeybindings.length; i < len; i++) {\r\n\t\t\tconst command = defaultKeybindings[i].command;\r\n\t\t\tif (command) {\r\n\t\t\t\tthis._defaultBoundCommands.set(command, true);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._map = new Map();\r\n\t\tthis._lookupMap = new Map();\r\n\r\n\t\tthis._keybindings = KeybindingResolver.combine(defaultKeybindings, overrides);\r\n\t\tfor (let i = 0, len = this._keybindings.length; i < len; i++) {\r\n\t\t\tlet k = this._keybindings[i];\r\n\t\t\tif (k.keypressParts.length === 0) {\r\n\t\t\t\t// unbound\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (k.when && k.when.type === ContextKeyExprType.False) {\r\n\t\t\t\t// when condition is false\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\t// TODO@chords\r\n\t\t\tthis._addKeyPress(k.keypressParts[0], k);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static _isTargetedForRemoval(defaultKb: ResolvedKeybindingItem, keypressFirstPart: string | null, keypressChordPart: string | null, command: string, when: ContextKeyExpression | undefined): boolean {\r\n\t\tif (defaultKb.command !== command) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\t// TODO@chords\r\n\t\tif (keypressFirstPart && defaultKb.keypressParts[0] !== keypressFirstPart) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\t// TODO@chords\r\n\t\tif (keypressChordPart && defaultKb.keypressParts[1] !== keypressChordPart) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (when) {\r\n\t\t\tif (!defaultKb.when) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t\tif (!when.equals(defaultKb.when)) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn true;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Looks for rules containing -command in `overrides` and removes them directly from `defaults`.\r\n\t */\r\n\tpublic static combine(defaults: ResolvedKeybindingItem[], rawOverrides: ResolvedKeybindingItem[]): ResolvedKeybindingItem[] {\r\n\t\tdefaults = defaults.slice(0);\r\n\t\tlet overrides: ResolvedKeybindingItem[] = [];\r\n\t\tfor (const override of rawOverrides) {\r\n\t\t\tif (!override.command || override.command.length === 0 || override.command.charAt(0) !== '-') {\r\n\t\t\t\toverrides.push(override);\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tconst command = override.command.substr(1);\r\n\t\t\t// TODO@chords\r\n\t\t\tconst keypressFirstPart = override.keypressParts[0];\r\n\t\t\tconst keypressChordPart = override.keypressParts[1];\r\n\t\t\tconst when = override.when;\r\n\t\t\tfor (let j = defaults.length - 1; j >= 0; j--) {\r\n\t\t\t\tif (this._isTargetedForRemoval(defaults[j], keypressFirstPart, keypressChordPart, command, when)) {\r\n\t\t\t\t\tdefaults.splice(j, 1);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn defaults.concat(overrides);\r\n\t}\r\n\r\n\tprivate _addKeyPress(keypress: string, item: ResolvedKeybindingItem): void {\r\n\r\n\t\tconst conflicts = this._map.get(keypress);\r\n\r\n\t\tif (typeof conflicts === 'undefined') {\r\n\t\t\t// There is no conflict so far\r\n\t\t\tthis._map.set(keypress, [item]);\r\n\t\t\tthis._addToLookupMap(item);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tfor (let i = conflicts.length - 1; i >= 0; i--) {\r\n\t\t\tlet conflict = conflicts[i];\r\n\r\n\t\t\tif (conflict.command === item.command) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tconst conflictIsChord = (conflict.keypressParts.length > 1);\r\n\t\t\tconst itemIsChord = (item.keypressParts.length > 1);\r\n\r\n\t\t\t// TODO@chords\r\n\t\t\tif (conflictIsChord && itemIsChord && conflict.keypressParts[1] !== item.keypressParts[1]) {\r\n\t\t\t\t// The conflict only shares the chord start with this command\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (KeybindingResolver.whenIsEntirelyIncluded(conflict.when, item.when)) {\r\n\t\t\t\t// `item` completely overwrites `conflict`\r\n\t\t\t\t// Remove conflict from the lookupMap\r\n\t\t\t\tthis._removeFromLookupMap(conflict);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconflicts.push(item);\r\n\t\tthis._addToLookupMap(item);\r\n\t}\r\n\r\n\tprivate _addToLookupMap(item: ResolvedKeybindingItem): void {\r\n\t\tif (!item.command) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet arr = this._lookupMap.get(item.command);\r\n\t\tif (typeof arr === 'undefined') {\r\n\t\t\tarr = [item];\r\n\t\t\tthis._lookupMap.set(item.command, arr);\r\n\t\t} else {\r\n\t\t\tarr.push(item);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _removeFromLookupMap(item: ResolvedKeybindingItem): void {\r\n\t\tif (!item.command) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tlet arr = this._lookupMap.get(item.command);\r\n\t\tif (typeof arr === 'undefined') {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tfor (let i = 0, len = arr.length; i < len; i++) {\r\n\t\t\tif (arr[i] === item) {\r\n\t\t\t\tarr.splice(i, 1);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Returns true if it is provable `a` implies `b`.\r\n\t */\r\n\tpublic static whenIsEntirelyIncluded(a: ContextKeyExpression | null | undefined, b: ContextKeyExpression | null | undefined): boolean {\r\n\t\tif (!b) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (!a) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\treturn this._implies(a, b);\r\n\t}\r\n\r\n\t/**\r\n\t * Returns true if it is provable `p` implies `q`.\r\n\t */\r\n\tprivate static _implies(p: ContextKeyExpression, q: ContextKeyExpression): boolean {\r\n\t\tconst notP = p.negate();\r\n\r\n\t\tconst terminals = (node: ContextKeyExpression) => {\r\n\t\t\tif (node.type === ContextKeyExprType.Or) {\r\n\t\t\t\treturn node.expr;\r\n\t\t\t}\r\n\t\t\treturn [node];\r\n\t\t};\r\n\r\n\t\tlet expr = terminals(notP).concat(terminals(q));\r\n\t\tfor (let i = 0; i < expr.length; i++) {\r\n\t\t\tconst a = expr[i];\r\n\t\t\tconst notA = a.negate();\r\n\t\t\tfor (let j = i + 1; j < expr.length; j++) {\r\n\t\t\t\tconst b = expr[j];\r\n\t\t\t\tif (notA.equals(b)) {\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic getKeybindings(): readonly ResolvedKeybindingItem[] {\r\n\t\treturn this._keybindings;\r\n\t}\r\n\r\n\tpublic lookupPrimaryKeybinding(commandId: string): ResolvedKeybindingItem | null {\r\n\t\tlet items = this._lookupMap.get(commandId);\r\n\t\tif (typeof items === 'undefined' || items.length === 0) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\treturn items[items.length - 1];\r\n\t}\r\n\r\n\tpublic resolve(context: IContext, currentChord: string | null, keypress: string): IResolveResult | null {\r\n\t\tthis._log(`| Resolving ${keypress}${currentChord ? ` chorded from ${currentChord}` : ``}`);\r\n\t\tlet lookupMap: ResolvedKeybindingItem[] | null = null;\r\n\r\n\t\tif (currentChord !== null) {\r\n\t\t\t// Fetch all chord bindings for `currentChord`\r\n\r\n\t\t\tconst candidates = this._map.get(currentChord);\r\n\t\t\tif (typeof candidates === 'undefined') {\r\n\t\t\t\t// No chords starting with `currentChord`\r\n\t\t\t\tthis._log(`\\\\ No keybinding entries.`);\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\r\n\t\t\tlookupMap = [];\r\n\t\t\tfor (let i = 0, len = candidates.length; i < len; i++) {\r\n\t\t\t\tlet candidate = candidates[i];\r\n\t\t\t\t// TODO@chords\r\n\t\t\t\tif (candidate.keypressParts[1] === keypress) {\r\n\t\t\t\t\tlookupMap.push(candidate);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tconst candidates = this._map.get(keypress);\r\n\t\t\tif (typeof candidates === 'undefined') {\r\n\t\t\t\t// No bindings with `keypress`\r\n\t\t\t\tthis._log(`\\\\ No keybinding entries.`);\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\r\n\t\t\tlookupMap = candidates;\r\n\t\t}\r\n\r\n\t\tlet result = this._findCommand(context, lookupMap);\r\n\t\tif (!result) {\r\n\t\t\tthis._log(`\\\\ From ${lookupMap.length} keybinding entries, no when clauses matched the context.`);\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\t// TODO@chords\r\n\t\tif (currentChord === null && result.keypressParts.length > 1 && result.keypressParts[1] !== null) {\r\n\t\t\tthis._log(`\\\\ From ${lookupMap.length} keybinding entries, matched chord, when: ${printWhenExplanation(result.when)}, source: ${printSourceExplanation(result)}.`);\r\n\t\t\treturn {\r\n\t\t\t\tenterChord: true,\r\n\t\t\t\tleaveChord: false,\r\n\t\t\t\tcommandId: null,\r\n\t\t\t\tcommandArgs: null,\r\n\t\t\t\tbubble: false\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tthis._log(`\\\\ From ${lookupMap.length} keybinding entries, matched ${result.command}, when: ${printWhenExplanation(result.when)}, source: ${printSourceExplanation(result)}.`);\r\n\t\treturn {\r\n\t\t\tenterChord: false,\r\n\t\t\tleaveChord: result.keypressParts.length > 1,\r\n\t\t\tcommandId: result.command,\r\n\t\t\tcommandArgs: result.commandArgs,\r\n\t\t\tbubble: result.bubble\r\n\t\t};\r\n\t}\r\n\r\n\tprivate _findCommand(context: IContext, matches: ResolvedKeybindingItem[]): ResolvedKeybindingItem | null {\r\n\t\tfor (let i = matches.length - 1; i >= 0; i--) {\r\n\t\t\tlet k = matches[i];\r\n\r\n\t\t\tif (!KeybindingResolver.contextMatchesRules(context, k.when)) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\treturn k;\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic static contextMatchesRules(context: IContext, rules: ContextKeyExpression | null | undefined): boolean {\r\n\t\tif (!rules) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn rules.evaluate(context);\r\n\t}\r\n}\r\n\r\nfunction printWhenExplanation(when: ContextKeyExpression | undefined): string {\r\n\tif (!when) {\r\n\t\treturn `no when condition`;\r\n\t}\r\n\treturn `${when.serialize()}`;\r\n}\r\n\r\nfunction printSourceExplanation(kb: ResolvedKeybindingItem): string {\r\n\treturn (\r\n\t\tkb.extensionId\r\n\t\t\t? (kb.isBuiltinExtension ? `built-in extension ${kb.extensionId}` : `user extension ${kb.extensionId}`)\r\n\t\t\t: (kb.isDefault ? `built-in` : `user`)\r\n\t);\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport { ResolvedKeybinding } from 'vs/base/common/keyCodes';\r\nimport { ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';\r\n\r\nexport class ResolvedKeybindingItem {\r\n\t_resolvedKeybindingItemBrand: void;\r\n\r\n\tpublic readonly resolvedKeybinding: ResolvedKeybinding | undefined;\r\n\tpublic readonly keypressParts: string[];\r\n\tpublic readonly bubble: boolean;\r\n\tpublic readonly command: string | null;\r\n\tpublic readonly commandArgs: any;\r\n\tpublic readonly when: ContextKeyExpression | undefined;\r\n\tpublic readonly isDefault: boolean;\r\n\tpublic readonly extensionId: string | null;\r\n\tpublic readonly isBuiltinExtension: boolean;\r\n\r\n\tconstructor(resolvedKeybinding: ResolvedKeybinding | undefined, command: string | null, commandArgs: any, when: ContextKeyExpression | undefined, isDefault: boolean, extensionId: string | null, isBuiltinExtension: boolean) {\r\n\t\tthis.resolvedKeybinding = resolvedKeybinding;\r\n\t\tthis.keypressParts = resolvedKeybinding ? removeElementsAfterNulls(resolvedKeybinding.getDispatchParts()) : [];\r\n\t\tthis.bubble = (command ? command.charCodeAt(0) === CharCode.Caret : false);\r\n\t\tthis.command = this.bubble ? command!.substr(1) : command;\r\n\t\tthis.commandArgs = commandArgs;\r\n\t\tthis.when = when;\r\n\t\tthis.isDefault = isDefault;\r\n\t\tthis.extensionId = extensionId;\r\n\t\tthis.isBuiltinExtension = isBuiltinExtension;\r\n\t}\r\n}\r\n\r\nexport function removeElementsAfterNulls(arr: (T | null)[]): T[] {\r\n\tlet result: T[] = [];\r\n\tfor (let i = 0, len = arr.length; i < len; i++) {\r\n\t\tconst element = arr[i];\r\n\t\tif (!element) {\r\n\t\t\t// stop processing at first encountered null\r\n\t\t\treturn result;\r\n\t\t}\r\n\t\tresult.push(element);\r\n\t}\r\n\treturn result;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { KeyCode, KeyCodeUtils, Keybinding, SimpleKeybinding } from 'vs/base/common/keyCodes';\r\nimport { OperatingSystem } from 'vs/base/common/platform';\r\nimport { BaseResolvedKeybinding } from 'vs/platform/keybinding/common/baseResolvedKeybinding';\r\n\r\n/**\r\n * Do not instantiate. Use KeybindingService to get a ResolvedKeybinding seeded with information about the current kb layout.\r\n */\r\nexport class USLayoutResolvedKeybinding extends BaseResolvedKeybinding {\r\n\r\n\tconstructor(actual: Keybinding, os: OperatingSystem) {\r\n\t\tsuper(os, actual.parts);\r\n\t}\r\n\r\n\tprivate _keyCodeToUILabel(keyCode: KeyCode): string {\r\n\t\tif (this._os === OperatingSystem.Macintosh) {\r\n\t\t\tswitch (keyCode) {\r\n\t\t\t\tcase KeyCode.LeftArrow:\r\n\t\t\t\t\treturn '←';\r\n\t\t\t\tcase KeyCode.UpArrow:\r\n\t\t\t\t\treturn '↑';\r\n\t\t\t\tcase KeyCode.RightArrow:\r\n\t\t\t\t\treturn '→';\r\n\t\t\t\tcase KeyCode.DownArrow:\r\n\t\t\t\t\treturn '↓';\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn KeyCodeUtils.toString(keyCode);\r\n\t}\r\n\r\n\tprotected _getLabel(keybinding: SimpleKeybinding): string | null {\r\n\t\tif (keybinding.isDuplicateModifierCase()) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\treturn this._keyCodeToUILabel(keybinding.keyCode);\r\n\t}\r\n\r\n\tprotected _getAriaLabel(keybinding: SimpleKeybinding): string | null {\r\n\t\tif (keybinding.isDuplicateModifierCase()) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\treturn KeyCodeUtils.toString(keybinding.keyCode);\r\n\t}\r\n\r\n\tprotected _getDispatchPart(keybinding: SimpleKeybinding): string | null {\r\n\t\treturn USLayoutResolvedKeybinding.getDispatchStr(keybinding);\r\n\t}\r\n\r\n\tpublic static getDispatchStr(keybinding: SimpleKeybinding): string | null {\r\n\t\tif (keybinding.isModifierKey()) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tlet result = '';\r\n\r\n\t\tif (keybinding.ctrlKey) {\r\n\t\t\tresult += 'ctrl+';\r\n\t\t}\r\n\t\tif (keybinding.shiftKey) {\r\n\t\t\tresult += 'shift+';\r\n\t\t}\r\n\t\tif (keybinding.altKey) {\r\n\t\t\tresult += 'alt+';\r\n\t\t}\r\n\t\tif (keybinding.metaKey) {\r\n\t\t\tresult += 'meta+';\r\n\t\t}\r\n\t\tresult += KeyCodeUtils.toString(keybinding.keyCode);\r\n\r\n\t\treturn result;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\n\r\nexport const ILabelService = createDecorator('labelService');\r\n\r\nexport interface ILabelService {\r\n\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\t/**\r\n\t * Gets the human readable label for a uri.\r\n\t * If relative is passed returns a label relative to the workspace root that the uri belongs to.\r\n\t * If noPrefix is passed does not tildify the label and also does not prepand the root name for relative labels in a multi root scenario.\r\n\t */\r\n\tgetUriLabel(resource: URI, options?: { relative?: boolean, noPrefix?: boolean, endWithSeparator?: boolean }): string;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Event } from 'vs/base/common/event';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IDimension } from 'vs/base/browser/dom';\r\n\r\nexport const ILayoutService = createDecorator('layoutService');\r\n\r\nexport interface ILayoutService {\r\n\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\t/**\r\n\t * The dimensions of the container.\r\n\t */\r\n\treadonly dimension: IDimension;\r\n\r\n\t/**\r\n\t * Container of the application.\r\n\t */\r\n\treadonly container: HTMLElement;\r\n\r\n\t/**\r\n\t * An offset to use for positioning elements inside the container.\r\n\t */\r\n\treadonly offset?: { top: number };\r\n\r\n\t/**\r\n\t * An event that is emitted when the container is layed out. The\r\n\t * event carries the dimensions of the container as part of it.\r\n\t */\r\n\treadonly onLayout: Event;\r\n\r\n\t/**\r\n\t * Focus the primary component of the container.\r\n\t */\r\n\tfocus(): void;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IContextViewService, IContextViewDelegate } from './contextView';\r\nimport { ContextView, ContextViewDOMPosition } from 'vs/base/browser/ui/contextview/contextview';\r\nimport { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\r\nimport { ILayoutService } from 'vs/platform/layout/browser/layoutService';\r\n\r\nexport class ContextViewService extends Disposable implements IContextViewService {\r\n\tdeclare readonly _serviceBrand: undefined;\r\n\r\n\tprivate currentViewDisposable: IDisposable = Disposable.None;\r\n\tprivate contextView: ContextView;\r\n\tprivate container: HTMLElement;\r\n\r\n\tconstructor(\r\n\t\t@ILayoutService readonly layoutService: ILayoutService\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\tthis.container = layoutService.container;\r\n\t\tthis.contextView = this._register(new ContextView(this.container, ContextViewDOMPosition.ABSOLUTE));\r\n\t\tthis.layout();\r\n\r\n\t\tthis._register(layoutService.onLayout(() => this.layout()));\r\n\t}\r\n\r\n\t// ContextView\r\n\r\n\tsetContainer(container: HTMLElement, domPosition?: ContextViewDOMPosition): void {\r\n\t\tthis.contextView.setContainer(container, domPosition || ContextViewDOMPosition.ABSOLUTE);\r\n\t}\r\n\r\n\tshowContextView(delegate: IContextViewDelegate, container?: HTMLElement, shadowRoot?: boolean): IDisposable {\r\n\t\tif (container) {\r\n\t\t\tif (container !== this.container) {\r\n\t\t\t\tthis.container = container;\r\n\t\t\t\tthis.setContainer(container, shadowRoot ? ContextViewDOMPosition.FIXED_SHADOW : ContextViewDOMPosition.FIXED);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tif (this.container !== this.layoutService.container) {\r\n\t\t\t\tthis.container = this.layoutService.container;\r\n\t\t\t\tthis.setContainer(this.container, ContextViewDOMPosition.ABSOLUTE);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis.contextView.show(delegate);\r\n\r\n\t\tconst disposable = toDisposable(() => {\r\n\t\t\tif (this.currentViewDisposable === disposable) {\r\n\t\t\t\tthis.hideContextView();\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tthis.currentViewDisposable = disposable;\r\n\t\treturn disposable;\r\n\t}\r\n\r\n\tgetContextViewElement(): HTMLElement {\r\n\t\treturn this.contextView.getViewElement();\r\n\t}\r\n\r\n\tlayout(): void {\r\n\t\tthis.contextView.layout();\r\n\t}\r\n\r\n\thideContextView(data?: any): void {\r\n\t\tthis.contextView.hide(data);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { createDecorator as createServiceDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IDisposable, Disposable } from 'vs/base/common/lifecycle';\r\nimport { Emitter } from 'vs/base/common/event';\r\n\r\nexport const ILogService = createServiceDecorator('logService');\r\n\r\nexport enum LogLevel {\r\n\tTrace,\r\n\tDebug,\r\n\tInfo,\r\n\tWarning,\r\n\tError,\r\n\tCritical,\r\n\tOff\r\n}\r\n\r\nexport const DEFAULT_LOG_LEVEL: LogLevel = LogLevel.Info;\r\n\r\nexport interface ILogger extends IDisposable {\r\n\tgetLevel(): LogLevel;\r\n\r\n\ttrace(message: string, ...args: any[]): void;\r\n\tdebug(message: string, ...args: any[]): void;\r\n\tinfo(message: string, ...args: any[]): void;\r\n\terror(message: string | Error, ...args: any[]): void;\r\n}\r\n\r\nexport interface ILogService extends ILogger {\r\n\treadonly _serviceBrand: undefined;\r\n}\r\n\r\nexport abstract class AbstractLogService extends Disposable {\r\n\r\n\tprivate level: LogLevel = DEFAULT_LOG_LEVEL;\r\n\tprivate readonly _onDidChangeLogLevel: Emitter = this._register(new Emitter());\r\n\r\n\tsetLevel(level: LogLevel): void {\r\n\t\tif (this.level !== level) {\r\n\t\t\tthis.level = level;\r\n\t\t\tthis._onDidChangeLogLevel.fire(this.level);\r\n\t\t}\r\n\t}\r\n\r\n\tgetLevel(): LogLevel {\r\n\t\treturn this.level;\r\n\t}\r\n\r\n}\r\n\r\nexport class ConsoleLogService extends AbstractLogService implements ILogService {\r\n\r\n\tdeclare readonly _serviceBrand: undefined;\r\n\r\n\tconstructor(logLevel: LogLevel = DEFAULT_LOG_LEVEL) {\r\n\t\tsuper();\r\n\t\tthis.setLevel(logLevel);\r\n\t}\r\n\r\n\ttrace(message: string, ...args: any[]): void {\r\n\t\tif (this.getLevel() <= LogLevel.Trace) {\r\n\t\t\tconsole.log('%cTRACE', 'color: #888', message, ...args);\r\n\t\t}\r\n\t}\r\n\r\n\tdebug(message: string, ...args: any[]): void {\r\n\t\tif (this.getLevel() <= LogLevel.Debug) {\r\n\t\t\tconsole.log('%cDEBUG', 'background: #eee; color: #888', message, ...args);\r\n\t\t}\r\n\t}\r\n\r\n\tinfo(message: string, ...args: any[]): void {\r\n\t\tif (this.getLevel() <= LogLevel.Info) {\r\n\t\t\tconsole.log('%c INFO', 'color: #33f', message, ...args);\r\n\t\t}\r\n\t}\r\n\r\n\terror(message: string, ...args: any[]): void {\r\n\t\tif (this.getLevel() <= LogLevel.Error) {\r\n\t\t\tconsole.log('%c ERR', 'color: #f33', message, ...args);\r\n\t\t}\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\t// noop\r\n\t}\r\n}\r\n\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IntervalTimer, timeout } from 'vs/base/common/async';\r\nimport { Disposable, IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { SimpleWorkerClient, logOnceWebWorkerWarning, IWorkerClient } from 'vs/base/common/worker/simpleWorker';\r\nimport { DefaultWorkerFactory } from 'vs/base/worker/defaultWorkerFactory';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { IRange, Range } from 'vs/editor/common/core/range';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport * as modes from 'vs/editor/common/modes';\r\nimport { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';\r\nimport { EditorSimpleWorker } from 'vs/editor/common/services/editorSimpleWorker';\r\nimport { IDiffComputationResult, IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';\r\nimport { IModelService } from 'vs/editor/common/services/modelService';\r\nimport { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfigurationService';\r\nimport { regExpFlags } from 'vs/base/common/strings';\r\nimport { isNonEmptyArray } from 'vs/base/common/arrays';\r\nimport { ILogService } from 'vs/platform/log/common/log';\r\nimport { StopWatch } from 'vs/base/common/stopwatch';\r\nimport { canceled } from 'vs/base/common/errors';\r\n\r\n/**\r\n * Stop syncing a model to the worker if it was not needed for 1 min.\r\n */\r\nconst STOP_SYNC_MODEL_DELTA_TIME_MS = 60 * 1000;\r\n\r\n/**\r\n * Stop the worker if it was not needed for 5 min.\r\n */\r\nconst STOP_WORKER_DELTA_TIME_MS = 5 * 60 * 1000;\r\n\r\nfunction canSyncModel(modelService: IModelService, resource: URI): boolean {\r\n\tlet model = modelService.getModel(resource);\r\n\tif (!model) {\r\n\t\treturn false;\r\n\t}\r\n\tif (model.isTooLargeForSyncing()) {\r\n\t\treturn false;\r\n\t}\r\n\treturn true;\r\n}\r\n\r\nexport class EditorWorkerServiceImpl extends Disposable implements IEditorWorkerService {\r\n\r\n\tdeclare readonly _serviceBrand: undefined;\r\n\r\n\tprivate readonly _modelService: IModelService;\r\n\tprivate readonly _workerManager: WorkerManager;\r\n\tprivate readonly _logService: ILogService;\r\n\r\n\tconstructor(\r\n\t\t@IModelService modelService: IModelService,\r\n\t\t@ITextResourceConfigurationService configurationService: ITextResourceConfigurationService,\r\n\t\t@ILogService logService: ILogService\r\n\t) {\r\n\t\tsuper();\r\n\t\tthis._modelService = modelService;\r\n\t\tthis._workerManager = this._register(new WorkerManager(this._modelService));\r\n\t\tthis._logService = logService;\r\n\r\n\t\t// register default link-provider and default completions-provider\r\n\t\tthis._register(modes.LinkProviderRegistry.register('*', {\r\n\t\t\tprovideLinks: (model, token) => {\r\n\t\t\t\tif (!canSyncModel(this._modelService, model.uri)) {\r\n\t\t\t\t\treturn Promise.resolve({ links: [] }); // File too large\r\n\t\t\t\t}\r\n\t\t\t\treturn this._workerManager.withWorker().then(client => client.computeLinks(model.uri)).then(links => {\r\n\t\t\t\t\treturn links && { links };\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._register(modes.CompletionProviderRegistry.register('*', new WordBasedCompletionItemProvider(this._workerManager, configurationService, this._modelService)));\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tpublic canComputeDiff(original: URI, modified: URI): boolean {\r\n\t\treturn (canSyncModel(this._modelService, original) && canSyncModel(this._modelService, modified));\r\n\t}\r\n\r\n\tpublic computeDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean, maxComputationTime: number): Promise {\r\n\t\treturn this._workerManager.withWorker().then(client => client.computeDiff(original, modified, ignoreTrimWhitespace, maxComputationTime));\r\n\t}\r\n\r\n\tpublic computeMoreMinimalEdits(resource: URI, edits: modes.TextEdit[] | null | undefined): Promise {\r\n\t\tif (isNonEmptyArray(edits)) {\r\n\t\t\tif (!canSyncModel(this._modelService, resource)) {\r\n\t\t\t\treturn Promise.resolve(edits); // File too large\r\n\t\t\t}\r\n\t\t\tconst sw = StopWatch.create(true);\r\n\t\t\tconst result = this._workerManager.withWorker().then(client => client.computeMoreMinimalEdits(resource, edits));\r\n\t\t\tresult.finally(() => this._logService.trace('FORMAT#computeMoreMinimalEdits', resource.toString(true), sw.elapsed()));\r\n\t\t\treturn Promise.race([result, timeout(1000).then(() => edits)]);\r\n\r\n\t\t} else {\r\n\t\t\treturn Promise.resolve(undefined);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic canNavigateValueSet(resource: URI): boolean {\r\n\t\treturn (canSyncModel(this._modelService, resource));\r\n\t}\r\n\r\n\tpublic navigateValueSet(resource: URI, range: IRange, up: boolean): Promise {\r\n\t\treturn this._workerManager.withWorker().then(client => client.navigateValueSet(resource, range, up));\r\n\t}\r\n\r\n\tcanComputeWordRanges(resource: URI): boolean {\r\n\t\treturn canSyncModel(this._modelService, resource);\r\n\t}\r\n\r\n\tcomputeWordRanges(resource: URI, range: IRange): Promise<{ [word: string]: IRange[] } | null> {\r\n\t\treturn this._workerManager.withWorker().then(client => client.computeWordRanges(resource, range));\r\n\t}\r\n}\r\n\r\nclass WordBasedCompletionItemProvider implements modes.CompletionItemProvider {\r\n\r\n\tprivate readonly _workerManager: WorkerManager;\r\n\tprivate readonly _configurationService: ITextResourceConfigurationService;\r\n\tprivate readonly _modelService: IModelService;\r\n\r\n\treadonly _debugDisplayName = 'wordbasedCompletions';\r\n\r\n\tconstructor(\r\n\t\tworkerManager: WorkerManager,\r\n\t\tconfigurationService: ITextResourceConfigurationService,\r\n\t\tmodelService: IModelService\r\n\t) {\r\n\t\tthis._workerManager = workerManager;\r\n\t\tthis._configurationService = configurationService;\r\n\t\tthis._modelService = modelService;\r\n\t}\r\n\r\n\tasync provideCompletionItems(model: ITextModel, position: Position): Promise {\r\n\t\ttype WordBasedSuggestionsConfig = {\r\n\t\t\twordBasedSuggestions?: boolean,\r\n\t\t\twordBasedSuggestionsMode?: 'currentDocument' | 'matchingDocuments' | 'allDocuments'\r\n\t\t};\r\n\t\tconst config = this._configurationService.getValue(model.uri, position, 'editor');\r\n\t\tif (!config.wordBasedSuggestions) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\r\n\t\tconst models: URI[] = [];\r\n\t\tif (config.wordBasedSuggestionsMode === 'currentDocument') {\r\n\t\t\t// only current file and only if not too large\r\n\t\t\tif (canSyncModel(this._modelService, model.uri)) {\r\n\t\t\t\tmodels.push(model.uri);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\t// either all files or files of same language\r\n\t\t\tfor (const candidate of this._modelService.getModels()) {\r\n\t\t\t\tif (!canSyncModel(this._modelService, candidate.uri)) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\tif (candidate === model) {\r\n\t\t\t\t\tmodels.unshift(candidate.uri);\r\n\r\n\t\t\t\t} else if (config.wordBasedSuggestionsMode === 'allDocuments' || candidate.getLanguageIdentifier().id === model.getLanguageIdentifier().id) {\r\n\t\t\t\t\tmodels.push(candidate.uri);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (models.length === 0) {\r\n\t\t\treturn undefined; // File too large, no other files\r\n\t\t}\r\n\r\n\t\tconst wordDefRegExp = LanguageConfigurationRegistry.getWordDefinition(model.getLanguageIdentifier().id);\r\n\t\tconst word = model.getWordAtPosition(position);\r\n\t\tconst replace = !word ? Range.fromPositions(position) : new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn);\r\n\t\tconst insert = replace.setEndPosition(position.lineNumber, position.column);\r\n\r\n\t\tconst client = await this._workerManager.withWorker();\r\n\t\tconst data = await client.textualSuggest(models, word?.word, wordDefRegExp);\r\n\t\tif (!data) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tduration: data.duration,\r\n\t\t\tsuggestions: data.words.map((word): modes.CompletionItem => {\r\n\t\t\t\treturn {\r\n\t\t\t\t\tkind: modes.CompletionItemKind.Text,\r\n\t\t\t\t\tlabel: word,\r\n\t\t\t\t\tinsertText: word,\r\n\t\t\t\t\trange: { insert, replace }\r\n\t\t\t\t};\r\n\t\t\t}),\r\n\t\t};\r\n\t}\r\n}\r\n\r\nclass WorkerManager extends Disposable {\r\n\r\n\tprivate readonly _modelService: IModelService;\r\n\tprivate _editorWorkerClient: EditorWorkerClient | null;\r\n\tprivate _lastWorkerUsedTime: number;\r\n\r\n\tconstructor(modelService: IModelService) {\r\n\t\tsuper();\r\n\t\tthis._modelService = modelService;\r\n\t\tthis._editorWorkerClient = null;\r\n\t\tthis._lastWorkerUsedTime = (new Date()).getTime();\r\n\r\n\t\tlet stopWorkerInterval = this._register(new IntervalTimer());\r\n\t\tstopWorkerInterval.cancelAndSet(() => this._checkStopIdleWorker(), Math.round(STOP_WORKER_DELTA_TIME_MS / 2));\r\n\r\n\t\tthis._register(this._modelService.onModelRemoved(_ => this._checkStopEmptyWorker()));\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tif (this._editorWorkerClient) {\r\n\t\t\tthis._editorWorkerClient.dispose();\r\n\t\t\tthis._editorWorkerClient = null;\r\n\t\t}\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\t/**\r\n\t * Check if the model service has no more models and stop the worker if that is the case.\r\n\t */\r\n\tprivate _checkStopEmptyWorker(): void {\r\n\t\tif (!this._editorWorkerClient) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet models = this._modelService.getModels();\r\n\t\tif (models.length === 0) {\r\n\t\t\t// There are no more models => nothing possible for me to do\r\n\t\t\tthis._editorWorkerClient.dispose();\r\n\t\t\tthis._editorWorkerClient = null;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Check if the worker has been idle for a while and then stop it.\r\n\t */\r\n\tprivate _checkStopIdleWorker(): void {\r\n\t\tif (!this._editorWorkerClient) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet timeSinceLastWorkerUsedTime = (new Date()).getTime() - this._lastWorkerUsedTime;\r\n\t\tif (timeSinceLastWorkerUsedTime > STOP_WORKER_DELTA_TIME_MS) {\r\n\t\t\tthis._editorWorkerClient.dispose();\r\n\t\t\tthis._editorWorkerClient = null;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic withWorker(): Promise {\r\n\t\tthis._lastWorkerUsedTime = (new Date()).getTime();\r\n\t\tif (!this._editorWorkerClient) {\r\n\t\t\tthis._editorWorkerClient = new EditorWorkerClient(this._modelService, false, 'editorWorkerService');\r\n\t\t}\r\n\t\treturn Promise.resolve(this._editorWorkerClient);\r\n\t}\r\n}\r\n\r\nclass EditorModelManager extends Disposable {\r\n\r\n\tprivate readonly _proxy: EditorSimpleWorker;\r\n\tprivate readonly _modelService: IModelService;\r\n\tprivate _syncedModels: { [modelUrl: string]: IDisposable; } = Object.create(null);\r\n\tprivate _syncedModelsLastUsedTime: { [modelUrl: string]: number; } = Object.create(null);\r\n\r\n\tconstructor(proxy: EditorSimpleWorker, modelService: IModelService, keepIdleModels: boolean) {\r\n\t\tsuper();\r\n\t\tthis._proxy = proxy;\r\n\t\tthis._modelService = modelService;\r\n\r\n\t\tif (!keepIdleModels) {\r\n\t\t\tlet timer = new IntervalTimer();\r\n\t\t\ttimer.cancelAndSet(() => this._checkStopModelSync(), Math.round(STOP_SYNC_MODEL_DELTA_TIME_MS / 2));\r\n\t\t\tthis._register(timer);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tfor (let modelUrl in this._syncedModels) {\r\n\t\t\tdispose(this._syncedModels[modelUrl]);\r\n\t\t}\r\n\t\tthis._syncedModels = Object.create(null);\r\n\t\tthis._syncedModelsLastUsedTime = Object.create(null);\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tpublic ensureSyncedResources(resources: URI[]): void {\r\n\t\tfor (const resource of resources) {\r\n\t\t\tlet resourceStr = resource.toString();\r\n\r\n\t\t\tif (!this._syncedModels[resourceStr]) {\r\n\t\t\t\tthis._beginModelSync(resource);\r\n\t\t\t}\r\n\t\t\tif (this._syncedModels[resourceStr]) {\r\n\t\t\t\tthis._syncedModelsLastUsedTime[resourceStr] = (new Date()).getTime();\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _checkStopModelSync(): void {\r\n\t\tlet currentTime = (new Date()).getTime();\r\n\r\n\t\tlet toRemove: string[] = [];\r\n\t\tfor (let modelUrl in this._syncedModelsLastUsedTime) {\r\n\t\t\tlet elapsedTime = currentTime - this._syncedModelsLastUsedTime[modelUrl];\r\n\t\t\tif (elapsedTime > STOP_SYNC_MODEL_DELTA_TIME_MS) {\r\n\t\t\t\ttoRemove.push(modelUrl);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tfor (const e of toRemove) {\r\n\t\t\tthis._stopModelSync(e);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _beginModelSync(resource: URI): void {\r\n\t\tlet model = this._modelService.getModel(resource);\r\n\t\tif (!model) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (model.isTooLargeForSyncing()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet modelUrl = resource.toString();\r\n\r\n\t\tthis._proxy.acceptNewModel({\r\n\t\t\turl: model.uri.toString(),\r\n\t\t\tlines: model.getLinesContent(),\r\n\t\t\tEOL: model.getEOL(),\r\n\t\t\tversionId: model.getVersionId()\r\n\t\t});\r\n\r\n\t\tconst toDispose = new DisposableStore();\r\n\t\ttoDispose.add(model.onDidChangeContent((e) => {\r\n\t\t\tthis._proxy.acceptModelChanged(modelUrl.toString(), e);\r\n\t\t}));\r\n\t\ttoDispose.add(model.onWillDispose(() => {\r\n\t\t\tthis._stopModelSync(modelUrl);\r\n\t\t}));\r\n\t\ttoDispose.add(toDisposable(() => {\r\n\t\t\tthis._proxy.acceptRemovedModel(modelUrl);\r\n\t\t}));\r\n\r\n\t\tthis._syncedModels[modelUrl] = toDispose;\r\n\t}\r\n\r\n\tprivate _stopModelSync(modelUrl: string): void {\r\n\t\tlet toDispose = this._syncedModels[modelUrl];\r\n\t\tdelete this._syncedModels[modelUrl];\r\n\t\tdelete this._syncedModelsLastUsedTime[modelUrl];\r\n\t\tdispose(toDispose);\r\n\t}\r\n}\r\n\r\nclass SynchronousWorkerClient implements IWorkerClient {\r\n\tprivate readonly _instance: T;\r\n\tprivate readonly _proxyObj: Promise;\r\n\r\n\tconstructor(instance: T) {\r\n\t\tthis._instance = instance;\r\n\t\tthis._proxyObj = Promise.resolve(this._instance);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._instance.dispose();\r\n\t}\r\n\r\n\tpublic getProxyObject(): Promise {\r\n\t\treturn this._proxyObj;\r\n\t}\r\n}\r\n\r\nexport class EditorWorkerHost {\r\n\r\n\tprivate readonly _workerClient: EditorWorkerClient;\r\n\r\n\tconstructor(workerClient: EditorWorkerClient) {\r\n\t\tthis._workerClient = workerClient;\r\n\t}\r\n\r\n\t// foreign host request\r\n\tpublic fhr(method: string, args: any[]): Promise {\r\n\t\treturn this._workerClient.fhr(method, args);\r\n\t}\r\n}\r\n\r\nexport class EditorWorkerClient extends Disposable {\r\n\r\n\tprivate readonly _modelService: IModelService;\r\n\tprivate readonly _keepIdleModels: boolean;\r\n\tprivate _worker: IWorkerClient | null;\r\n\tprivate readonly _workerFactory: DefaultWorkerFactory;\r\n\tprivate _modelManager: EditorModelManager | null;\r\n\tprivate _disposed = false;\r\n\r\n\tconstructor(modelService: IModelService, keepIdleModels: boolean, label: string | undefined) {\r\n\t\tsuper();\r\n\t\tthis._modelService = modelService;\r\n\t\tthis._keepIdleModels = keepIdleModels;\r\n\t\tthis._workerFactory = new DefaultWorkerFactory(label);\r\n\t\tthis._worker = null;\r\n\t\tthis._modelManager = null;\r\n\t}\r\n\r\n\t// foreign host request\r\n\tpublic fhr(method: string, args: any[]): Promise {\r\n\t\tthrow new Error(`Not implemented!`);\r\n\t}\r\n\r\n\tprivate _getOrCreateWorker(): IWorkerClient {\r\n\t\tif (!this._worker) {\r\n\t\t\ttry {\r\n\t\t\t\tthis._worker = this._register(new SimpleWorkerClient(\r\n\t\t\t\t\tthis._workerFactory,\r\n\t\t\t\t\t'vs/editor/common/services/editorSimpleWorker',\r\n\t\t\t\t\tnew EditorWorkerHost(this)\r\n\t\t\t\t));\r\n\t\t\t} catch (err) {\r\n\t\t\t\tlogOnceWebWorkerWarning(err);\r\n\t\t\t\tthis._worker = new SynchronousWorkerClient(new EditorSimpleWorker(new EditorWorkerHost(this), null));\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this._worker;\r\n\t}\r\n\r\n\tprotected _getProxy(): Promise {\r\n\t\treturn this._getOrCreateWorker().getProxyObject().then(undefined, (err) => {\r\n\t\t\tlogOnceWebWorkerWarning(err);\r\n\t\t\tthis._worker = new SynchronousWorkerClient(new EditorSimpleWorker(new EditorWorkerHost(this), null));\r\n\t\t\treturn this._getOrCreateWorker().getProxyObject();\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _getOrCreateModelManager(proxy: EditorSimpleWorker): EditorModelManager {\r\n\t\tif (!this._modelManager) {\r\n\t\t\tthis._modelManager = this._register(new EditorModelManager(proxy, this._modelService, this._keepIdleModels));\r\n\t\t}\r\n\t\treturn this._modelManager;\r\n\t}\r\n\r\n\tprotected _withSyncedResources(resources: URI[]): Promise {\r\n\t\tif (this._disposed) {\r\n\t\t\treturn Promise.reject(canceled());\r\n\t\t}\r\n\t\treturn this._getProxy().then((proxy) => {\r\n\t\t\tthis._getOrCreateModelManager(proxy).ensureSyncedResources(resources);\r\n\t\t\treturn proxy;\r\n\t\t});\r\n\t}\r\n\r\n\tpublic computeDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean, maxComputationTime: number): Promise {\r\n\t\treturn this._withSyncedResources([original, modified]).then(proxy => {\r\n\t\t\treturn proxy.computeDiff(original.toString(), modified.toString(), ignoreTrimWhitespace, maxComputationTime);\r\n\t\t});\r\n\t}\r\n\r\n\tpublic computeMoreMinimalEdits(resource: URI, edits: modes.TextEdit[]): Promise {\r\n\t\treturn this._withSyncedResources([resource]).then(proxy => {\r\n\t\t\treturn proxy.computeMoreMinimalEdits(resource.toString(), edits);\r\n\t\t});\r\n\t}\r\n\r\n\tpublic computeLinks(resource: URI): Promise {\r\n\t\treturn this._withSyncedResources([resource]).then(proxy => {\r\n\t\t\treturn proxy.computeLinks(resource.toString());\r\n\t\t});\r\n\t}\r\n\r\n\tpublic async textualSuggest(resources: URI[], leadingWord: string | undefined, wordDefRegExp: RegExp): Promise<{ words: string[], duration: number } | null> {\r\n\t\tconst proxy = await this._withSyncedResources(resources);\r\n\t\tconst wordDef = wordDefRegExp.source;\r\n\t\tconst wordDefFlags = regExpFlags(wordDefRegExp);\r\n\t\treturn proxy.textualSuggest(resources.map(r => r.toString()), leadingWord, wordDef, wordDefFlags);\r\n\t}\r\n\r\n\tcomputeWordRanges(resource: URI, range: IRange): Promise<{ [word: string]: IRange[] } | null> {\r\n\t\treturn this._withSyncedResources([resource]).then(proxy => {\r\n\t\t\tlet model = this._modelService.getModel(resource);\r\n\t\t\tif (!model) {\r\n\t\t\t\treturn Promise.resolve(null);\r\n\t\t\t}\r\n\t\t\tlet wordDefRegExp = LanguageConfigurationRegistry.getWordDefinition(model.getLanguageIdentifier().id);\r\n\t\t\tlet wordDef = wordDefRegExp.source;\r\n\t\t\tlet wordDefFlags = regExpFlags(wordDefRegExp);\r\n\t\t\treturn proxy.computeWordRanges(resource.toString(), range, wordDef, wordDefFlags);\r\n\t\t});\r\n\t}\r\n\r\n\tpublic navigateValueSet(resource: URI, range: IRange, up: boolean): Promise {\r\n\t\treturn this._withSyncedResources([resource]).then(proxy => {\r\n\t\t\tlet model = this._modelService.getModel(resource);\r\n\t\t\tif (!model) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t\tlet wordDefRegExp = LanguageConfigurationRegistry.getWordDefinition(model.getLanguageIdentifier().id);\r\n\t\t\tlet wordDef = wordDefRegExp.source;\r\n\t\t\tlet wordDefFlags = regExpFlags(wordDefRegExp);\r\n\t\t\treturn proxy.navigateValueSet(resource.toString(), range, up, wordDef, wordDefFlags);\r\n\t\t});\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tsuper.dispose();\r\n\t\tthis._disposed = true;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { SemanticTokensLegend, TokenMetadata, FontStyle, MetadataConsts, SemanticTokens, LanguageIdentifier } from 'vs/editor/common/modes';\r\nimport { IThemeService } from 'vs/platform/theme/common/themeService';\r\nimport { ILogService, LogLevel } from 'vs/platform/log/common/log';\r\nimport { MultilineTokens2, SparseEncodedTokens } from 'vs/editor/common/model/tokensStore';\r\n\r\nexport const enum SemanticTokensProviderStylingConstants {\r\n\tNO_STYLING = 0b01111111111111111111111111111111\r\n}\r\n\r\nexport class SemanticTokensProviderStyling {\r\n\r\n\tprivate readonly _hashTable: HashTable;\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _legend: SemanticTokensLegend,\r\n\t\tprivate readonly _themeService: IThemeService,\r\n\t\tprivate readonly _logService: ILogService\r\n\t) {\r\n\t\tthis._hashTable = new HashTable();\r\n\t}\r\n\r\n\tpublic getMetadata(tokenTypeIndex: number, tokenModifierSet: number, languageId: LanguageIdentifier): number {\r\n\t\tconst entry = this._hashTable.get(tokenTypeIndex, tokenModifierSet, languageId.id);\r\n\t\tlet metadata: number;\r\n\t\tif (entry) {\r\n\t\t\tmetadata = entry.metadata;\r\n\t\t\tif (this._logService.getLevel() === LogLevel.Trace) {\r\n\t\t\t\tthis._logService.trace(`SemanticTokensProviderStyling [CACHED] ${tokenTypeIndex} / ${tokenModifierSet}: foreground ${TokenMetadata.getForeground(metadata)}, fontStyle ${TokenMetadata.getFontStyle(metadata).toString(2)}`);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tlet tokenType = this._legend.tokenTypes[tokenTypeIndex];\r\n\t\t\tconst tokenModifiers: string[] = [];\r\n\t\t\tif (tokenType) {\r\n\t\t\t\tlet modifierSet = tokenModifierSet;\r\n\t\t\t\tfor (let modifierIndex = 0; modifierSet > 0 && modifierIndex < this._legend.tokenModifiers.length; modifierIndex++) {\r\n\t\t\t\t\tif (modifierSet & 1) {\r\n\t\t\t\t\t\ttokenModifiers.push(this._legend.tokenModifiers[modifierIndex]);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tmodifierSet = modifierSet >> 1;\r\n\t\t\t\t}\r\n\t\t\t\tif (modifierSet > 0 && this._logService.getLevel() === LogLevel.Trace) {\r\n\t\t\t\t\tthis._logService.trace(`SemanticTokensProviderStyling: unknown token modifier index: ${tokenModifierSet.toString(2)} for legend: ${JSON.stringify(this._legend.tokenModifiers)}`);\r\n\t\t\t\t\ttokenModifiers.push('not-in-legend');\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst tokenStyle = this._themeService.getColorTheme().getTokenStyleMetadata(tokenType, tokenModifiers, languageId.language);\r\n\t\t\t\tif (typeof tokenStyle === 'undefined') {\r\n\t\t\t\t\tmetadata = SemanticTokensProviderStylingConstants.NO_STYLING;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tmetadata = 0;\r\n\t\t\t\t\tif (typeof tokenStyle.italic !== 'undefined') {\r\n\t\t\t\t\t\tconst italicBit = (tokenStyle.italic ? FontStyle.Italic : 0) << MetadataConsts.FONT_STYLE_OFFSET;\r\n\t\t\t\t\t\tmetadata |= italicBit | MetadataConsts.SEMANTIC_USE_ITALIC;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (typeof tokenStyle.bold !== 'undefined') {\r\n\t\t\t\t\t\tconst boldBit = (tokenStyle.bold ? FontStyle.Bold : 0) << MetadataConsts.FONT_STYLE_OFFSET;\r\n\t\t\t\t\t\tmetadata |= boldBit | MetadataConsts.SEMANTIC_USE_BOLD;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (typeof tokenStyle.underline !== 'undefined') {\r\n\t\t\t\t\t\tconst underlineBit = (tokenStyle.underline ? FontStyle.Underline : 0) << MetadataConsts.FONT_STYLE_OFFSET;\r\n\t\t\t\t\t\tmetadata |= underlineBit | MetadataConsts.SEMANTIC_USE_UNDERLINE;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (tokenStyle.foreground) {\r\n\t\t\t\t\t\tconst foregroundBits = (tokenStyle.foreground) << MetadataConsts.FOREGROUND_OFFSET;\r\n\t\t\t\t\t\tmetadata |= foregroundBits | MetadataConsts.SEMANTIC_USE_FOREGROUND;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (metadata === 0) {\r\n\t\t\t\t\t\t// Nothing!\r\n\t\t\t\t\t\tmetadata = SemanticTokensProviderStylingConstants.NO_STYLING;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tif (this._logService.getLevel() === LogLevel.Trace) {\r\n\t\t\t\t\tthis._logService.trace(`SemanticTokensProviderStyling: unknown token type index: ${tokenTypeIndex} for legend: ${JSON.stringify(this._legend.tokenTypes)}`);\r\n\t\t\t\t}\r\n\t\t\t\tmetadata = SemanticTokensProviderStylingConstants.NO_STYLING;\r\n\t\t\t\ttokenType = 'not-in-legend';\r\n\t\t\t}\r\n\t\t\tthis._hashTable.add(tokenTypeIndex, tokenModifierSet, languageId.id, metadata);\r\n\r\n\t\t\tif (this._logService.getLevel() === LogLevel.Trace) {\r\n\t\t\t\tthis._logService.trace(`SemanticTokensProviderStyling ${tokenTypeIndex} (${tokenType}) / ${tokenModifierSet} (${tokenModifiers.join(' ')}): foreground ${TokenMetadata.getForeground(metadata)}, fontStyle ${TokenMetadata.getFontStyle(metadata).toString(2)}`);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn metadata;\r\n\t}\r\n}\r\n\r\nconst enum SemanticColoringConstants {\r\n\t/**\r\n\t * Let's aim at having 8KB buffers if possible...\r\n\t * So that would be 8192 / (5 * 4) = 409.6 tokens per area\r\n\t */\r\n\tDesiredTokensPerArea = 400,\r\n\r\n\t/**\r\n\t * Try to keep the total number of areas under 1024 if possible,\r\n\t * simply compensate by having more tokens per area...\r\n\t */\r\n\tDesiredMaxAreas = 1024,\r\n}\r\n\r\nexport function toMultilineTokens2(tokens: SemanticTokens, styling: SemanticTokensProviderStyling, languageId: LanguageIdentifier): MultilineTokens2[] {\r\n\tconst srcData = tokens.data;\r\n\tconst tokenCount = (tokens.data.length / 5) | 0;\r\n\tconst tokensPerArea = Math.max(Math.ceil(tokenCount / SemanticColoringConstants.DesiredMaxAreas), SemanticColoringConstants.DesiredTokensPerArea);\r\n\tconst result: MultilineTokens2[] = [];\r\n\r\n\tlet tokenIndex = 0;\r\n\tlet lastLineNumber = 1;\r\n\tlet lastStartCharacter = 0;\r\n\twhile (tokenIndex < tokenCount) {\r\n\t\tconst tokenStartIndex = tokenIndex;\r\n\t\tlet tokenEndIndex = Math.min(tokenStartIndex + tokensPerArea, tokenCount);\r\n\r\n\t\t// Keep tokens on the same line in the same area...\r\n\t\tif (tokenEndIndex < tokenCount) {\r\n\r\n\t\t\tlet smallTokenEndIndex = tokenEndIndex;\r\n\t\t\twhile (smallTokenEndIndex - 1 > tokenStartIndex && srcData[5 * smallTokenEndIndex] === 0) {\r\n\t\t\t\tsmallTokenEndIndex--;\r\n\t\t\t}\r\n\r\n\t\t\tif (smallTokenEndIndex - 1 === tokenStartIndex) {\r\n\t\t\t\t// there are so many tokens on this line that our area would be empty, we must now go right\r\n\t\t\t\tlet bigTokenEndIndex = tokenEndIndex;\r\n\t\t\t\twhile (bigTokenEndIndex + 1 < tokenCount && srcData[5 * bigTokenEndIndex] === 0) {\r\n\t\t\t\t\tbigTokenEndIndex++;\r\n\t\t\t\t}\r\n\t\t\t\ttokenEndIndex = bigTokenEndIndex;\r\n\t\t\t} else {\r\n\t\t\t\ttokenEndIndex = smallTokenEndIndex;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet destData = new Uint32Array((tokenEndIndex - tokenStartIndex) * 4);\r\n\t\tlet destOffset = 0;\r\n\t\tlet areaLine = 0;\r\n\t\twhile (tokenIndex < tokenEndIndex) {\r\n\t\t\tconst srcOffset = 5 * tokenIndex;\r\n\t\t\tconst deltaLine = srcData[srcOffset];\r\n\t\t\tconst deltaCharacter = srcData[srcOffset + 1];\r\n\t\t\tconst lineNumber = lastLineNumber + deltaLine;\r\n\t\t\tconst startCharacter = (deltaLine === 0 ? lastStartCharacter + deltaCharacter : deltaCharacter);\r\n\t\t\tconst length = srcData[srcOffset + 2];\r\n\t\t\tconst tokenTypeIndex = srcData[srcOffset + 3];\r\n\t\t\tconst tokenModifierSet = srcData[srcOffset + 4];\r\n\t\t\tconst metadata = styling.getMetadata(tokenTypeIndex, tokenModifierSet, languageId);\r\n\r\n\t\t\tif (metadata !== SemanticTokensProviderStylingConstants.NO_STYLING) {\r\n\t\t\t\tif (areaLine === 0) {\r\n\t\t\t\t\tareaLine = lineNumber;\r\n\t\t\t\t}\r\n\t\t\t\tdestData[destOffset] = lineNumber - areaLine;\r\n\t\t\t\tdestData[destOffset + 1] = startCharacter;\r\n\t\t\t\tdestData[destOffset + 2] = startCharacter + length;\r\n\t\t\t\tdestData[destOffset + 3] = metadata;\r\n\t\t\t\tdestOffset += 4;\r\n\t\t\t}\r\n\r\n\t\t\tlastLineNumber = lineNumber;\r\n\t\t\tlastStartCharacter = startCharacter;\r\n\t\t\ttokenIndex++;\r\n\t\t}\r\n\r\n\t\tif (destOffset !== destData.length) {\r\n\t\t\tdestData = destData.subarray(0, destOffset);\r\n\t\t}\r\n\r\n\t\tconst tokens = new MultilineTokens2(areaLine, new SparseEncodedTokens(destData));\r\n\t\tresult.push(tokens);\r\n\t}\r\n\r\n\treturn result;\r\n}\r\n\r\nclass HashTableEntry {\r\n\tpublic readonly tokenTypeIndex: number;\r\n\tpublic readonly tokenModifierSet: number;\r\n\tpublic readonly languageId: number;\r\n\tpublic readonly metadata: number;\r\n\tpublic next: HashTableEntry | null;\r\n\r\n\tconstructor(tokenTypeIndex: number, tokenModifierSet: number, languageId: number, metadata: number) {\r\n\t\tthis.tokenTypeIndex = tokenTypeIndex;\r\n\t\tthis.tokenModifierSet = tokenModifierSet;\r\n\t\tthis.languageId = languageId;\r\n\t\tthis.metadata = metadata;\r\n\t\tthis.next = null;\r\n\t}\r\n}\r\n\r\nclass HashTable {\r\n\r\n\tprivate static _SIZES = [3, 7, 13, 31, 61, 127, 251, 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139, 524287, 1048573, 2097143];\r\n\r\n\tprivate _elementsCount: number;\r\n\tprivate _currentLengthIndex: number;\r\n\tprivate _currentLength: number;\r\n\tprivate _growCount: number;\r\n\tprivate _elements: (HashTableEntry | null)[];\r\n\r\n\tconstructor() {\r\n\t\tthis._elementsCount = 0;\r\n\t\tthis._currentLengthIndex = 0;\r\n\t\tthis._currentLength = HashTable._SIZES[this._currentLengthIndex];\r\n\t\tthis._growCount = Math.round(this._currentLengthIndex + 1 < HashTable._SIZES.length ? 2 / 3 * this._currentLength : 0);\r\n\t\tthis._elements = [];\r\n\t\tHashTable._nullOutEntries(this._elements, this._currentLength);\r\n\t}\r\n\r\n\tprivate static _nullOutEntries(entries: (HashTableEntry | null)[], length: number): void {\r\n\t\tfor (let i = 0; i < length; i++) {\r\n\t\t\tentries[i] = null;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _hash2(n1: number, n2: number): number {\r\n\t\treturn (((n1 << 5) - n1) + n2) | 0; // n1 * 31 + n2, keep as int32\r\n\t}\r\n\r\n\tprivate _hashFunc(tokenTypeIndex: number, tokenModifierSet: number, languageId: number): number {\r\n\t\treturn this._hash2(this._hash2(tokenTypeIndex, tokenModifierSet), languageId) % this._currentLength;\r\n\t}\r\n\r\n\tpublic get(tokenTypeIndex: number, tokenModifierSet: number, languageId: number): HashTableEntry | null {\r\n\t\tconst hash = this._hashFunc(tokenTypeIndex, tokenModifierSet, languageId);\r\n\r\n\t\tlet p = this._elements[hash];\r\n\t\twhile (p) {\r\n\t\t\tif (p.tokenTypeIndex === tokenTypeIndex && p.tokenModifierSet === tokenModifierSet && p.languageId === languageId) {\r\n\t\t\t\treturn p;\r\n\t\t\t}\r\n\t\t\tp = p.next;\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic add(tokenTypeIndex: number, tokenModifierSet: number, languageId: number, metadata: number): void {\r\n\t\tthis._elementsCount++;\r\n\t\tif (this._growCount !== 0 && this._elementsCount >= this._growCount) {\r\n\t\t\t// expand!\r\n\t\t\tconst oldElements = this._elements;\r\n\r\n\t\t\tthis._currentLengthIndex++;\r\n\t\t\tthis._currentLength = HashTable._SIZES[this._currentLengthIndex];\r\n\t\t\tthis._growCount = Math.round(this._currentLengthIndex + 1 < HashTable._SIZES.length ? 2 / 3 * this._currentLength : 0);\r\n\t\t\tthis._elements = [];\r\n\t\t\tHashTable._nullOutEntries(this._elements, this._currentLength);\r\n\r\n\t\t\tfor (const first of oldElements) {\r\n\t\t\t\tlet p = first;\r\n\t\t\t\twhile (p) {\r\n\t\t\t\t\tconst oldNext = p.next;\r\n\t\t\t\t\tp.next = null;\r\n\t\t\t\t\tthis._add(p);\r\n\t\t\t\t\tp = oldNext;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis._add(new HashTableEntry(tokenTypeIndex, tokenModifierSet, languageId, metadata));\r\n\t}\r\n\r\n\tprivate _add(element: HashTableEntry): void {\r\n\t\tconst hash = this._hashFunc(element.tokenTypeIndex, element.tokenModifierSet, element.languageId);\r\n\t\telement.next = this._elements[hash];\r\n\t\tthis._elements[hash] = element;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { EditorWorkerClient } from 'vs/editor/common/services/editorWorkerServiceImpl';\r\nimport { IModelService } from 'vs/editor/common/services/modelService';\r\nimport * as types from 'vs/base/common/types';\r\n\r\n/**\r\n * Create a new web worker that has model syncing capabilities built in.\r\n * Specify an AMD module to load that will `create` an object that will be proxied.\r\n */\r\nexport function createWebWorker(modelService: IModelService, opts: IWebWorkerOptions): MonacoWebWorker {\r\n\treturn new MonacoWebWorkerImpl(modelService, opts);\r\n}\r\n\r\n/**\r\n * A web worker that can provide a proxy to an arbitrary file.\r\n */\r\nexport interface MonacoWebWorker {\r\n\t/**\r\n\t * Terminate the web worker, thus invalidating the returned proxy.\r\n\t */\r\n\tdispose(): void;\r\n\t/**\r\n\t * Get a proxy to the arbitrary loaded code.\r\n\t */\r\n\tgetProxy(): Promise;\r\n\t/**\r\n\t * Synchronize (send) the models at `resources` to the web worker,\r\n\t * making them available in the monaco.worker.getMirrorModels().\r\n\t */\r\n\twithSyncedResources(resources: URI[]): Promise;\r\n}\r\n\r\nexport interface IWebWorkerOptions {\r\n\t/**\r\n\t * The AMD moduleId to load.\r\n\t * It should export a function `create` that should return the exported proxy.\r\n\t */\r\n\tmoduleId: string;\r\n\t/**\r\n\t * The data to send over when calling create on the module.\r\n\t */\r\n\tcreateData?: any;\r\n\t/**\r\n\t * A label to be used to identify the web worker for debugging purposes.\r\n\t */\r\n\tlabel?: string;\r\n\t/**\r\n\t * An object that can be used by the web worker to make calls back to the main thread.\r\n\t */\r\n\thost?: any;\r\n\t/**\r\n\t * Keep idle models.\r\n\t * Defaults to false, which means that idle models will stop syncing after a while.\r\n\t */\r\n\tkeepIdleModels?: boolean;\r\n}\r\n\r\nclass MonacoWebWorkerImpl extends EditorWorkerClient implements MonacoWebWorker {\r\n\r\n\tprivate readonly _foreignModuleId: string;\r\n\tprivate readonly _foreignModuleHost: { [method: string]: Function } | null;\r\n\tprivate _foreignModuleCreateData: any | null;\r\n\tprivate _foreignProxy: Promise | null;\r\n\r\n\tconstructor(modelService: IModelService, opts: IWebWorkerOptions) {\r\n\t\tsuper(modelService, opts.keepIdleModels || false, opts.label);\r\n\t\tthis._foreignModuleId = opts.moduleId;\r\n\t\tthis._foreignModuleCreateData = opts.createData || null;\r\n\t\tthis._foreignModuleHost = opts.host || null;\r\n\t\tthis._foreignProxy = null;\r\n\t}\r\n\r\n\t// foreign host request\r\n\tpublic fhr(method: string, args: any[]): Promise {\r\n\t\tif (!this._foreignModuleHost || typeof this._foreignModuleHost[method] !== 'function') {\r\n\t\t\treturn Promise.reject(new Error('Missing method ' + method + ' or missing main thread foreign host.'));\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\treturn Promise.resolve(this._foreignModuleHost[method].apply(this._foreignModuleHost, args));\r\n\t\t} catch (e) {\r\n\t\t\treturn Promise.reject(e);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _getForeignProxy(): Promise {\r\n\t\tif (!this._foreignProxy) {\r\n\t\t\tthis._foreignProxy = this._getProxy().then((proxy) => {\r\n\t\t\t\tconst foreignHostMethods = this._foreignModuleHost ? types.getAllMethodNames(this._foreignModuleHost) : [];\r\n\t\t\t\treturn proxy.loadForeignModule(this._foreignModuleId, this._foreignModuleCreateData, foreignHostMethods).then((foreignMethods) => {\r\n\t\t\t\t\tthis._foreignModuleCreateData = null;\r\n\r\n\t\t\t\t\tconst proxyMethodRequest = (method: string, args: any[]): Promise => {\r\n\t\t\t\t\t\treturn proxy.fmr(method, args);\r\n\t\t\t\t\t};\r\n\r\n\t\t\t\t\tconst createProxyMethod = (method: string, proxyMethodRequest: (method: string, args: any[]) => Promise): () => Promise => {\r\n\t\t\t\t\t\treturn function () {\r\n\t\t\t\t\t\t\tconst args = Array.prototype.slice.call(arguments, 0);\r\n\t\t\t\t\t\t\treturn proxyMethodRequest(method, args);\r\n\t\t\t\t\t\t};\r\n\t\t\t\t\t};\r\n\r\n\t\t\t\t\tlet foreignProxy = {} as T;\r\n\t\t\t\t\tfor (const foreignMethod of foreignMethods) {\r\n\t\t\t\t\t\t(foreignProxy)[foreignMethod] = createProxyMethod(foreignMethod, proxyMethodRequest);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\treturn foreignProxy;\r\n\t\t\t\t});\r\n\t\t\t});\r\n\t\t}\r\n\t\treturn this._foreignProxy;\r\n\t}\r\n\r\n\tpublic getProxy(): Promise {\r\n\t\treturn this._getForeignProxy();\r\n\t}\r\n\r\n\tpublic withSyncedResources(resources: URI[]): Promise {\r\n\t\treturn this._withSyncedResources(resources).then(_ => this.getProxy());\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { Event } from 'vs/base/common/event';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { localize } from 'vs/nls';\r\nimport Severity from 'vs/base/common/severity';\r\n\r\nexport interface IMarkerService {\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\tchangeOne(owner: string, resource: URI, markers: IMarkerData[]): void;\r\n\r\n\tremove(owner: string, resources: URI[]): void;\r\n\r\n\tread(filter?: { owner?: string; resource?: URI; severities?: number, take?: number; }): IMarker[];\r\n\r\n\treadonly onMarkerChanged: Event;\r\n}\r\n\r\n/**\r\n *\r\n */\r\nexport interface IRelatedInformation {\r\n\tresource: URI;\r\n\tmessage: string;\r\n\tstartLineNumber: number;\r\n\tstartColumn: number;\r\n\tendLineNumber: number;\r\n\tendColumn: number;\r\n}\r\n\r\nexport const enum MarkerTag {\r\n\tUnnecessary = 1,\r\n\tDeprecated = 2\r\n}\r\n\r\nexport enum MarkerSeverity {\r\n\tHint = 1,\r\n\tInfo = 2,\r\n\tWarning = 4,\r\n\tError = 8,\r\n}\r\n\r\nexport namespace MarkerSeverity {\r\n\r\n\texport function compare(a: MarkerSeverity, b: MarkerSeverity): number {\r\n\t\treturn b - a;\r\n\t}\r\n\r\n\tconst _displayStrings: { [value: number]: string; } = Object.create(null);\r\n\t_displayStrings[MarkerSeverity.Error] = localize('sev.error', \"Error\");\r\n\t_displayStrings[MarkerSeverity.Warning] = localize('sev.warning', \"Warning\");\r\n\t_displayStrings[MarkerSeverity.Info] = localize('sev.info', \"Info\");\r\n\r\n\texport function toString(a: MarkerSeverity): string {\r\n\t\treturn _displayStrings[a] || '';\r\n\t}\r\n\r\n\texport function fromSeverity(severity: Severity): MarkerSeverity {\r\n\t\tswitch (severity) {\r\n\t\t\tcase Severity.Error: return MarkerSeverity.Error;\r\n\t\t\tcase Severity.Warning: return MarkerSeverity.Warning;\r\n\t\t\tcase Severity.Info: return MarkerSeverity.Info;\r\n\t\t\tcase Severity.Ignore: return MarkerSeverity.Hint;\r\n\t\t}\r\n\t}\r\n\r\n\texport function toSeverity(severity: MarkerSeverity): Severity {\r\n\t\tswitch (severity) {\r\n\t\t\tcase MarkerSeverity.Error: return Severity.Error;\r\n\t\t\tcase MarkerSeverity.Warning: return Severity.Warning;\r\n\t\t\tcase MarkerSeverity.Info: return Severity.Info;\r\n\t\t\tcase MarkerSeverity.Hint: return Severity.Ignore;\r\n\t\t}\r\n\t}\r\n}\r\n\r\n/**\r\n * A structure defining a problem/warning/etc.\r\n */\r\nexport interface IMarkerData {\r\n\tcode?: string | { value: string; target: URI };\r\n\tseverity: MarkerSeverity;\r\n\tmessage: string;\r\n\tsource?: string;\r\n\tstartLineNumber: number;\r\n\tstartColumn: number;\r\n\tendLineNumber: number;\r\n\tendColumn: number;\r\n\trelatedInformation?: IRelatedInformation[];\r\n\ttags?: MarkerTag[];\r\n}\r\n\r\nexport interface IMarker {\r\n\towner: string;\r\n\tresource: URI;\r\n\tseverity: MarkerSeverity;\r\n\tcode?: string | { value: string; target: URI };\r\n\tmessage: string;\r\n\tsource?: string;\r\n\tstartLineNumber: number;\r\n\tstartColumn: number;\r\n\tendLineNumber: number;\r\n\tendColumn: number;\r\n\trelatedInformation?: IRelatedInformation[];\r\n\ttags?: MarkerTag[];\r\n}\r\n\r\nexport interface MarkerStatistics {\r\n\terrors: number;\r\n\twarnings: number;\r\n\tinfos: number;\r\n\tunknowns: number;\r\n}\r\n\r\nexport namespace IMarkerData {\r\n\tconst emptyString = '';\r\n\texport function makeKey(markerData: IMarkerData): string {\r\n\t\treturn makeKeyOptionalMessage(markerData, true);\r\n\t}\r\n\r\n\texport function makeKeyOptionalMessage(markerData: IMarkerData, useMessage: boolean): string {\r\n\t\tlet result: string[] = [emptyString];\r\n\t\tif (markerData.source) {\r\n\t\t\tresult.push(markerData.source.replace('¦', '\\\\¦'));\r\n\t\t} else {\r\n\t\t\tresult.push(emptyString);\r\n\t\t}\r\n\t\tif (markerData.code) {\r\n\t\t\tif (typeof markerData.code === 'string') {\r\n\t\t\t\tresult.push(markerData.code.replace('¦', '\\\\¦'));\r\n\t\t\t} else {\r\n\t\t\t\tresult.push(markerData.code.value.replace('¦', '\\\\¦'));\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tresult.push(emptyString);\r\n\t\t}\r\n\t\tif (markerData.severity !== undefined && markerData.severity !== null) {\r\n\t\t\tresult.push(MarkerSeverity.toString(markerData.severity));\r\n\t\t} else {\r\n\t\t\tresult.push(emptyString);\r\n\t\t}\r\n\r\n\t\t// Modifed to not include the message as part of the marker key to work around\r\n\t\t// https://github.com/microsoft/vscode/issues/77475\r\n\t\tif (markerData.message && useMessage) {\r\n\t\t\tresult.push(markerData.message.replace('¦', '\\\\¦'));\r\n\t\t} else {\r\n\t\t\tresult.push(emptyString);\r\n\t\t}\r\n\t\tif (markerData.startLineNumber !== undefined && markerData.startLineNumber !== null) {\r\n\t\t\tresult.push(markerData.startLineNumber.toString());\r\n\t\t} else {\r\n\t\t\tresult.push(emptyString);\r\n\t\t}\r\n\t\tif (markerData.startColumn !== undefined && markerData.startColumn !== null) {\r\n\t\t\tresult.push(markerData.startColumn.toString());\r\n\t\t} else {\r\n\t\t\tresult.push(emptyString);\r\n\t\t}\r\n\t\tif (markerData.endLineNumber !== undefined && markerData.endLineNumber !== null) {\r\n\t\t\tresult.push(markerData.endLineNumber.toString());\r\n\t\t} else {\r\n\t\t\tresult.push(emptyString);\r\n\t\t}\r\n\t\tif (markerData.endColumn !== undefined && markerData.endColumn !== null) {\r\n\t\t\tresult.push(markerData.endColumn.toString());\r\n\t\t} else {\r\n\t\t\tresult.push(emptyString);\r\n\t\t}\r\n\t\tresult.push(emptyString);\r\n\t\treturn result.join('¦');\r\n\t}\r\n}\r\n\r\nexport const IMarkerService = createDecorator('markerService');\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IMarkerService, MarkerSeverity, IMarker } from 'vs/platform/markers/common/markers';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { compare } from 'vs/base/common/strings';\r\nimport { binarySearch } from 'vs/base/common/arrays';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { registerSingleton } from 'vs/platform/instantiation/common/extensions';\r\nimport { LinkedList } from 'vs/base/common/linkedList';\r\n\r\nexport class MarkerCoordinate {\r\n\tconstructor(\r\n\t\treadonly marker: IMarker,\r\n\t\treadonly index: number,\r\n\t\treadonly total: number\r\n\t) { }\r\n}\r\n\r\nexport class MarkerList {\r\n\r\n\tprivate readonly _onDidChange = new Emitter();\r\n\treadonly onDidChange: Event = this._onDidChange.event;\r\n\r\n\tprivate readonly _resourceFilter?: (uri: URI) => boolean;\r\n\tprivate readonly _dispoables = new DisposableStore();\r\n\r\n\tprivate _markers: IMarker[] = [];\r\n\tprivate _nextIdx: number = -1;\r\n\r\n\tconstructor(\r\n\t\tresourceFilter: URI | ((uri: URI) => boolean) | undefined,\r\n\t\t@IMarkerService private readonly _markerService: IMarkerService,\r\n\t) {\r\n\t\tif (URI.isUri(resourceFilter)) {\r\n\t\t\tthis._resourceFilter = uri => uri.toString() === resourceFilter.toString();\r\n\t\t} else if (resourceFilter) {\r\n\t\t\tthis._resourceFilter = resourceFilter;\r\n\t\t}\r\n\r\n\t\tconst updateMarker = () => {\r\n\t\t\tthis._markers = this._markerService.read({\r\n\t\t\t\tresource: URI.isUri(resourceFilter) ? resourceFilter : undefined,\r\n\t\t\t\tseverities: MarkerSeverity.Error | MarkerSeverity.Warning | MarkerSeverity.Info\r\n\t\t\t});\r\n\t\t\tif (typeof resourceFilter === 'function') {\r\n\t\t\t\tthis._markers = this._markers.filter(m => this._resourceFilter!(m.resource));\r\n\t\t\t}\r\n\t\t\tthis._markers.sort(MarkerList._compareMarker);\r\n\t\t};\r\n\r\n\t\tupdateMarker();\r\n\r\n\t\tthis._dispoables.add(_markerService.onMarkerChanged(uris => {\r\n\t\t\tif (!this._resourceFilter || uris.some(uri => this._resourceFilter!(uri))) {\r\n\t\t\t\tupdateMarker();\r\n\t\t\t\tthis._nextIdx = -1;\r\n\t\t\t\tthis._onDidChange.fire();\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._dispoables.dispose();\r\n\t\tthis._onDidChange.dispose();\r\n\t}\r\n\r\n\tmatches(uri: URI | undefined) {\r\n\t\tif (!this._resourceFilter && !uri) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (!this._resourceFilter || !uri) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn this._resourceFilter(uri);\r\n\t}\r\n\r\n\tget selected(): MarkerCoordinate | undefined {\r\n\t\tconst marker = this._markers[this._nextIdx];\r\n\t\treturn marker && new MarkerCoordinate(marker, this._nextIdx + 1, this._markers.length);\r\n\t}\r\n\r\n\tprivate _initIdx(model: ITextModel, position: Position, fwd: boolean): void {\r\n\t\tlet found = false;\r\n\r\n\t\tlet idx = this._markers.findIndex(marker => marker.resource.toString() === model.uri.toString());\r\n\t\tif (idx < 0) {\r\n\t\t\tidx = binarySearch(this._markers, { resource: model.uri }, (a, b) => compare(a.resource.toString(), b.resource.toString()));\r\n\t\t\tif (idx < 0) {\r\n\t\t\t\tidx = ~idx;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tfor (let i = idx; i < this._markers.length; i++) {\r\n\t\t\tlet range = Range.lift(this._markers[i]);\r\n\r\n\t\t\tif (range.isEmpty()) {\r\n\t\t\t\tconst word = model.getWordAtPosition(range.getStartPosition());\r\n\t\t\t\tif (word) {\r\n\t\t\t\t\trange = new Range(range.startLineNumber, word.startColumn, range.startLineNumber, word.endColumn);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (position && (range.containsPosition(position) || position.isBeforeOrEqual(range.getStartPosition()))) {\r\n\t\t\t\tthis._nextIdx = i;\r\n\t\t\t\tfound = true;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tif (this._markers[i].resource.toString() !== model.uri.toString()) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!found) {\r\n\t\t\t// after the last change\r\n\t\t\tthis._nextIdx = fwd ? 0 : this._markers.length - 1;\r\n\t\t}\r\n\t\tif (this._nextIdx < 0) {\r\n\t\t\tthis._nextIdx = this._markers.length - 1;\r\n\t\t}\r\n\t}\r\n\r\n\tresetIndex() {\r\n\t\tthis._nextIdx = -1;\r\n\t}\r\n\r\n\tmove(fwd: boolean, model: ITextModel, position: Position): boolean {\r\n\t\tif (this._markers.length === 0) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tlet oldIdx = this._nextIdx;\r\n\t\tif (this._nextIdx === -1) {\r\n\t\t\tthis._initIdx(model, position, fwd);\r\n\t\t} else if (fwd) {\r\n\t\t\tthis._nextIdx = (this._nextIdx + 1) % this._markers.length;\r\n\t\t} else if (!fwd) {\r\n\t\t\tthis._nextIdx = (this._nextIdx - 1 + this._markers.length) % this._markers.length;\r\n\t\t}\r\n\r\n\t\tif (oldIdx !== this._nextIdx) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tfind(uri: URI, position: Position): MarkerCoordinate | undefined {\r\n\t\tlet idx = this._markers.findIndex(marker => marker.resource.toString() === uri.toString());\r\n\t\tif (idx < 0) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\t\tfor (; idx < this._markers.length; idx++) {\r\n\t\t\tif (Range.containsPosition(this._markers[idx], position)) {\r\n\t\t\t\treturn new MarkerCoordinate(this._markers[idx], idx + 1, this._markers.length);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tprivate static _compareMarker(a: IMarker, b: IMarker): number {\r\n\t\tlet res = compare(a.resource.toString(), b.resource.toString());\r\n\t\tif (res === 0) {\r\n\t\t\tres = MarkerSeverity.compare(a.severity, b.severity);\r\n\t\t}\r\n\t\tif (res === 0) {\r\n\t\t\tres = Range.compareRangesUsingStarts(a, b);\r\n\t\t}\r\n\t\treturn res;\r\n\t}\r\n}\r\n\r\nexport const IMarkerNavigationService = createDecorator('IMarkerNavigationService');\r\n\r\nexport interface IMarkerNavigationService {\r\n\treadonly _serviceBrand: undefined;\r\n\tgetMarkerList(resource: URI | undefined): MarkerList;\r\n}\r\n\r\nexport interface IMarkerListProvider {\r\n\tgetMarkerList(resource: URI | undefined): MarkerList | undefined;\r\n}\r\n\r\nclass MarkerNavigationService implements IMarkerNavigationService, IMarkerListProvider {\r\n\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\tprivate readonly _provider = new LinkedList();\r\n\r\n\tconstructor(@IMarkerService private readonly _markerService: IMarkerService) { }\r\n\r\n\tgetMarkerList(resource: URI | undefined): MarkerList {\r\n\t\tfor (let provider of this._provider) {\r\n\t\t\tconst result = provider.getMarkerList(resource);\r\n\t\t\tif (result) {\r\n\t\t\t\treturn result;\r\n\t\t\t}\r\n\t\t}\r\n\t\t// default\r\n\t\treturn new MarkerList(resource, this._markerService);\r\n\t}\r\n}\r\n\r\nregisterSingleton(IMarkerNavigationService, MarkerNavigationService, true);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { isFalsyOrEmpty } from 'vs/base/common/arrays';\r\nimport { Schemas } from 'vs/base/common/network';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { Event, Emitter } from 'vs/base/common/event';\r\nimport { IMarkerService, IMarkerData, IMarker, MarkerStatistics, MarkerSeverity } from './markers';\r\nimport { ResourceMap } from 'vs/base/common/map';\r\nimport { Iterable } from 'vs/base/common/iterator';\r\n\r\nclass DoubleResourceMap{\r\n\r\n\tprivate _byResource = new ResourceMap>();\r\n\tprivate _byOwner = new Map>();\r\n\r\n\tset(resource: URI, owner: string, value: V) {\r\n\t\tlet ownerMap = this._byResource.get(resource);\r\n\t\tif (!ownerMap) {\r\n\t\t\townerMap = new Map();\r\n\t\t\tthis._byResource.set(resource, ownerMap);\r\n\t\t}\r\n\t\townerMap.set(owner, value);\r\n\r\n\t\tlet resourceMap = this._byOwner.get(owner);\r\n\t\tif (!resourceMap) {\r\n\t\t\tresourceMap = new ResourceMap();\r\n\t\t\tthis._byOwner.set(owner, resourceMap);\r\n\t\t}\r\n\t\tresourceMap.set(resource, value);\r\n\t}\r\n\r\n\tget(resource: URI, owner: string): V | undefined {\r\n\t\tlet ownerMap = this._byResource.get(resource);\r\n\t\treturn ownerMap?.get(owner);\r\n\t}\r\n\r\n\tdelete(resource: URI, owner: string): boolean {\r\n\t\tlet removedA = false;\r\n\t\tlet removedB = false;\r\n\t\tlet ownerMap = this._byResource.get(resource);\r\n\t\tif (ownerMap) {\r\n\t\t\tremovedA = ownerMap.delete(owner);\r\n\t\t}\r\n\t\tlet resourceMap = this._byOwner.get(owner);\r\n\t\tif (resourceMap) {\r\n\t\t\tremovedB = resourceMap.delete(resource);\r\n\t\t}\r\n\t\tif (removedA !== removedB) {\r\n\t\t\tthrow new Error('illegal state');\r\n\t\t}\r\n\t\treturn removedA && removedB;\r\n\t}\r\n\r\n\tvalues(key?: URI | string): Iterable {\r\n\t\tif (typeof key === 'string') {\r\n\t\t\treturn this._byOwner.get(key)?.values() ?? Iterable.empty();\r\n\t\t}\r\n\t\tif (URI.isUri(key)) {\r\n\t\t\treturn this._byResource.get(key)?.values() ?? Iterable.empty();\r\n\t\t}\r\n\r\n\t\treturn Iterable.map(Iterable.concat(...this._byOwner.values()), map => map[1]);\r\n\t}\r\n}\r\n\r\nclass MarkerStats implements MarkerStatistics {\r\n\r\n\terrors: number = 0;\r\n\tinfos: number = 0;\r\n\twarnings: number = 0;\r\n\tunknowns: number = 0;\r\n\r\n\tprivate readonly _data = new ResourceMap();\r\n\tprivate readonly _service: IMarkerService;\r\n\tprivate readonly _subscription: IDisposable;\r\n\r\n\tconstructor(service: IMarkerService) {\r\n\t\tthis._service = service;\r\n\t\tthis._subscription = service.onMarkerChanged(this._update, this);\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._subscription.dispose();\r\n\t}\r\n\r\n\tprivate _update(resources: readonly URI[]): void {\r\n\t\tfor (const resource of resources) {\r\n\t\t\tconst oldStats = this._data.get(resource);\r\n\t\t\tif (oldStats) {\r\n\t\t\t\tthis._substract(oldStats);\r\n\t\t\t}\r\n\t\t\tconst newStats = this._resourceStats(resource);\r\n\t\t\tthis._add(newStats);\r\n\t\t\tthis._data.set(resource, newStats);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _resourceStats(resource: URI): MarkerStatistics {\r\n\t\tconst result: MarkerStatistics = { errors: 0, warnings: 0, infos: 0, unknowns: 0 };\r\n\r\n\t\t// TODO this is a hack\r\n\t\tif (resource.scheme === Schemas.inMemory || resource.scheme === Schemas.walkThrough || resource.scheme === Schemas.walkThroughSnippet) {\r\n\t\t\treturn result;\r\n\t\t}\r\n\r\n\t\tfor (const { severity } of this._service.read({ resource })) {\r\n\t\t\tif (severity === MarkerSeverity.Error) {\r\n\t\t\t\tresult.errors += 1;\r\n\t\t\t} else if (severity === MarkerSeverity.Warning) {\r\n\t\t\t\tresult.warnings += 1;\r\n\t\t\t} else if (severity === MarkerSeverity.Info) {\r\n\t\t\t\tresult.infos += 1;\r\n\t\t\t} else {\r\n\t\t\t\tresult.unknowns += 1;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate _substract(op: MarkerStatistics) {\r\n\t\tthis.errors -= op.errors;\r\n\t\tthis.warnings -= op.warnings;\r\n\t\tthis.infos -= op.infos;\r\n\t\tthis.unknowns -= op.unknowns;\r\n\t}\r\n\r\n\tprivate _add(op: MarkerStatistics) {\r\n\t\tthis.errors += op.errors;\r\n\t\tthis.warnings += op.warnings;\r\n\t\tthis.infos += op.infos;\r\n\t\tthis.unknowns += op.unknowns;\r\n\t}\r\n}\r\n\r\nexport class MarkerService implements IMarkerService {\r\n\r\n\tdeclare readonly _serviceBrand: undefined;\r\n\r\n\tprivate readonly _onMarkerChanged = new Emitter();\r\n\treadonly onMarkerChanged: Event = Event.debounce(this._onMarkerChanged.event, MarkerService._debouncer, 0);\r\n\r\n\tprivate readonly _data = new DoubleResourceMap();\r\n\tprivate readonly _stats = new MarkerStats(this);\r\n\r\n\tdispose(): void {\r\n\t\tthis._stats.dispose();\r\n\t\tthis._onMarkerChanged.dispose();\r\n\t}\r\n\r\n\tremove(owner: string, resources: URI[]): void {\r\n\t\tfor (const resource of resources || []) {\r\n\t\t\tthis.changeOne(owner, resource, []);\r\n\t\t}\r\n\t}\r\n\r\n\tchangeOne(owner: string, resource: URI, markerData: IMarkerData[]): void {\r\n\r\n\t\tif (isFalsyOrEmpty(markerData)) {\r\n\t\t\t// remove marker for this (owner,resource)-tuple\r\n\t\t\tconst removed = this._data.delete(resource, owner);\r\n\t\t\tif (removed) {\r\n\t\t\t\tthis._onMarkerChanged.fire([resource]);\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\t\t\t// insert marker for this (owner,resource)-tuple\r\n\t\t\tconst markers: IMarker[] = [];\r\n\t\t\tfor (const data of markerData) {\r\n\t\t\t\tconst marker = MarkerService._toMarker(owner, resource, data);\r\n\t\t\t\tif (marker) {\r\n\t\t\t\t\tmarkers.push(marker);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tthis._data.set(resource, owner, markers);\r\n\t\t\tthis._onMarkerChanged.fire([resource]);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static _toMarker(owner: string, resource: URI, data: IMarkerData): IMarker | undefined {\r\n\t\tlet {\r\n\t\t\tcode, severity,\r\n\t\t\tmessage, source,\r\n\t\t\tstartLineNumber, startColumn, endLineNumber, endColumn,\r\n\t\t\trelatedInformation,\r\n\t\t\ttags,\r\n\t\t} = data;\r\n\r\n\t\tif (!message) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\r\n\t\t// santize data\r\n\t\tstartLineNumber = startLineNumber > 0 ? startLineNumber : 1;\r\n\t\tstartColumn = startColumn > 0 ? startColumn : 1;\r\n\t\tendLineNumber = endLineNumber >= startLineNumber ? endLineNumber : startLineNumber;\r\n\t\tendColumn = endColumn > 0 ? endColumn : startColumn;\r\n\r\n\t\treturn {\r\n\t\t\tresource,\r\n\t\t\towner,\r\n\t\t\tcode,\r\n\t\t\tseverity,\r\n\t\t\tmessage,\r\n\t\t\tsource,\r\n\t\t\tstartLineNumber,\r\n\t\t\tstartColumn,\r\n\t\t\tendLineNumber,\r\n\t\t\tendColumn,\r\n\t\t\trelatedInformation,\r\n\t\t\ttags,\r\n\t\t};\r\n\t}\r\n\r\n\tread(filter: { owner?: string; resource?: URI; severities?: number, take?: number; } = Object.create(null)): IMarker[] {\r\n\r\n\t\tlet { owner, resource, severities, take } = filter;\r\n\r\n\t\tif (!take || take < 0) {\r\n\t\t\ttake = -1;\r\n\t\t}\r\n\r\n\t\tif (owner && resource) {\r\n\t\t\t// exactly one owner AND resource\r\n\t\t\tconst data = this._data.get(resource, owner);\r\n\t\t\tif (!data) {\r\n\t\t\t\treturn [];\r\n\t\t\t} else {\r\n\t\t\t\tconst result: IMarker[] = [];\r\n\t\t\t\tfor (const marker of data) {\r\n\t\t\t\t\tif (MarkerService._accept(marker, severities)) {\r\n\t\t\t\t\t\tconst newLen = result.push(marker);\r\n\t\t\t\t\t\tif (take > 0 && newLen === take) {\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\treturn result;\r\n\t\t\t}\r\n\r\n\t\t} else if (!owner && !resource) {\r\n\t\t\t// all\r\n\t\t\tconst result: IMarker[] = [];\r\n\t\t\tfor (let markers of this._data.values()) {\r\n\t\t\t\tfor (let data of markers) {\r\n\t\t\t\t\tif (MarkerService._accept(data, severities)) {\r\n\t\t\t\t\t\tconst newLen = result.push(data);\r\n\t\t\t\t\t\tif (take > 0 && newLen === take) {\r\n\t\t\t\t\t\t\treturn result;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn result;\r\n\r\n\t\t} else {\r\n\t\t\t// of one resource OR owner\r\n\t\t\tconst iterable = this._data.values(resource ?? owner!);\r\n\t\t\tconst result: IMarker[] = [];\r\n\t\t\tfor (const markers of iterable) {\r\n\t\t\t\tfor (const data of markers) {\r\n\t\t\t\t\tif (MarkerService._accept(data, severities)) {\r\n\t\t\t\t\t\tconst newLen = result.push(data);\r\n\t\t\t\t\t\tif (take > 0 && newLen === take) {\r\n\t\t\t\t\t\t\treturn result;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn result;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static _accept(marker: IMarker, severities?: number): boolean {\r\n\t\treturn severities === undefined || (severities & marker.severity) === marker.severity;\r\n\t}\r\n\r\n\t// --- event debounce logic\r\n\r\n\tprivate static _dedupeMap: ResourceMap;\r\n\r\n\tprivate static _debouncer(last: URI[] | undefined, event: readonly URI[]): URI[] {\r\n\t\tif (!last) {\r\n\t\t\tMarkerService._dedupeMap = new ResourceMap();\r\n\t\t\tlast = [];\r\n\t\t}\r\n\t\tfor (const uri of event) {\r\n\t\t\tif (!MarkerService._dedupeMap.has(uri)) {\r\n\t\t\t\tMarkerService._dedupeMap.set(uri, true);\r\n\t\t\t\tlast.push(uri);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn last;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport BaseSeverity from 'vs/base/common/severity';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\n\r\nexport import Severity = BaseSeverity;\r\n\r\nexport const INotificationService = createDecorator('notificationService');\r\n\r\nexport type NotificationMessage = string | Error;\r\n\r\nexport interface INotificationProperties {\r\n}\r\n\r\nexport interface INotification extends INotificationProperties {\r\n\r\n\t/**\r\n\t * The severity of the notification. Either `Info`, `Warning` or `Error`.\r\n\t */\r\n\treadonly severity: Severity;\r\n\r\n\t/**\r\n\t * The message of the notification. This can either be a `string` or `Error`. Messages\r\n\t * can optionally include links in the format: `[text](link)`\r\n\t */\r\n\treadonly message: NotificationMessage;\r\n}\r\n\r\nexport interface INotificationHandle {\r\n}\r\n\r\nexport interface IStatusMessageOptions {\r\n\r\n\t/**\r\n\t * An optional timeout after which the status message is to be hidden. By default\r\n\t * the status message will not hide until another status message is displayed.\r\n\t */\r\n\treadonly hideAfter?: number;\r\n}\r\n\r\n/**\r\n * A service to bring up notifications and non-modal prompts.\r\n *\r\n * Note: use the `IDialogService` for a modal way to ask the user for input.\r\n */\r\nexport interface INotificationService {\r\n\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\t/**\r\n\t * A convenient way of reporting infos. Use the `INotificationService.notify`\r\n\t * method if you need more control over the notification.\r\n\t */\r\n\tinfo(message: NotificationMessage | NotificationMessage[]): void;\r\n\r\n\t/**\r\n\t * A convenient way of reporting warnings. Use the `INotificationService.notify`\r\n\t * method if you need more control over the notification.\r\n\t */\r\n\twarn(message: NotificationMessage | NotificationMessage[]): void;\r\n\r\n\t/**\r\n\t * A convenient way of reporting errors. Use the `INotificationService.notify`\r\n\t * method if you need more control over the notification.\r\n\t */\r\n\terror(message: NotificationMessage | NotificationMessage[]): void;\r\n\r\n\t/**\r\n\t * Shows a status message in the status area with the provided text.\r\n\t *\r\n\t * @param message the message to show as status\r\n\t * @param options provides some optional configuration options\r\n\t *\r\n\t * @returns a disposable to hide the status message\r\n\t */\r\n\tstatus(message: NotificationMessage, options?: IStatusMessageOptions): IDisposable;\r\n}\r\n\r\nexport class NoOpNotification implements INotificationHandle {\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\r\nimport { equalsIgnoreCase, startsWithIgnoreCase } from 'vs/base/common/strings';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { IEditorOptions } from 'vs/platform/editor/common/editor';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\n\r\nexport const IOpenerService = createDecorator('openerService');\r\n\r\nexport type OpenInternalOptions = {\r\n\r\n\t/**\r\n\t * Signals that the intent is to open an editor to the side\r\n\t * of the currently active editor.\r\n\t */\r\n\treadonly openToSide?: boolean;\r\n\r\n\t/**\r\n\t * Extra editor options to apply in case an editor is used to open.\r\n\t */\r\n\treadonly editorOptions?: IEditorOptions;\r\n\r\n\t/**\r\n\t * Signals that the editor to open was triggered through a user\r\n\t * action, such as keyboard or mouse usage.\r\n\t */\r\n\treadonly fromUserGesture?: boolean;\r\n};\r\n\r\nexport type OpenExternalOptions = {\r\n\treadonly openExternal?: boolean;\r\n\treadonly allowTunneling?: boolean;\r\n\treadonly allowContributedOpeners?: boolean | string;\r\n};\r\n\r\nexport type OpenOptions = OpenInternalOptions & OpenExternalOptions;\r\n\r\nexport type ResolveExternalUriOptions = { readonly allowTunneling?: boolean };\r\n\r\nexport interface IResolvedExternalUri extends IDisposable {\r\n\tresolved: URI;\r\n}\r\n\r\nexport interface IOpener {\r\n\topen(resource: URI | string, options?: OpenInternalOptions | OpenExternalOptions): Promise;\r\n}\r\n\r\nexport interface IExternalOpener {\r\n\topenExternal(href: string, ctx: { sourceUri: URI, preferredOpenerId?: string }, token: CancellationToken): Promise;\r\n\tdispose?(): void;\r\n}\r\n\r\nexport interface IValidator {\r\n\tshouldOpen(resource: URI | string): Promise;\r\n}\r\n\r\nexport interface IExternalUriResolver {\r\n\tresolveExternalUri(resource: URI, options?: OpenOptions): Promise<{ resolved: URI, dispose(): void } | undefined>;\r\n}\r\n\r\nexport interface IOpenerService {\r\n\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\t/**\r\n\t * Register a participant that can handle the open() call.\r\n\t */\r\n\tregisterOpener(opener: IOpener): IDisposable;\r\n\r\n\t/**\r\n\t * Register a participant that can validate if the URI resource be opened.\r\n\t * Validators are run before openers.\r\n\t */\r\n\tregisterValidator(validator: IValidator): IDisposable;\r\n\r\n\t/**\r\n\t * Register a participant that can resolve an external URI resource to be opened.\r\n\t */\r\n\tregisterExternalUriResolver(resolver: IExternalUriResolver): IDisposable;\r\n\r\n\t/**\r\n\t * Sets the handler for opening externally. If not provided,\r\n\t * a default handler will be used.\r\n\t */\r\n\tsetDefaultExternalOpener(opener: IExternalOpener): void;\r\n\r\n\t/**\r\n\t * Registers a new opener external resources openers.\r\n\t */\r\n\tregisterExternalOpener(opener: IExternalOpener): IDisposable;\r\n\r\n\t/**\r\n\t * Opens a resource, like a webaddress, a document uri, or executes command.\r\n\t *\r\n\t * @param resource A resource\r\n\t * @return A promise that resolves when the opening is done.\r\n\t */\r\n\topen(resource: URI | string, options?: OpenInternalOptions | OpenExternalOptions): Promise;\r\n\r\n\t/**\r\n\t * Resolve a resource to its external form.\r\n\t */\r\n\tresolveExternalUri(resource: URI, options?: ResolveExternalUriOptions): Promise;\r\n}\r\n\r\nexport const NullOpenerService = Object.freeze({\r\n\t_serviceBrand: undefined,\r\n\tregisterOpener() { return Disposable.None; },\r\n\tregisterValidator() { return Disposable.None; },\r\n\tregisterExternalUriResolver() { return Disposable.None; },\r\n\tsetDefaultExternalOpener() { },\r\n\tregisterExternalOpener() { return Disposable.None; },\r\n\tasync open() { return false; },\r\n\tasync resolveExternalUri(uri: URI) { return { resolved: uri, dispose() { } }; },\r\n} as IOpenerService);\r\n\r\nexport function matchesScheme(target: URI | string, scheme: string) {\r\n\tif (URI.isUri(target)) {\r\n\t\treturn equalsIgnoreCase(target.scheme, scheme);\r\n\t} else {\r\n\t\treturn startsWithIgnoreCase(target, scheme + ':');\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IMarkdownString } from 'vs/base/common/htmlContent';\r\nimport { renderMarkdown, MarkdownRenderOptions, MarkedOptions } from 'vs/base/browser/markdownRenderer';\r\nimport { IOpenerService } from 'vs/platform/opener/common/opener';\r\nimport { IModeService } from 'vs/editor/common/services/modeService';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport { tokenizeToString } from 'vs/editor/common/modes/textToHtmlTokenizer';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { Emitter } from 'vs/base/common/event';\r\nimport { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { ITokenizationSupport, TokenizationRegistry } from 'vs/editor/common/modes';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { URI } from 'vs/base/common/uri';\r\n\r\nexport interface IMarkdownRenderResult extends IDisposable {\r\n\telement: HTMLElement;\r\n}\r\n\r\nexport interface IMarkdownRendererOptions {\r\n\teditor?: ICodeEditor;\r\n\tbaseUrl?: URI;\r\n\tcodeBlockFontFamily?: string;\r\n}\r\n\r\n/**\r\n * Markdown renderer that can render codeblocks with the editor mechanics. This\r\n * renderer should always be preferred.\r\n */\r\nexport class MarkdownRenderer {\r\n\r\n\tprivate static _ttpTokenizer = window.trustedTypes?.createPolicy('tokenizeToString', {\r\n\t\tcreateHTML(value: string, tokenizer: ITokenizationSupport | undefined) {\r\n\t\t\treturn tokenizeToString(value, tokenizer);\r\n\t\t}\r\n\t});\r\n\r\n\tprivate readonly _onDidRenderAsync = new Emitter();\r\n\treadonly onDidRenderAsync = this._onDidRenderAsync.event;\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _options: IMarkdownRendererOptions,\r\n\t\t@IModeService private readonly _modeService: IModeService,\r\n\t\t@IOpenerService private readonly _openerService: IOpenerService,\r\n\t) { }\r\n\r\n\tdispose(): void {\r\n\t\tthis._onDidRenderAsync.dispose();\r\n\t}\r\n\r\n\trender(markdown: IMarkdownString | undefined, options?: MarkdownRenderOptions, markedOptions?: MarkedOptions): IMarkdownRenderResult {\r\n\t\tconst disposeables = new DisposableStore();\r\n\r\n\t\tlet element: HTMLElement;\r\n\t\tif (!markdown) {\r\n\t\t\telement = document.createElement('span');\r\n\t\t} else {\r\n\t\t\telement = renderMarkdown(markdown, { ...this._getRenderOptions(disposeables), ...options }, markedOptions);\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\telement,\r\n\t\t\tdispose: () => disposeables.dispose()\r\n\t\t};\r\n\t}\r\n\r\n\tprotected _getRenderOptions(disposeables: DisposableStore): MarkdownRenderOptions {\r\n\t\treturn {\r\n\t\t\tbaseUrl: this._options.baseUrl,\r\n\t\t\tcodeBlockRenderer: async (languageAlias, value) => {\r\n\t\t\t\t// In markdown,\r\n\t\t\t\t// it is possible that we stumble upon language aliases (e.g.js instead of javascript)\r\n\t\t\t\t// it is possible no alias is given in which case we fall back to the current editor lang\r\n\t\t\t\tlet modeId: string | undefined | null;\r\n\t\t\t\tif (languageAlias) {\r\n\t\t\t\t\tmodeId = this._modeService.getModeIdForLanguageName(languageAlias);\r\n\t\t\t\t} else if (this._options.editor) {\r\n\t\t\t\t\tmodeId = this._options.editor.getModel()?.getLanguageIdentifier().language;\r\n\t\t\t\t}\r\n\t\t\t\tif (!modeId) {\r\n\t\t\t\t\tmodeId = 'plaintext';\r\n\t\t\t\t}\r\n\t\t\t\tthis._modeService.triggerMode(modeId);\r\n\t\t\t\tconst tokenization = await TokenizationRegistry.getPromise(modeId) ?? undefined;\r\n\r\n\t\t\t\tconst element = document.createElement('span');\r\n\r\n\t\t\t\telement.innerHTML = (MarkdownRenderer._ttpTokenizer?.createHTML(value, tokenization) ?? tokenizeToString(value, tokenization)) as string;\r\n\r\n\t\t\t\t// use \"good\" font\r\n\t\t\t\tlet fontFamily = this._options.codeBlockFontFamily;\r\n\t\t\t\tif (this._options.editor) {\r\n\t\t\t\t\tfontFamily = this._options.editor.getOption(EditorOption.fontInfo).fontFamily;\r\n\t\t\t\t}\r\n\t\t\t\tif (fontFamily) {\r\n\t\t\t\t\telement.style.fontFamily = fontFamily;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn element;\r\n\t\t\t},\r\n\t\t\tasyncRenderCallback: () => this._onDidRenderAsync.fire(),\r\n\t\t\tactionHandler: {\r\n\t\t\t\tcallback: (content) => this._openerService.open(content, { fromUserGesture: true, allowContributedOpeners: true }).catch(onUnexpectedError),\r\n\t\t\t\tdisposeables\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { LinkedList } from 'vs/base/common/linkedList';\r\nimport { ResourceMap } from 'vs/base/common/map';\r\nimport { parse } from 'vs/base/common/marshalling';\r\nimport { Schemas } from 'vs/base/common/network';\r\nimport { normalizePath } from 'vs/base/common/resources';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\r\nimport { ICommandService } from 'vs/platform/commands/common/commands';\r\nimport { EditorOpenContext } from 'vs/platform/editor/common/editor';\r\nimport { IExternalOpener, IExternalUriResolver, IOpener, IOpenerService, IResolvedExternalUri, IValidator, matchesScheme, OpenOptions, ResolveExternalUriOptions } from 'vs/platform/opener/common/opener';\r\n\r\nclass CommandOpener implements IOpener {\r\n\r\n\tconstructor(@ICommandService private readonly _commandService: ICommandService) { }\r\n\r\n\tasync open(target: URI | string) {\r\n\t\tif (!matchesScheme(target, Schemas.command)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\t// run command or bail out if command isn't known\r\n\t\tif (typeof target === 'string') {\r\n\t\t\ttarget = URI.parse(target);\r\n\t\t}\r\n\t\t// execute as command\r\n\t\tlet args: any = [];\r\n\t\ttry {\r\n\t\t\targs = parse(decodeURIComponent(target.query));\r\n\t\t} catch {\r\n\t\t\t// ignore and retry\r\n\t\t\ttry {\r\n\t\t\t\targs = parse(target.query);\r\n\t\t\t} catch {\r\n\t\t\t\t// ignore error\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (!Array.isArray(args)) {\r\n\t\t\targs = [args];\r\n\t\t}\r\n\t\tawait this._commandService.executeCommand(target.path, ...args);\r\n\t\treturn true;\r\n\t}\r\n}\r\n\r\nclass EditorOpener implements IOpener {\r\n\r\n\tconstructor(@ICodeEditorService private readonly _editorService: ICodeEditorService) { }\r\n\r\n\tasync open(target: URI | string, options: OpenOptions) {\r\n\t\tif (typeof target === 'string') {\r\n\t\t\ttarget = URI.parse(target);\r\n\t\t}\r\n\t\tlet selection: { startLineNumber: number; startColumn: number; } | undefined = undefined;\r\n\t\tconst match = /^L?(\\d+)(?:,(\\d+))?/.exec(target.fragment);\r\n\t\tif (match) {\r\n\t\t\t// support file:///some/file.js#73,84\r\n\t\t\t// support file:///some/file.js#L73\r\n\t\t\tselection = {\r\n\t\t\t\tstartLineNumber: parseInt(match[1]),\r\n\t\t\t\tstartColumn: match[2] ? parseInt(match[2]) : 1\r\n\t\t\t};\r\n\t\t\t// remove fragment\r\n\t\t\ttarget = target.with({ fragment: '' });\r\n\t\t}\r\n\r\n\t\tif (target.scheme === Schemas.file) {\r\n\t\t\ttarget = normalizePath(target); // workaround for non-normalized paths (https://github.com/microsoft/vscode/issues/12954)\r\n\t\t}\r\n\r\n\t\tawait this._editorService.openCodeEditor(\r\n\t\t\t{\r\n\t\t\t\tresource: target,\r\n\t\t\t\toptions: {\r\n\t\t\t\t\tselection,\r\n\t\t\t\t\tcontext: options?.fromUserGesture ? EditorOpenContext.USER : EditorOpenContext.API,\r\n\t\t\t\t\t...options?.editorOptions\r\n\t\t\t\t}\r\n\t\t\t},\r\n\t\t\tthis._editorService.getFocusedCodeEditor(),\r\n\t\t\toptions?.openToSide\r\n\t\t);\r\n\r\n\t\treturn true;\r\n\t}\r\n}\r\n\r\nexport class OpenerService implements IOpenerService {\r\n\r\n\tdeclare readonly _serviceBrand: undefined;\r\n\r\n\tprivate readonly _openers = new LinkedList();\r\n\tprivate readonly _validators = new LinkedList();\r\n\tprivate readonly _resolvers = new LinkedList();\r\n\tprivate readonly _resolvedUriTargets = new ResourceMap(uri => uri.with({ path: null, fragment: null, query: null }).toString());\r\n\r\n\tprivate _defaultExternalOpener: IExternalOpener;\r\n\tprivate readonly _externalOpeners = new LinkedList();\r\n\r\n\tconstructor(\r\n\t\t@ICodeEditorService editorService: ICodeEditorService,\r\n\t\t@ICommandService commandService: ICommandService,\r\n\t) {\r\n\t\t// Default external opener is going through window.open()\r\n\t\tthis._defaultExternalOpener = {\r\n\t\t\topenExternal: async href => {\r\n\t\t\t\t// ensure to open HTTP/HTTPS links into new windows\r\n\t\t\t\t// to not trigger a navigation. Any other link is\r\n\t\t\t\t// safe to be set as HREF to prevent a blank window\r\n\t\t\t\t// from opening.\r\n\t\t\t\tif (matchesScheme(href, Schemas.http) || matchesScheme(href, Schemas.https)) {\r\n\t\t\t\t\tdom.windowOpenNoOpener(href);\r\n\t\t\t\t} else {\r\n\t\t\t\t\twindow.location.href = href;\r\n\t\t\t\t}\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t// Default opener: any external, maito, http(s), command, and catch-all-editors\r\n\t\tthis._openers.push({\r\n\t\t\topen: async (target: URI | string, options?: OpenOptions) => {\r\n\t\t\t\tif (options?.openExternal || matchesScheme(target, Schemas.mailto) || matchesScheme(target, Schemas.http) || matchesScheme(target, Schemas.https)) {\r\n\t\t\t\t\t// open externally\r\n\t\t\t\t\tawait this._doOpenExternal(target, options);\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t});\r\n\t\tthis._openers.push(new CommandOpener(commandService));\r\n\t\tthis._openers.push(new EditorOpener(editorService));\r\n\t}\r\n\r\n\tregisterOpener(opener: IOpener): IDisposable {\r\n\t\tconst remove = this._openers.unshift(opener);\r\n\t\treturn { dispose: remove };\r\n\t}\r\n\r\n\tregisterValidator(validator: IValidator): IDisposable {\r\n\t\tconst remove = this._validators.push(validator);\r\n\t\treturn { dispose: remove };\r\n\t}\r\n\r\n\tregisterExternalUriResolver(resolver: IExternalUriResolver): IDisposable {\r\n\t\tconst remove = this._resolvers.push(resolver);\r\n\t\treturn { dispose: remove };\r\n\t}\r\n\r\n\tsetDefaultExternalOpener(externalOpener: IExternalOpener): void {\r\n\t\tthis._defaultExternalOpener = externalOpener;\r\n\t}\r\n\r\n\tregisterExternalOpener(opener: IExternalOpener): IDisposable {\r\n\t\tconst remove = this._externalOpeners.push(opener);\r\n\t\treturn { dispose: remove };\r\n\t}\r\n\r\n\tasync open(target: URI | string, options?: OpenOptions): Promise {\r\n\t\t// check with contributed validators\r\n\t\tconst targetURI = typeof target === 'string' ? URI.parse(target) : target;\r\n\t\t// validate against the original URI that this URI resolves to, if one exists\r\n\t\tconst validationTarget = this._resolvedUriTargets.get(targetURI) ?? target;\r\n\t\tfor (const validator of this._validators) {\r\n\t\t\tif (!(await validator.shouldOpen(validationTarget))) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// check with contributed openers\r\n\t\tfor (const opener of this._openers) {\r\n\t\t\tconst handled = await opener.open(target, options);\r\n\t\t\tif (handled) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\t}\r\n\r\n\tasync resolveExternalUri(resource: URI, options?: ResolveExternalUriOptions): Promise {\r\n\t\tfor (const resolver of this._resolvers) {\r\n\t\t\tconst result = await resolver.resolveExternalUri(resource, options);\r\n\t\t\tif (result) {\r\n\t\t\t\tthis._resolvedUriTargets.set(result.resolved, resource);\r\n\t\t\t\treturn result;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn { resolved: resource, dispose: () => { } };\r\n\t}\r\n\r\n\tprivate async _doOpenExternal(resource: URI | string, options: OpenOptions | undefined): Promise {\r\n\r\n\t\t//todo@jrieken IExternalUriResolver should support `uri: URI | string`\r\n\t\tconst uri = typeof resource === 'string' ? URI.parse(resource) : resource;\r\n\t\tconst { resolved } = await this.resolveExternalUri(uri, options);\r\n\r\n\t\tlet href: string;\r\n\t\tif (typeof resource === 'string' && uri.toString() === resolved.toString()) {\r\n\t\t\t// open the url-string AS IS\r\n\t\t\thref = resource;\r\n\t\t} else {\r\n\t\t\t// open URI using the toString(noEncode)+encodeURI-trick\r\n\t\t\thref = encodeURI(resolved.toString(true));\r\n\t\t}\r\n\r\n\t\tif (options?.allowContributedOpeners) {\r\n\t\t\tconst preferredOpenerId = typeof options?.allowContributedOpeners === 'string' ? options?.allowContributedOpeners : undefined;\r\n\t\t\tfor (const opener of this._externalOpeners) {\r\n\t\t\t\tconst didOpen = await opener.openExternal(href, {\r\n\t\t\t\t\tsourceUri: uri,\r\n\t\t\t\t\tpreferredOpenerId,\r\n\t\t\t\t}, CancellationToken.None);\r\n\t\t\t\tif (didOpen) {\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this._defaultExternalOpener.openExternal(href, { sourceUri: uri }, CancellationToken.None);\r\n\t}\r\n\r\n\tdispose() {\r\n\t\tthis._validators.clear();\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { $ } from 'vs/base/browser/dom';\r\nimport { IMarkdownString, isEmptyMarkdownString } from 'vs/base/common/htmlContent';\r\nimport { DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { HoverOperation, HoverStartMode, IHoverComputer } from 'vs/editor/contrib/hover/hoverOperation';\r\nimport { GlyphHoverWidget } from 'vs/editor/contrib/hover/hoverWidgets';\r\nimport { MarkdownRenderer } from 'vs/editor/browser/core/markdownRenderer';\r\nimport { IModeService } from 'vs/editor/common/services/modeService';\r\nimport { IOpenerService, NullOpenerService } from 'vs/platform/opener/common/opener';\r\nimport { asArray } from 'vs/base/common/arrays';\r\n\r\nexport interface IHoverMessage {\r\n\tvalue: IMarkdownString;\r\n}\r\n\r\nclass MarginComputer implements IHoverComputer {\r\n\r\n\tprivate readonly _editor: ICodeEditor;\r\n\tprivate _lineNumber: number;\r\n\tprivate _result: IHoverMessage[];\r\n\r\n\tconstructor(editor: ICodeEditor) {\r\n\t\tthis._editor = editor;\r\n\t\tthis._lineNumber = -1;\r\n\t\tthis._result = [];\r\n\t}\r\n\r\n\tpublic setLineNumber(lineNumber: number): void {\r\n\t\tthis._lineNumber = lineNumber;\r\n\t\tthis._result = [];\r\n\t}\r\n\r\n\tpublic clearResult(): void {\r\n\t\tthis._result = [];\r\n\t}\r\n\r\n\tpublic computeSync(): IHoverMessage[] {\r\n\r\n\t\tconst toHoverMessage = (contents: IMarkdownString): IHoverMessage => {\r\n\t\t\treturn {\r\n\t\t\t\tvalue: contents\r\n\t\t\t};\r\n\t\t};\r\n\r\n\t\tconst lineDecorations = this._editor.getLineDecorations(this._lineNumber);\r\n\r\n\t\tconst result: IHoverMessage[] = [];\r\n\t\tif (!lineDecorations) {\r\n\t\t\treturn result;\r\n\t\t}\r\n\r\n\t\tfor (const d of lineDecorations) {\r\n\t\t\tif (!d.options.glyphMarginClassName) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tconst hoverMessage = d.options.glyphMarginHoverMessage;\r\n\t\t\tif (!hoverMessage || isEmptyMarkdownString(hoverMessage)) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tresult.push(...asArray(hoverMessage).map(toHoverMessage));\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic onResult(result: IHoverMessage[], isFromSynchronousComputation: boolean): void {\r\n\t\tthis._result = this._result.concat(result);\r\n\t}\r\n\r\n\tpublic getResult(): IHoverMessage[] {\r\n\t\treturn this._result;\r\n\t}\r\n\r\n\tpublic getResultWithLoadingMessage(): IHoverMessage[] {\r\n\t\treturn this.getResult();\r\n\t}\r\n}\r\n\r\nexport class ModesGlyphHoverWidget extends GlyphHoverWidget {\r\n\r\n\tpublic static readonly ID = 'editor.contrib.modesGlyphHoverWidget';\r\n\tprivate _messages: IHoverMessage[];\r\n\tprivate _lastLineNumber: number;\r\n\r\n\tprivate readonly _markdownRenderer: MarkdownRenderer;\r\n\tprivate readonly _computer: MarginComputer;\r\n\tprivate readonly _hoverOperation: HoverOperation;\r\n\tprivate readonly _renderDisposeables = this._register(new DisposableStore());\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor,\r\n\t\tmodeService: IModeService,\r\n\t\topenerService: IOpenerService = NullOpenerService,\r\n\t) {\r\n\t\tsuper(ModesGlyphHoverWidget.ID, editor);\r\n\r\n\t\tthis._messages = [];\r\n\t\tthis._lastLineNumber = -1;\r\n\r\n\t\tthis._markdownRenderer = this._register(new MarkdownRenderer({ editor: this._editor }, modeService, openerService));\r\n\t\tthis._computer = new MarginComputer(this._editor);\r\n\r\n\t\tthis._hoverOperation = new HoverOperation(\r\n\t\t\tthis._computer,\r\n\t\t\t(result: IHoverMessage[]) => this._withResult(result),\r\n\t\t\tundefined,\r\n\t\t\t(result: any) => this._withResult(result),\r\n\t\t\t300\r\n\t\t);\r\n\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._hoverOperation.cancel();\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tpublic onModelDecorationsChanged(): void {\r\n\t\tif (this.isVisible) {\r\n\t\t\t// The decorations have changed and the hover is visible,\r\n\t\t\t// we need to recompute the displayed text\r\n\t\t\tthis._hoverOperation.cancel();\r\n\t\t\tthis._computer.clearResult();\r\n\t\t\tthis._hoverOperation.start(HoverStartMode.Delayed);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic startShowingAt(lineNumber: number): void {\r\n\t\tif (this._lastLineNumber === lineNumber) {\r\n\t\t\t// We have to show the widget at the exact same line number as before, so no work is needed\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._hoverOperation.cancel();\r\n\r\n\t\tthis.hide();\r\n\r\n\t\tthis._lastLineNumber = lineNumber;\r\n\t\tthis._computer.setLineNumber(lineNumber);\r\n\t\tthis._hoverOperation.start(HoverStartMode.Delayed);\r\n\t}\r\n\r\n\tpublic hide(): void {\r\n\t\tthis._lastLineNumber = -1;\r\n\t\tthis._hoverOperation.cancel();\r\n\t\tsuper.hide();\r\n\t}\r\n\r\n\tpublic _withResult(result: IHoverMessage[]): void {\r\n\t\tthis._messages = result;\r\n\r\n\t\tif (this._messages.length > 0) {\r\n\t\t\tthis._renderMessages(this._lastLineNumber, this._messages);\r\n\t\t} else {\r\n\t\t\tthis.hide();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _renderMessages(lineNumber: number, messages: IHoverMessage[]): void {\r\n\t\tthis._renderDisposeables.clear();\r\n\r\n\t\tconst fragment = document.createDocumentFragment();\r\n\r\n\t\tfor (const msg of messages) {\r\n\t\t\tconst renderedContents = this._markdownRenderer.render(msg.value);\r\n\t\t\tthis._renderDisposeables.add(renderedContents);\r\n\t\t\tfragment.appendChild($('div.hover-row', undefined, renderedContents.element));\r\n\t\t}\r\n\r\n\t\tthis.updateContents(fragment);\r\n\t\tthis.showAt(lineNumber);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { DisposableStore } from 'vs/base/common/lifecycle';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { ICodeEditor, IOverlayWidget } from 'vs/editor/browser/editorBrowser';\r\nimport { CompletionItem } from './suggest';\r\nimport { MarkdownRenderer } from 'vs/editor/browser/core/markdownRenderer';\r\nimport { MarkdownString } from 'vs/base/common/htmlContent';\r\nimport { Codicon } from 'vs/base/common/codicons';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { ResizableHTMLElement } from 'vs/editor/contrib/suggest/resizable';\r\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\r\n\r\nexport function canExpandCompletionItem(item: CompletionItem | undefined): boolean {\r\n\treturn !!item && Boolean(item.completion.documentation || item.completion.detail && item.completion.detail !== item.completion.label);\r\n}\r\n\r\nexport class SuggestDetailsWidget {\r\n\r\n\treadonly domNode: HTMLDivElement;\r\n\r\n\tprivate readonly _onDidClose = new Emitter();\r\n\treadonly onDidClose: Event = this._onDidClose.event;\r\n\r\n\tprivate readonly _onDidChangeContents = new Emitter();\r\n\treadonly onDidChangeContents: Event = this._onDidChangeContents.event;\r\n\r\n\tprivate readonly _close: HTMLElement;\r\n\tprivate readonly _scrollbar: DomScrollableElement;\r\n\tprivate readonly _body: HTMLElement;\r\n\tprivate readonly _header: HTMLElement;\r\n\tprivate readonly _type: HTMLElement;\r\n\tprivate readonly _docs: HTMLElement;\r\n\tprivate readonly _disposables = new DisposableStore();\r\n\r\n\tprivate readonly _markdownRenderer: MarkdownRenderer;\r\n\tprivate readonly _renderDisposeable = new DisposableStore();\r\n\tprivate _borderWidth: number = 1;\r\n\tprivate _size = new dom.Dimension(330, 0);\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _editor: ICodeEditor,\r\n\t\t@IInstantiationService instaService: IInstantiationService,\r\n\t) {\r\n\t\tthis.domNode = dom.$('.suggest-details');\r\n\t\tthis.domNode.classList.add('no-docs');\r\n\r\n\t\tthis._markdownRenderer = instaService.createInstance(MarkdownRenderer, { editor: _editor });\r\n\r\n\t\tthis._body = dom.$('.body');\r\n\r\n\t\tthis._scrollbar = new DomScrollableElement(this._body, {});\r\n\t\tdom.append(this.domNode, this._scrollbar.getDomNode());\r\n\t\tthis._disposables.add(this._scrollbar);\r\n\r\n\t\tthis._header = dom.append(this._body, dom.$('.header'));\r\n\t\tthis._close = dom.append(this._header, dom.$('span' + Codicon.close.cssSelector));\r\n\t\tthis._close.title = nls.localize('details.close', \"Close\");\r\n\t\tthis._type = dom.append(this._header, dom.$('p.type'));\r\n\r\n\t\tthis._docs = dom.append(this._body, dom.$('p.docs'));\r\n\r\n\t\tthis._configureFont();\r\n\r\n\t\tthis._disposables.add(this._editor.onDidChangeConfiguration(e => {\r\n\t\t\tif (e.hasChanged(EditorOption.fontInfo)) {\r\n\t\t\t\tthis._configureFont();\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._disposables.dispose();\r\n\t\tthis._renderDisposeable.dispose();\r\n\t}\r\n\r\n\tprivate _configureFont(): void {\r\n\t\tconst options = this._editor.getOptions();\r\n\t\tconst fontInfo = options.get(EditorOption.fontInfo);\r\n\t\tconst fontFamily = fontInfo.fontFamily;\r\n\t\tconst fontSize = options.get(EditorOption.suggestFontSize) || fontInfo.fontSize;\r\n\t\tconst lineHeight = options.get(EditorOption.suggestLineHeight) || fontInfo.lineHeight;\r\n\t\tconst fontWeight = fontInfo.fontWeight;\r\n\t\tconst fontSizePx = `${fontSize}px`;\r\n\t\tconst lineHeightPx = `${lineHeight}px`;\r\n\r\n\t\tthis.domNode.style.fontSize = fontSizePx;\r\n\t\tthis.domNode.style.lineHeight = lineHeightPx;\r\n\t\tthis.domNode.style.fontWeight = fontWeight;\r\n\t\tthis.domNode.style.fontFeatureSettings = fontInfo.fontFeatureSettings;\r\n\t\tthis._type.style.fontFamily = fontFamily;\r\n\t\tthis._close.style.height = lineHeightPx;\r\n\t\tthis._close.style.width = lineHeightPx;\r\n\t}\r\n\r\n\tgetLayoutInfo() {\r\n\t\tconst lineHeight = this._editor.getOption(EditorOption.suggestLineHeight) || this._editor.getOption(EditorOption.fontInfo).lineHeight;\r\n\t\tconst borderWidth = this._borderWidth;\r\n\t\tconst borderHeight = borderWidth * 2;\r\n\t\treturn {\r\n\t\t\tlineHeight,\r\n\t\t\tborderWidth,\r\n\t\t\tborderHeight,\r\n\t\t\tverticalPadding: 22,\r\n\t\t\thorizontalPadding: 14\r\n\t\t};\r\n\t}\r\n\r\n\r\n\trenderLoading(): void {\r\n\t\tthis._type.textContent = nls.localize('loading', \"Loading...\");\r\n\t\tthis._docs.textContent = '';\r\n\t\tthis.domNode.classList.remove('no-docs', 'no-type');\r\n\t\tthis.layout(this.size.width, this.getLayoutInfo().lineHeight * 2);\r\n\t\tthis._onDidChangeContents.fire(this);\r\n\t}\r\n\r\n\trenderItem(item: CompletionItem, explainMode: boolean): void {\r\n\t\tthis._renderDisposeable.clear();\r\n\r\n\t\tlet { detail, documentation } = item.completion;\r\n\r\n\t\tif (explainMode) {\r\n\t\t\tlet md = '';\r\n\t\t\tmd += `score: ${item.score[0]}${item.word ? `, compared '${item.completion.filterText && (item.completion.filterText + ' (filterText)') || typeof item.completion.label === 'string' ? item.completion.label : item.completion.label.name}' with '${item.word}'` : ' (no prefix)'}\\n`;\r\n\t\t\tmd += `distance: ${item.distance}, see localityBonus-setting\\n`;\r\n\t\t\tmd += `index: ${item.idx}, based on ${item.completion.sortText && `sortText: \"${item.completion.sortText}\"` || 'label'}\\n`;\r\n\t\t\tmd += `commit characters: ${item.completion.commitCharacters}\\n`;\r\n\t\t\tdocumentation = new MarkdownString().appendCodeblock('empty', md);\r\n\t\t\tdetail = `Provider: ${item.provider._debugDisplayName}`;\r\n\t\t}\r\n\r\n\t\tif (!explainMode && !canExpandCompletionItem(item)) {\r\n\t\t\tthis.clearContents();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.domNode.classList.remove('no-docs', 'no-type');\r\n\r\n\t\t// --- details\r\n\r\n\t\tif (detail) {\r\n\t\t\tconst cappedDetail = detail.length > 100000 ? `${detail.substr(0, 100000)}…` : detail;\r\n\t\t\tthis._type.textContent = cappedDetail;\r\n\t\t\tthis._type.title = cappedDetail;\r\n\t\t\tdom.show(this._type);\r\n\t\t\tthis._type.classList.toggle('auto-wrap', !/\\r?\\n^\\s+/gmi.test(cappedDetail));\r\n\t\t} else {\r\n\t\t\tdom.clearNode(this._type);\r\n\t\t\tthis._type.title = '';\r\n\t\t\tdom.hide(this._type);\r\n\t\t\tthis.domNode.classList.add('no-type');\r\n\t\t}\r\n\r\n\t\t// --- documentation\r\n\t\tdom.clearNode(this._docs);\r\n\t\tif (typeof documentation === 'string') {\r\n\t\t\tthis._docs.classList.remove('markdown-docs');\r\n\t\t\tthis._docs.textContent = documentation;\r\n\r\n\t\t} else if (documentation) {\r\n\t\t\tthis._docs.classList.add('markdown-docs');\r\n\t\t\tdom.clearNode(this._docs);\r\n\t\t\tconst renderedContents = this._markdownRenderer.render(documentation);\r\n\t\t\tthis._docs.appendChild(renderedContents.element);\r\n\t\t\tthis._renderDisposeable.add(renderedContents);\r\n\t\t\tthis._renderDisposeable.add(this._markdownRenderer.onDidRenderAsync(() => {\r\n\t\t\t\tthis.layout(this._size.width, this._type.clientHeight + this._docs.clientHeight);\r\n\t\t\t\tthis._onDidChangeContents.fire(this);\r\n\t\t\t}));\r\n\t\t}\r\n\r\n\t\tthis.domNode.style.userSelect = 'text';\r\n\t\tthis.domNode.tabIndex = -1;\r\n\r\n\t\tthis._close.onmousedown = e => {\r\n\t\t\te.preventDefault();\r\n\t\t\te.stopPropagation();\r\n\t\t};\r\n\t\tthis._close.onclick = e => {\r\n\t\t\te.preventDefault();\r\n\t\t\te.stopPropagation();\r\n\t\t\tthis._onDidClose.fire();\r\n\t\t};\r\n\r\n\t\tthis._body.scrollTop = 0;\r\n\r\n\t\tthis.layout(this._size.width, this._type.clientHeight + this._docs.clientHeight);\r\n\t\tthis._onDidChangeContents.fire(this);\r\n\t}\r\n\r\n\tclearContents() {\r\n\t\tthis.domNode.classList.add('no-docs');\r\n\t\tthis._type.textContent = '';\r\n\t\tthis._docs.textContent = '';\r\n\t}\r\n\r\n\tget size() {\r\n\t\treturn this._size;\r\n\t}\r\n\r\n\tlayout(width: number, height: number): void {\r\n\t\tconst newSize = new dom.Dimension(width, height);\r\n\t\tif (!dom.Dimension.equals(newSize, this._size)) {\r\n\t\t\tthis._size = newSize;\r\n\t\t\tdom.size(this.domNode, width, height);\r\n\t\t}\r\n\t\tthis._scrollbar.scanDomNode();\r\n\t}\r\n\r\n\tscrollDown(much = 8): void {\r\n\t\tthis._body.scrollTop += much;\r\n\t}\r\n\r\n\tscrollUp(much = 8): void {\r\n\t\tthis._body.scrollTop -= much;\r\n\t}\r\n\r\n\tscrollTop(): void {\r\n\t\tthis._body.scrollTop = 0;\r\n\t}\r\n\r\n\tscrollBottom(): void {\r\n\t\tthis._body.scrollTop = this._body.scrollHeight;\r\n\t}\r\n\r\n\tpageDown(): void {\r\n\t\tthis.scrollDown(80);\r\n\t}\r\n\r\n\tpageUp(): void {\r\n\t\tthis.scrollUp(80);\r\n\t}\r\n\r\n\tset borderWidth(width: number) {\r\n\t\tthis._borderWidth = width;\r\n\t}\r\n\r\n\tget borderWidth() {\r\n\t\treturn this._borderWidth;\r\n\t}\r\n}\r\n\r\ninterface TopLeftPosition {\r\n\ttop: number;\r\n\tleft: number;\r\n}\r\n\r\nexport class SuggestDetailsOverlay implements IOverlayWidget {\r\n\r\n\tprivate readonly _disposables = new DisposableStore();\r\n\tprivate readonly _resizable: ResizableHTMLElement;\r\n\r\n\tprivate _added: boolean = false;\r\n\tprivate _anchorBox?: dom.IDomNodePagePosition;\r\n\tprivate _userSize?: dom.Dimension;\r\n\tprivate _topLeft?: TopLeftPosition;\r\n\r\n\tconstructor(\r\n\t\treadonly widget: SuggestDetailsWidget,\r\n\t\tprivate readonly _editor: ICodeEditor\r\n\t) {\r\n\r\n\t\tthis._resizable = new ResizableHTMLElement();\r\n\t\tthis._resizable.domNode.classList.add('suggest-details-container');\r\n\t\tthis._resizable.domNode.appendChild(widget.domNode);\r\n\t\tthis._resizable.enableSashes(false, true, true, false);\r\n\r\n\t\tlet topLeftNow: TopLeftPosition | undefined;\r\n\t\tlet sizeNow: dom.Dimension | undefined;\r\n\t\tlet deltaTop: number = 0;\r\n\t\tlet deltaLeft: number = 0;\r\n\t\tthis._disposables.add(this._resizable.onDidWillResize(() => {\r\n\t\t\ttopLeftNow = this._topLeft;\r\n\t\t\tsizeNow = this._resizable.size;\r\n\t\t}));\r\n\r\n\t\tthis._disposables.add(this._resizable.onDidResize(e => {\r\n\t\t\tif (topLeftNow && sizeNow) {\r\n\t\t\t\tthis.widget.layout(e.dimension.width, e.dimension.height);\r\n\r\n\t\t\t\tlet updateTopLeft = false;\r\n\t\t\t\tif (e.west) {\r\n\t\t\t\t\tdeltaLeft = sizeNow.width - e.dimension.width;\r\n\t\t\t\t\tupdateTopLeft = true;\r\n\t\t\t\t}\r\n\t\t\t\tif (e.north) {\r\n\t\t\t\t\tdeltaTop = sizeNow.height - e.dimension.height;\r\n\t\t\t\t\tupdateTopLeft = true;\r\n\t\t\t\t}\r\n\t\t\t\tif (updateTopLeft) {\r\n\t\t\t\t\tthis._applyTopLeft({\r\n\t\t\t\t\t\ttop: topLeftNow.top + deltaTop,\r\n\t\t\t\t\t\tleft: topLeftNow.left + deltaLeft,\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (e.done) {\r\n\t\t\t\ttopLeftNow = undefined;\r\n\t\t\t\tsizeNow = undefined;\r\n\t\t\t\tdeltaTop = 0;\r\n\t\t\t\tdeltaLeft = 0;\r\n\t\t\t\tthis._userSize = e.dimension;\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._disposables.add(this.widget.onDidChangeContents(() => {\r\n\t\t\tif (this._anchorBox) {\r\n\t\t\t\tthis._placeAtAnchor(this._anchorBox, this._userSize ?? this.widget.size);\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._disposables.dispose();\r\n\t\tthis.hide();\r\n\t}\r\n\r\n\tgetId(): string {\r\n\t\treturn 'suggest.details';\r\n\t}\r\n\r\n\tgetDomNode(): HTMLElement {\r\n\t\treturn this._resizable.domNode;\r\n\t}\r\n\r\n\tgetPosition(): null {\r\n\t\treturn null;\r\n\t}\r\n\r\n\tshow(): void {\r\n\t\tif (!this._added) {\r\n\t\t\tthis._editor.addOverlayWidget(this);\r\n\t\t\tthis.getDomNode().style.position = 'fixed';\r\n\t\t\tthis._added = true;\r\n\t\t}\r\n\t}\r\n\r\n\thide(sessionEnded: boolean = false): void {\r\n\t\tif (this._added) {\r\n\t\t\tthis._editor.removeOverlayWidget(this);\r\n\t\t\tthis._added = false;\r\n\t\t\tthis._anchorBox = undefined;\r\n\t\t\tthis._topLeft = undefined;\r\n\t\t}\r\n\t\tif (sessionEnded) {\r\n\t\t\tthis._userSize = undefined;\r\n\t\t\tthis.widget.clearContents();\r\n\t\t}\r\n\t}\r\n\r\n\tplaceAtAnchor(anchor: HTMLElement) {\r\n\t\tconst anchorBox = dom.getDomNodePagePosition(anchor);\r\n\t\tthis._anchorBox = anchorBox;\r\n\t\tthis._placeAtAnchor(this._anchorBox, this._userSize ?? this.widget.size);\r\n\t}\r\n\r\n\t_placeAtAnchor(anchorBox: dom.IDomNodePagePosition, size: dom.Dimension) {\r\n\t\tconst bodyBox = dom.getClientArea(document.body);\r\n\r\n\t\tconst info = this.widget.getLayoutInfo();\r\n\r\n\t\tlet maxSizeTop: dom.Dimension;\r\n\t\tlet maxSizeBottom: dom.Dimension;\r\n\t\tlet minSize = new dom.Dimension(220, 2 * info.lineHeight);\r\n\r\n\t\tlet left = 0;\r\n\t\tlet top = anchorBox.top;\r\n\t\tlet bottom = anchorBox.top + anchorBox.height - info.borderHeight;\r\n\r\n\t\tlet alignAtTop: boolean;\r\n\t\tlet alignEast: boolean;\r\n\r\n\t\t// position: EAST, west, south\r\n\t\tlet width = bodyBox.width - (anchorBox.left + anchorBox.width + info.borderWidth + info.horizontalPadding);\r\n\t\tleft = -info.borderWidth + anchorBox.left + anchorBox.width;\r\n\t\talignEast = true;\r\n\t\tmaxSizeTop = new dom.Dimension(width, bodyBox.height - anchorBox.top - info.borderHeight - info.verticalPadding);\r\n\t\tmaxSizeBottom = maxSizeTop.with(undefined, anchorBox.top + anchorBox.height - info.borderHeight - info.verticalPadding);\r\n\r\n\t\t// find a better place if the widget is wider than there is space available\r\n\t\tif (size.width > width) {\r\n\t\t\t// position: east, WEST, south\r\n\t\t\tif (anchorBox.left > width) {\r\n\t\t\t\t// pos = SuggestDetailsPosition.West;\r\n\t\t\t\twidth = anchorBox.left - info.borderWidth - info.horizontalPadding;\r\n\t\t\t\talignEast = false;\r\n\t\t\t\tleft = Math.max(info.horizontalPadding, anchorBox.left - size.width - info.borderWidth);\r\n\t\t\t\tmaxSizeTop = maxSizeTop.with(width);\r\n\t\t\t\tmaxSizeBottom = maxSizeTop.with(undefined, maxSizeBottom.height);\r\n\t\t\t}\r\n\r\n\t\t\t// position: east, west, SOUTH\r\n\t\t\tif (anchorBox.width > width * 1.3 && bodyBox.height - (anchorBox.top + anchorBox.height) > anchorBox.height) {\r\n\t\t\t\twidth = anchorBox.width;\r\n\t\t\t\tleft = anchorBox.left;\r\n\t\t\t\ttop = -info.borderWidth + anchorBox.top + anchorBox.height;\r\n\t\t\t\tmaxSizeTop = new dom.Dimension(anchorBox.width - info.borderHeight, bodyBox.height - anchorBox.top - anchorBox.height - info.verticalPadding);\r\n\t\t\t\tmaxSizeBottom = maxSizeTop.with(undefined, anchorBox.top - info.verticalPadding);\r\n\t\t\t\tminSize = minSize.with(maxSizeTop.width);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// top/bottom placement\r\n\t\tlet height = size.height;\r\n\t\tlet maxHeight = Math.max(maxSizeTop.height, maxSizeBottom.height);\r\n\t\tif (height > maxHeight) {\r\n\t\t\theight = maxHeight;\r\n\t\t}\r\n\t\tlet maxSize: dom.Dimension;\r\n\t\tif (height <= maxSizeTop.height) {\r\n\t\t\talignAtTop = true;\r\n\t\t\tmaxSize = maxSizeTop;\r\n\t\t} else {\r\n\t\t\talignAtTop = false;\r\n\t\t\tmaxSize = maxSizeBottom;\r\n\t\t}\r\n\r\n\t\tthis._applyTopLeft({ left, top: alignAtTop ? top : bottom - height });\r\n\t\tthis.getDomNode().style.position = 'fixed';\r\n\r\n\t\tthis._resizable.enableSashes(!alignAtTop, alignEast, alignAtTop, !alignEast);\r\n\r\n\t\tthis._resizable.minSize = minSize;\r\n\t\tthis._resizable.maxSize = maxSize;\r\n\t\tthis._resizable.layout(height, Math.min(maxSize.width, size.width));\r\n\t\tthis.widget.layout(this._resizable.size.width, this._resizable.size.height);\r\n\t}\r\n\r\n\tprivate _applyTopLeft(topLeft: TopLeftPosition): void {\r\n\t\tthis._topLeft = topLeft;\r\n\t\tthis.getDomNode().style.left = `${this._topLeft.left}px`;\r\n\t\tthis.getDomNode().style.top = `${this._topLeft.top}px`;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\n\r\nexport interface IProgressIndicator {\r\n\r\n\t/**\r\n\t * Show progress customized with the provided flags.\r\n\t */\r\n\tshow(infinite: true, delay?: number): IProgressRunner;\r\n\tshow(total: number, delay?: number): IProgressRunner;\r\n\r\n\t/**\r\n\t * Indicate progress for the duration of the provided promise. Progress will stop in\r\n\t * any case of promise completion, error or cancellation.\r\n\t */\r\n\tshowWhile(promise: Promise, delay?: number): Promise;\r\n}\r\n\r\nexport interface IProgressRunner {\r\n\ttotal(value: number): void;\r\n\tworked(value: number): void;\r\n\tdone(): void;\r\n}\r\n\r\nexport interface IProgress {\r\n\treport(item: T): void;\r\n}\r\n\r\nexport class Progress implements IProgress {\r\n\r\n\tstatic readonly None: IProgress = Object.freeze({ report() { } });\r\n\r\n\tprivate _value?: T;\r\n\r\n\tconstructor(private callback: (data: T) => void) { }\r\n\r\n\treport(item: T) {\r\n\t\tthis._value = item;\r\n\t\tthis.callback(this._value);\r\n\t}\r\n}\r\n\r\nexport const IEditorProgressService = createDecorator('editorProgressService');\r\n\r\n/**\r\n * A progress service that will report progress local to the editor triggered from.\r\n */\r\nexport interface IEditorProgressService extends IProgressIndicator {\r\n\r\n\treadonly _serviceBrand: undefined;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IQuickPick, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';\r\nimport { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\r\nimport { IQuickPickSeparator, IKeyMods, IQuickPickAcceptEvent } from 'vs/base/parts/quickinput/common/quickInput';\r\nimport { IQuickAccessProvider } from 'vs/platform/quickinput/common/quickAccess';\r\nimport { IDisposable, DisposableStore, Disposable, MutableDisposable } from 'vs/base/common/lifecycle';\r\nimport { timeout } from 'vs/base/common/async';\r\n\r\nexport enum TriggerAction {\r\n\r\n\t/**\r\n\t * Do nothing after the button was clicked.\r\n\t */\r\n\tNO_ACTION,\r\n\r\n\t/**\r\n\t * Close the picker.\r\n\t */\r\n\tCLOSE_PICKER,\r\n\r\n\t/**\r\n\t * Update the results of the picker.\r\n\t */\r\n\tREFRESH_PICKER,\r\n\r\n\t/**\r\n\t * Remove the item from the picker.\r\n\t */\r\n\tREMOVE_ITEM\r\n}\r\n\r\nexport interface IPickerQuickAccessItem extends IQuickPickItem {\r\n\r\n\t/**\r\n\t* A method that will be executed when the pick item is accepted from\r\n\t* the picker. The picker will close automatically before running this.\r\n\t*\r\n\t* @param keyMods the state of modifier keys when the item was accepted.\r\n\t* @param event the underlying event that caused the accept to trigger.\r\n\t*/\r\n\taccept?(keyMods: IKeyMods, event: IQuickPickAcceptEvent): void;\r\n\r\n\t/**\r\n\t * A method that will be executed when a button of the pick item was\r\n\t * clicked on.\r\n\t *\r\n\t * @param buttonIndex index of the button of the item that\r\n\t * was clicked.\r\n\t *\r\n\t * @param the state of modifier keys when the button was triggered.\r\n\t *\r\n\t * @returns a value that indicates what should happen after the trigger\r\n\t * which can be a `Promise` for long running operations.\r\n\t */\r\n\ttrigger?(buttonIndex: number, keyMods: IKeyMods): TriggerAction | Promise;\r\n}\r\n\r\nexport interface IPickerQuickAccessProviderOptions {\r\n\r\n\t/**\r\n\t * Enables support for opening picks in the background via gesture.\r\n\t */\r\n\tcanAcceptInBackground?: boolean;\r\n\r\n\t/**\r\n\t * Enables to show a pick entry when no results are returned from a search.\r\n\t */\r\n\tnoResultsPick?: T;\r\n}\r\n\r\nexport type Pick = T | IQuickPickSeparator;\r\nexport type PicksWithActive = { items: ReadonlyArray>, active?: T };\r\nexport type Picks = ReadonlyArray> | PicksWithActive;\r\nexport type FastAndSlowPicks = { picks: Picks, additionalPicks: Promise> };\r\n\r\nfunction isPicksWithActive(obj: unknown): obj is PicksWithActive {\r\n\tconst candidate = obj as PicksWithActive;\r\n\r\n\treturn Array.isArray(candidate.items);\r\n}\r\n\r\nfunction isFastAndSlowPicks(obj: unknown): obj is FastAndSlowPicks {\r\n\tconst candidate = obj as FastAndSlowPicks;\r\n\r\n\treturn !!candidate.picks && candidate.additionalPicks instanceof Promise;\r\n}\r\n\r\nexport abstract class PickerQuickAccessProvider extends Disposable implements IQuickAccessProvider {\r\n\r\n\tprivate static FAST_PICKS_RACE_DELAY = 200; // timeout before we accept fast results before slow results are present\r\n\r\n\tconstructor(private prefix: string, protected options?: IPickerQuickAccessProviderOptions) {\r\n\t\tsuper();\r\n\t}\r\n\r\n\tprovide(picker: IQuickPick, token: CancellationToken): IDisposable {\r\n\t\tconst disposables = new DisposableStore();\r\n\r\n\t\t// Apply options if any\r\n\t\tpicker.canAcceptInBackground = !!this.options?.canAcceptInBackground;\r\n\r\n\t\t// Disable filtering & sorting, we control the results\r\n\t\tpicker.matchOnLabel = picker.matchOnDescription = picker.matchOnDetail = picker.sortByLabel = false;\r\n\r\n\t\t// Set initial picks and update on type\r\n\t\tlet picksCts: CancellationTokenSource | undefined = undefined;\r\n\t\tconst picksDisposable = disposables.add(new MutableDisposable());\r\n\t\tconst updatePickerItems = async () => {\r\n\t\t\tconst picksDisposables = picksDisposable.value = new DisposableStore();\r\n\r\n\t\t\t// Cancel any previous ask for picks and busy\r\n\t\t\tpicksCts?.dispose(true);\r\n\t\t\tpicker.busy = false;\r\n\r\n\t\t\t// Create new cancellation source for this run\r\n\t\t\tpicksCts = new CancellationTokenSource(token);\r\n\r\n\t\t\t// Collect picks and support both long running and short or combined\r\n\t\t\tconst picksToken = picksCts.token;\r\n\t\t\tconst picksFilter = picker.value.substr(this.prefix.length).trim();\r\n\t\t\tconst providedPicks = this.getPicks(picksFilter, picksDisposables, picksToken);\r\n\r\n\t\t\tconst applyPicks = (picks: Picks, skipEmpty?: boolean): boolean => {\r\n\t\t\t\tlet items: ReadonlyArray>;\r\n\t\t\t\tlet activeItem: T | undefined = undefined;\r\n\r\n\t\t\t\tif (isPicksWithActive(picks)) {\r\n\t\t\t\t\titems = picks.items;\r\n\t\t\t\t\tactiveItem = picks.active;\r\n\t\t\t\t} else {\r\n\t\t\t\t\titems = picks;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (items.length === 0) {\r\n\t\t\t\t\tif (skipEmpty) {\r\n\t\t\t\t\t\treturn false;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (picksFilter.length > 0 && this.options?.noResultsPick) {\r\n\t\t\t\t\t\titems = [this.options.noResultsPick];\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tpicker.items = items;\r\n\t\t\t\tif (activeItem) {\r\n\t\t\t\t\tpicker.activeItems = [activeItem];\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn true;\r\n\t\t\t};\r\n\r\n\t\t\t// No Picks\r\n\t\t\tif (providedPicks === null) {\r\n\t\t\t\t// Ignore\r\n\t\t\t}\r\n\r\n\t\t\t// Fast and Slow Picks\r\n\t\t\telse if (isFastAndSlowPicks(providedPicks)) {\r\n\t\t\t\tlet fastPicksApplied = false;\r\n\t\t\t\tlet slowPicksApplied = false;\r\n\r\n\t\t\t\tawait Promise.all([\r\n\r\n\t\t\t\t\t// Fast Picks: to reduce amount of flicker, we race against\r\n\t\t\t\t\t// the slow picks over 500ms and then set the fast picks.\r\n\t\t\t\t\t// If the slow picks are faster, we reduce the flicker by\r\n\t\t\t\t\t// only setting the items once.\r\n\t\t\t\t\t(async () => {\r\n\t\t\t\t\t\tawait timeout(PickerQuickAccessProvider.FAST_PICKS_RACE_DELAY);\r\n\t\t\t\t\t\tif (picksToken.isCancellationRequested) {\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif (!slowPicksApplied) {\r\n\t\t\t\t\t\t\tfastPicksApplied = applyPicks(providedPicks.picks, true /* skip over empty to reduce flicker */);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t})(),\r\n\r\n\t\t\t\t\t// Slow Picks: we await the slow picks and then set them at\r\n\t\t\t\t\t// once together with the fast picks, but only if we actually\r\n\t\t\t\t\t// have additional results.\r\n\t\t\t\t\t(async () => {\r\n\t\t\t\t\t\tpicker.busy = true;\r\n\t\t\t\t\t\ttry {\r\n\t\t\t\t\t\t\tconst awaitedAdditionalPicks = await providedPicks.additionalPicks;\r\n\t\t\t\t\t\t\tif (picksToken.isCancellationRequested) {\r\n\t\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tlet picks: ReadonlyArray>;\r\n\t\t\t\t\t\t\tlet activePick: Pick | undefined = undefined;\r\n\t\t\t\t\t\t\tif (isPicksWithActive(providedPicks.picks)) {\r\n\t\t\t\t\t\t\t\tpicks = providedPicks.picks.items;\r\n\t\t\t\t\t\t\t\tactivePick = providedPicks.picks.active;\r\n\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\tpicks = providedPicks.picks;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tlet additionalPicks: ReadonlyArray>;\r\n\t\t\t\t\t\t\tlet additionalActivePick: Pick | undefined = undefined;\r\n\t\t\t\t\t\t\tif (isPicksWithActive(awaitedAdditionalPicks)) {\r\n\t\t\t\t\t\t\t\tadditionalPicks = awaitedAdditionalPicks.items;\r\n\t\t\t\t\t\t\t\tadditionalActivePick = awaitedAdditionalPicks.active;\r\n\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\tadditionalPicks = awaitedAdditionalPicks;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tif (additionalPicks.length > 0 || !fastPicksApplied) {\r\n\t\t\t\t\t\t\t\t// If we do not have any activePick or additionalActivePick\r\n\t\t\t\t\t\t\t\t// we try to preserve the currently active pick from the\r\n\t\t\t\t\t\t\t\t// fast results. This fixes an issue where the user might\r\n\t\t\t\t\t\t\t\t// have made a pick active before the additional results\r\n\t\t\t\t\t\t\t\t// kick in.\r\n\t\t\t\t\t\t\t\t// See https://github.com/microsoft/vscode/issues/102480\r\n\t\t\t\t\t\t\t\tlet fallbackActivePick: Pick | undefined = undefined;\r\n\t\t\t\t\t\t\t\tif (!activePick && !additionalActivePick) {\r\n\t\t\t\t\t\t\t\t\tconst fallbackActivePickCandidate = picker.activeItems[0];\r\n\t\t\t\t\t\t\t\t\tif (fallbackActivePickCandidate && picks.indexOf(fallbackActivePickCandidate) !== -1) {\r\n\t\t\t\t\t\t\t\t\t\tfallbackActivePick = fallbackActivePickCandidate;\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\tapplyPicks({\r\n\t\t\t\t\t\t\t\t\titems: [...picks, ...additionalPicks],\r\n\t\t\t\t\t\t\t\t\tactive: activePick || additionalActivePick || fallbackActivePick\r\n\t\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t} finally {\r\n\t\t\t\t\t\t\tif (!picksToken.isCancellationRequested) {\r\n\t\t\t\t\t\t\t\tpicker.busy = false;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tslowPicksApplied = true;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t})()\r\n\t\t\t\t]);\r\n\t\t\t}\r\n\r\n\t\t\t// Fast Picks\r\n\t\t\telse if (!(providedPicks instanceof Promise)) {\r\n\t\t\t\tapplyPicks(providedPicks);\r\n\t\t\t}\r\n\r\n\t\t\t// Slow Picks\r\n\t\t\telse {\r\n\t\t\t\tpicker.busy = true;\r\n\t\t\t\ttry {\r\n\t\t\t\t\tconst awaitedPicks = await providedPicks;\r\n\t\t\t\t\tif (picksToken.isCancellationRequested) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tapplyPicks(awaitedPicks);\r\n\t\t\t\t} finally {\r\n\t\t\t\t\tif (!picksToken.isCancellationRequested) {\r\n\t\t\t\t\t\tpicker.busy = false;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\t\tdisposables.add(picker.onDidChangeValue(() => updatePickerItems()));\r\n\t\tupdatePickerItems();\r\n\r\n\t\t// Accept the pick on accept and hide picker\r\n\t\tdisposables.add(picker.onDidAccept(event => {\r\n\t\t\tconst [item] = picker.selectedItems;\r\n\t\t\tif (typeof item?.accept === 'function') {\r\n\t\t\t\tif (!event.inBackground) {\r\n\t\t\t\t\tpicker.hide(); // hide picker unless we accept in background\r\n\t\t\t\t}\r\n\r\n\t\t\t\titem.accept(picker.keyMods, event);\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\t// Trigger the pick with button index if button triggered\r\n\t\tdisposables.add(picker.onDidTriggerItemButton(async ({ button, item }) => {\r\n\t\t\tif (typeof item.trigger === 'function') {\r\n\t\t\t\tconst buttonIndex = item.buttons?.indexOf(button) ?? -1;\r\n\t\t\t\tif (buttonIndex >= 0) {\r\n\t\t\t\t\tconst result = item.trigger(buttonIndex, picker.keyMods);\r\n\t\t\t\t\tconst action = (typeof result === 'number') ? result : await result;\r\n\r\n\t\t\t\t\tif (token.isCancellationRequested) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tswitch (action) {\r\n\t\t\t\t\t\tcase TriggerAction.NO_ACTION:\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\tcase TriggerAction.CLOSE_PICKER:\r\n\t\t\t\t\t\t\tpicker.hide();\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\tcase TriggerAction.REFRESH_PICKER:\r\n\t\t\t\t\t\t\tupdatePickerItems();\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\tcase TriggerAction.REMOVE_ITEM:\r\n\t\t\t\t\t\t\tconst index = picker.items.indexOf(item);\r\n\t\t\t\t\t\t\tif (index !== -1) {\r\n\t\t\t\t\t\t\t\tconst items = picker.items.slice();\r\n\t\t\t\t\t\t\t\titems.splice(index, 1);\r\n\t\t\t\t\t\t\t\tpicker.items = items;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\treturn disposables;\r\n\t}\r\n\r\n\t/**\r\n\t * Returns an array of picks and separators as needed. If the picks are resolved\r\n\t * long running, the provided cancellation token should be used to cancel the\r\n\t * operation when the token signals this.\r\n\t *\r\n\t * The implementor is responsible for filtering and sorting the picks given the\r\n\t * provided `filter`.\r\n\t *\r\n\t * @param filter a filter to apply to the picks.\r\n\t * @param disposables can be used to register disposables that should be cleaned\r\n\t * up when the picker closes.\r\n\t * @param token for long running tasks, implementors need to check on cancellation\r\n\t * through this token.\r\n\t * @returns the picks either directly, as promise or combined fast and slow results.\r\n\t * Pickers can return `null` to signal that no change in picks is needed.\r\n\t */\r\n\tprotected abstract getPicks(filter: string, disposables: DisposableStore, token: CancellationToken): Picks | Promise> | FastAndSlowPicks | null;\r\n}\r\n","\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { IQuickPickItem, IPickOptions, IQuickPick, QuickPickInput } from 'vs/base/parts/quickinput/common/quickInput';\r\nimport { IQuickAccessController } from 'vs/platform/quickinput/common/quickAccess';\r\n\r\nexport * from 'vs/base/parts/quickinput/common/quickInput';\r\n\r\nexport const IQuickInputService = createDecorator('quickInputService');\r\n\r\nexport type Omit = Pick>;\r\n\r\nexport interface IQuickInputService {\r\n\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\t/**\r\n\t * Provides access to the quick access providers.\r\n\t */\r\n\treadonly quickAccess: IQuickAccessController;\r\n\r\n\t/**\r\n\t * Opens the quick input box for selecting items and returns a promise\r\n\t * with the user selected item(s) if any.\r\n\t */\r\n\tpick(picks: Promise[]> | QuickPickInput[], options?: IPickOptions & { canPickMany: true }, token?: CancellationToken): Promise;\r\n\tpick(picks: Promise[]> | QuickPickInput[], options?: IPickOptions & { canPickMany: false }, token?: CancellationToken): Promise;\r\n\tpick(picks: Promise[]> | QuickPickInput[], options?: Omit, 'canPickMany'>, token?: CancellationToken): Promise;\r\n\r\n\t/**\r\n\t * Provides raw access to the quick pick controller.\r\n\t */\r\n\tcreateQuickPick(): IQuickPick;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as Types from 'vs/base/common/types';\r\nimport * as Assert from 'vs/base/common/assert';\r\n\r\nexport interface IRegistry {\r\n\r\n\t/**\r\n\t * Adds the extension functions and properties defined by data to the\r\n\t * platform. The provided id must be unique.\r\n\t * @param id a unique identifier\r\n\t * @param data a contribution\r\n\t */\r\n\tadd(id: string, data: any): void;\r\n\r\n\t/**\r\n\t * Returns the extension functions and properties defined by the specified key or null.\r\n\t * @param id an extension identifier\r\n\t */\r\n\tas(id: string): T;\r\n}\r\n\r\nclass RegistryImpl implements IRegistry {\r\n\r\n\tprivate readonly data = new Map();\r\n\r\n\tpublic add(id: string, data: any): void {\r\n\t\tAssert.ok(Types.isString(id));\r\n\t\tAssert.ok(Types.isObject(data));\r\n\t\tAssert.ok(!this.data.has(id), 'There is already an extension with this id');\r\n\r\n\t\tthis.data.set(id, data);\r\n\t}\r\n\r\n\tpublic as(id: string): any {\r\n\t\treturn this.data.get(id) || null;\r\n\t}\r\n}\r\n\r\nexport const Registry: IRegistry = new RegistryImpl();\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { LanguageId, LanguageIdentifier } from 'vs/editor/common/modes';\r\nimport { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';\r\nimport { ILanguageExtensionPoint } from 'vs/editor/common/services/modeService';\r\nimport { Registry } from 'vs/platform/registry/common/platform';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\n\r\n// Define extension point ids\r\nexport const Extensions = {\r\n\tModesRegistry: 'editor.modesRegistry'\r\n};\r\n\r\nexport class EditorModesRegistry {\r\n\r\n\tprivate readonly _languages: ILanguageExtensionPoint[];\r\n\tprivate _dynamicLanguages: ILanguageExtensionPoint[];\r\n\r\n\tprivate readonly _onDidChangeLanguages = new Emitter();\r\n\tpublic readonly onDidChangeLanguages: Event = this._onDidChangeLanguages.event;\r\n\r\n\tconstructor() {\r\n\t\tthis._languages = [];\r\n\t\tthis._dynamicLanguages = [];\r\n\t}\r\n\r\n\t// --- languages\r\n\r\n\tpublic registerLanguage(def: ILanguageExtensionPoint): IDisposable {\r\n\t\tthis._languages.push(def);\r\n\t\tthis._onDidChangeLanguages.fire(undefined);\r\n\t\treturn {\r\n\t\t\tdispose: () => {\r\n\t\t\t\tfor (let i = 0, len = this._languages.length; i < len; i++) {\r\n\t\t\t\t\tif (this._languages[i] === def) {\r\n\t\t\t\t\t\tthis._languages.splice(i, 1);\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\tpublic getLanguages(): ILanguageExtensionPoint[] {\r\n\t\treturn ([]).concat(this._languages).concat(this._dynamicLanguages);\r\n\t}\r\n}\r\n\r\nexport const ModesRegistry = new EditorModesRegistry();\r\nRegistry.add(Extensions.ModesRegistry, ModesRegistry);\r\n\r\nexport const PLAINTEXT_MODE_ID = 'plaintext';\r\nexport const PLAINTEXT_LANGUAGE_IDENTIFIER = new LanguageIdentifier(PLAINTEXT_MODE_ID, LanguageId.PlainText);\r\n\r\nModesRegistry.registerLanguage({\r\n\tid: PLAINTEXT_MODE_ID,\r\n\textensions: ['.txt'],\r\n\taliases: [nls.localize('plainText.alias', \"Plain Text\"), 'text'],\r\n\tmimetypes: ['text/plain']\r\n});\r\nLanguageConfigurationRegistry.register(PLAINTEXT_LANGUAGE_IDENTIFIER, {\r\n\tbrackets: [\r\n\t\t['(', ')'],\r\n\t\t['[', ']'],\r\n\t\t['{', '}'],\r\n\t],\r\n\tsurroundingPairs: [\r\n\t\t{ open: '{', close: '}' },\r\n\t\t{ open: '[', close: ']' },\r\n\t\t{ open: '(', close: ')' },\r\n\t\t{ open: '<', close: '>' },\r\n\t\t{ open: '\\\"', close: '\\\"' },\r\n\t\t{ open: '\\'', close: '\\'' },\r\n\t\t{ open: '`', close: '`' },\r\n\t],\r\n\tfolding: {\r\n\t\toffSide: true\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Schemas } from 'vs/base/common/network';\r\nimport { DataUri, basenameOrAuthority } from 'vs/base/common/resources';\r\nimport { URI as uri } from 'vs/base/common/uri';\r\nimport { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry';\r\nimport { IModeService } from 'vs/editor/common/services/modeService';\r\nimport { IModelService } from 'vs/editor/common/services/modelService';\r\nimport { FileKind } from 'vs/platform/files/common/files';\r\n\r\nexport function getIconClasses(modelService: IModelService, modeService: IModeService, resource: uri | undefined, fileKind?: FileKind): string[] {\r\n\r\n\t// we always set these base classes even if we do not have a path\r\n\tconst classes = fileKind === FileKind.ROOT_FOLDER ? ['rootfolder-icon'] : fileKind === FileKind.FOLDER ? ['folder-icon'] : ['file-icon'];\r\n\tif (resource) {\r\n\r\n\t\t// Get the path and name of the resource. For data-URIs, we need to parse specially\r\n\t\tlet name: string | undefined;\r\n\t\tif (resource.scheme === Schemas.data) {\r\n\t\t\tconst metadata = DataUri.parseMetaData(resource);\r\n\t\t\tname = metadata.get(DataUri.META_DATA_LABEL);\r\n\t\t} else {\r\n\t\t\tname = cssEscape(basenameOrAuthority(resource).toLowerCase());\r\n\t\t}\r\n\r\n\t\t// Folders\r\n\t\tif (fileKind === FileKind.FOLDER) {\r\n\t\t\tclasses.push(`${name}-name-folder-icon`);\r\n\t\t}\r\n\r\n\t\t// Files\r\n\t\telse {\r\n\r\n\t\t\t// Name & Extension(s)\r\n\t\t\tif (name) {\r\n\t\t\t\tclasses.push(`${name}-name-file-icon`);\r\n\t\t\t\tconst dotSegments = name.split('.');\r\n\t\t\t\tfor (let i = 1; i < dotSegments.length; i++) {\r\n\t\t\t\t\tclasses.push(`${dotSegments.slice(i).join('.')}-ext-file-icon`); // add each combination of all found extensions if more than one\r\n\t\t\t\t}\r\n\t\t\t\tclasses.push(`ext-file-icon`); // extra segment to increase file-ext score\r\n\t\t\t}\r\n\r\n\t\t\t// Detected Mode\r\n\t\t\tconst detectedModeId = detectModeId(modelService, modeService, resource);\r\n\t\t\tif (detectedModeId) {\r\n\t\t\t\tclasses.push(`${cssEscape(detectedModeId)}-lang-file-icon`);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn classes;\r\n}\r\n\r\nexport function detectModeId(modelService: IModelService, modeService: IModeService, resource: uri): string | null {\r\n\tif (!resource) {\r\n\t\treturn null; // we need a resource at least\r\n\t}\r\n\r\n\tlet modeId: string | null = null;\r\n\r\n\t// Data URI: check for encoded metadata\r\n\tif (resource.scheme === Schemas.data) {\r\n\t\tconst metadata = DataUri.parseMetaData(resource);\r\n\t\tconst mime = metadata.get(DataUri.META_DATA_MIME);\r\n\r\n\t\tif (mime) {\r\n\t\t\tmodeId = modeService.getModeId(mime);\r\n\t\t}\r\n\t}\r\n\r\n\t// Any other URI: check for model if existing\r\n\telse {\r\n\t\tconst model = modelService.getModel(resource);\r\n\t\tif (model) {\r\n\t\t\tmodeId = model.getModeId();\r\n\t\t}\r\n\t}\r\n\r\n\t// only take if the mode is specific (aka no just plain text)\r\n\tif (modeId && modeId !== PLAINTEXT_MODE_ID) {\r\n\t\treturn modeId;\r\n\t}\r\n\r\n\t// otherwise fallback to path based detection\r\n\treturn modeService.getModeIdByFilepathOrFirstLine(resource);\r\n}\r\n\r\nexport function cssEscape(str: string): string {\r\n\treturn str.replace(/[\\11\\12\\14\\15\\40]/g, '/'); // HTML class names can not contain certain whitespace characters, use / instead, which doesn't exist in file names.\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IJSONSchema } from 'vs/base/common/jsonSchema';\r\nimport * as platform from 'vs/platform/registry/common/platform';\r\nimport { Emitter } from 'vs/base/common/event';\r\n\r\nexport const Extensions = {\r\n\tJSONContribution: 'base.contributions.json'\r\n};\r\n\r\nexport interface IJSONContributionRegistry {\r\n\r\n\t/**\r\n\t * Register a schema to the registry.\r\n\t */\r\n\tregisterSchema(uri: string, unresolvedSchemaContent: IJSONSchema): void;\r\n\r\n\r\n\t/**\r\n\t * Notifies all listeners that the content of the given schema has changed.\r\n\t * @param uri The id of the schema\r\n\t */\r\n\tnotifySchemaChanged(uri: string): void;\r\n}\r\n\r\n\r\n\r\nfunction normalizeId(id: string) {\r\n\tif (id.length > 0 && id.charAt(id.length - 1) === '#') {\r\n\t\treturn id.substring(0, id.length - 1);\r\n\t}\r\n\treturn id;\r\n}\r\n\r\n\r\n\r\nclass JSONContributionRegistry implements IJSONContributionRegistry {\r\n\r\n\tprivate schemasById: { [id: string]: IJSONSchema };\r\n\r\n\tprivate readonly _onDidChangeSchema = new Emitter();\r\n\r\n\tconstructor() {\r\n\t\tthis.schemasById = {};\r\n\t}\r\n\r\n\tpublic registerSchema(uri: string, unresolvedSchemaContent: IJSONSchema): void {\r\n\t\tthis.schemasById[normalizeId(uri)] = unresolvedSchemaContent;\r\n\t\tthis._onDidChangeSchema.fire(uri);\r\n\t}\r\n\r\n\tpublic notifySchemaChanged(uri: string): void {\r\n\t\tthis._onDidChangeSchema.fire(uri);\r\n\t}\r\n\r\n}\r\n\r\nconst jsonContributionRegistry = new JSONContributionRegistry();\r\nplatform.Registry.add(Extensions.JSONContribution, jsonContributionRegistry);","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { Emitter } from 'vs/base/common/event';\r\nimport { IJSONSchema } from 'vs/base/common/jsonSchema';\r\nimport { Registry } from 'vs/platform/registry/common/platform';\r\nimport * as types from 'vs/base/common/types';\r\nimport { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';\r\nimport { IStringDictionary } from 'vs/base/common/collections';\r\n\r\nexport const Extensions = {\r\n\tConfiguration: 'base.contributions.configuration'\r\n};\r\n\r\nexport interface IConfigurationRegistry {\r\n\r\n\t/**\r\n\t * Register a configuration to the registry.\r\n\t */\r\n\tregisterConfiguration(configuration: IConfigurationNode): void;\r\n\r\n\t/**\r\n\t * Returns all configurations settings of all configuration nodes contributed to this registry.\r\n\t */\r\n\tgetConfigurationProperties(): { [qualifiedKey: string]: IConfigurationPropertySchema };\r\n\r\n\t/**\r\n\t * Register the identifiers for editor configurations\r\n\t */\r\n\tregisterOverrideIdentifiers(identifiers: string[]): void;\r\n}\r\n\r\nexport const enum ConfigurationScope {\r\n\t/**\r\n\t * Application specific configuration, which can be configured only in local user settings.\r\n\t */\r\n\tAPPLICATION = 1,\r\n\t/**\r\n\t * Machine specific configuration, which can be configured only in local and remote user settings.\r\n\t */\r\n\tMACHINE,\r\n\t/**\r\n\t * Window specific configuration, which can be configured in the user or workspace settings.\r\n\t */\r\n\tWINDOW,\r\n\t/**\r\n\t * Resource specific configuration, which can be configured in the user, workspace or folder settings.\r\n\t */\r\n\tRESOURCE,\r\n\t/**\r\n\t * Resource specific configuration that can be configured in language specific settings\r\n\t */\r\n\tLANGUAGE_OVERRIDABLE,\r\n\t/**\r\n\t * Machine specific configuration that can also be configured in workspace or folder settings.\r\n\t */\r\n\tMACHINE_OVERRIDABLE,\r\n}\r\n\r\nexport interface IConfigurationPropertySchema extends IJSONSchema {\r\n\tscope?: ConfigurationScope;\r\n\tincluded?: boolean;\r\n}\r\n\r\nexport interface IConfigurationNode {\r\n\tid?: string;\r\n\torder?: number;\r\n\ttype?: string | string[];\r\n\ttitle?: string;\r\n\tproperties?: { [path: string]: IConfigurationPropertySchema; };\r\n\tallOf?: IConfigurationNode[];\r\n\tscope?: ConfigurationScope;\r\n}\r\n\r\ntype SettingProperties = { [key: string]: any };\r\n\r\nexport const allSettings: { properties: SettingProperties, patternProperties: SettingProperties } = { properties: {}, patternProperties: {} };\r\nexport const applicationSettings: { properties: SettingProperties, patternProperties: SettingProperties } = { properties: {}, patternProperties: {} };\r\nexport const machineSettings: { properties: SettingProperties, patternProperties: SettingProperties } = { properties: {}, patternProperties: {} };\r\nexport const machineOverridableSettings: { properties: SettingProperties, patternProperties: SettingProperties } = { properties: {}, patternProperties: {} };\r\nexport const windowSettings: { properties: SettingProperties, patternProperties: SettingProperties } = { properties: {}, patternProperties: {} };\r\nexport const resourceSettings: { properties: SettingProperties, patternProperties: SettingProperties } = { properties: {}, patternProperties: {} };\r\n\r\nexport const resourceLanguageSettingsSchemaId = 'vscode://schemas/settings/resourceLanguage';\r\n\r\nconst contributionRegistry = Registry.as(JSONExtensions.JSONContribution);\r\n\r\nclass ConfigurationRegistry implements IConfigurationRegistry {\r\n\r\n\tprivate readonly defaultValues: IStringDictionary;\r\n\tprivate readonly defaultLanguageConfigurationOverridesNode: IConfigurationNode;\r\n\tprivate readonly configurationContributors: IConfigurationNode[];\r\n\tprivate readonly configurationProperties: { [qualifiedKey: string]: IJSONSchema };\r\n\tprivate readonly excludedConfigurationProperties: { [qualifiedKey: string]: IJSONSchema };\r\n\tprivate readonly resourceLanguageSettingsSchema: IJSONSchema;\r\n\tprivate readonly overrideIdentifiers = new Set();\r\n\r\n\tprivate readonly _onDidSchemaChange = new Emitter();\r\n\r\n\tprivate readonly _onDidUpdateConfiguration: Emitter = new Emitter();\r\n\r\n\tconstructor() {\r\n\t\tthis.defaultValues = {};\r\n\t\tthis.defaultLanguageConfigurationOverridesNode = {\r\n\t\t\tid: 'defaultOverrides',\r\n\t\t\ttitle: nls.localize('defaultLanguageConfigurationOverrides.title', \"Default Language Configuration Overrides\"),\r\n\t\t\tproperties: {}\r\n\t\t};\r\n\t\tthis.configurationContributors = [this.defaultLanguageConfigurationOverridesNode];\r\n\t\tthis.resourceLanguageSettingsSchema = { properties: {}, patternProperties: {}, additionalProperties: false, errorMessage: 'Unknown editor configuration setting', allowTrailingCommas: true, allowComments: true };\r\n\t\tthis.configurationProperties = {};\r\n\t\tthis.excludedConfigurationProperties = {};\r\n\r\n\t\tcontributionRegistry.registerSchema(resourceLanguageSettingsSchemaId, this.resourceLanguageSettingsSchema);\r\n\t}\r\n\r\n\tpublic registerConfiguration(configuration: IConfigurationNode, validate: boolean = true): void {\r\n\t\tthis.registerConfigurations([configuration], validate);\r\n\t}\r\n\r\n\tpublic registerConfigurations(configurations: IConfigurationNode[], validate: boolean = true): void {\r\n\t\tconst properties: string[] = [];\r\n\t\tconfigurations.forEach(configuration => {\r\n\t\t\tproperties.push(...this.validateAndRegisterProperties(configuration, validate)); // fills in defaults\r\n\t\t\tthis.configurationContributors.push(configuration);\r\n\t\t\tthis.registerJSONConfiguration(configuration);\r\n\t\t});\r\n\r\n\t\tcontributionRegistry.registerSchema(resourceLanguageSettingsSchemaId, this.resourceLanguageSettingsSchema);\r\n\t\tthis._onDidSchemaChange.fire();\r\n\t\tthis._onDidUpdateConfiguration.fire(properties);\r\n\t}\r\n\r\n\tpublic registerOverrideIdentifiers(overrideIdentifiers: string[]): void {\r\n\t\tfor (const overrideIdentifier of overrideIdentifiers) {\r\n\t\t\tthis.overrideIdentifiers.add(overrideIdentifier);\r\n\t\t}\r\n\t\tthis.updateOverridePropertyPatternKey();\r\n\t}\r\n\r\n\tprivate validateAndRegisterProperties(configuration: IConfigurationNode, validate: boolean = true, scope: ConfigurationScope = ConfigurationScope.WINDOW): string[] {\r\n\t\tscope = types.isUndefinedOrNull(configuration.scope) ? scope : configuration.scope;\r\n\t\tlet propertyKeys: string[] = [];\r\n\t\tlet properties = configuration.properties;\r\n\t\tif (properties) {\r\n\t\t\tfor (let key in properties) {\r\n\t\t\t\tif (validate && validateProperty(key)) {\r\n\t\t\t\t\tdelete properties[key];\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst property = properties[key];\r\n\r\n\t\t\t\t// update default value\r\n\t\t\t\tthis.updatePropertyDefaultValue(key, property);\r\n\r\n\t\t\t\t// update scope\r\n\t\t\t\tif (OVERRIDE_PROPERTY_PATTERN.test(key)) {\r\n\t\t\t\t\tproperty.scope = undefined; // No scope for overridable properties `[${identifier}]`\r\n\t\t\t\t} else {\r\n\t\t\t\t\tproperty.scope = types.isUndefinedOrNull(property.scope) ? scope : property.scope;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Add to properties maps\r\n\t\t\t\t// Property is included by default if 'included' is unspecified\r\n\t\t\t\tif (properties[key].hasOwnProperty('included') && !properties[key].included) {\r\n\t\t\t\t\tthis.excludedConfigurationProperties[key] = properties[key];\r\n\t\t\t\t\tdelete properties[key];\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis.configurationProperties[key] = properties[key];\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (!properties[key].deprecationMessage && properties[key].markdownDeprecationMessage) {\r\n\t\t\t\t\t// If not set, default deprecationMessage to the markdown source\r\n\t\t\t\t\tproperties[key].deprecationMessage = properties[key].markdownDeprecationMessage;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tpropertyKeys.push(key);\r\n\t\t\t}\r\n\t\t}\r\n\t\tlet subNodes = configuration.allOf;\r\n\t\tif (subNodes) {\r\n\t\t\tfor (let node of subNodes) {\r\n\t\t\t\tpropertyKeys.push(...this.validateAndRegisterProperties(node, validate, scope));\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn propertyKeys;\r\n\t}\r\n\r\n\tgetConfigurationProperties(): { [qualifiedKey: string]: IConfigurationPropertySchema } {\r\n\t\treturn this.configurationProperties;\r\n\t}\r\n\r\n\tprivate registerJSONConfiguration(configuration: IConfigurationNode) {\r\n\t\tconst register = (configuration: IConfigurationNode) => {\r\n\t\t\tlet properties = configuration.properties;\r\n\t\t\tif (properties) {\r\n\t\t\t\tfor (const key in properties) {\r\n\t\t\t\t\tthis.updateSchema(key, properties[key]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tlet subNodes = configuration.allOf;\r\n\t\t\tif (subNodes) {\r\n\t\t\t\tsubNodes.forEach(register);\r\n\t\t\t}\r\n\t\t};\r\n\t\tregister(configuration);\r\n\t}\r\n\r\n\tprivate updateSchema(key: string, property: IConfigurationPropertySchema): void {\r\n\t\tallSettings.properties[key] = property;\r\n\t\tswitch (property.scope) {\r\n\t\t\tcase ConfigurationScope.APPLICATION:\r\n\t\t\t\tapplicationSettings.properties[key] = property;\r\n\t\t\t\tbreak;\r\n\t\t\tcase ConfigurationScope.MACHINE:\r\n\t\t\t\tmachineSettings.properties[key] = property;\r\n\t\t\t\tbreak;\r\n\t\t\tcase ConfigurationScope.MACHINE_OVERRIDABLE:\r\n\t\t\t\tmachineOverridableSettings.properties[key] = property;\r\n\t\t\t\tbreak;\r\n\t\t\tcase ConfigurationScope.WINDOW:\r\n\t\t\t\twindowSettings.properties[key] = property;\r\n\t\t\t\tbreak;\r\n\t\t\tcase ConfigurationScope.RESOURCE:\r\n\t\t\t\tresourceSettings.properties[key] = property;\r\n\t\t\t\tbreak;\r\n\t\t\tcase ConfigurationScope.LANGUAGE_OVERRIDABLE:\r\n\t\t\t\tresourceSettings.properties[key] = property;\r\n\t\t\t\tthis.resourceLanguageSettingsSchema.properties![key] = property;\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate updateOverridePropertyPatternKey(): void {\r\n\t\tfor (const overrideIdentifier of this.overrideIdentifiers.values()) {\r\n\t\t\tconst overrideIdentifierProperty = `[${overrideIdentifier}]`;\r\n\t\t\tconst resourceLanguagePropertiesSchema: IJSONSchema = {\r\n\t\t\t\ttype: 'object',\r\n\t\t\t\tdescription: nls.localize('overrideSettings.defaultDescription', \"Configure editor settings to be overridden for a language.\"),\r\n\t\t\t\terrorMessage: nls.localize('overrideSettings.errorMessage', \"This setting does not support per-language configuration.\"),\r\n\t\t\t\t$ref: resourceLanguageSettingsSchemaId,\r\n\t\t\t};\r\n\t\t\tthis.updatePropertyDefaultValue(overrideIdentifierProperty, resourceLanguagePropertiesSchema);\r\n\t\t\tallSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;\r\n\t\t\tapplicationSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;\r\n\t\t\tmachineSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;\r\n\t\t\tmachineOverridableSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;\r\n\t\t\twindowSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;\r\n\t\t\tresourceSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;\r\n\t\t}\r\n\t\tthis._onDidSchemaChange.fire();\r\n\t}\r\n\r\n\tprivate updatePropertyDefaultValue(key: string, property: IConfigurationPropertySchema): void {\r\n\t\tlet defaultValue = this.defaultValues[key];\r\n\t\tif (types.isUndefined(defaultValue)) {\r\n\t\t\tdefaultValue = property.default;\r\n\t\t}\r\n\t\tif (types.isUndefined(defaultValue)) {\r\n\t\t\tdefaultValue = getDefaultValue(property.type);\r\n\t\t}\r\n\t\tproperty.default = defaultValue;\r\n\t}\r\n}\r\n\r\nconst OVERRIDE_PROPERTY = '\\\\[.*\\\\]$';\r\nexport const OVERRIDE_PROPERTY_PATTERN = new RegExp(OVERRIDE_PROPERTY);\r\n\r\nexport function overrideIdentifierFromKey(key: string): string {\r\n\treturn key.substring(1, key.length - 1);\r\n}\r\n\r\nexport function getDefaultValue(type: string | string[] | undefined): any {\r\n\tconst t = Array.isArray(type) ? (type)[0] : type;\r\n\tswitch (t) {\r\n\t\tcase 'boolean':\r\n\t\t\treturn false;\r\n\t\tcase 'integer':\r\n\t\tcase 'number':\r\n\t\t\treturn 0;\r\n\t\tcase 'string':\r\n\t\t\treturn '';\r\n\t\tcase 'array':\r\n\t\t\treturn [];\r\n\t\tcase 'object':\r\n\t\t\treturn {};\r\n\t\tdefault:\r\n\t\t\treturn null;\r\n\t}\r\n}\r\n\r\n\r\nconst configurationRegistry = new ConfigurationRegistry();\r\nRegistry.add(Extensions.Configuration, configurationRegistry);\r\n\r\nexport function validateProperty(property: string): string | null {\r\n\tif (!property.trim()) {\r\n\t\treturn nls.localize('config.property.empty', \"Cannot register an empty property\");\r\n\t}\r\n\tif (OVERRIDE_PROPERTY_PATTERN.test(property)) {\r\n\t\treturn nls.localize('config.property.languageDefault', \"Cannot register '{0}'. This matches property pattern '\\\\\\\\[.*\\\\\\\\]$' for describing language specific editor settings. Use 'configurationDefaults' contribution.\", property);\r\n\t}\r\n\tif (configurationRegistry.getConfigurationProperties()[property] !== undefined) {\r\n\t\treturn nls.localize('config.property.duplicate', \"Cannot register '{0}'. This property is already registered.\", property);\r\n\t}\r\n\treturn null;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport * as objects from 'vs/base/common/objects';\r\nimport * as arrays from 'vs/base/common/arrays';\r\nimport { IEditorOptions, editorOptionsRegistry, ValidatedEditorOptions, IEnvironmentalOptions, IComputedEditorOptions, ConfigurationChangedEvent, EDITOR_MODEL_DEFAULTS, EditorOption, FindComputedEditorOptionValueById, ComputeOptionsMemory } from 'vs/editor/common/config/editorOptions';\r\nimport { EditorZoom } from 'vs/editor/common/config/editorZoom';\r\nimport { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo';\r\nimport { IConfiguration, IDimension } from 'vs/editor/common/editorCommon';\r\nimport { ConfigurationScope, Extensions, IConfigurationNode, IConfigurationRegistry, IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry';\r\nimport { Registry } from 'vs/platform/registry/common/platform';\r\nimport { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';\r\nimport { forEach } from 'vs/base/common/collections';\r\n\r\n/**\r\n * Control what pressing Tab does.\r\n * If it is false, pressing Tab or Shift-Tab will be handled by the editor.\r\n * If it is true, pressing Tab or Shift-Tab will move the browser focus.\r\n * Defaults to false.\r\n */\r\nexport interface ITabFocus {\r\n\tonDidChangeTabFocus: Event;\r\n\tgetTabFocusMode(): boolean;\r\n\tsetTabFocusMode(tabFocusMode: boolean): void;\r\n}\r\n\r\nexport const TabFocus: ITabFocus = new class implements ITabFocus {\r\n\tprivate _tabFocus: boolean = false;\r\n\r\n\tprivate readonly _onDidChangeTabFocus = new Emitter();\r\n\tpublic readonly onDidChangeTabFocus: Event = this._onDidChangeTabFocus.event;\r\n\r\n\tpublic getTabFocusMode(): boolean {\r\n\t\treturn this._tabFocus;\r\n\t}\r\n\r\n\tpublic setTabFocusMode(tabFocusMode: boolean): void {\r\n\t\tif (this._tabFocus === tabFocusMode) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._tabFocus = tabFocusMode;\r\n\t\tthis._onDidChangeTabFocus.fire(this._tabFocus);\r\n\t}\r\n};\r\n\r\nexport interface IEnvConfiguration {\r\n\textraEditorClassName: string;\r\n\touterWidth: number;\r\n\touterHeight: number;\r\n\temptySelectionClipboard: boolean;\r\n\tpixelRatio: number;\r\n\tzoomLevel: number;\r\n\taccessibilitySupport: AccessibilitySupport;\r\n}\r\n\r\nconst hasOwnProperty = Object.hasOwnProperty;\r\n\r\nexport class ComputedEditorOptions implements IComputedEditorOptions {\r\n\tprivate readonly _values: any[] = [];\r\n\tpublic _read(id: EditorOption): T {\r\n\t\treturn this._values[id];\r\n\t}\r\n\tpublic get(id: T): FindComputedEditorOptionValueById {\r\n\t\treturn this._values[id];\r\n\t}\r\n\tpublic _write(id: EditorOption, value: T): void {\r\n\t\tthis._values[id] = value;\r\n\t}\r\n}\r\n\r\nclass RawEditorOptions {\r\n\tprivate readonly _values: any[] = [];\r\n\tpublic _read(id: EditorOption): T | undefined {\r\n\t\treturn this._values[id];\r\n\t}\r\n\tpublic _write(id: EditorOption, value: T | undefined): void {\r\n\t\tthis._values[id] = value;\r\n\t}\r\n}\r\n\r\nclass EditorConfiguration2 {\r\n\tpublic static readOptions(_options: IEditorOptions): RawEditorOptions {\r\n\t\tconst options: { [key: string]: any; } = _options;\r\n\t\tconst result = new RawEditorOptions();\r\n\t\tfor (const editorOption of editorOptionsRegistry) {\r\n\t\t\tconst value = (editorOption.name === '_never_' ? undefined : options[editorOption.name]);\r\n\t\t\tresult._write(editorOption.id, value);\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic static validateOptions(options: RawEditorOptions): ValidatedEditorOptions {\r\n\t\tconst result = new ValidatedEditorOptions();\r\n\t\tfor (const editorOption of editorOptionsRegistry) {\r\n\t\t\tresult._write(editorOption.id, editorOption.validate(options._read(editorOption.id)));\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic static computeOptions(options: ValidatedEditorOptions, env: IEnvironmentalOptions): ComputedEditorOptions {\r\n\t\tconst result = new ComputedEditorOptions();\r\n\t\tfor (const editorOption of editorOptionsRegistry) {\r\n\t\t\tresult._write(editorOption.id, editorOption.compute(env, result, options._read(editorOption.id)));\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _deepEquals(a: T, b: T): boolean {\r\n\t\tif (typeof a !== 'object' || typeof b !== 'object') {\r\n\t\t\treturn (a === b);\r\n\t\t}\r\n\t\tif (Array.isArray(a) || Array.isArray(b)) {\r\n\t\t\treturn (Array.isArray(a) && Array.isArray(b) ? arrays.equals(a, b) : false);\r\n\t\t}\r\n\t\tfor (let key in a) {\r\n\t\t\tif (!EditorConfiguration2._deepEquals(a[key], b[key])) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic static checkEquals(a: ComputedEditorOptions, b: ComputedEditorOptions): ConfigurationChangedEvent | null {\r\n\t\tconst result: boolean[] = [];\r\n\t\tlet somethingChanged = false;\r\n\t\tfor (const editorOption of editorOptionsRegistry) {\r\n\t\t\tconst changed = !EditorConfiguration2._deepEquals(a._read(editorOption.id), b._read(editorOption.id));\r\n\t\t\tresult[editorOption.id] = changed;\r\n\t\t\tif (changed) {\r\n\t\t\t\tsomethingChanged = true;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn (somethingChanged ? new ConfigurationChangedEvent(result) : null);\r\n\t}\r\n}\r\n\r\n/**\r\n * Compatibility with old options\r\n */\r\nfunction migrateOptions(options: IEditorOptions): void {\r\n\tconst wordWrap = options.wordWrap;\r\n\tif (wordWrap === true) {\r\n\t\toptions.wordWrap = 'on';\r\n\t} else if (wordWrap === false) {\r\n\t\toptions.wordWrap = 'off';\r\n\t}\r\n\r\n\tconst lineNumbers = options.lineNumbers;\r\n\tif (lineNumbers === true) {\r\n\t\toptions.lineNumbers = 'on';\r\n\t} else if (lineNumbers === false) {\r\n\t\toptions.lineNumbers = 'off';\r\n\t}\r\n\r\n\tconst autoClosingBrackets = options.autoClosingBrackets;\r\n\tif (autoClosingBrackets === false) {\r\n\t\toptions.autoClosingBrackets = 'never';\r\n\t\toptions.autoClosingQuotes = 'never';\r\n\t\toptions.autoSurround = 'never';\r\n\t}\r\n\r\n\tconst cursorBlinking = options.cursorBlinking;\r\n\tif (cursorBlinking === 'visible') {\r\n\t\toptions.cursorBlinking = 'solid';\r\n\t}\r\n\r\n\tconst renderWhitespace = options.renderWhitespace;\r\n\tif (renderWhitespace === true) {\r\n\t\toptions.renderWhitespace = 'boundary';\r\n\t} else if (renderWhitespace === false) {\r\n\t\toptions.renderWhitespace = 'none';\r\n\t}\r\n\r\n\tconst renderLineHighlight = options.renderLineHighlight;\r\n\tif (renderLineHighlight === true) {\r\n\t\toptions.renderLineHighlight = 'line';\r\n\t} else if (renderLineHighlight === false) {\r\n\t\toptions.renderLineHighlight = 'none';\r\n\t}\r\n\r\n\tconst acceptSuggestionOnEnter = options.acceptSuggestionOnEnter;\r\n\tif (acceptSuggestionOnEnter === true) {\r\n\t\toptions.acceptSuggestionOnEnter = 'on';\r\n\t} else if (acceptSuggestionOnEnter === false) {\r\n\t\toptions.acceptSuggestionOnEnter = 'off';\r\n\t}\r\n\r\n\tconst tabCompletion = options.tabCompletion;\r\n\tif (tabCompletion === false) {\r\n\t\toptions.tabCompletion = 'off';\r\n\t} else if (tabCompletion === true) {\r\n\t\toptions.tabCompletion = 'onlySnippets';\r\n\t}\r\n\r\n\tconst suggest = options.suggest;\r\n\tif (suggest && typeof (suggest).filteredTypes === 'object' && (suggest).filteredTypes) {\r\n\t\tconst mapping: Record = {};\r\n\t\tmapping['method'] = 'showMethods';\r\n\t\tmapping['function'] = 'showFunctions';\r\n\t\tmapping['constructor'] = 'showConstructors';\r\n\t\tmapping['field'] = 'showFields';\r\n\t\tmapping['variable'] = 'showVariables';\r\n\t\tmapping['class'] = 'showClasses';\r\n\t\tmapping['struct'] = 'showStructs';\r\n\t\tmapping['interface'] = 'showInterfaces';\r\n\t\tmapping['module'] = 'showModules';\r\n\t\tmapping['property'] = 'showProperties';\r\n\t\tmapping['event'] = 'showEvents';\r\n\t\tmapping['operator'] = 'showOperators';\r\n\t\tmapping['unit'] = 'showUnits';\r\n\t\tmapping['value'] = 'showValues';\r\n\t\tmapping['constant'] = 'showConstants';\r\n\t\tmapping['enum'] = 'showEnums';\r\n\t\tmapping['enumMember'] = 'showEnumMembers';\r\n\t\tmapping['keyword'] = 'showKeywords';\r\n\t\tmapping['text'] = 'showWords';\r\n\t\tmapping['color'] = 'showColors';\r\n\t\tmapping['file'] = 'showFiles';\r\n\t\tmapping['reference'] = 'showReferences';\r\n\t\tmapping['folder'] = 'showFolders';\r\n\t\tmapping['typeParameter'] = 'showTypeParameters';\r\n\t\tmapping['snippet'] = 'showSnippets';\r\n\t\tforEach(mapping, entry => {\r\n\t\t\tconst value = (suggest).filteredTypes[entry.key];\r\n\t\t\tif (value === false) {\r\n\t\t\t\t(suggest)[entry.value] = value;\r\n\t\t\t}\r\n\t\t});\r\n\t\t// delete (suggest).filteredTypes;\r\n\t}\r\n\r\n\tconst hover = options.hover;\r\n\tif (hover === true) {\r\n\t\toptions.hover = {\r\n\t\t\tenabled: true\r\n\t\t};\r\n\t} else if (hover === false) {\r\n\t\toptions.hover = {\r\n\t\t\tenabled: false\r\n\t\t};\r\n\t}\r\n\r\n\tconst parameterHints = options.parameterHints;\r\n\tif (parameterHints === true) {\r\n\t\toptions.parameterHints = {\r\n\t\t\tenabled: true\r\n\t\t};\r\n\t} else if (parameterHints === false) {\r\n\t\toptions.parameterHints = {\r\n\t\t\tenabled: false\r\n\t\t};\r\n\t}\r\n\r\n\tconst autoIndent = options.autoIndent;\r\n\tif (autoIndent === true) {\r\n\t\toptions.autoIndent = 'full';\r\n\t} else if (autoIndent === false) {\r\n\t\toptions.autoIndent = 'advanced';\r\n\t}\r\n\r\n\tconst matchBrackets = options.matchBrackets;\r\n\tif (matchBrackets === true) {\r\n\t\toptions.matchBrackets = 'always';\r\n\t} else if (matchBrackets === false) {\r\n\t\toptions.matchBrackets = 'never';\r\n\t}\r\n}\r\n\r\nfunction deepCloneAndMigrateOptions(_options: Readonly): IEditorOptions {\r\n\tconst options = objects.deepClone(_options);\r\n\tmigrateOptions(options);\r\n\treturn options;\r\n}\r\n\r\nexport abstract class CommonEditorConfiguration extends Disposable implements IConfiguration {\r\n\r\n\tprivate _onDidChange = this._register(new Emitter());\r\n\tpublic readonly onDidChange: Event = this._onDidChange.event;\r\n\r\n\tprivate _onDidChangeFast = this._register(new Emitter());\r\n\tpublic readonly onDidChangeFast: Event = this._onDidChangeFast.event;\r\n\r\n\tpublic readonly isSimpleWidget: boolean;\r\n\tprivate _computeOptionsMemory: ComputeOptionsMemory;\r\n\tpublic options!: ComputedEditorOptions;\r\n\r\n\tprivate _isDominatedByLongLines: boolean;\r\n\tprivate _viewLineCount: number;\r\n\tprivate _lineNumbersDigitCount: number;\r\n\r\n\tprivate _rawOptions: IEditorOptions;\r\n\tprivate _readOptions: RawEditorOptions;\r\n\tprotected _validatedOptions: ValidatedEditorOptions;\r\n\r\n\tconstructor(isSimpleWidget: boolean, _options: Readonly) {\r\n\t\tsuper();\r\n\t\tthis.isSimpleWidget = isSimpleWidget;\r\n\r\n\t\tthis._isDominatedByLongLines = false;\r\n\t\tthis._computeOptionsMemory = new ComputeOptionsMemory();\r\n\t\tthis._viewLineCount = 1;\r\n\t\tthis._lineNumbersDigitCount = 1;\r\n\r\n\t\tthis._rawOptions = deepCloneAndMigrateOptions(_options);\r\n\t\tthis._readOptions = EditorConfiguration2.readOptions(this._rawOptions);\r\n\t\tthis._validatedOptions = EditorConfiguration2.validateOptions(this._readOptions);\r\n\r\n\t\tthis._register(EditorZoom.onDidChangeZoomLevel(_ => this._recomputeOptions()));\r\n\t\tthis._register(TabFocus.onDidChangeTabFocus(_ => this._recomputeOptions()));\r\n\t}\r\n\r\n\tpublic observeReferenceElement(dimension?: IDimension): void {\r\n\t}\r\n\r\n\tpublic updatePixelRatio(): void {\r\n\t}\r\n\r\n\tprotected _recomputeOptions(): void {\r\n\t\tconst oldOptions = this.options;\r\n\t\tconst newOptions = this._computeInternalOptions();\r\n\r\n\t\tif (!oldOptions) {\r\n\t\t\tthis.options = newOptions;\r\n\t\t} else {\r\n\t\t\tconst changeEvent = EditorConfiguration2.checkEquals(oldOptions, newOptions);\r\n\r\n\t\t\tif (changeEvent === null) {\r\n\t\t\t\t// nothing changed!\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tthis.options = newOptions;\r\n\t\t\tthis._onDidChangeFast.fire(changeEvent);\r\n\t\t\tthis._onDidChange.fire(changeEvent);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getRawOptions(): IEditorOptions {\r\n\t\treturn this._rawOptions;\r\n\t}\r\n\r\n\tprivate _computeInternalOptions(): ComputedEditorOptions {\r\n\t\tconst partialEnv = this._getEnvConfiguration();\r\n\t\tconst bareFontInfo = BareFontInfo.createFromValidatedSettings(this._validatedOptions, partialEnv.zoomLevel, partialEnv.pixelRatio, this.isSimpleWidget);\r\n\t\tconst env: IEnvironmentalOptions = {\r\n\t\t\tmemory: this._computeOptionsMemory,\r\n\t\t\touterWidth: partialEnv.outerWidth,\r\n\t\t\touterHeight: partialEnv.outerHeight,\r\n\t\t\tfontInfo: this.readConfiguration(bareFontInfo),\r\n\t\t\textraEditorClassName: partialEnv.extraEditorClassName,\r\n\t\t\tisDominatedByLongLines: this._isDominatedByLongLines,\r\n\t\t\tviewLineCount: this._viewLineCount,\r\n\t\t\tlineNumbersDigitCount: this._lineNumbersDigitCount,\r\n\t\t\temptySelectionClipboard: partialEnv.emptySelectionClipboard,\r\n\t\t\tpixelRatio: partialEnv.pixelRatio,\r\n\t\t\ttabFocusMode: TabFocus.getTabFocusMode(),\r\n\t\t\taccessibilitySupport: partialEnv.accessibilitySupport\r\n\t\t};\r\n\t\treturn EditorConfiguration2.computeOptions(this._validatedOptions, env);\r\n\t}\r\n\r\n\tprivate static _subsetEquals(base: { [key: string]: any }, subset: { [key: string]: any }): boolean {\r\n\t\tfor (const key in subset) {\r\n\t\t\tif (hasOwnProperty.call(subset, key)) {\r\n\t\t\t\tconst subsetValue = subset[key];\r\n\t\t\t\tconst baseValue = base[key];\r\n\r\n\t\t\t\tif (baseValue === subsetValue) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\tif (Array.isArray(baseValue) && Array.isArray(subsetValue)) {\r\n\t\t\t\t\tif (!arrays.equals(baseValue, subsetValue)) {\r\n\t\t\t\t\t\treturn false;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\tif (baseValue && typeof baseValue === 'object' && subsetValue && typeof subsetValue === 'object') {\r\n\t\t\t\t\tif (!this._subsetEquals(baseValue, subsetValue)) {\r\n\t\t\t\t\t\treturn false;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic updateOptions(_newOptions: Readonly): void {\r\n\t\tif (typeof _newOptions === 'undefined') {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst newOptions = deepCloneAndMigrateOptions(_newOptions);\r\n\t\tif (CommonEditorConfiguration._subsetEquals(this._rawOptions, newOptions)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._rawOptions = objects.mixin(this._rawOptions, newOptions || {});\r\n\t\tthis._readOptions = EditorConfiguration2.readOptions(this._rawOptions);\r\n\t\tthis._validatedOptions = EditorConfiguration2.validateOptions(this._readOptions);\r\n\r\n\t\tthis._recomputeOptions();\r\n\t}\r\n\r\n\tpublic setIsDominatedByLongLines(isDominatedByLongLines: boolean): void {\r\n\t\tthis._isDominatedByLongLines = isDominatedByLongLines;\r\n\t\tthis._recomputeOptions();\r\n\t}\r\n\r\n\tpublic setMaxLineNumber(maxLineNumber: number): void {\r\n\t\tconst lineNumbersDigitCount = CommonEditorConfiguration._digitCount(maxLineNumber);\r\n\t\tif (this._lineNumbersDigitCount === lineNumbersDigitCount) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._lineNumbersDigitCount = lineNumbersDigitCount;\r\n\t\tthis._recomputeOptions();\r\n\t}\r\n\r\n\tpublic setViewLineCount(viewLineCount: number): void {\r\n\t\tif (this._viewLineCount === viewLineCount) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._viewLineCount = viewLineCount;\r\n\t\tthis._recomputeOptions();\r\n\t}\r\n\r\n\tprivate static _digitCount(n: number): number {\r\n\t\tlet r = 0;\r\n\t\twhile (n) {\r\n\t\t\tn = Math.floor(n / 10);\r\n\t\t\tr++;\r\n\t\t}\r\n\t\treturn r ? r : 1;\r\n\t}\r\n\tprotected abstract _getEnvConfiguration(): IEnvConfiguration;\r\n\r\n\tprotected abstract readConfiguration(styling: BareFontInfo): FontInfo;\r\n\r\n}\r\n\r\nexport const editorConfigurationBaseNode = Object.freeze({\r\n\tid: 'editor',\r\n\torder: 5,\r\n\ttype: 'object',\r\n\ttitle: nls.localize('editorConfigurationTitle', \"Editor\"),\r\n\tscope: ConfigurationScope.LANGUAGE_OVERRIDABLE,\r\n});\r\n\r\nconst configurationRegistry = Registry.as(Extensions.Configuration);\r\nconst editorConfiguration: IConfigurationNode = {\r\n\t...editorConfigurationBaseNode,\r\n\tproperties: {\r\n\t\t'editor.tabSize': {\r\n\t\t\ttype: 'number',\r\n\t\t\tdefault: EDITOR_MODEL_DEFAULTS.tabSize,\r\n\t\t\tminimum: 1,\r\n\t\t\tmarkdownDescription: nls.localize('tabSize', \"The number of spaces a tab is equal to. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.\")\r\n\t\t},\r\n\t\t// 'editor.indentSize': {\r\n\t\t// \t'anyOf': [\r\n\t\t// \t\t{\r\n\t\t// \t\t\ttype: 'string',\r\n\t\t// \t\t\tenum: ['tabSize']\r\n\t\t// \t\t},\r\n\t\t// \t\t{\r\n\t\t// \t\t\ttype: 'number',\r\n\t\t// \t\t\tminimum: 1\r\n\t\t// \t\t}\r\n\t\t// \t],\r\n\t\t// \tdefault: 'tabSize',\r\n\t\t// \tmarkdownDescription: nls.localize('indentSize', \"The number of spaces used for indentation or 'tabSize' to use the value from `#editor.tabSize#`. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.\")\r\n\t\t// },\r\n\t\t'editor.insertSpaces': {\r\n\t\t\ttype: 'boolean',\r\n\t\t\tdefault: EDITOR_MODEL_DEFAULTS.insertSpaces,\r\n\t\t\tmarkdownDescription: nls.localize('insertSpaces', \"Insert spaces when pressing `Tab`. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.\")\r\n\t\t},\r\n\t\t'editor.detectIndentation': {\r\n\t\t\ttype: 'boolean',\r\n\t\t\tdefault: EDITOR_MODEL_DEFAULTS.detectIndentation,\r\n\t\t\tmarkdownDescription: nls.localize('detectIndentation', \"Controls whether `#editor.tabSize#` and `#editor.insertSpaces#` will be automatically detected when a file is opened based on the file contents.\")\r\n\t\t},\r\n\t\t'editor.trimAutoWhitespace': {\r\n\t\t\ttype: 'boolean',\r\n\t\t\tdefault: EDITOR_MODEL_DEFAULTS.trimAutoWhitespace,\r\n\t\t\tdescription: nls.localize('trimAutoWhitespace', \"Remove trailing auto inserted whitespace.\")\r\n\t\t},\r\n\t\t'editor.largeFileOptimizations': {\r\n\t\t\ttype: 'boolean',\r\n\t\t\tdefault: EDITOR_MODEL_DEFAULTS.largeFileOptimizations,\r\n\t\t\tdescription: nls.localize('largeFileOptimizations', \"Special handling for large files to disable certain memory intensive features.\")\r\n\t\t},\r\n\t\t'editor.wordBasedSuggestions': {\r\n\t\t\ttype: 'boolean',\r\n\t\t\tdefault: true,\r\n\t\t\tdescription: nls.localize('wordBasedSuggestions', \"Controls whether completions should be computed based on words in the document.\")\r\n\t\t},\r\n\t\t'editor.wordBasedSuggestionsMode': {\r\n\t\t\tenum: ['currentDocument', 'matchingDocuments', 'allDocuments'],\r\n\t\t\tdefault: 'matchingDocuments',\r\n\t\t\tenumDescriptions: [\r\n\t\t\t\tnls.localize('wordBasedSuggestionsMode.currentDocument', 'Only suggest words from the active document.'),\r\n\t\t\t\tnls.localize('wordBasedSuggestionsMode.matchingDocuments', 'Suggest words from all open documents of the same language.'),\r\n\t\t\t\tnls.localize('wordBasedSuggestionsMode.allDocuments', 'Suggest words from all open documents.')\r\n\t\t\t],\r\n\t\t\tdescription: nls.localize('wordBasedSuggestionsMode', \"Controls form what documents word based completions are computed.\")\r\n\t\t},\r\n\t\t'editor.semanticHighlighting.enabled': {\r\n\t\t\tenum: [true, false, 'configuredByTheme'],\r\n\t\t\tenumDescriptions: [\r\n\t\t\t\tnls.localize('semanticHighlighting.true', 'Semantic highlighting enabled for all color themes.'),\r\n\t\t\t\tnls.localize('semanticHighlighting.false', 'Semantic highlighting disabled for all color themes.'),\r\n\t\t\t\tnls.localize('semanticHighlighting.configuredByTheme', 'Semantic highlighting is configured by the current color theme\\'s `semanticHighlighting` setting.')\r\n\t\t\t],\r\n\t\t\tdefault: 'configuredByTheme',\r\n\t\t\tdescription: nls.localize('semanticHighlighting.enabled', \"Controls whether the semanticHighlighting is shown for the languages that support it.\")\r\n\t\t},\r\n\t\t'editor.stablePeek': {\r\n\t\t\ttype: 'boolean',\r\n\t\t\tdefault: false,\r\n\t\t\tmarkdownDescription: nls.localize('stablePeek', \"Keep peek editors open even when double clicking their content or when hitting `Escape`.\")\r\n\t\t},\r\n\t\t'editor.maxTokenizationLineLength': {\r\n\t\t\ttype: 'integer',\r\n\t\t\tdefault: 20_000,\r\n\t\t\tdescription: nls.localize('maxTokenizationLineLength', \"Lines above this length will not be tokenized for performance reasons\")\r\n\t\t},\r\n\t\t'diffEditor.maxComputationTime': {\r\n\t\t\ttype: 'number',\r\n\t\t\tdefault: 5000,\r\n\t\t\tdescription: nls.localize('maxComputationTime', \"Timeout in milliseconds after which diff computation is cancelled. Use 0 for no timeout.\")\r\n\t\t},\r\n\t\t'diffEditor.renderSideBySide': {\r\n\t\t\ttype: 'boolean',\r\n\t\t\tdefault: true,\r\n\t\t\tdescription: nls.localize('sideBySide', \"Controls whether the diff editor shows the diff side by side or inline.\")\r\n\t\t},\r\n\t\t'diffEditor.ignoreTrimWhitespace': {\r\n\t\t\ttype: 'boolean',\r\n\t\t\tdefault: true,\r\n\t\t\tdescription: nls.localize('ignoreTrimWhitespace', \"When enabled, the diff editor ignores changes in leading or trailing whitespace.\")\r\n\t\t},\r\n\t\t'diffEditor.renderIndicators': {\r\n\t\t\ttype: 'boolean',\r\n\t\t\tdefault: true,\r\n\t\t\tdescription: nls.localize('renderIndicators', \"Controls whether the diff editor shows +/- indicators for added/removed changes.\")\r\n\t\t},\r\n\t\t'diffEditor.codeLens': {\r\n\t\t\ttype: 'boolean',\r\n\t\t\tdefault: false,\r\n\t\t\tdescription: nls.localize('codeLens', \"Controls whether the editor shows CodeLens.\")\r\n\t\t},\r\n\t\t'diffEditor.wordWrap': {\r\n\t\t\ttype: 'string',\r\n\t\t\tenum: ['off', 'on', 'inherit'],\r\n\t\t\tdefault: 'inherit',\r\n\t\t\tmarkdownEnumDescriptions: [\r\n\t\t\t\tnls.localize('wordWrap.off', \"Lines will never wrap.\"),\r\n\t\t\t\tnls.localize('wordWrap.on', \"Lines will wrap at the viewport width.\"),\r\n\t\t\t\tnls.localize('wordWrap.inherit', \"Lines will wrap according to the `#editor.wordWrap#` setting.\"),\r\n\t\t\t]\r\n\t\t}\r\n\t}\r\n};\r\n\r\nfunction isConfigurationPropertySchema(x: IConfigurationPropertySchema | { [path: string]: IConfigurationPropertySchema; }): x is IConfigurationPropertySchema {\r\n\treturn (typeof x.type !== 'undefined' || typeof x.anyOf !== 'undefined');\r\n}\r\n\r\n// Add properties from the Editor Option Registry\r\nfor (const editorOption of editorOptionsRegistry) {\r\n\tconst schema = editorOption.schema;\r\n\tif (typeof schema !== 'undefined') {\r\n\t\tif (isConfigurationPropertySchema(schema)) {\r\n\t\t\t// This is a single schema contribution\r\n\t\t\teditorConfiguration.properties![`editor.${editorOption.name}`] = schema;\r\n\t\t} else {\r\n\t\t\tfor (let key in schema) {\r\n\t\t\t\tif (hasOwnProperty.call(schema, key)) {\r\n\t\t\t\t\teditorConfiguration.properties![key] = schema[key];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\nlet cachedEditorConfigurationKeys: { [key: string]: boolean; } | null = null;\r\nfunction getEditorConfigurationKeys(): { [key: string]: boolean; } {\r\n\tif (cachedEditorConfigurationKeys === null) {\r\n\t\tcachedEditorConfigurationKeys = <{ [key: string]: boolean; }>Object.create(null);\r\n\t\tObject.keys(editorConfiguration.properties!).forEach((prop) => {\r\n\t\t\tcachedEditorConfigurationKeys![prop] = true;\r\n\t\t});\r\n\t}\r\n\treturn cachedEditorConfigurationKeys;\r\n}\r\n\r\nexport function isEditorConfigurationKey(key: string): boolean {\r\n\tconst editorConfigurationKeys = getEditorConfigurationKeys();\r\n\treturn (editorConfigurationKeys[`editor.${key}`] || false);\r\n}\r\nexport function isDiffEditorConfigurationKey(key: string): boolean {\r\n\tconst editorConfigurationKeys = getEditorConfigurationKeys();\r\n\treturn (editorConfigurationKeys[`diffEditor.${key}`] || false);\r\n}\r\n\r\nconfigurationRegistry.registerConfiguration(editorConfiguration);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as browser from 'vs/base/browser/browser';\r\nimport { FastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport { CharWidthRequest, CharWidthRequestType, readCharWidths } from 'vs/editor/browser/config/charWidthReader';\r\nimport { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver';\r\nimport { CommonEditorConfiguration, IEnvConfiguration } from 'vs/editor/common/config/commonEditorConfig';\r\nimport { EditorOption, EditorFontLigatures } from 'vs/editor/common/config/editorOptions';\r\nimport { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo';\r\nimport { IDimension } from 'vs/editor/common/editorCommon';\r\nimport { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';\r\nimport { IEditorConstructionOptions } from 'vs/editor/browser/editorBrowser';\r\n\r\nclass CSSBasedConfigurationCache {\r\n\r\n\tprivate readonly _keys: { [key: string]: BareFontInfo; };\r\n\tprivate readonly _values: { [key: string]: FontInfo; };\r\n\r\n\tconstructor() {\r\n\t\tthis._keys = Object.create(null);\r\n\t\tthis._values = Object.create(null);\r\n\t}\r\n\r\n\tpublic has(item: BareFontInfo): boolean {\r\n\t\tconst itemId = item.getId();\r\n\t\treturn !!this._values[itemId];\r\n\t}\r\n\r\n\tpublic get(item: BareFontInfo): FontInfo {\r\n\t\tconst itemId = item.getId();\r\n\t\treturn this._values[itemId];\r\n\t}\r\n\r\n\tpublic put(item: BareFontInfo, value: FontInfo): void {\r\n\t\tconst itemId = item.getId();\r\n\t\tthis._keys[itemId] = item;\r\n\t\tthis._values[itemId] = value;\r\n\t}\r\n\r\n\tpublic remove(item: BareFontInfo): void {\r\n\t\tconst itemId = item.getId();\r\n\t\tdelete this._keys[itemId];\r\n\t\tdelete this._values[itemId];\r\n\t}\r\n\r\n\tpublic getValues(): FontInfo[] {\r\n\t\treturn Object.keys(this._keys).map(id => this._values[id]);\r\n\t}\r\n}\r\n\r\nexport function clearAllFontInfos(): void {\r\n\tCSSBasedConfiguration.INSTANCE.clearCache();\r\n}\r\n\r\nclass CSSBasedConfiguration extends Disposable {\r\n\r\n\tpublic static readonly INSTANCE = new CSSBasedConfiguration();\r\n\r\n\tprivate _cache: CSSBasedConfigurationCache;\r\n\tprivate _evictUntrustedReadingsTimeout: any;\r\n\r\n\tprivate _onDidChange = this._register(new Emitter());\r\n\tpublic readonly onDidChange: Event = this._onDidChange.event;\r\n\r\n\tconstructor() {\r\n\t\tsuper();\r\n\r\n\t\tthis._cache = new CSSBasedConfigurationCache();\r\n\t\tthis._evictUntrustedReadingsTimeout = -1;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tif (this._evictUntrustedReadingsTimeout !== -1) {\r\n\t\t\tclearTimeout(this._evictUntrustedReadingsTimeout);\r\n\t\t\tthis._evictUntrustedReadingsTimeout = -1;\r\n\t\t}\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tpublic clearCache(): void {\r\n\t\tthis._cache = new CSSBasedConfigurationCache();\r\n\t\tthis._onDidChange.fire();\r\n\t}\r\n\r\n\tprivate _writeToCache(item: BareFontInfo, value: FontInfo): void {\r\n\t\tthis._cache.put(item, value);\r\n\r\n\t\tif (!value.isTrusted && this._evictUntrustedReadingsTimeout === -1) {\r\n\t\t\t// Try reading again after some time\r\n\t\t\tthis._evictUntrustedReadingsTimeout = setTimeout(() => {\r\n\t\t\t\tthis._evictUntrustedReadingsTimeout = -1;\r\n\t\t\t\tthis._evictUntrustedReadings();\r\n\t\t\t}, 5000);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _evictUntrustedReadings(): void {\r\n\t\tconst values = this._cache.getValues();\r\n\t\tlet somethingRemoved = false;\r\n\t\tfor (const item of values) {\r\n\t\t\tif (!item.isTrusted) {\r\n\t\t\t\tsomethingRemoved = true;\r\n\t\t\t\tthis._cache.remove(item);\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (somethingRemoved) {\r\n\t\t\tthis._onDidChange.fire();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic readConfiguration(bareFontInfo: BareFontInfo): FontInfo {\r\n\t\tif (!this._cache.has(bareFontInfo)) {\r\n\t\t\tlet readConfig = CSSBasedConfiguration._actualReadConfiguration(bareFontInfo);\r\n\r\n\t\t\tif (readConfig.typicalHalfwidthCharacterWidth <= 2 || readConfig.typicalFullwidthCharacterWidth <= 2 || readConfig.spaceWidth <= 2 || readConfig.maxDigitWidth <= 2) {\r\n\t\t\t\t// Hey, it's Bug 14341 ... we couldn't read\r\n\t\t\t\treadConfig = new FontInfo({\r\n\t\t\t\t\tzoomLevel: browser.getZoomLevel(),\r\n\t\t\t\t\tpixelRatio: browser.getPixelRatio(),\r\n\t\t\t\t\tfontFamily: readConfig.fontFamily,\r\n\t\t\t\t\tfontWeight: readConfig.fontWeight,\r\n\t\t\t\t\tfontSize: readConfig.fontSize,\r\n\t\t\t\t\tfontFeatureSettings: readConfig.fontFeatureSettings,\r\n\t\t\t\t\tlineHeight: readConfig.lineHeight,\r\n\t\t\t\t\tletterSpacing: readConfig.letterSpacing,\r\n\t\t\t\t\tisMonospace: readConfig.isMonospace,\r\n\t\t\t\t\ttypicalHalfwidthCharacterWidth: Math.max(readConfig.typicalHalfwidthCharacterWidth, 5),\r\n\t\t\t\t\ttypicalFullwidthCharacterWidth: Math.max(readConfig.typicalFullwidthCharacterWidth, 5),\r\n\t\t\t\t\tcanUseHalfwidthRightwardsArrow: readConfig.canUseHalfwidthRightwardsArrow,\r\n\t\t\t\t\tspaceWidth: Math.max(readConfig.spaceWidth, 5),\r\n\t\t\t\t\tmiddotWidth: Math.max(readConfig.middotWidth, 5),\r\n\t\t\t\t\twsmiddotWidth: Math.max(readConfig.wsmiddotWidth, 5),\r\n\t\t\t\t\tmaxDigitWidth: Math.max(readConfig.maxDigitWidth, 5),\r\n\t\t\t\t}, false);\r\n\t\t\t}\r\n\r\n\t\t\tthis._writeToCache(bareFontInfo, readConfig);\r\n\t\t}\r\n\t\treturn this._cache.get(bareFontInfo);\r\n\t}\r\n\r\n\tprivate static createRequest(chr: string, type: CharWidthRequestType, all: CharWidthRequest[], monospace: CharWidthRequest[] | null): CharWidthRequest {\r\n\t\tconst result = new CharWidthRequest(chr, type);\r\n\t\tall.push(result);\r\n\t\tif (monospace) {\r\n\t\t\tmonospace.push(result);\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _actualReadConfiguration(bareFontInfo: BareFontInfo): FontInfo {\r\n\t\tconst all: CharWidthRequest[] = [];\r\n\t\tconst monospace: CharWidthRequest[] = [];\r\n\r\n\t\tconst typicalHalfwidthCharacter = this.createRequest('n', CharWidthRequestType.Regular, all, monospace);\r\n\t\tconst typicalFullwidthCharacter = this.createRequest('\\uff4d', CharWidthRequestType.Regular, all, null);\r\n\t\tconst space = this.createRequest(' ', CharWidthRequestType.Regular, all, monospace);\r\n\t\tconst digit0 = this.createRequest('0', CharWidthRequestType.Regular, all, monospace);\r\n\t\tconst digit1 = this.createRequest('1', CharWidthRequestType.Regular, all, monospace);\r\n\t\tconst digit2 = this.createRequest('2', CharWidthRequestType.Regular, all, monospace);\r\n\t\tconst digit3 = this.createRequest('3', CharWidthRequestType.Regular, all, monospace);\r\n\t\tconst digit4 = this.createRequest('4', CharWidthRequestType.Regular, all, monospace);\r\n\t\tconst digit5 = this.createRequest('5', CharWidthRequestType.Regular, all, monospace);\r\n\t\tconst digit6 = this.createRequest('6', CharWidthRequestType.Regular, all, monospace);\r\n\t\tconst digit7 = this.createRequest('7', CharWidthRequestType.Regular, all, monospace);\r\n\t\tconst digit8 = this.createRequest('8', CharWidthRequestType.Regular, all, monospace);\r\n\t\tconst digit9 = this.createRequest('9', CharWidthRequestType.Regular, all, monospace);\r\n\r\n\t\t// monospace test: used for whitespace rendering\r\n\t\tconst rightwardsArrow = this.createRequest('→', CharWidthRequestType.Regular, all, monospace);\r\n\t\tconst halfwidthRightwardsArrow = this.createRequest('→', CharWidthRequestType.Regular, all, null);\r\n\r\n\t\t// U+00B7 - MIDDLE DOT\r\n\t\tconst middot = this.createRequest('·', CharWidthRequestType.Regular, all, monospace);\r\n\r\n\t\t// U+2E31 - WORD SEPARATOR MIDDLE DOT\r\n\t\tconst wsmiddotWidth = this.createRequest(String.fromCharCode(0x2E31), CharWidthRequestType.Regular, all, null);\r\n\r\n\t\t// monospace test: some characters\r\n\t\tthis.createRequest('|', CharWidthRequestType.Regular, all, monospace);\r\n\t\tthis.createRequest('/', CharWidthRequestType.Regular, all, monospace);\r\n\t\tthis.createRequest('-', CharWidthRequestType.Regular, all, monospace);\r\n\t\tthis.createRequest('_', CharWidthRequestType.Regular, all, monospace);\r\n\t\tthis.createRequest('i', CharWidthRequestType.Regular, all, monospace);\r\n\t\tthis.createRequest('l', CharWidthRequestType.Regular, all, monospace);\r\n\t\tthis.createRequest('m', CharWidthRequestType.Regular, all, monospace);\r\n\r\n\t\t// monospace italic test\r\n\t\tthis.createRequest('|', CharWidthRequestType.Italic, all, monospace);\r\n\t\tthis.createRequest('_', CharWidthRequestType.Italic, all, monospace);\r\n\t\tthis.createRequest('i', CharWidthRequestType.Italic, all, monospace);\r\n\t\tthis.createRequest('l', CharWidthRequestType.Italic, all, monospace);\r\n\t\tthis.createRequest('m', CharWidthRequestType.Italic, all, monospace);\r\n\t\tthis.createRequest('n', CharWidthRequestType.Italic, all, monospace);\r\n\r\n\t\t// monospace bold test\r\n\t\tthis.createRequest('|', CharWidthRequestType.Bold, all, monospace);\r\n\t\tthis.createRequest('_', CharWidthRequestType.Bold, all, monospace);\r\n\t\tthis.createRequest('i', CharWidthRequestType.Bold, all, monospace);\r\n\t\tthis.createRequest('l', CharWidthRequestType.Bold, all, monospace);\r\n\t\tthis.createRequest('m', CharWidthRequestType.Bold, all, monospace);\r\n\t\tthis.createRequest('n', CharWidthRequestType.Bold, all, monospace);\r\n\r\n\t\treadCharWidths(bareFontInfo, all);\r\n\r\n\t\tconst maxDigitWidth = Math.max(digit0.width, digit1.width, digit2.width, digit3.width, digit4.width, digit5.width, digit6.width, digit7.width, digit8.width, digit9.width);\r\n\r\n\t\tlet isMonospace = (bareFontInfo.fontFeatureSettings === EditorFontLigatures.OFF);\r\n\t\tconst referenceWidth = monospace[0].width;\r\n\t\tfor (let i = 1, len = monospace.length; isMonospace && i < len; i++) {\r\n\t\t\tconst diff = referenceWidth - monospace[i].width;\r\n\t\t\tif (diff < -0.001 || diff > 0.001) {\r\n\t\t\t\tisMonospace = false;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet canUseHalfwidthRightwardsArrow = true;\r\n\t\tif (isMonospace && halfwidthRightwardsArrow.width !== referenceWidth) {\r\n\t\t\t// using a halfwidth rightwards arrow would break monospace...\r\n\t\t\tcanUseHalfwidthRightwardsArrow = false;\r\n\t\t}\r\n\t\tif (halfwidthRightwardsArrow.width > rightwardsArrow.width) {\r\n\t\t\t// using a halfwidth rightwards arrow would paint a larger arrow than a regular rightwards arrow\r\n\t\t\tcanUseHalfwidthRightwardsArrow = false;\r\n\t\t}\r\n\r\n\t\t// let's trust the zoom level only 2s after it was changed.\r\n\t\tconst canTrustBrowserZoomLevel = (browser.getTimeSinceLastZoomLevelChanged() > 2000);\r\n\t\treturn new FontInfo({\r\n\t\t\tzoomLevel: browser.getZoomLevel(),\r\n\t\t\tpixelRatio: browser.getPixelRatio(),\r\n\t\t\tfontFamily: bareFontInfo.fontFamily,\r\n\t\t\tfontWeight: bareFontInfo.fontWeight,\r\n\t\t\tfontSize: bareFontInfo.fontSize,\r\n\t\t\tfontFeatureSettings: bareFontInfo.fontFeatureSettings,\r\n\t\t\tlineHeight: bareFontInfo.lineHeight,\r\n\t\t\tletterSpacing: bareFontInfo.letterSpacing,\r\n\t\t\tisMonospace: isMonospace,\r\n\t\t\ttypicalHalfwidthCharacterWidth: typicalHalfwidthCharacter.width,\r\n\t\t\ttypicalFullwidthCharacterWidth: typicalFullwidthCharacter.width,\r\n\t\t\tcanUseHalfwidthRightwardsArrow: canUseHalfwidthRightwardsArrow,\r\n\t\t\tspaceWidth: space.width,\r\n\t\t\tmiddotWidth: middot.width,\r\n\t\t\twsmiddotWidth: wsmiddotWidth.width,\r\n\t\t\tmaxDigitWidth: maxDigitWidth\r\n\t\t}, canTrustBrowserZoomLevel);\r\n\t}\r\n}\r\n\r\nexport class Configuration extends CommonEditorConfiguration {\r\n\r\n\tpublic static applyFontInfoSlow(domNode: HTMLElement, fontInfo: BareFontInfo): void {\r\n\t\tdomNode.style.fontFamily = fontInfo.getMassagedFontFamily();\r\n\t\tdomNode.style.fontWeight = fontInfo.fontWeight;\r\n\t\tdomNode.style.fontSize = fontInfo.fontSize + 'px';\r\n\t\tdomNode.style.fontFeatureSettings = fontInfo.fontFeatureSettings;\r\n\t\tdomNode.style.lineHeight = fontInfo.lineHeight + 'px';\r\n\t\tdomNode.style.letterSpacing = fontInfo.letterSpacing + 'px';\r\n\t}\r\n\r\n\tpublic static applyFontInfo(domNode: FastDomNode, fontInfo: BareFontInfo): void {\r\n\t\tdomNode.setFontFamily(fontInfo.getMassagedFontFamily());\r\n\t\tdomNode.setFontWeight(fontInfo.fontWeight);\r\n\t\tdomNode.setFontSize(fontInfo.fontSize);\r\n\t\tdomNode.setFontFeatureSettings(fontInfo.fontFeatureSettings);\r\n\t\tdomNode.setLineHeight(fontInfo.lineHeight);\r\n\t\tdomNode.setLetterSpacing(fontInfo.letterSpacing);\r\n\t}\r\n\r\n\tprivate readonly _elementSizeObserver: ElementSizeObserver;\r\n\r\n\tconstructor(\r\n\t\tisSimpleWidget: boolean,\r\n\t\toptions: Readonly,\r\n\t\treferenceDomElement: HTMLElement | null = null,\r\n\t\tprivate readonly accessibilityService: IAccessibilityService\r\n\t) {\r\n\t\tsuper(isSimpleWidget, options);\r\n\r\n\t\tthis._elementSizeObserver = this._register(new ElementSizeObserver(referenceDomElement, options.dimension, () => this._recomputeOptions()));\r\n\r\n\t\tthis._register(CSSBasedConfiguration.INSTANCE.onDidChange(() => this._recomputeOptions()));\r\n\r\n\t\tif (this._validatedOptions.get(EditorOption.automaticLayout)) {\r\n\t\t\tthis._elementSizeObserver.startObserving();\r\n\t\t}\r\n\r\n\t\tthis._register(browser.onDidChangeZoomLevel(_ => this._recomputeOptions()));\r\n\t\tthis._register(this.accessibilityService.onDidChangeScreenReaderOptimized(() => this._recomputeOptions()));\r\n\r\n\t\tthis._recomputeOptions();\r\n\t}\r\n\r\n\tpublic observeReferenceElement(dimension?: IDimension): void {\r\n\t\tthis._elementSizeObserver.observe(dimension);\r\n\t}\r\n\r\n\tpublic updatePixelRatio(): void {\r\n\t\tthis._recomputeOptions();\r\n\t}\r\n\r\n\tprivate static _getExtraEditorClassName(): string {\r\n\t\tlet extra = '';\r\n\t\tif (!browser.isSafari && !browser.isWebkitWebView) {\r\n\t\t\t// Use user-select: none in all browsers except Safari and native macOS WebView\r\n\t\t\textra += 'no-user-select ';\r\n\t\t}\r\n\t\tif (browser.isSafari) {\r\n\t\t\t// See https://github.com/microsoft/vscode/issues/108822\r\n\t\t\textra += 'no-minimap-shadow ';\r\n\t\t}\r\n\t\tif (platform.isMacintosh) {\r\n\t\t\textra += 'mac ';\r\n\t\t}\r\n\t\treturn extra;\r\n\t}\r\n\r\n\tprotected _getEnvConfiguration(): IEnvConfiguration {\r\n\t\treturn {\r\n\t\t\textraEditorClassName: Configuration._getExtraEditorClassName(),\r\n\t\t\touterWidth: this._elementSizeObserver.getWidth(),\r\n\t\t\touterHeight: this._elementSizeObserver.getHeight(),\r\n\t\t\temptySelectionClipboard: browser.isWebKit || browser.isFirefox,\r\n\t\t\tpixelRatio: browser.getPixelRatio(),\r\n\t\t\tzoomLevel: browser.getZoomLevel(),\r\n\t\t\taccessibilitySupport: (\r\n\t\t\t\tthis.accessibilityService.isScreenReaderOptimized()\r\n\t\t\t\t\t? AccessibilitySupport.Enabled\r\n\t\t\t\t\t: this.accessibilityService.getAccessibilitySupport()\r\n\t\t\t)\r\n\t\t};\r\n\t}\r\n\r\n\tprotected readConfiguration(bareFontInfo: BareFontInfo): FontInfo {\r\n\t\treturn CSSBasedConfiguration.INSTANCE.readConfiguration(bareFontInfo);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { ILineBreaksComputerFactory } from 'vs/editor/common/viewModel/splitLinesCollection';\r\nimport { WrappingIndent } from 'vs/editor/common/config/editorOptions';\r\nimport { FontInfo } from 'vs/editor/common/config/fontInfo';\r\nimport { createStringBuilder, IStringBuilder } from 'vs/editor/common/core/stringBuilder';\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { Configuration } from 'vs/editor/browser/config/configuration';\r\nimport { ILineBreaksComputer, LineBreakData } from 'vs/editor/common/viewModel/viewModel';\r\n\r\nconst ttPolicy = window.trustedTypes?.createPolicy('domLineBreaksComputer', { createHTML: value => value });\r\n\r\nexport class DOMLineBreaksComputerFactory implements ILineBreaksComputerFactory {\r\n\r\n\tpublic static create(): DOMLineBreaksComputerFactory {\r\n\t\treturn new DOMLineBreaksComputerFactory();\r\n\t}\r\n\r\n\tconstructor() {\r\n\t}\r\n\r\n\tpublic createLineBreaksComputer(fontInfo: FontInfo, tabSize: number, wrappingColumn: number, wrappingIndent: WrappingIndent): ILineBreaksComputer {\r\n\t\ttabSize = tabSize | 0; //@perf\r\n\t\twrappingColumn = +wrappingColumn; //@perf\r\n\r\n\t\tlet requests: string[] = [];\r\n\t\treturn {\r\n\t\t\taddRequest: (lineText: string, previousLineBreakData: LineBreakData | null) => {\r\n\t\t\t\trequests.push(lineText);\r\n\t\t\t},\r\n\t\t\tfinalize: () => {\r\n\t\t\t\treturn createLineBreaks(requests, fontInfo, tabSize, wrappingColumn, wrappingIndent);\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n}\r\n\r\nfunction createLineBreaks(requests: string[], fontInfo: FontInfo, tabSize: number, firstLineBreakColumn: number, wrappingIndent: WrappingIndent): (LineBreakData | null)[] {\r\n\tif (firstLineBreakColumn === -1) {\r\n\t\tconst result: null[] = [];\r\n\t\tfor (let i = 0, len = requests.length; i < len; i++) {\r\n\t\t\tresult[i] = null;\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tconst overallWidth = Math.round(firstLineBreakColumn * fontInfo.typicalHalfwidthCharacterWidth);\r\n\r\n\t// Cannot respect WrappingIndent.Indent and WrappingIndent.DeepIndent because that would require\r\n\t// two dom layouts, in order to first set the width of the first line, and then set the width of the wrapped lines\r\n\tif (wrappingIndent === WrappingIndent.Indent || wrappingIndent === WrappingIndent.DeepIndent) {\r\n\t\twrappingIndent = WrappingIndent.Same;\r\n\t}\r\n\r\n\tconst containerDomNode = document.createElement('div');\r\n\tConfiguration.applyFontInfoSlow(containerDomNode, fontInfo);\r\n\r\n\tconst sb = createStringBuilder(10000);\r\n\tconst firstNonWhitespaceIndices: number[] = [];\r\n\tconst wrappedTextIndentLengths: number[] = [];\r\n\tconst renderLineContents: string[] = [];\r\n\tconst allCharOffsets: number[][] = [];\r\n\tconst allVisibleColumns: number[][] = [];\r\n\tfor (let i = 0; i < requests.length; i++) {\r\n\t\tconst lineContent = requests[i];\r\n\r\n\t\tlet firstNonWhitespaceIndex = 0;\r\n\t\tlet wrappedTextIndentLength = 0;\r\n\t\tlet width = overallWidth;\r\n\r\n\t\tif (wrappingIndent !== WrappingIndent.None) {\r\n\t\t\tfirstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(lineContent);\r\n\t\t\tif (firstNonWhitespaceIndex === -1) {\r\n\t\t\t\t// all whitespace line\r\n\t\t\t\tfirstNonWhitespaceIndex = 0;\r\n\r\n\t\t\t} else {\r\n\t\t\t\t// Track existing indent\r\n\r\n\t\t\t\tfor (let i = 0; i < firstNonWhitespaceIndex; i++) {\r\n\t\t\t\t\tconst charWidth = (\r\n\t\t\t\t\t\tlineContent.charCodeAt(i) === CharCode.Tab\r\n\t\t\t\t\t\t\t? (tabSize - (wrappedTextIndentLength % tabSize))\r\n\t\t\t\t\t\t\t: 1\r\n\t\t\t\t\t);\r\n\t\t\t\t\twrappedTextIndentLength += charWidth;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst indentWidth = Math.ceil(fontInfo.spaceWidth * wrappedTextIndentLength);\r\n\r\n\t\t\t\t// Force sticking to beginning of line if no character would fit except for the indentation\r\n\t\t\t\tif (indentWidth + fontInfo.typicalFullwidthCharacterWidth > overallWidth) {\r\n\t\t\t\t\tfirstNonWhitespaceIndex = 0;\r\n\t\t\t\t\twrappedTextIndentLength = 0;\r\n\t\t\t\t} else {\r\n\t\t\t\t\twidth = overallWidth - indentWidth;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst renderLineContent = lineContent.substr(firstNonWhitespaceIndex);\r\n\t\tconst tmp = renderLine(renderLineContent, wrappedTextIndentLength, tabSize, width, sb);\r\n\t\tfirstNonWhitespaceIndices[i] = firstNonWhitespaceIndex;\r\n\t\twrappedTextIndentLengths[i] = wrappedTextIndentLength;\r\n\t\trenderLineContents[i] = renderLineContent;\r\n\t\tallCharOffsets[i] = tmp[0];\r\n\t\tallVisibleColumns[i] = tmp[1];\r\n\t}\r\n\tconst html = sb.build();\r\n\tconst trustedhtml = ttPolicy?.createHTML(html) ?? html;\r\n\tcontainerDomNode.innerHTML = trustedhtml as string;\r\n\r\n\tcontainerDomNode.style.position = 'absolute';\r\n\tcontainerDomNode.style.top = '10000';\r\n\tcontainerDomNode.style.wordWrap = 'break-word';\r\n\tdocument.body.appendChild(containerDomNode);\r\n\r\n\tlet range = document.createRange();\r\n\tconst lineDomNodes = Array.prototype.slice.call(containerDomNode.children, 0);\r\n\r\n\tlet result: (LineBreakData | null)[] = [];\r\n\tfor (let i = 0; i < requests.length; i++) {\r\n\t\tconst lineDomNode = lineDomNodes[i];\r\n\t\tconst breakOffsets: number[] | null = readLineBreaks(range, lineDomNode, renderLineContents[i], allCharOffsets[i]);\r\n\t\tif (breakOffsets === null) {\r\n\t\t\tresult[i] = null;\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tconst firstNonWhitespaceIndex = firstNonWhitespaceIndices[i];\r\n\t\tconst wrappedTextIndentLength = wrappedTextIndentLengths[i];\r\n\t\tconst visibleColumns = allVisibleColumns[i];\r\n\r\n\t\tconst breakOffsetsVisibleColumn: number[] = [];\r\n\t\tfor (let j = 0, len = breakOffsets.length; j < len; j++) {\r\n\t\t\tbreakOffsetsVisibleColumn[j] = visibleColumns[breakOffsets[j]];\r\n\t\t}\r\n\r\n\t\tif (firstNonWhitespaceIndex !== 0) {\r\n\t\t\t// All break offsets are relative to the renderLineContent, make them absolute again\r\n\t\t\tfor (let j = 0, len = breakOffsets.length; j < len; j++) {\r\n\t\t\t\tbreakOffsets[j] += firstNonWhitespaceIndex;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tresult[i] = new LineBreakData(breakOffsets, breakOffsetsVisibleColumn, wrappedTextIndentLength);\r\n\t}\r\n\r\n\tdocument.body.removeChild(containerDomNode);\r\n\treturn result;\r\n}\r\n\r\nconst enum Constants {\r\n\tSPAN_MODULO_LIMIT = 16384\r\n}\r\n\r\nfunction renderLine(lineContent: string, initialVisibleColumn: number, tabSize: number, width: number, sb: IStringBuilder): [number[], number[]] {\r\n\tsb.appendASCIIString('
    ');\r\n\t// if (containsRTL) {\r\n\t// \tsb.appendASCIIString('\" dir=\"ltr');\r\n\t// }\r\n\r\n\tconst len = lineContent.length;\r\n\tlet visibleColumn = initialVisibleColumn;\r\n\tlet charOffset = 0;\r\n\tlet charOffsets: number[] = [];\r\n\tlet visibleColumns: number[] = [];\r\n\tlet nextCharCode = (0 < len ? lineContent.charCodeAt(0) : CharCode.Null);\r\n\r\n\tsb.appendASCIIString('');\r\n\tfor (let charIndex = 0; charIndex < len; charIndex++) {\r\n\t\tif (charIndex !== 0 && charIndex % Constants.SPAN_MODULO_LIMIT === 0) {\r\n\t\t\tsb.appendASCIIString('');\r\n\t\t}\r\n\t\tcharOffsets[charIndex] = charOffset;\r\n\t\tvisibleColumns[charIndex] = visibleColumn;\r\n\t\tconst charCode = nextCharCode;\r\n\t\tnextCharCode = (charIndex + 1 < len ? lineContent.charCodeAt(charIndex + 1) : CharCode.Null);\r\n\t\tlet producedCharacters = 1;\r\n\t\tlet charWidth = 1;\r\n\t\tswitch (charCode) {\r\n\t\t\tcase CharCode.Tab:\r\n\t\t\t\tproducedCharacters = (tabSize - (visibleColumn % tabSize));\r\n\t\t\t\tcharWidth = producedCharacters;\r\n\t\t\t\tfor (let space = 1; space <= producedCharacters; space++) {\r\n\t\t\t\t\tif (space < producedCharacters) {\r\n\t\t\t\t\t\tsb.write1(0xA0); //  \r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tsb.appendASCII(CharCode.Space);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase CharCode.Space:\r\n\t\t\t\tif (nextCharCode === CharCode.Space) {\r\n\t\t\t\t\tsb.write1(0xA0); //  \r\n\t\t\t\t} else {\r\n\t\t\t\t\tsb.appendASCII(CharCode.Space);\r\n\t\t\t\t}\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase CharCode.LessThan:\r\n\t\t\t\tsb.appendASCIIString('<');\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase CharCode.GreaterThan:\r\n\t\t\t\tsb.appendASCIIString('>');\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase CharCode.Ampersand:\r\n\t\t\t\tsb.appendASCIIString('&');\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase CharCode.Null:\r\n\t\t\t\tsb.appendASCIIString('�');\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase CharCode.UTF8_BOM:\r\n\t\t\tcase CharCode.LINE_SEPARATOR:\r\n\t\t\tcase CharCode.PARAGRAPH_SEPARATOR:\r\n\t\t\tcase CharCode.NEXT_LINE:\r\n\t\t\t\tsb.write1(0xFFFD);\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tdefault:\r\n\t\t\t\tif (strings.isFullWidthCharacter(charCode)) {\r\n\t\t\t\t\tcharWidth++;\r\n\t\t\t\t}\r\n\t\t\t\t// if (renderControlCharacters && charCode < 32) {\r\n\t\t\t\t// \tsb.write1(9216 + charCode);\r\n\t\t\t\t// } else {\r\n\t\t\t\tsb.write1(charCode);\r\n\t\t\t// }\r\n\t\t}\r\n\r\n\t\tcharOffset += producedCharacters;\r\n\t\tvisibleColumn += charWidth;\r\n\t}\r\n\tsb.appendASCIIString('');\r\n\r\n\tcharOffsets[lineContent.length] = charOffset;\r\n\tvisibleColumns[lineContent.length] = visibleColumn;\r\n\r\n\tsb.appendASCIIString('
    ');\r\n\r\n\treturn [charOffsets, visibleColumns];\r\n}\r\n\r\nfunction readLineBreaks(range: Range, lineDomNode: HTMLDivElement, lineContent: string, charOffsets: number[]): number[] | null {\r\n\tif (lineContent.length <= 1) {\r\n\t\treturn null;\r\n\t}\r\n\tconst spans = Array.prototype.slice.call(lineDomNode.children, 0);\r\n\r\n\tconst breakOffsets: number[] = [];\r\n\ttry {\r\n\t\tdiscoverBreaks(range, spans, charOffsets, 0, null, lineContent.length - 1, null, breakOffsets);\r\n\t} catch (err) {\r\n\t\tconsole.log(err);\r\n\t\treturn null;\r\n\t}\r\n\r\n\tif (breakOffsets.length === 0) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\tbreakOffsets.push(lineContent.length);\r\n\treturn breakOffsets;\r\n}\r\n\r\ntype MaybeRects = ClientRectList | DOMRectList | null;\r\n\r\nfunction discoverBreaks(range: Range, spans: HTMLSpanElement[], charOffsets: number[], low: number, lowRects: MaybeRects, high: number, highRects: MaybeRects, result: number[]): void {\r\n\tif (low === high) {\r\n\t\treturn;\r\n\t}\r\n\r\n\tlowRects = lowRects || readClientRect(range, spans, charOffsets[low], charOffsets[low + 1]);\r\n\thighRects = highRects || readClientRect(range, spans, charOffsets[high], charOffsets[high + 1]);\r\n\r\n\tif (Math.abs(lowRects[0].top - highRects[0].top) <= 0.1) {\r\n\t\t// same line\r\n\t\treturn;\r\n\t}\r\n\r\n\t// there is at least one line break between these two offsets\r\n\tif (low + 1 === high) {\r\n\t\t// the two characters are adjacent, so the line break must be exactly between them\r\n\t\tresult.push(high);\r\n\t\treturn;\r\n\t}\r\n\r\n\tconst mid = low + ((high - low) / 2) | 0;\r\n\tconst midRects = readClientRect(range, spans, charOffsets[mid], charOffsets[mid + 1]);\r\n\tdiscoverBreaks(range, spans, charOffsets, low, lowRects, mid, midRects, result);\r\n\tdiscoverBreaks(range, spans, charOffsets, mid, midRects, high, highRects, result);\r\n}\r\n\r\nfunction readClientRect(range: Range, spans: HTMLSpanElement[], startOffset: number, endOffset: number): ClientRectList | DOMRectList {\r\n\trange.setStart(spans[(startOffset / Constants.SPAN_MODULO_LIMIT) | 0].firstChild!, startOffset % Constants.SPAN_MODULO_LIMIT);\r\n\trange.setEnd(spans[(endOffset / Constants.SPAN_MODULO_LIMIT) | 0].firstChild!, endOffset % Constants.SPAN_MODULO_LIMIT);\r\n\treturn range.getClientRects();\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { Configuration } from 'vs/editor/browser/config/configuration';\r\nimport { DynamicViewOverlay } from 'vs/editor/browser/view/dynamicViewOverlay';\r\nimport { IVisibleLine, IVisibleLinesHost, VisibleLinesCollection } from 'vs/editor/browser/view/viewLayer';\r\nimport { ViewPart } from 'vs/editor/browser/view/viewPart';\r\nimport { IStringBuilder } from 'vs/editor/common/core/stringBuilder';\r\nimport { IConfiguration } from 'vs/editor/common/editorCommon';\r\nimport { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\n\r\nexport class ViewOverlays extends ViewPart implements IVisibleLinesHost {\r\n\r\n\tprivate readonly _visibleLines: VisibleLinesCollection;\r\n\tprotected readonly domNode: FastDomNode;\r\n\tprivate _dynamicOverlays: DynamicViewOverlay[];\r\n\tprivate _isFocused: boolean;\r\n\r\n\tconstructor(context: ViewContext) {\r\n\t\tsuper(context);\r\n\r\n\t\tthis._visibleLines = new VisibleLinesCollection(this);\r\n\t\tthis.domNode = this._visibleLines.domNode;\r\n\r\n\t\tthis._dynamicOverlays = [];\r\n\t\tthis._isFocused = false;\r\n\r\n\t\tthis.domNode.setClassName('view-overlays');\r\n\t}\r\n\r\n\tpublic shouldRender(): boolean {\r\n\t\tif (super.shouldRender()) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tfor (let i = 0, len = this._dynamicOverlays.length; i < len; i++) {\r\n\t\t\tconst dynamicOverlay = this._dynamicOverlays[i];\r\n\t\t\tif (dynamicOverlay.shouldRender()) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tsuper.dispose();\r\n\r\n\t\tfor (let i = 0, len = this._dynamicOverlays.length; i < len; i++) {\r\n\t\t\tconst dynamicOverlay = this._dynamicOverlays[i];\r\n\t\t\tdynamicOverlay.dispose();\r\n\t\t}\r\n\t\tthis._dynamicOverlays = [];\r\n\t}\r\n\r\n\tpublic getDomNode(): FastDomNode {\r\n\t\treturn this.domNode;\r\n\t}\r\n\r\n\t// ---- begin IVisibleLinesHost\r\n\r\n\tpublic createVisibleLine(): ViewOverlayLine {\r\n\t\treturn new ViewOverlayLine(this._context.configuration, this._dynamicOverlays);\r\n\t}\r\n\r\n\t// ---- end IVisibleLinesHost\r\n\r\n\tpublic addDynamicOverlay(overlay: DynamicViewOverlay): void {\r\n\t\tthis._dynamicOverlays.push(overlay);\r\n\t}\r\n\r\n\t// ----- event handlers\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tthis._visibleLines.onConfigurationChanged(e);\r\n\t\tconst startLineNumber = this._visibleLines.getStartLineNumber();\r\n\t\tconst endLineNumber = this._visibleLines.getEndLineNumber();\r\n\t\tfor (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {\r\n\t\t\tconst line = this._visibleLines.getVisibleLine(lineNumber);\r\n\t\t\tline.onConfigurationChanged(e);\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\tpublic onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\r\n\t\treturn this._visibleLines.onFlushed(e);\r\n\t}\r\n\tpublic onFocusChanged(e: viewEvents.ViewFocusChangedEvent): boolean {\r\n\t\tthis._isFocused = e.isFocused;\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\r\n\t\treturn this._visibleLines.onLinesChanged(e);\r\n\t}\r\n\tpublic onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\r\n\t\treturn this._visibleLines.onLinesDeleted(e);\r\n\t}\r\n\tpublic onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\r\n\t\treturn this._visibleLines.onLinesInserted(e);\r\n\t}\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\treturn this._visibleLines.onScrollChanged(e) || true;\r\n\t}\r\n\tpublic onTokensChanged(e: viewEvents.ViewTokensChangedEvent): boolean {\r\n\t\treturn this._visibleLines.onTokensChanged(e);\r\n\t}\r\n\tpublic onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\r\n\t\treturn this._visibleLines.onZonesChanged(e);\r\n\t}\r\n\r\n\t// ----- end event handlers\r\n\r\n\tpublic prepareRender(ctx: RenderingContext): void {\r\n\t\tconst toRender = this._dynamicOverlays.filter(overlay => overlay.shouldRender());\r\n\r\n\t\tfor (let i = 0, len = toRender.length; i < len; i++) {\r\n\t\t\tconst dynamicOverlay = toRender[i];\r\n\t\t\tdynamicOverlay.prepareRender(ctx);\r\n\t\t\tdynamicOverlay.onDidRender();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic render(ctx: RestrictedRenderingContext): void {\r\n\t\t// Overwriting to bypass `shouldRender` flag\r\n\t\tthis._viewOverlaysRender(ctx);\r\n\r\n\t\tthis.domNode.toggleClassName('focused', this._isFocused);\r\n\t}\r\n\r\n\t_viewOverlaysRender(ctx: RestrictedRenderingContext): void {\r\n\t\tthis._visibleLines.renderLines(ctx.viewportData);\r\n\t}\r\n}\r\n\r\nexport class ViewOverlayLine implements IVisibleLine {\r\n\r\n\tprivate readonly _configuration: IConfiguration;\r\n\tprivate readonly _dynamicOverlays: DynamicViewOverlay[];\r\n\tprivate _domNode: FastDomNode | null;\r\n\tprivate _renderedContent: string | null;\r\n\tprivate _lineHeight: number;\r\n\r\n\tconstructor(configuration: IConfiguration, dynamicOverlays: DynamicViewOverlay[]) {\r\n\t\tthis._configuration = configuration;\r\n\t\tthis._lineHeight = this._configuration.options.get(EditorOption.lineHeight);\r\n\t\tthis._dynamicOverlays = dynamicOverlays;\r\n\r\n\t\tthis._domNode = null;\r\n\t\tthis._renderedContent = null;\r\n\t}\r\n\r\n\tpublic getDomNode(): HTMLElement | null {\r\n\t\tif (!this._domNode) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn this._domNode.domNode;\r\n\t}\r\n\tpublic setDomNode(domNode: HTMLElement): void {\r\n\t\tthis._domNode = createFastDomNode(domNode);\r\n\t}\r\n\r\n\tpublic onContentChanged(): void {\r\n\t\t// Nothing\r\n\t}\r\n\tpublic onTokensChanged(): void {\r\n\t\t// Nothing\r\n\t}\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): void {\r\n\t\tthis._lineHeight = this._configuration.options.get(EditorOption.lineHeight);\r\n\t}\r\n\r\n\tpublic renderLine(lineNumber: number, deltaTop: number, viewportData: ViewportData, sb: IStringBuilder): boolean {\r\n\t\tlet result = '';\r\n\t\tfor (let i = 0, len = this._dynamicOverlays.length; i < len; i++) {\r\n\t\t\tconst dynamicOverlay = this._dynamicOverlays[i];\r\n\t\t\tresult += dynamicOverlay.render(viewportData.startLineNumber, lineNumber);\r\n\t\t}\r\n\r\n\t\tif (this._renderedContent === result) {\r\n\t\t\t// No rendering needed\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tthis._renderedContent = result;\r\n\r\n\t\tsb.appendASCIIString('
    ');\r\n\t\tsb.appendASCIIString(result);\r\n\t\tsb.appendASCIIString('
    ');\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic layoutLine(lineNumber: number, deltaTop: number): void {\r\n\t\tif (this._domNode) {\r\n\t\t\tthis._domNode.setTop(deltaTop);\r\n\t\t\tthis._domNode.setHeight(this._lineHeight);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class ContentViewOverlays extends ViewOverlays {\r\n\r\n\tprivate _contentWidth: number;\r\n\r\n\tconstructor(context: ViewContext) {\r\n\t\tsuper(context);\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\t\tthis._contentWidth = layoutInfo.contentWidth;\r\n\r\n\t\tthis.domNode.setHeight(0);\r\n\t}\r\n\r\n\t// --- begin event handlers\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\t\tthis._contentWidth = layoutInfo.contentWidth;\r\n\t\treturn super.onConfigurationChanged(e) || true;\r\n\t}\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\treturn super.onScrollChanged(e) || e.scrollWidthChanged;\r\n\t}\r\n\r\n\t// --- end event handlers\r\n\r\n\t_viewOverlaysRender(ctx: RestrictedRenderingContext): void {\r\n\t\tsuper._viewOverlaysRender(ctx);\r\n\r\n\t\tthis.domNode.setWidth(Math.max(ctx.scrollWidth, this._contentWidth));\r\n\t}\r\n}\r\n\r\nexport class MarginViewOverlays extends ViewOverlays {\r\n\r\n\tprivate _contentLeft: number;\r\n\r\n\tconstructor(context: ViewContext) {\r\n\t\tsuper(context);\r\n\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\t\tthis._contentLeft = layoutInfo.contentLeft;\r\n\r\n\t\tthis.domNode.setClassName('margin-view-overlays');\r\n\t\tthis.domNode.setWidth(1);\r\n\r\n\t\tConfiguration.applyFontInfo(this.domNode, options.get(EditorOption.fontInfo));\r\n\t}\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tConfiguration.applyFontInfo(this.domNode, options.get(EditorOption.fontInfo));\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\t\tthis._contentLeft = layoutInfo.contentLeft;\r\n\t\treturn super.onConfigurationChanged(e) || true;\r\n\t}\r\n\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\treturn super.onScrollChanged(e) || e.scrollHeightChanged;\r\n\t}\r\n\r\n\t_viewOverlaysRender(ctx: RestrictedRenderingContext): void {\r\n\t\tsuper._viewOverlaysRender(ctx);\r\n\t\tconst height = Math.min(ctx.scrollHeight, 1000000);\r\n\t\tthis.domNode.setHeight(height);\r\n\t\tthis.domNode.setWidth(this._contentLeft);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { Configuration } from 'vs/editor/browser/config/configuration';\r\nimport { TextEditorCursorStyle, EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { MOUSE_CURSOR_TEXT_CSS_CLASS_NAME } from 'vs/base/browser/ui/mouseCursor/mouseCursor';\r\n\r\nexport interface IViewCursorRenderData {\r\n\tdomNode: HTMLElement;\r\n\tposition: Position;\r\n\tcontentLeft: number;\r\n\twidth: number;\r\n\theight: number;\r\n}\r\n\r\nclass ViewCursorRenderData {\r\n\tconstructor(\r\n\t\tpublic readonly top: number,\r\n\t\tpublic readonly left: number,\r\n\t\tpublic readonly width: number,\r\n\t\tpublic readonly height: number,\r\n\t\tpublic readonly textContent: string,\r\n\t\tpublic readonly textContentClassName: string\r\n\t) { }\r\n}\r\n\r\nexport class ViewCursor {\r\n\tprivate readonly _context: ViewContext;\r\n\tprivate readonly _domNode: FastDomNode;\r\n\r\n\tprivate _cursorStyle: TextEditorCursorStyle;\r\n\tprivate _lineCursorWidth: number;\r\n\tprivate _lineHeight: number;\r\n\tprivate _typicalHalfwidthCharacterWidth: number;\r\n\r\n\tprivate _isVisible: boolean;\r\n\r\n\tprivate _position: Position;\r\n\r\n\tprivate _lastRenderedContent: string;\r\n\tprivate _renderData: ViewCursorRenderData | null;\r\n\r\n\tconstructor(context: ViewContext) {\r\n\t\tthis._context = context;\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst fontInfo = options.get(EditorOption.fontInfo);\r\n\r\n\t\tthis._cursorStyle = options.get(EditorOption.cursorStyle);\r\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tthis._typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth;\r\n\t\tthis._lineCursorWidth = Math.min(options.get(EditorOption.cursorWidth), this._typicalHalfwidthCharacterWidth);\r\n\r\n\t\tthis._isVisible = true;\r\n\r\n\t\t// Create the dom node\r\n\t\tthis._domNode = createFastDomNode(document.createElement('div'));\r\n\t\tthis._domNode.setClassName(`cursor ${MOUSE_CURSOR_TEXT_CSS_CLASS_NAME}`);\r\n\t\tthis._domNode.setHeight(this._lineHeight);\r\n\t\tthis._domNode.setTop(0);\r\n\t\tthis._domNode.setLeft(0);\r\n\t\tConfiguration.applyFontInfo(this._domNode, fontInfo);\r\n\t\tthis._domNode.setDisplay('none');\r\n\r\n\t\tthis._position = new Position(1, 1);\r\n\r\n\t\tthis._lastRenderedContent = '';\r\n\t\tthis._renderData = null;\r\n\t}\r\n\r\n\tpublic getDomNode(): FastDomNode {\r\n\t\treturn this._domNode;\r\n\t}\r\n\r\n\tpublic getPosition(): Position {\r\n\t\treturn this._position;\r\n\t}\r\n\r\n\tpublic show(): void {\r\n\t\tif (!this._isVisible) {\r\n\t\t\tthis._domNode.setVisibility('inherit');\r\n\t\t\tthis._isVisible = true;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic hide(): void {\r\n\t\tif (this._isVisible) {\r\n\t\t\tthis._domNode.setVisibility('hidden');\r\n\t\t\tthis._isVisible = false;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst fontInfo = options.get(EditorOption.fontInfo);\r\n\r\n\t\tthis._cursorStyle = options.get(EditorOption.cursorStyle);\r\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tthis._typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth;\r\n\t\tthis._lineCursorWidth = Math.min(options.get(EditorOption.cursorWidth), this._typicalHalfwidthCharacterWidth);\r\n\t\tConfiguration.applyFontInfo(this._domNode, fontInfo);\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic onCursorPositionChanged(position: Position): boolean {\r\n\t\tthis._position = position;\r\n\t\treturn true;\r\n\t}\r\n\r\n\tprivate _prepareRender(ctx: RenderingContext): ViewCursorRenderData | null {\r\n\t\tlet textContent = '';\r\n\r\n\t\tif (this._cursorStyle === TextEditorCursorStyle.Line || this._cursorStyle === TextEditorCursorStyle.LineThin) {\r\n\t\t\tconst visibleRange = ctx.visibleRangeForPosition(this._position);\r\n\t\t\tif (!visibleRange || visibleRange.outsideRenderedLine) {\r\n\t\t\t\t// Outside viewport\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\r\n\t\t\tlet width: number;\r\n\t\t\tif (this._cursorStyle === TextEditorCursorStyle.Line) {\r\n\t\t\t\twidth = dom.computeScreenAwareSize(this._lineCursorWidth > 0 ? this._lineCursorWidth : 2);\r\n\t\t\t\tif (width > 2) {\r\n\t\t\t\t\tconst lineContent = this._context.model.getLineContent(this._position.lineNumber);\r\n\t\t\t\t\tconst nextCharLength = strings.nextCharLength(lineContent, this._position.column - 1);\r\n\t\t\t\t\ttextContent = lineContent.substr(this._position.column - 1, nextCharLength);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\twidth = dom.computeScreenAwareSize(1);\r\n\t\t\t}\r\n\r\n\t\t\tlet left = visibleRange.left;\r\n\t\t\tif (width >= 2 && left >= 1) {\r\n\t\t\t\t// try to center cursor\r\n\t\t\t\tleft -= 1;\r\n\t\t\t}\r\n\r\n\t\t\tconst top = ctx.getVerticalOffsetForLineNumber(this._position.lineNumber) - ctx.bigNumbersDelta;\r\n\t\t\treturn new ViewCursorRenderData(top, left, width, this._lineHeight, textContent, '');\r\n\t\t}\r\n\r\n\t\tconst lineContent = this._context.model.getLineContent(this._position.lineNumber);\r\n\t\tconst nextCharLength = strings.nextCharLength(lineContent, this._position.column - 1);\r\n\t\tconst visibleRangeForCharacter = ctx.linesVisibleRangesForRange(new Range(this._position.lineNumber, this._position.column, this._position.lineNumber, this._position.column + nextCharLength), false);\r\n\t\tif (!visibleRangeForCharacter || visibleRangeForCharacter.length === 0) {\r\n\t\t\t// Outside viewport\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst firstVisibleRangeForCharacter = visibleRangeForCharacter[0];\r\n\t\tif (firstVisibleRangeForCharacter.outsideRenderedLine || firstVisibleRangeForCharacter.ranges.length === 0) {\r\n\t\t\t// Outside viewport\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst range = firstVisibleRangeForCharacter.ranges[0];\r\n\t\tconst width = range.width < 1 ? this._typicalHalfwidthCharacterWidth : range.width;\r\n\r\n\t\tlet textContentClassName = '';\r\n\t\tif (this._cursorStyle === TextEditorCursorStyle.Block) {\r\n\t\t\tconst lineData = this._context.model.getViewLineData(this._position.lineNumber);\r\n\t\t\ttextContent = lineContent.substr(this._position.column - 1, nextCharLength);\r\n\t\t\tconst tokenIndex = lineData.tokens.findTokenIndexAtOffset(this._position.column - 1);\r\n\t\t\ttextContentClassName = lineData.tokens.getClassName(tokenIndex);\r\n\t\t}\r\n\r\n\t\tlet top = ctx.getVerticalOffsetForLineNumber(this._position.lineNumber) - ctx.bigNumbersDelta;\r\n\t\tlet height = this._lineHeight;\r\n\r\n\t\t// Underline might interfere with clicking\r\n\t\tif (this._cursorStyle === TextEditorCursorStyle.Underline || this._cursorStyle === TextEditorCursorStyle.UnderlineThin) {\r\n\t\t\ttop += this._lineHeight - 2;\r\n\t\t\theight = 2;\r\n\t\t}\r\n\r\n\t\treturn new ViewCursorRenderData(top, range.left, width, height, textContent, textContentClassName);\r\n\t}\r\n\r\n\tpublic prepareRender(ctx: RenderingContext): void {\r\n\t\tthis._renderData = this._prepareRender(ctx);\r\n\t}\r\n\r\n\tpublic render(ctx: RestrictedRenderingContext): IViewCursorRenderData | null {\r\n\t\tif (!this._renderData) {\r\n\t\t\tthis._domNode.setDisplay('none');\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (this._lastRenderedContent !== this._renderData.textContent) {\r\n\t\t\tthis._lastRenderedContent = this._renderData.textContent;\r\n\t\t\tthis._domNode.domNode.textContent = this._lastRenderedContent;\r\n\t\t}\r\n\r\n\t\tthis._domNode.setClassName(`cursor ${MOUSE_CURSOR_TEXT_CSS_CLASS_NAME} ${this._renderData.textContentClassName}`);\r\n\r\n\t\tthis._domNode.setDisplay('block');\r\n\t\tthis._domNode.setTop(this._renderData.top);\r\n\t\tthis._domNode.setLeft(this._renderData.left);\r\n\t\tthis._domNode.setWidth(this._renderData.width);\r\n\t\tthis._domNode.setLineHeight(this._renderData.height);\r\n\t\tthis._domNode.setHeight(this._renderData.height);\r\n\r\n\t\treturn {\r\n\t\t\tdomNode: this._domNode.domNode,\r\n\t\t\tposition: this._position,\r\n\t\t\tcontentLeft: this._renderData.left,\r\n\t\t\theight: this._renderData.height,\r\n\t\t\twidth: 2\r\n\t\t};\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport * as mime from 'vs/base/common/mime';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { LanguageId, LanguageIdentifier } from 'vs/editor/common/modes';\r\nimport { ModesRegistry } from 'vs/editor/common/modes/modesRegistry';\r\nimport { NULL_LANGUAGE_IDENTIFIER, NULL_MODE_ID } from 'vs/editor/common/modes/nullMode';\r\nimport { ILanguageExtensionPoint } from 'vs/editor/common/services/modeService';\r\nimport { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';\r\nimport { Registry } from 'vs/platform/registry/common/platform';\r\n\r\nconst hasOwnProperty = Object.prototype.hasOwnProperty;\r\n\r\nexport interface IResolvedLanguage {\r\n\tidentifier: LanguageIdentifier;\r\n\tname: string | null;\r\n\tmimetypes: string[];\r\n\taliases: string[];\r\n\textensions: string[];\r\n\tfilenames: string[];\r\n\tconfigurationFiles: URI[];\r\n}\r\n\r\nexport class LanguagesRegistry extends Disposable {\r\n\r\n\tprivate readonly _onDidChange: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidChange: Event = this._onDidChange.event;\r\n\r\n\tprivate readonly _warnOnOverwrite: boolean;\r\n\r\n\tprivate _nextLanguageId2: number;\r\n\tprivate readonly _languageIdToLanguage: string[];\r\n\tprivate readonly _languageToLanguageId: { [id: string]: number; };\r\n\r\n\tprivate _languages: { [id: string]: IResolvedLanguage; };\r\n\tprivate _mimeTypesMap: { [mimeType: string]: LanguageIdentifier; };\r\n\tprivate _nameMap: { [name: string]: LanguageIdentifier; };\r\n\tprivate _lowercaseNameMap: { [name: string]: LanguageIdentifier; };\r\n\r\n\tconstructor(useModesRegistry = true, warnOnOverwrite = false) {\r\n\t\tsuper();\r\n\r\n\t\tthis._warnOnOverwrite = warnOnOverwrite;\r\n\r\n\t\tthis._nextLanguageId2 = 1;\r\n\t\tthis._languageIdToLanguage = [];\r\n\t\tthis._languageToLanguageId = Object.create(null);\r\n\r\n\t\tthis._languages = {};\r\n\t\tthis._mimeTypesMap = {};\r\n\t\tthis._nameMap = {};\r\n\t\tthis._lowercaseNameMap = {};\r\n\r\n\t\tif (useModesRegistry) {\r\n\t\t\tthis._initializeFromRegistry();\r\n\t\t\tthis._register(ModesRegistry.onDidChangeLanguages((m) => this._initializeFromRegistry()));\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _initializeFromRegistry(): void {\r\n\t\tthis._languages = {};\r\n\t\tthis._mimeTypesMap = {};\r\n\t\tthis._nameMap = {};\r\n\t\tthis._lowercaseNameMap = {};\r\n\r\n\t\tconst desc = ModesRegistry.getLanguages();\r\n\t\tthis._registerLanguages(desc);\r\n\t}\r\n\r\n\t_registerLanguages(desc: ILanguageExtensionPoint[]): void {\r\n\r\n\t\tfor (const d of desc) {\r\n\t\t\tthis._registerLanguage(d);\r\n\t\t}\r\n\r\n\t\t// Rebuild fast path maps\r\n\t\tthis._mimeTypesMap = {};\r\n\t\tthis._nameMap = {};\r\n\t\tthis._lowercaseNameMap = {};\r\n\t\tObject.keys(this._languages).forEach((langId) => {\r\n\t\t\tlet language = this._languages[langId];\r\n\t\t\tif (language.name) {\r\n\t\t\t\tthis._nameMap[language.name] = language.identifier;\r\n\t\t\t}\r\n\t\t\tlanguage.aliases.forEach((alias) => {\r\n\t\t\t\tthis._lowercaseNameMap[alias.toLowerCase()] = language.identifier;\r\n\t\t\t});\r\n\t\t\tlanguage.mimetypes.forEach((mimetype) => {\r\n\t\t\t\tthis._mimeTypesMap[mimetype] = language.identifier;\r\n\t\t\t});\r\n\t\t});\r\n\r\n\t\tRegistry.as(Extensions.Configuration).registerOverrideIdentifiers(ModesRegistry.getLanguages().map(language => language.id));\r\n\r\n\t\tthis._onDidChange.fire();\r\n\t}\r\n\r\n\tprivate _getLanguageId(language: string): number {\r\n\t\tif (this._languageToLanguageId[language]) {\r\n\t\t\treturn this._languageToLanguageId[language];\r\n\t\t}\r\n\r\n\t\tconst languageId = this._nextLanguageId2++;\r\n\t\tthis._languageIdToLanguage[languageId] = language;\r\n\t\tthis._languageToLanguageId[language] = languageId;\r\n\r\n\t\treturn languageId;\r\n\t}\r\n\r\n\tprivate _registerLanguage(lang: ILanguageExtensionPoint): void {\r\n\t\tconst langId = lang.id;\r\n\r\n\t\tlet resolvedLanguage: IResolvedLanguage;\r\n\t\tif (hasOwnProperty.call(this._languages, langId)) {\r\n\t\t\tresolvedLanguage = this._languages[langId];\r\n\t\t} else {\r\n\t\t\tconst languageId = this._getLanguageId(langId);\r\n\t\t\tresolvedLanguage = {\r\n\t\t\t\tidentifier: new LanguageIdentifier(langId, languageId),\r\n\t\t\t\tname: null,\r\n\t\t\t\tmimetypes: [],\r\n\t\t\t\taliases: [],\r\n\t\t\t\textensions: [],\r\n\t\t\t\tfilenames: [],\r\n\t\t\t\tconfigurationFiles: []\r\n\t\t\t};\r\n\t\t\tthis._languages[langId] = resolvedLanguage;\r\n\t\t}\r\n\r\n\t\tthis._mergeLanguage(resolvedLanguage, lang);\r\n\t}\r\n\r\n\tprivate _mergeLanguage(resolvedLanguage: IResolvedLanguage, lang: ILanguageExtensionPoint): void {\r\n\t\tconst langId = lang.id;\r\n\r\n\t\tlet primaryMime: string | null = null;\r\n\r\n\t\tif (Array.isArray(lang.mimetypes) && lang.mimetypes.length > 0) {\r\n\t\t\tresolvedLanguage.mimetypes.push(...lang.mimetypes);\r\n\t\t\tprimaryMime = lang.mimetypes[0];\r\n\t\t}\r\n\r\n\t\tif (!primaryMime) {\r\n\t\t\tprimaryMime = `text/x-${langId}`;\r\n\t\t\tresolvedLanguage.mimetypes.push(primaryMime);\r\n\t\t}\r\n\r\n\t\tif (Array.isArray(lang.extensions)) {\r\n\t\t\tif (lang.configuration) {\r\n\t\t\t\t// insert first as this appears to be the 'primary' language definition\r\n\t\t\t\tresolvedLanguage.extensions = lang.extensions.concat(resolvedLanguage.extensions);\r\n\t\t\t} else {\r\n\t\t\t\tresolvedLanguage.extensions = resolvedLanguage.extensions.concat(lang.extensions);\r\n\t\t\t}\r\n\t\t\tfor (let extension of lang.extensions) {\r\n\t\t\t\tmime.registerTextMime({ id: langId, mime: primaryMime, extension: extension }, this._warnOnOverwrite);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (Array.isArray(lang.filenames)) {\r\n\t\t\tfor (let filename of lang.filenames) {\r\n\t\t\t\tmime.registerTextMime({ id: langId, mime: primaryMime, filename: filename }, this._warnOnOverwrite);\r\n\t\t\t\tresolvedLanguage.filenames.push(filename);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (Array.isArray(lang.filenamePatterns)) {\r\n\t\t\tfor (let filenamePattern of lang.filenamePatterns) {\r\n\t\t\t\tmime.registerTextMime({ id: langId, mime: primaryMime, filepattern: filenamePattern }, this._warnOnOverwrite);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (typeof lang.firstLine === 'string' && lang.firstLine.length > 0) {\r\n\t\t\tlet firstLineRegexStr = lang.firstLine;\r\n\t\t\tif (firstLineRegexStr.charAt(0) !== '^') {\r\n\t\t\t\tfirstLineRegexStr = '^' + firstLineRegexStr;\r\n\t\t\t}\r\n\t\t\ttry {\r\n\t\t\t\tlet firstLineRegex = new RegExp(firstLineRegexStr);\r\n\t\t\t\tif (!strings.regExpLeadsToEndlessLoop(firstLineRegex)) {\r\n\t\t\t\t\tmime.registerTextMime({ id: langId, mime: primaryMime, firstline: firstLineRegex }, this._warnOnOverwrite);\r\n\t\t\t\t}\r\n\t\t\t} catch (err) {\r\n\t\t\t\t// Most likely, the regex was bad\r\n\t\t\t\tonUnexpectedError(err);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tresolvedLanguage.aliases.push(langId);\r\n\r\n\t\tlet langAliases: Array | null = null;\r\n\t\tif (typeof lang.aliases !== 'undefined' && Array.isArray(lang.aliases)) {\r\n\t\t\tif (lang.aliases.length === 0) {\r\n\t\t\t\t// signal that this language should not get a name\r\n\t\t\t\tlangAliases = [null];\r\n\t\t\t} else {\r\n\t\t\t\tlangAliases = lang.aliases;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (langAliases !== null) {\r\n\t\t\tfor (const langAlias of langAliases) {\r\n\t\t\t\tif (!langAlias || langAlias.length === 0) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\tresolvedLanguage.aliases.push(langAlias);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet containsAliases = (langAliases !== null && langAliases.length > 0);\r\n\t\tif (containsAliases && langAliases![0] === null) {\r\n\t\t\t// signal that this language should not get a name\r\n\t\t} else {\r\n\t\t\tlet bestName = (containsAliases ? langAliases![0] : null) || langId;\r\n\t\t\tif (containsAliases || !resolvedLanguage.name) {\r\n\t\t\t\tresolvedLanguage.name = bestName;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (lang.configuration) {\r\n\t\t\tresolvedLanguage.configurationFiles.push(lang.configuration);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic isRegisteredMode(mimetypeOrModeId: string): boolean {\r\n\t\t// Is this a known mime type ?\r\n\t\tif (hasOwnProperty.call(this._mimeTypesMap, mimetypeOrModeId)) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\t// Is this a known mode id ?\r\n\t\treturn hasOwnProperty.call(this._languages, mimetypeOrModeId);\r\n\t}\r\n\r\n\tpublic getModeIdForLanguageNameLowercase(languageNameLower: string): string | null {\r\n\t\tif (!hasOwnProperty.call(this._lowercaseNameMap, languageNameLower)) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn this._lowercaseNameMap[languageNameLower].language;\r\n\t}\r\n\r\n\tpublic extractModeIds(commaSeparatedMimetypesOrCommaSeparatedIds: string | undefined): string[] {\r\n\t\tif (!commaSeparatedMimetypesOrCommaSeparatedIds) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\treturn (\r\n\t\t\tcommaSeparatedMimetypesOrCommaSeparatedIds.\r\n\t\t\t\tsplit(',').\r\n\t\t\t\tmap((mimeTypeOrId) => mimeTypeOrId.trim()).\r\n\t\t\t\tmap((mimeTypeOrId) => {\r\n\t\t\t\t\tif (hasOwnProperty.call(this._mimeTypesMap, mimeTypeOrId)) {\r\n\t\t\t\t\t\treturn this._mimeTypesMap[mimeTypeOrId].language;\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn mimeTypeOrId;\r\n\t\t\t\t}).\r\n\t\t\t\tfilter((modeId) => {\r\n\t\t\t\t\treturn hasOwnProperty.call(this._languages, modeId);\r\n\t\t\t\t})\r\n\t\t);\r\n\t}\r\n\r\n\tpublic getLanguageIdentifier(_modeId: string | LanguageId): LanguageIdentifier | null {\r\n\t\tif (_modeId === NULL_MODE_ID || _modeId === LanguageId.Null) {\r\n\t\t\treturn NULL_LANGUAGE_IDENTIFIER;\r\n\t\t}\r\n\r\n\t\tlet modeId: string;\r\n\t\tif (typeof _modeId === 'string') {\r\n\t\t\tmodeId = _modeId;\r\n\t\t} else {\r\n\t\t\tmodeId = this._languageIdToLanguage[_modeId];\r\n\t\t\tif (!modeId) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!hasOwnProperty.call(this._languages, modeId)) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn this._languages[modeId].identifier;\r\n\t}\r\n\r\n\tpublic getModeIdsFromFilepathOrFirstLine(resource: URI | null, firstLine?: string): string[] {\r\n\t\tif (!resource && !firstLine) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\t\tlet mimeTypes = mime.guessMimeTypes(resource, firstLine);\r\n\t\treturn this.extractModeIds(mimeTypes.join(','));\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { IMode, LanguageId, LanguageIdentifier } from 'vs/editor/common/modes';\r\nimport { FrankensteinMode } from 'vs/editor/common/modes/abstractMode';\r\nimport { NULL_LANGUAGE_IDENTIFIER } from 'vs/editor/common/modes/nullMode';\r\nimport { LanguagesRegistry } from 'vs/editor/common/services/languagesRegistry';\r\nimport { ILanguageSelection, IModeService } from 'vs/editor/common/services/modeService';\r\nimport { firstOrDefault } from 'vs/base/common/arrays';\r\n\r\nclass LanguageSelection extends Disposable implements ILanguageSelection {\r\n\r\n\tpublic languageIdentifier: LanguageIdentifier;\r\n\r\n\tprivate readonly _selector: () => LanguageIdentifier;\r\n\r\n\tprivate readonly _onDidChange: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidChange: Event = this._onDidChange.event;\r\n\r\n\tconstructor(onLanguagesMaybeChanged: Event, selector: () => LanguageIdentifier) {\r\n\t\tsuper();\r\n\t\tthis._selector = selector;\r\n\t\tthis.languageIdentifier = this._selector();\r\n\t\tthis._register(onLanguagesMaybeChanged(() => this._evaluate()));\r\n\t}\r\n\r\n\tprivate _evaluate(): void {\r\n\t\tlet languageIdentifier = this._selector();\r\n\t\tif (languageIdentifier.id === this.languageIdentifier.id) {\r\n\t\t\t// no change\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis.languageIdentifier = languageIdentifier;\r\n\t\tthis._onDidChange.fire(this.languageIdentifier);\r\n\t}\r\n}\r\n\r\nexport class ModeServiceImpl extends Disposable implements IModeService {\r\n\tpublic _serviceBrand: undefined;\r\n\r\n\tprivate readonly _instantiatedModes: { [modeId: string]: IMode; };\r\n\tprivate readonly _registry: LanguagesRegistry;\r\n\r\n\tprivate readonly _onDidCreateMode = this._register(new Emitter());\r\n\tpublic readonly onDidCreateMode: Event = this._onDidCreateMode.event;\r\n\r\n\tprotected readonly _onLanguagesMaybeChanged = this._register(new Emitter());\r\n\tpublic readonly onLanguagesMaybeChanged: Event = this._onLanguagesMaybeChanged.event;\r\n\r\n\tconstructor(warnOnOverwrite = false) {\r\n\t\tsuper();\r\n\t\tthis._instantiatedModes = {};\r\n\r\n\t\tthis._registry = this._register(new LanguagesRegistry(true, warnOnOverwrite));\r\n\t\tthis._register(this._registry.onDidChange(() => this._onLanguagesMaybeChanged.fire()));\r\n\t}\r\n\r\n\tpublic isRegisteredMode(mimetypeOrModeId: string): boolean {\r\n\t\treturn this._registry.isRegisteredMode(mimetypeOrModeId);\r\n\t}\r\n\r\n\tpublic getModeIdForLanguageName(alias: string): string | null {\r\n\t\treturn this._registry.getModeIdForLanguageNameLowercase(alias);\r\n\t}\r\n\r\n\tpublic getModeIdByFilepathOrFirstLine(resource: URI | null, firstLine?: string): string | null {\r\n\t\tconst modeIds = this._registry.getModeIdsFromFilepathOrFirstLine(resource, firstLine);\r\n\t\treturn firstOrDefault(modeIds, null);\r\n\t}\r\n\r\n\tpublic getModeId(commaSeparatedMimetypesOrCommaSeparatedIds: string | undefined): string | null {\r\n\t\tconst modeIds = this._registry.extractModeIds(commaSeparatedMimetypesOrCommaSeparatedIds);\r\n\t\treturn firstOrDefault(modeIds, null);\r\n\t}\r\n\r\n\tpublic getLanguageIdentifier(modeId: string | LanguageId): LanguageIdentifier | null {\r\n\t\treturn this._registry.getLanguageIdentifier(modeId);\r\n\t}\r\n\r\n\t// --- instantiation\r\n\r\n\tpublic create(commaSeparatedMimetypesOrCommaSeparatedIds: string | undefined): ILanguageSelection {\r\n\t\treturn new LanguageSelection(this.onLanguagesMaybeChanged, () => {\r\n\t\t\tconst modeId = this.getModeId(commaSeparatedMimetypesOrCommaSeparatedIds);\r\n\t\t\treturn this._createModeAndGetLanguageIdentifier(modeId);\r\n\t\t});\r\n\t}\r\n\r\n\tpublic createByFilepathOrFirstLine(resource: URI | null, firstLine?: string): ILanguageSelection {\r\n\t\treturn new LanguageSelection(this.onLanguagesMaybeChanged, () => {\r\n\t\t\tconst modeId = this.getModeIdByFilepathOrFirstLine(resource, firstLine);\r\n\t\t\treturn this._createModeAndGetLanguageIdentifier(modeId);\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _createModeAndGetLanguageIdentifier(modeId: string | null): LanguageIdentifier {\r\n\t\t// Fall back to plain text if no mode was found\r\n\t\tconst languageIdentifier = this.getLanguageIdentifier(modeId || 'plaintext') || NULL_LANGUAGE_IDENTIFIER;\r\n\t\tthis._getOrCreateMode(languageIdentifier.language);\r\n\t\treturn languageIdentifier;\r\n\t}\r\n\r\n\tpublic triggerMode(commaSeparatedMimetypesOrCommaSeparatedIds: string): void {\r\n\t\tconst modeId = this.getModeId(commaSeparatedMimetypesOrCommaSeparatedIds);\r\n\t\t// Fall back to plain text if no mode was found\r\n\t\tthis._getOrCreateMode(modeId || 'plaintext');\r\n\t}\r\n\r\n\tprivate _getOrCreateMode(modeId: string): IMode {\r\n\t\tif (!this._instantiatedModes.hasOwnProperty(modeId)) {\r\n\t\t\tlet languageIdentifier = this.getLanguageIdentifier(modeId) || NULL_LANGUAGE_IDENTIFIER;\r\n\t\t\tthis._instantiatedModes[modeId] = new FrankensteinMode(languageIdentifier);\r\n\r\n\t\t\tthis._onDidCreateMode.fire(this._instantiatedModes[modeId]);\r\n\t\t}\r\n\t\treturn this._instantiatedModes[modeId];\r\n\t}\r\n}\r\n","\r\nimport { URI, UriComponents } from 'vs/base/common/uri';\r\nimport { Event } from 'vs/base/common/event';\r\nimport { Registry } from 'vs/platform/registry/common/platform';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry';\r\n\r\nexport const IConfigurationService = createDecorator('configurationService');\r\n\r\nexport interface IConfigurationOverrides {\r\n\toverrideIdentifier?: string | null;\r\n\tresource?: URI | null;\r\n}\r\n\r\nexport const enum ConfigurationTarget {\r\n\tUSER = 1,\r\n\tUSER_LOCAL,\r\n\tUSER_REMOTE,\r\n\tWORKSPACE,\r\n\tWORKSPACE_FOLDER,\r\n\tDEFAULT,\r\n\tMEMORY\r\n}\r\n\r\nexport interface IConfigurationChange {\r\n\tkeys: string[];\r\n\toverrides: [string, string[]][];\r\n}\r\n\r\nexport interface IConfigurationChangeEvent {\r\n\r\n\treadonly source: ConfigurationTarget;\r\n\treadonly affectedKeys: string[];\r\n\r\n\taffectsConfiguration(configuration: string, overrides?: IConfigurationOverrides): boolean;\r\n}\r\n\r\nexport interface IConfigurationService {\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\tonDidChangeConfiguration: Event;\r\n\r\n\t/**\r\n\t * Fetches the value of the section for the given overrides.\r\n\t * Value can be of native type or an object keyed off the section name.\r\n\t *\r\n\t * @param section - Section of the configuraion. Can be `null` or `undefined`.\r\n\t * @param overrides - Overrides that has to be applied while fetching\r\n\t *\r\n\t */\r\n\tgetValue(): T;\r\n\tgetValue(section: string): T;\r\n\tgetValue(overrides: IConfigurationOverrides): T;\r\n\tgetValue(section: string, overrides: IConfigurationOverrides): T;\r\n}\r\n\r\nexport interface IConfigurationModel {\r\n\tcontents: any;\r\n\tkeys: string[];\r\n\toverrides: IOverrides[];\r\n}\r\n\r\nexport interface IOverrides {\r\n\tkeys: string[];\r\n\tcontents: any;\r\n\tidentifiers: string[];\r\n}\r\n\r\nexport interface IConfigurationData {\r\n\tdefaults: IConfigurationModel;\r\n\tuser: IConfigurationModel;\r\n\tworkspace: IConfigurationModel;\r\n\tfolders: [UriComponents, IConfigurationModel][];\r\n}\r\n\r\nexport function toValuesTree(properties: { [qualifiedKey: string]: any }, conflictReporter: (message: string) => void): any {\r\n\tconst root = Object.create(null);\r\n\r\n\tfor (let key in properties) {\r\n\t\taddToValueTree(root, key, properties[key], conflictReporter);\r\n\t}\r\n\r\n\treturn root;\r\n}\r\n\r\nexport function addToValueTree(settingsTreeRoot: any, key: string, value: any, conflictReporter: (message: string) => void): void {\r\n\tconst segments = key.split('.');\r\n\tconst last = segments.pop()!;\r\n\r\n\tlet curr = settingsTreeRoot;\r\n\tfor (let i = 0; i < segments.length; i++) {\r\n\t\tlet s = segments[i];\r\n\t\tlet obj = curr[s];\r\n\t\tswitch (typeof obj) {\r\n\t\t\tcase 'undefined':\r\n\t\t\t\tobj = curr[s] = Object.create(null);\r\n\t\t\t\tbreak;\r\n\t\t\tcase 'object':\r\n\t\t\t\tbreak;\r\n\t\t\tdefault:\r\n\t\t\t\tconflictReporter(`Ignoring ${key} as ${segments.slice(0, i + 1).join('.')} is ${JSON.stringify(obj)}`);\r\n\t\t\t\treturn;\r\n\t\t}\r\n\t\tcurr = obj;\r\n\t}\r\n\r\n\tif (typeof curr === 'object' && curr !== null) {\r\n\t\ttry {\r\n\t\t\tcurr[last] = value; // workaround https://github.com/microsoft/vscode/issues/13606\r\n\t\t} catch (e) {\r\n\t\t\tconflictReporter(`Ignoring ${key} as ${segments.join('.')} is ${JSON.stringify(curr)}`);\r\n\t\t}\r\n\t} else {\r\n\t\tconflictReporter(`Ignoring ${key} as ${segments.join('.')} is ${JSON.stringify(curr)}`);\r\n\t}\r\n}\r\n\r\nexport function removeFromValueTree(valueTree: any, key: string): void {\r\n\tconst segments = key.split('.');\r\n\tdoRemoveFromValueTree(valueTree, segments);\r\n}\r\n\r\nfunction doRemoveFromValueTree(valueTree: any, segments: string[]): void {\r\n\tconst first = segments.shift()!;\r\n\tif (segments.length === 0) {\r\n\t\t// Reached last segment\r\n\t\tdelete valueTree[first];\r\n\t\treturn;\r\n\t}\r\n\r\n\tif (Object.keys(valueTree).indexOf(first) !== -1) {\r\n\t\tconst value = valueTree[first];\r\n\t\tif (typeof value === 'object' && !Array.isArray(value)) {\r\n\t\t\tdoRemoveFromValueTree(value, segments);\r\n\t\t\tif (Object.keys(value).length === 0) {\r\n\t\t\t\tdelete valueTree[first];\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\n/**\r\n * A helper function to get the configuration value with a specific settings path (e.g. config.some.setting)\r\n */\r\nexport function getConfigurationValue(config: any, settingPath: string, defaultValue?: T): T {\r\n\tfunction accessSetting(config: any, path: string[]): any {\r\n\t\tlet current = config;\r\n\t\tfor (const component of path) {\r\n\t\t\tif (typeof current !== 'object' || current === null) {\r\n\t\t\t\treturn undefined;\r\n\t\t\t}\r\n\t\t\tcurrent = current[component];\r\n\t\t}\r\n\t\treturn current;\r\n\t}\r\n\r\n\tconst path = settingPath.split('.');\r\n\tconst result = accessSetting(config, path);\r\n\r\n\treturn typeof result === 'undefined' ? defaultValue : result;\r\n}\r\n\r\nexport function getConfigurationKeys(): string[] {\r\n\tconst properties = Registry.as(Extensions.Configuration).getConfigurationProperties();\r\n\treturn Object.keys(properties);\r\n}\r\n\r\nexport function getDefaultValues(): any {\r\n\tconst valueTreeRoot: any = Object.create(null);\r\n\tconst properties = Registry.as(Extensions.Configuration).getConfigurationProperties();\r\n\r\n\tfor (let key in properties) {\r\n\t\tlet value = properties[key].default;\r\n\t\taddToValueTree(valueTreeRoot, key, value, message => console.error(`Conflict in default settings: ${message}`));\r\n\t}\r\n\r\n\treturn valueTreeRoot;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { IAccessibilityService, AccessibilitySupport, CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility';\r\nimport { Event, Emitter } from 'vs/base/common/event';\r\nimport { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\r\n\r\nexport class AccessibilityService extends Disposable implements IAccessibilityService {\r\n\tdeclare readonly _serviceBrand: undefined;\r\n\r\n\tprivate _accessibilityModeEnabledContext: IContextKey;\r\n\tprotected _accessibilitySupport = AccessibilitySupport.Unknown;\r\n\tprotected readonly _onDidChangeScreenReaderOptimized = new Emitter();\r\n\r\n\tconstructor(\r\n\t\t@IContextKeyService private readonly _contextKeyService: IContextKeyService,\r\n\t\t@IConfigurationService protected readonly _configurationService: IConfigurationService,\r\n\t) {\r\n\t\tsuper();\r\n\t\tthis._accessibilityModeEnabledContext = CONTEXT_ACCESSIBILITY_MODE_ENABLED.bindTo(this._contextKeyService);\r\n\t\tconst updateContextKey = () => this._accessibilityModeEnabledContext.set(this.isScreenReaderOptimized());\r\n\t\tthis._register(this._configurationService.onDidChangeConfiguration(e => {\r\n\t\t\tif (e.affectsConfiguration('editor.accessibilitySupport')) {\r\n\t\t\t\tupdateContextKey();\r\n\t\t\t\tthis._onDidChangeScreenReaderOptimized.fire();\r\n\t\t\t}\r\n\t\t}));\r\n\t\tupdateContextKey();\r\n\t\tthis.onDidChangeScreenReaderOptimized(() => updateContextKey());\r\n\t}\r\n\r\n\tget onDidChangeScreenReaderOptimized(): Event {\r\n\t\treturn this._onDidChangeScreenReaderOptimized.event;\r\n\t}\r\n\r\n\tisScreenReaderOptimized(): boolean {\r\n\t\tconst config = this._configurationService.getValue('editor.accessibilitySupport');\r\n\t\treturn config === 'on' || (config === 'auto' && this._accessibilitySupport === AccessibilitySupport.Enabled);\r\n\t}\r\n\r\n\tgetAccessibilitySupport(): AccessibilitySupport {\r\n\t\treturn this._accessibilitySupport;\r\n\t}\r\n}\r\n","\r\nimport { ResourceMap } from 'vs/base/common/map';\r\nimport * as arrays from 'vs/base/common/arrays';\r\nimport * as types from 'vs/base/common/types';\r\nimport * as objects from 'vs/base/common/objects';\r\nimport { URI, UriComponents } from 'vs/base/common/uri';\r\nimport { OVERRIDE_PROPERTY_PATTERN, overrideIdentifierFromKey } from 'vs/platform/configuration/common/configurationRegistry';\r\nimport { IOverrides, addToValueTree, toValuesTree, IConfigurationModel, getConfigurationValue, IConfigurationOverrides, IConfigurationData, getDefaultValues, getConfigurationKeys, removeFromValueTree, ConfigurationTarget, IConfigurationChangeEvent, IConfigurationChange } from 'vs/platform/configuration/common/configuration';\r\nimport { Workspace } from 'vs/platform/workspace/common/workspace';\r\n\r\nexport class ConfigurationModel implements IConfigurationModel {\r\n\r\n\tprivate isFrozen: boolean = false;\r\n\r\n\tconstructor(\r\n\t\tprivate _contents: any = {},\r\n\t\tprivate _keys: string[] = [],\r\n\t\tprivate _overrides: IOverrides[] = []\r\n\t) {\r\n\t}\r\n\r\n\tget contents(): any {\r\n\t\treturn this.checkAndFreeze(this._contents);\r\n\t}\r\n\r\n\tget overrides(): IOverrides[] {\r\n\t\treturn this.checkAndFreeze(this._overrides);\r\n\t}\r\n\r\n\tget keys(): string[] {\r\n\t\treturn this.checkAndFreeze(this._keys);\r\n\t}\r\n\r\n\tisEmpty(): boolean {\r\n\t\treturn this._keys.length === 0 && Object.keys(this._contents).length === 0 && this._overrides.length === 0;\r\n\t}\r\n\r\n\tgetValue(section: string | undefined): V {\r\n\t\treturn section ? getConfigurationValue(this.contents, section) : this.contents;\r\n\t}\r\n\r\n\toverride(identifier: string): ConfigurationModel {\r\n\t\tconst overrideContents = this.getContentsForOverrideIdentifer(identifier);\r\n\r\n\t\tif (!overrideContents || typeof overrideContents !== 'object' || !Object.keys(overrideContents).length) {\r\n\t\t\t// If there are no valid overrides, return self\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tlet contents: any = {};\r\n\t\tfor (const key of arrays.distinct([...Object.keys(this.contents), ...Object.keys(overrideContents)])) {\r\n\r\n\t\t\tlet contentsForKey = this.contents[key];\r\n\t\t\tlet overrideContentsForKey = overrideContents[key];\r\n\r\n\t\t\t// If there are override contents for the key, clone and merge otherwise use base contents\r\n\t\t\tif (overrideContentsForKey) {\r\n\t\t\t\t// Clone and merge only if base contents and override contents are of type object otherwise just override\r\n\t\t\t\tif (typeof contentsForKey === 'object' && typeof overrideContentsForKey === 'object') {\r\n\t\t\t\t\tcontentsForKey = objects.deepClone(contentsForKey);\r\n\t\t\t\t\tthis.mergeContents(contentsForKey, overrideContentsForKey);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tcontentsForKey = overrideContentsForKey;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tcontents[key] = contentsForKey;\r\n\t\t}\r\n\r\n\t\treturn new ConfigurationModel(contents, this.keys, this.overrides);\r\n\t}\r\n\r\n\tmerge(...others: ConfigurationModel[]): ConfigurationModel {\r\n\t\tconst contents = objects.deepClone(this.contents);\r\n\t\tconst overrides = objects.deepClone(this.overrides);\r\n\t\tconst keys = [...this.keys];\r\n\r\n\t\tfor (const other of others) {\r\n\t\t\tthis.mergeContents(contents, other.contents);\r\n\r\n\t\t\tfor (const otherOverride of other.overrides) {\r\n\t\t\t\tconst [override] = overrides.filter(o => arrays.equals(o.identifiers, otherOverride.identifiers));\r\n\t\t\t\tif (override) {\r\n\t\t\t\t\tthis.mergeContents(override.contents, otherOverride.contents);\r\n\t\t\t\t} else {\r\n\t\t\t\t\toverrides.push(objects.deepClone(otherOverride));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tfor (const key of other.keys) {\r\n\t\t\t\tif (keys.indexOf(key) === -1) {\r\n\t\t\t\t\tkeys.push(key);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn new ConfigurationModel(contents, keys, overrides);\r\n\t}\r\n\r\n\tfreeze(): ConfigurationModel {\r\n\t\tthis.isFrozen = true;\r\n\t\treturn this;\r\n\t}\r\n\r\n\tprivate mergeContents(source: any, target: any): void {\r\n\t\tfor (const key of Object.keys(target)) {\r\n\t\t\tif (key in source) {\r\n\t\t\t\tif (types.isObject(source[key]) && types.isObject(target[key])) {\r\n\t\t\t\t\tthis.mergeContents(source[key], target[key]);\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tsource[key] = objects.deepClone(target[key]);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate checkAndFreeze(data: T): T {\r\n\t\tif (this.isFrozen && !Object.isFrozen(data)) {\r\n\t\t\treturn objects.deepFreeze(data);\r\n\t\t}\r\n\t\treturn data;\r\n\t}\r\n\r\n\tprivate getContentsForOverrideIdentifer(identifier: string): any {\r\n\t\tfor (const override of this.overrides) {\r\n\t\t\tif (override.identifiers.indexOf(identifier) !== -1) {\r\n\t\t\t\treturn override.contents;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\ttoJSON(): IConfigurationModel {\r\n\t\treturn {\r\n\t\t\tcontents: this.contents,\r\n\t\t\toverrides: this.overrides,\r\n\t\t\tkeys: this.keys\r\n\t\t};\r\n\t}\r\n\r\n\t// Update methods\r\n\r\n\tpublic setValue(key: string, value: any) {\r\n\t\tthis.addKey(key);\r\n\t\taddToValueTree(this.contents, key, value, e => { throw new Error(e); });\r\n\t}\r\n\r\n\tpublic removeValue(key: string): void {\r\n\t\tif (this.removeKey(key)) {\r\n\t\t\tremoveFromValueTree(this.contents, key);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate addKey(key: string): void {\r\n\t\tlet index = this.keys.length;\r\n\t\tfor (let i = 0; i < index; i++) {\r\n\t\t\tif (key.indexOf(this.keys[i]) === 0) {\r\n\t\t\t\tindex = i;\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis.keys.splice(index, 1, key);\r\n\t}\r\n\r\n\tprivate removeKey(key: string): boolean {\r\n\t\tlet index = this.keys.indexOf(key);\r\n\t\tif (index !== -1) {\r\n\t\t\tthis.keys.splice(index, 1);\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\nexport class DefaultConfigurationModel extends ConfigurationModel {\r\n\r\n\tconstructor() {\r\n\t\tconst contents = getDefaultValues();\r\n\t\tconst keys = getConfigurationKeys();\r\n\t\tconst overrides: IOverrides[] = [];\r\n\t\tfor (const key of Object.keys(contents)) {\r\n\t\t\tif (OVERRIDE_PROPERTY_PATTERN.test(key)) {\r\n\t\t\t\toverrides.push({\r\n\t\t\t\t\tidentifiers: [overrideIdentifierFromKey(key).trim()],\r\n\t\t\t\t\tkeys: Object.keys(contents[key]),\r\n\t\t\t\t\tcontents: toValuesTree(contents[key], message => console.error(`Conflict in default settings file: ${message}`)),\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\t\tsuper(contents, keys, overrides);\r\n\t}\r\n}\r\n\r\n\r\nexport class Configuration {\r\n\r\n\tprivate _workspaceConsolidatedConfiguration: ConfigurationModel | null = null;\r\n\tprivate _foldersConsolidatedConfigurations: ResourceMap = new ResourceMap();\r\n\r\n\tconstructor(\r\n\t\tprivate _defaultConfiguration: ConfigurationModel,\r\n\t\tprivate _localUserConfiguration: ConfigurationModel,\r\n\t\tprivate _remoteUserConfiguration: ConfigurationModel = new ConfigurationModel(),\r\n\t\tprivate _workspaceConfiguration: ConfigurationModel = new ConfigurationModel(),\r\n\t\tprivate _folderConfigurations: ResourceMap = new ResourceMap(),\r\n\t\tprivate _memoryConfiguration: ConfigurationModel = new ConfigurationModel(),\r\n\t\tprivate _memoryConfigurationByResource: ResourceMap = new ResourceMap(),\r\n\t\tprivate _freeze: boolean = true) {\r\n\t}\r\n\r\n\tgetValue(section: string | undefined, overrides: IConfigurationOverrides, workspace: Workspace | undefined): any {\r\n\t\tconst consolidateConfigurationModel = this.getConsolidateConfigurationModel(overrides, workspace);\r\n\t\treturn consolidateConfigurationModel.getValue(section);\r\n\t}\r\n\r\n\tupdateValue(key: string, value: any, overrides: IConfigurationOverrides = {}): void {\r\n\t\tlet memoryConfiguration: ConfigurationModel | undefined;\r\n\t\tif (overrides.resource) {\r\n\t\t\tmemoryConfiguration = this._memoryConfigurationByResource.get(overrides.resource);\r\n\t\t\tif (!memoryConfiguration) {\r\n\t\t\t\tmemoryConfiguration = new ConfigurationModel();\r\n\t\t\t\tthis._memoryConfigurationByResource.set(overrides.resource, memoryConfiguration);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tmemoryConfiguration = this._memoryConfiguration;\r\n\t\t}\r\n\r\n\t\tif (value === undefined) {\r\n\t\t\tmemoryConfiguration.removeValue(key);\r\n\t\t} else {\r\n\t\t\tmemoryConfiguration.setValue(key, value);\r\n\t\t}\r\n\r\n\t\tif (!overrides.resource) {\r\n\t\t\tthis._workspaceConsolidatedConfiguration = null;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _userConfiguration: ConfigurationModel | null = null;\r\n\tget userConfiguration(): ConfigurationModel {\r\n\t\tif (!this._userConfiguration) {\r\n\t\t\tthis._userConfiguration = this._remoteUserConfiguration.isEmpty() ? this._localUserConfiguration : this._localUserConfiguration.merge(this._remoteUserConfiguration);\r\n\t\t\tif (this._freeze) {\r\n\t\t\t\tthis._userConfiguration.freeze();\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this._userConfiguration;\r\n\t}\r\n\r\n\tprivate getConsolidateConfigurationModel(overrides: IConfigurationOverrides, workspace: Workspace | undefined): ConfigurationModel {\r\n\t\tlet configurationModel = this.getConsolidatedConfigurationModelForResource(overrides, workspace);\r\n\t\treturn overrides.overrideIdentifier ? configurationModel.override(overrides.overrideIdentifier) : configurationModel;\r\n\t}\r\n\r\n\tprivate getConsolidatedConfigurationModelForResource({ resource }: IConfigurationOverrides, workspace: Workspace | undefined): ConfigurationModel {\r\n\t\tlet consolidateConfiguration = this.getWorkspaceConsolidatedConfiguration();\r\n\r\n\t\tif (workspace && resource) {\r\n\t\t\tconst root = workspace.getFolder(resource);\r\n\t\t\tif (root) {\r\n\t\t\t\tconsolidateConfiguration = this.getFolderConsolidatedConfiguration(root.uri) || consolidateConfiguration;\r\n\t\t\t}\r\n\t\t\tconst memoryConfigurationForResource = this._memoryConfigurationByResource.get(resource);\r\n\t\t\tif (memoryConfigurationForResource) {\r\n\t\t\t\tconsolidateConfiguration = consolidateConfiguration.merge(memoryConfigurationForResource);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn consolidateConfiguration;\r\n\t}\r\n\r\n\tprivate getWorkspaceConsolidatedConfiguration(): ConfigurationModel {\r\n\t\tif (!this._workspaceConsolidatedConfiguration) {\r\n\t\t\tthis._workspaceConsolidatedConfiguration = this._defaultConfiguration.merge(this.userConfiguration, this._workspaceConfiguration, this._memoryConfiguration);\r\n\t\t\tif (this._freeze) {\r\n\t\t\t\tthis._workspaceConfiguration = this._workspaceConfiguration.freeze();\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this._workspaceConsolidatedConfiguration;\r\n\t}\r\n\r\n\tprivate getFolderConsolidatedConfiguration(folder: URI): ConfigurationModel {\r\n\t\tlet folderConsolidatedConfiguration = this._foldersConsolidatedConfigurations.get(folder);\r\n\t\tif (!folderConsolidatedConfiguration) {\r\n\t\t\tconst workspaceConsolidateConfiguration = this.getWorkspaceConsolidatedConfiguration();\r\n\t\t\tconst folderConfiguration = this._folderConfigurations.get(folder);\r\n\t\t\tif (folderConfiguration) {\r\n\t\t\t\tfolderConsolidatedConfiguration = workspaceConsolidateConfiguration.merge(folderConfiguration);\r\n\t\t\t\tif (this._freeze) {\r\n\t\t\t\t\tfolderConsolidatedConfiguration = folderConsolidatedConfiguration.freeze();\r\n\t\t\t\t}\r\n\t\t\t\tthis._foldersConsolidatedConfigurations.set(folder, folderConsolidatedConfiguration);\r\n\t\t\t} else {\r\n\t\t\t\tfolderConsolidatedConfiguration = workspaceConsolidateConfiguration;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn folderConsolidatedConfiguration;\r\n\t}\r\n\r\n\ttoData(): IConfigurationData {\r\n\t\treturn {\r\n\t\t\tdefaults: {\r\n\t\t\t\tcontents: this._defaultConfiguration.contents,\r\n\t\t\t\toverrides: this._defaultConfiguration.overrides,\r\n\t\t\t\tkeys: this._defaultConfiguration.keys\r\n\t\t\t},\r\n\t\t\tuser: {\r\n\t\t\t\tcontents: this.userConfiguration.contents,\r\n\t\t\t\toverrides: this.userConfiguration.overrides,\r\n\t\t\t\tkeys: this.userConfiguration.keys\r\n\t\t\t},\r\n\t\t\tworkspace: {\r\n\t\t\t\tcontents: this._workspaceConfiguration.contents,\r\n\t\t\t\toverrides: this._workspaceConfiguration.overrides,\r\n\t\t\t\tkeys: this._workspaceConfiguration.keys\r\n\t\t\t},\r\n\t\t\tfolders: [...this._folderConfigurations.keys()].reduce<[UriComponents, IConfigurationModel][]>((result, folder) => {\r\n\t\t\t\tconst { contents, overrides, keys } = this._folderConfigurations.get(folder)!;\r\n\t\t\t\tresult.push([folder, { contents, overrides, keys }]);\r\n\t\t\t\treturn result;\r\n\t\t\t}, [])\r\n\t\t};\r\n\t}\r\n\r\n\tstatic parse(data: IConfigurationData): Configuration {\r\n\t\tconst defaultConfiguration = this.parseConfigurationModel(data.defaults);\r\n\t\tconst userConfiguration = this.parseConfigurationModel(data.user);\r\n\t\tconst workspaceConfiguration = this.parseConfigurationModel(data.workspace);\r\n\t\tconst folders: ResourceMap = data.folders.reduce((result, value) => {\r\n\t\t\tresult.set(URI.revive(value[0]), this.parseConfigurationModel(value[1]));\r\n\t\t\treturn result;\r\n\t\t}, new ResourceMap());\r\n\t\treturn new Configuration(defaultConfiguration, userConfiguration, new ConfigurationModel(), workspaceConfiguration, folders, new ConfigurationModel(), new ResourceMap(), false);\r\n\t}\r\n\r\n\tprivate static parseConfigurationModel(model: IConfigurationModel): ConfigurationModel {\r\n\t\treturn new ConfigurationModel(model.contents, model.keys, model.overrides).freeze();\r\n\t}\r\n\r\n}\r\n\r\nexport class ConfigurationChangeEvent implements IConfigurationChangeEvent {\r\n\r\n\tprivate readonly affectedKeysTree: any;\r\n\treadonly affectedKeys: string[];\r\n\tsource!: ConfigurationTarget;\r\n\tsourceConfig: any;\r\n\r\n\tconstructor(readonly change: IConfigurationChange, private readonly previous: { workspace?: Workspace, data: IConfigurationData } | undefined, private readonly currentConfiguraiton: Configuration, private readonly currentWorkspace?: Workspace) {\r\n\t\tconst keysSet = new Set();\r\n\t\tchange.keys.forEach(key => keysSet.add(key));\r\n\t\tchange.overrides.forEach(([, keys]) => keys.forEach(key => keysSet.add(key)));\r\n\t\tthis.affectedKeys = [...keysSet.values()];\r\n\r\n\t\tconst configurationModel = new ConfigurationModel();\r\n\t\tthis.affectedKeys.forEach(key => configurationModel.setValue(key, {}));\r\n\t\tthis.affectedKeysTree = configurationModel.contents;\r\n\t}\r\n\r\n\tprivate _previousConfiguration: Configuration | undefined = undefined;\r\n\tget previousConfiguration(): Configuration | undefined {\r\n\t\tif (!this._previousConfiguration && this.previous) {\r\n\t\t\tthis._previousConfiguration = Configuration.parse(this.previous.data);\r\n\t\t}\r\n\t\treturn this._previousConfiguration;\r\n\t}\r\n\r\n\taffectsConfiguration(section: string, overrides?: IConfigurationOverrides): boolean {\r\n\t\tif (this.doesAffectedKeysTreeContains(this.affectedKeysTree, section)) {\r\n\t\t\tif (overrides) {\r\n\t\t\t\tconst value1 = this.previousConfiguration ? this.previousConfiguration.getValue(section, overrides, this.previous?.workspace) : undefined;\r\n\t\t\t\tconst value2 = this.currentConfiguraiton.getValue(section, overrides, this.currentWorkspace);\r\n\t\t\t\treturn !objects.equals(value1, value2);\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tprivate doesAffectedKeysTreeContains(affectedKeysTree: any, section: string): boolean {\r\n\t\tlet requestedTree = toValuesTree({ [section]: true }, () => { });\r\n\r\n\t\tlet key;\r\n\t\twhile (typeof requestedTree === 'object' && (key = Object.keys(requestedTree)[0])) { // Only one key should present, since we added only one property\r\n\t\t\taffectedKeysTree = affectedKeysTree[key];\r\n\t\t\tif (!affectedKeysTree) {\r\n\t\t\t\treturn false; // Requested tree is not found\r\n\t\t\t}\r\n\t\t\trequestedTree = requestedTree[key];\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Emitter, PauseableEmitter } from 'vs/base/common/event';\r\nimport { Iterable } from 'vs/base/common/iterator';\r\nimport { IDisposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';\r\nimport { TernarySearchTree } from 'vs/base/common/map';\r\nimport { CommandsRegistry } from 'vs/platform/commands/common/commands';\r\nimport { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';\r\nimport { IContext, IContextKey, IContextKeyChangeEvent, IContextKeyService, IContextKeyServiceTarget, IReadableSet, SET_CONTEXT_COMMAND_ID, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';\r\nimport { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver';\r\n\r\nconst KEYBINDING_CONTEXT_ATTR = 'data-keybinding-context';\r\n\r\nexport class Context implements IContext {\r\n\r\n\tprotected _parent: Context | null;\r\n\tprotected _value: { [key: string]: any; };\r\n\tprotected _id: number;\r\n\r\n\tconstructor(id: number, parent: Context | null) {\r\n\t\tthis._id = id;\r\n\t\tthis._parent = parent;\r\n\t\tthis._value = Object.create(null);\r\n\t\tthis._value['_contextId'] = id;\r\n\t}\r\n\r\n\tpublic setValue(key: string, value: any): boolean {\r\n\t\t// console.log('SET ' + key + ' = ' + value + ' ON ' + this._id);\r\n\t\tif (this._value[key] !== value) {\r\n\t\t\tthis._value[key] = value;\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic removeValue(key: string): boolean {\r\n\t\t// console.log('REMOVE ' + key + ' FROM ' + this._id);\r\n\t\tif (key in this._value) {\r\n\t\t\tdelete this._value[key];\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic getValue(key: string): T | undefined {\r\n\t\tconst ret = this._value[key];\r\n\t\tif (typeof ret === 'undefined' && this._parent) {\r\n\t\t\treturn this._parent.getValue(key);\r\n\t\t}\r\n\t\treturn ret;\r\n\t}\r\n}\r\n\r\nclass NullContext extends Context {\r\n\r\n\tstatic readonly INSTANCE = new NullContext();\r\n\r\n\tconstructor() {\r\n\t\tsuper(-1, null);\r\n\t}\r\n\r\n\tpublic setValue(key: string, value: any): boolean {\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic removeValue(key: string): boolean {\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic getValue(key: string): T | undefined {\r\n\t\treturn undefined;\r\n\t}\r\n}\r\n\r\nclass ConfigAwareContextValuesContainer extends Context {\r\n\tprivate static readonly _keyPrefix = 'config.';\r\n\r\n\tprivate readonly _values = TernarySearchTree.forConfigKeys();\r\n\tprivate readonly _listener: IDisposable;\r\n\r\n\tconstructor(\r\n\t\tid: number,\r\n\t\tprivate readonly _configurationService: IConfigurationService,\r\n\t\temitter: Emitter\r\n\t) {\r\n\t\tsuper(id, null);\r\n\r\n\t\tthis._listener = this._configurationService.onDidChangeConfiguration(event => {\r\n\t\t\tif (event.source === ConfigurationTarget.DEFAULT) {\r\n\t\t\t\t// new setting, reset everything\r\n\t\t\t\tconst allKeys = Array.from(Iterable.map(this._values, ([k]) => k));\r\n\t\t\t\tthis._values.clear();\r\n\t\t\t\temitter.fire(new ArrayContextKeyChangeEvent(allKeys));\r\n\t\t\t} else {\r\n\t\t\t\tconst changedKeys: string[] = [];\r\n\t\t\t\tfor (const configKey of event.affectedKeys) {\r\n\t\t\t\t\tconst contextKey = `config.${configKey}`;\r\n\r\n\t\t\t\t\tconst cachedItems = this._values.findSuperstr(contextKey);\r\n\t\t\t\t\tif (cachedItems !== undefined) {\r\n\t\t\t\t\t\tchangedKeys.push(...Iterable.map(cachedItems, ([key]) => key));\r\n\t\t\t\t\t\tthis._values.deleteSuperstr(contextKey);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (this._values.has(contextKey)) {\r\n\t\t\t\t\t\tchangedKeys.push(contextKey);\r\n\t\t\t\t\t\tthis._values.delete(contextKey);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\temitter.fire(new ArrayContextKeyChangeEvent(changedKeys));\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._listener.dispose();\r\n\t}\r\n\r\n\tgetValue(key: string): any {\r\n\r\n\t\tif (key.indexOf(ConfigAwareContextValuesContainer._keyPrefix) !== 0) {\r\n\t\t\treturn super.getValue(key);\r\n\t\t}\r\n\r\n\t\tif (this._values.has(key)) {\r\n\t\t\treturn this._values.get(key);\r\n\t\t}\r\n\r\n\t\tconst configKey = key.substr(ConfigAwareContextValuesContainer._keyPrefix.length);\r\n\t\tconst configValue = this._configurationService.getValue(configKey);\r\n\t\tlet value: any = undefined;\r\n\t\tswitch (typeof configValue) {\r\n\t\t\tcase 'number':\r\n\t\t\tcase 'boolean':\r\n\t\t\tcase 'string':\r\n\t\t\t\tvalue = configValue;\r\n\t\t\t\tbreak;\r\n\t\t\tdefault:\r\n\t\t\t\tif (Array.isArray(configValue)) {\r\n\t\t\t\t\tvalue = JSON.stringify(configValue);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tvalue = configValue;\r\n\t\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._values.set(key, value);\r\n\t\treturn value;\r\n\t}\r\n\r\n\tsetValue(key: string, value: any): boolean {\r\n\t\treturn super.setValue(key, value);\r\n\t}\r\n\r\n\tremoveValue(key: string): boolean {\r\n\t\treturn super.removeValue(key);\r\n\t}\r\n}\r\n\r\nclass ContextKey implements IContextKey {\r\n\r\n\tprivate _service: AbstractContextKeyService;\r\n\tprivate _key: string;\r\n\tprivate _defaultValue: T | undefined;\r\n\r\n\tconstructor(service: AbstractContextKeyService, key: string, defaultValue: T | undefined) {\r\n\t\tthis._service = service;\r\n\t\tthis._key = key;\r\n\t\tthis._defaultValue = defaultValue;\r\n\t\tthis.reset();\r\n\t}\r\n\r\n\tpublic set(value: T): void {\r\n\t\tthis._service.setContext(this._key, value);\r\n\t}\r\n\r\n\tpublic reset(): void {\r\n\t\tif (typeof this._defaultValue === 'undefined') {\r\n\t\t\tthis._service.removeContext(this._key);\r\n\t\t} else {\r\n\t\t\tthis._service.setContext(this._key, this._defaultValue);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic get(): T | undefined {\r\n\t\treturn this._service.getContextKeyValue(this._key);\r\n\t}\r\n}\r\n\r\nclass SimpleContextKeyChangeEvent implements IContextKeyChangeEvent {\r\n\tconstructor(readonly key: string) { }\r\n\taffectsSome(keys: IReadableSet): boolean {\r\n\t\treturn keys.has(this.key);\r\n\t}\r\n}\r\n\r\nclass ArrayContextKeyChangeEvent implements IContextKeyChangeEvent {\r\n\tconstructor(readonly keys: string[]) { }\r\n\taffectsSome(keys: IReadableSet): boolean {\r\n\t\tfor (const key of this.keys) {\r\n\t\t\tif (keys.has(key)) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\nclass CompositeContextKeyChangeEvent implements IContextKeyChangeEvent {\r\n\tconstructor(readonly events: IContextKeyChangeEvent[]) { }\r\n\taffectsSome(keys: IReadableSet): boolean {\r\n\t\tfor (const e of this.events) {\r\n\t\t\tif (e.affectsSome(keys)) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\nexport abstract class AbstractContextKeyService implements IContextKeyService {\r\n\tdeclare _serviceBrand: undefined;\r\n\r\n\tprotected _isDisposed: boolean;\r\n\tprotected _myContextId: number;\r\n\r\n\tprotected _onDidChangeContext = new PauseableEmitter({ merge: input => new CompositeContextKeyChangeEvent(input) });\r\n\treadonly onDidChangeContext = this._onDidChangeContext.event;\r\n\r\n\tconstructor(myContextId: number) {\r\n\t\tthis._isDisposed = false;\r\n\t\tthis._myContextId = myContextId;\r\n\t}\r\n\r\n\tabstract dispose(): void;\r\n\r\n\tpublic createKey(key: string, defaultValue: T | undefined): IContextKey {\r\n\t\tif (this._isDisposed) {\r\n\t\t\tthrow new Error(`AbstractContextKeyService has been disposed`);\r\n\t\t}\r\n\t\treturn new ContextKey(this, key, defaultValue);\r\n\t}\r\n\r\n\r\n\tbufferChangeEvents(callback: Function): void {\r\n\t\tthis._onDidChangeContext.pause();\r\n\t\ttry {\r\n\t\t\tcallback();\r\n\t\t} finally {\r\n\t\t\tthis._onDidChangeContext.resume();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic createScoped(domNode: IContextKeyServiceTarget): IContextKeyService {\r\n\t\tif (this._isDisposed) {\r\n\t\t\tthrow new Error(`AbstractContextKeyService has been disposed`);\r\n\t\t}\r\n\t\treturn new ScopedContextKeyService(this, domNode);\r\n\t}\r\n\r\n\tpublic contextMatchesRules(rules: ContextKeyExpression | undefined): boolean {\r\n\t\tif (this._isDisposed) {\r\n\t\t\tthrow new Error(`AbstractContextKeyService has been disposed`);\r\n\t\t}\r\n\t\tconst context = this.getContextValuesContainer(this._myContextId);\r\n\t\tconst result = KeybindingResolver.contextMatchesRules(context, rules);\r\n\t\t// console.group(rules.serialize() + ' -> ' + result);\r\n\t\t// rules.keys().forEach(key => { console.log(key, ctx[key]); });\r\n\t\t// console.groupEnd();\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic getContextKeyValue(key: string): T | undefined {\r\n\t\tif (this._isDisposed) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\t\treturn this.getContextValuesContainer(this._myContextId).getValue(key);\r\n\t}\r\n\r\n\tpublic setContext(key: string, value: any): void {\r\n\t\tif (this._isDisposed) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst myContext = this.getContextValuesContainer(this._myContextId);\r\n\t\tif (!myContext) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (myContext.setValue(key, value)) {\r\n\t\t\tthis._onDidChangeContext.fire(new SimpleContextKeyChangeEvent(key));\r\n\t\t}\r\n\t}\r\n\r\n\tpublic removeContext(key: string): void {\r\n\t\tif (this._isDisposed) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (this.getContextValuesContainer(this._myContextId).removeValue(key)) {\r\n\t\t\tthis._onDidChangeContext.fire(new SimpleContextKeyChangeEvent(key));\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getContext(target: IContextKeyServiceTarget | null): IContext {\r\n\t\tif (this._isDisposed) {\r\n\t\t\treturn NullContext.INSTANCE;\r\n\t\t}\r\n\t\treturn this.getContextValuesContainer(findContextAttr(target));\r\n\t}\r\n\r\n\tpublic abstract getContextValuesContainer(contextId: number): Context;\r\n\tpublic abstract createChildContext(parentContextId?: number): number;\r\n\tpublic abstract disposeContext(contextId: number): void;\r\n}\r\n\r\nexport class ContextKeyService extends AbstractContextKeyService implements IContextKeyService {\r\n\r\n\tprivate _lastContextId: number;\r\n\tprivate readonly _contexts = new Map();\r\n\r\n\tprivate readonly _toDispose = new DisposableStore();\r\n\r\n\tconstructor(@IConfigurationService configurationService: IConfigurationService) {\r\n\t\tsuper(0);\r\n\t\tthis._lastContextId = 0;\r\n\r\n\r\n\t\tconst myContext = new ConfigAwareContextValuesContainer(this._myContextId, configurationService, this._onDidChangeContext);\r\n\t\tthis._contexts.set(this._myContextId, myContext);\r\n\t\tthis._toDispose.add(myContext);\r\n\r\n\t\t// Uncomment this to see the contexts continuously logged\r\n\t\t// let lastLoggedValue: string | null = null;\r\n\t\t// setInterval(() => {\r\n\t\t// \tlet values = Object.keys(this._contexts).map((key) => this._contexts[key]);\r\n\t\t// \tlet logValue = values.map(v => JSON.stringify(v._value, null, '\\t')).join('\\n');\r\n\t\t// \tif (lastLoggedValue !== logValue) {\r\n\t\t// \t\tlastLoggedValue = logValue;\r\n\t\t// \t\tconsole.log(lastLoggedValue);\r\n\t\t// \t}\r\n\t\t// }, 2000);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._onDidChangeContext.dispose();\r\n\t\tthis._isDisposed = true;\r\n\t\tthis._toDispose.dispose();\r\n\t}\r\n\r\n\tpublic getContextValuesContainer(contextId: number): Context {\r\n\t\tif (this._isDisposed) {\r\n\t\t\treturn NullContext.INSTANCE;\r\n\t\t}\r\n\t\treturn this._contexts.get(contextId) || NullContext.INSTANCE;\r\n\t}\r\n\r\n\tpublic createChildContext(parentContextId: number = this._myContextId): number {\r\n\t\tif (this._isDisposed) {\r\n\t\t\tthrow new Error(`ContextKeyService has been disposed`);\r\n\t\t}\r\n\t\tlet id = (++this._lastContextId);\r\n\t\tthis._contexts.set(id, new Context(id, this.getContextValuesContainer(parentContextId)));\r\n\t\treturn id;\r\n\t}\r\n\r\n\tpublic disposeContext(contextId: number): void {\r\n\t\tif (!this._isDisposed) {\r\n\t\t\tthis._contexts.delete(contextId);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass ScopedContextKeyService extends AbstractContextKeyService {\r\n\r\n\tprivate _parent: AbstractContextKeyService;\r\n\tprivate _domNode: IContextKeyServiceTarget | undefined;\r\n\r\n\tprivate readonly _parentChangeListener = new MutableDisposable();\r\n\r\n\tconstructor(parent: AbstractContextKeyService, domNode?: IContextKeyServiceTarget) {\r\n\t\tsuper(parent.createChildContext());\r\n\t\tthis._parent = parent;\r\n\t\tthis._updateParentChangeListener();\r\n\r\n\t\tif (domNode) {\r\n\t\t\tthis._domNode = domNode;\r\n\t\t\tif (this._domNode.hasAttribute(KEYBINDING_CONTEXT_ATTR)) {\r\n\t\t\t\tlet extraInfo = '';\r\n\t\t\t\tif ((this._domNode as HTMLElement).classList) {\r\n\t\t\t\t\textraInfo = Array.from((this._domNode as HTMLElement).classList.values()).join(', ');\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconsole.error(`Element already has context attribute${extraInfo ? ': ' + extraInfo : ''}`);\r\n\t\t\t}\r\n\t\t\tthis._domNode.setAttribute(KEYBINDING_CONTEXT_ATTR, String(this._myContextId));\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _updateParentChangeListener(): void {\r\n\t\t// Forward parent events to this listener. Parent will change.\r\n\t\tthis._parentChangeListener.value = this._parent.onDidChangeContext(this._onDidChangeContext.fire, this._onDidChangeContext);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._onDidChangeContext.dispose();\r\n\t\tthis._isDisposed = true;\r\n\t\tthis._parent.disposeContext(this._myContextId);\r\n\t\tthis._parentChangeListener?.dispose();\r\n\t\tif (this._domNode) {\r\n\t\t\tthis._domNode.removeAttribute(KEYBINDING_CONTEXT_ATTR);\r\n\t\t\tthis._domNode = undefined;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getContextValuesContainer(contextId: number): Context {\r\n\t\tif (this._isDisposed) {\r\n\t\t\treturn NullContext.INSTANCE;\r\n\t\t}\r\n\t\treturn this._parent.getContextValuesContainer(contextId);\r\n\t}\r\n\r\n\tpublic createChildContext(parentContextId: number = this._myContextId): number {\r\n\t\tif (this._isDisposed) {\r\n\t\t\tthrow new Error(`ScopedContextKeyService has been disposed`);\r\n\t\t}\r\n\t\treturn this._parent.createChildContext(parentContextId);\r\n\t}\r\n\r\n\tpublic disposeContext(contextId: number): void {\r\n\t\tif (this._isDisposed) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._parent.disposeContext(contextId);\r\n\t}\r\n}\r\n\r\nfunction findContextAttr(domNode: IContextKeyServiceTarget | null): number {\r\n\twhile (domNode) {\r\n\t\tif (domNode.hasAttribute(KEYBINDING_CONTEXT_ATTR)) {\r\n\t\t\tconst attr = domNode.getAttribute(KEYBINDING_CONTEXT_ATTR);\r\n\t\t\tif (attr) {\r\n\t\t\t\treturn parseInt(attr, 10);\r\n\t\t\t}\r\n\t\t\treturn NaN;\r\n\t\t}\r\n\t\tdomNode = domNode.parentElement;\r\n\t}\r\n\treturn 0;\r\n}\r\n\r\nCommandsRegistry.registerCommand(SET_CONTEXT_COMMAND_ID, function (accessor, contextKey: any, contextValue: any) {\r\n\taccessor.get(IContextKeyService).createKey(String(contextKey), contextValue);\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { KeyCode, Keybinding, SimpleKeybinding, createKeybinding } from 'vs/base/common/keyCodes';\r\nimport { OS, OperatingSystem } from 'vs/base/common/platform';\r\nimport { CommandsRegistry, ICommandHandler, ICommandHandlerDescription } from 'vs/platform/commands/common/commands';\r\nimport { ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';\r\nimport { Registry } from 'vs/platform/registry/common/platform';\r\n\r\nexport interface IKeybindingItem {\r\n\tkeybinding: Keybinding;\r\n\tcommand: string;\r\n\tcommandArgs?: any;\r\n\twhen: ContextKeyExpression | null | undefined;\r\n\tweight1: number;\r\n\tweight2: number;\r\n\textensionId: string | null;\r\n\tisBuiltinExtension: boolean;\r\n}\r\n\r\nexport interface IKeybindings {\r\n\tprimary?: number;\r\n\tsecondary?: number[];\r\n\twin?: {\r\n\t\tprimary: number;\r\n\t\tsecondary?: number[];\r\n\t};\r\n\tlinux?: {\r\n\t\tprimary: number;\r\n\t\tsecondary?: number[];\r\n\t};\r\n\tmac?: {\r\n\t\tprimary: number;\r\n\t\tsecondary?: number[];\r\n\t};\r\n}\r\n\r\nexport interface IKeybindingRule extends IKeybindings {\r\n\tid: string;\r\n\tweight: number;\r\n\targs?: any;\r\n\twhen?: ContextKeyExpression | null | undefined;\r\n}\r\n\r\nexport const enum KeybindingWeight {\r\n\tEditorCore = 0,\r\n\tEditorContrib = 100,\r\n\tWorkbenchContrib = 200,\r\n\tBuiltinExtension = 300,\r\n\tExternalExtension = 400\r\n}\r\n\r\nexport interface ICommandAndKeybindingRule extends IKeybindingRule {\r\n\thandler: ICommandHandler;\r\n\tdescription?: ICommandHandlerDescription | null;\r\n}\r\n\r\nexport interface IKeybindingsRegistry {\r\n\tregisterKeybindingRule(rule: IKeybindingRule): void;\r\n\tregisterCommandAndKeybindingRule(desc: ICommandAndKeybindingRule): void;\r\n\tgetDefaultKeybindings(): IKeybindingItem[];\r\n}\r\n\r\nclass KeybindingsRegistryImpl implements IKeybindingsRegistry {\r\n\r\n\tprivate _coreKeybindings: IKeybindingItem[];\r\n\tprivate _extensionKeybindings: IKeybindingItem[];\r\n\tprivate _cachedMergedKeybindings: IKeybindingItem[] | null;\r\n\r\n\tconstructor() {\r\n\t\tthis._coreKeybindings = [];\r\n\t\tthis._extensionKeybindings = [];\r\n\t\tthis._cachedMergedKeybindings = null;\r\n\t}\r\n\r\n\t/**\r\n\t * Take current platform into account and reduce to primary & secondary.\r\n\t */\r\n\tprivate static bindToCurrentPlatform(kb: IKeybindings): { primary?: number; secondary?: number[]; } {\r\n\t\tif (OS === OperatingSystem.Windows) {\r\n\t\t\tif (kb && kb.win) {\r\n\t\t\t\treturn kb.win;\r\n\t\t\t}\r\n\t\t} else if (OS === OperatingSystem.Macintosh) {\r\n\t\t\tif (kb && kb.mac) {\r\n\t\t\t\treturn kb.mac;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tif (kb && kb.linux) {\r\n\t\t\t\treturn kb.linux;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn kb;\r\n\t}\r\n\r\n\tpublic registerKeybindingRule(rule: IKeybindingRule): void {\r\n\t\tconst actualKb = KeybindingsRegistryImpl.bindToCurrentPlatform(rule);\r\n\r\n\t\tif (actualKb && actualKb.primary) {\r\n\t\t\tconst kk = createKeybinding(actualKb.primary, OS);\r\n\t\t\tif (kk) {\r\n\t\t\t\tthis._registerDefaultKeybinding(kk, rule.id, rule.args, rule.weight, 0, rule.when);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (actualKb && Array.isArray(actualKb.secondary)) {\r\n\t\t\tfor (let i = 0, len = actualKb.secondary.length; i < len; i++) {\r\n\t\t\t\tconst k = actualKb.secondary[i];\r\n\t\t\t\tconst kk = createKeybinding(k, OS);\r\n\t\t\t\tif (kk) {\r\n\t\t\t\t\tthis._registerDefaultKeybinding(kk, rule.id, rule.args, rule.weight, -i - 1, rule.when);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic registerCommandAndKeybindingRule(desc: ICommandAndKeybindingRule): void {\r\n\t\tthis.registerKeybindingRule(desc);\r\n\t\tCommandsRegistry.registerCommand(desc);\r\n\t}\r\n\r\n\tprivate static _mightProduceChar(keyCode: KeyCode): boolean {\r\n\t\tif (keyCode >= KeyCode.KEY_0 && keyCode <= KeyCode.KEY_9) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (keyCode >= KeyCode.KEY_A && keyCode <= KeyCode.KEY_Z) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn (\r\n\t\t\tkeyCode === KeyCode.US_SEMICOLON\r\n\t\t\t|| keyCode === KeyCode.US_EQUAL\r\n\t\t\t|| keyCode === KeyCode.US_COMMA\r\n\t\t\t|| keyCode === KeyCode.US_MINUS\r\n\t\t\t|| keyCode === KeyCode.US_DOT\r\n\t\t\t|| keyCode === KeyCode.US_SLASH\r\n\t\t\t|| keyCode === KeyCode.US_BACKTICK\r\n\t\t\t|| keyCode === KeyCode.ABNT_C1\r\n\t\t\t|| keyCode === KeyCode.ABNT_C2\r\n\t\t\t|| keyCode === KeyCode.US_OPEN_SQUARE_BRACKET\r\n\t\t\t|| keyCode === KeyCode.US_BACKSLASH\r\n\t\t\t|| keyCode === KeyCode.US_CLOSE_SQUARE_BRACKET\r\n\t\t\t|| keyCode === KeyCode.US_QUOTE\r\n\t\t\t|| keyCode === KeyCode.OEM_8\r\n\t\t\t|| keyCode === KeyCode.OEM_102\r\n\t\t);\r\n\t}\r\n\r\n\tprivate _assertNoCtrlAlt(keybinding: SimpleKeybinding, commandId: string): void {\r\n\t\tif (keybinding.ctrlKey && keybinding.altKey && !keybinding.metaKey) {\r\n\t\t\tif (KeybindingsRegistryImpl._mightProduceChar(keybinding.keyCode)) {\r\n\t\t\t\tconsole.warn('Ctrl+Alt+ keybindings should not be used by default under Windows. Offender: ', keybinding, ' for ', commandId);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _registerDefaultKeybinding(keybinding: Keybinding, commandId: string, commandArgs: any, weight1: number, weight2: number, when: ContextKeyExpression | null | undefined): void {\r\n\t\tif (OS === OperatingSystem.Windows) {\r\n\t\t\tthis._assertNoCtrlAlt(keybinding.parts[0], commandId);\r\n\t\t}\r\n\t\tthis._coreKeybindings.push({\r\n\t\t\tkeybinding: keybinding,\r\n\t\t\tcommand: commandId,\r\n\t\t\tcommandArgs: commandArgs,\r\n\t\t\twhen: when,\r\n\t\t\tweight1: weight1,\r\n\t\t\tweight2: weight2,\r\n\t\t\textensionId: null,\r\n\t\t\tisBuiltinExtension: false\r\n\t\t});\r\n\t\tthis._cachedMergedKeybindings = null;\r\n\t}\r\n\r\n\tpublic getDefaultKeybindings(): IKeybindingItem[] {\r\n\t\tif (!this._cachedMergedKeybindings) {\r\n\t\t\tthis._cachedMergedKeybindings = ([]).concat(this._coreKeybindings).concat(this._extensionKeybindings);\r\n\t\t\tthis._cachedMergedKeybindings.sort(sorter);\r\n\t\t}\r\n\t\treturn this._cachedMergedKeybindings.slice(0);\r\n\t}\r\n}\r\nexport const KeybindingsRegistry: IKeybindingsRegistry = new KeybindingsRegistryImpl();\r\n\r\n// Define extension point ids\r\nexport const Extensions = {\r\n\tEditorModes: 'platform.keybindingsRegistry'\r\n};\r\nRegistry.add(Extensions.EditorModes, KeybindingsRegistry);\r\n\r\nfunction sorter(a: IKeybindingItem, b: IKeybindingItem): number {\r\n\tif (a.weight1 !== b.weight1) {\r\n\t\treturn a.weight1 - b.weight1;\r\n\t}\r\n\tif (a.command < b.command) {\r\n\t\treturn -1;\r\n\t}\r\n\tif (a.command > b.command) {\r\n\t\treturn 1;\r\n\t}\r\n\treturn a.weight2 - b.weight2;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IContextKeyService, ContextKeyExpr, RawContextKey, IContextKey, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey';\r\nimport { FindInput, IFindInputOptions } from 'vs/base/browser/ui/findinput/findInput';\r\nimport { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';\r\nimport { IHistoryNavigationWidget } from 'vs/base/browser/history';\r\nimport { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { ReplaceInput, IReplaceInputOptions } from 'vs/base/browser/ui/findinput/replaceInput';\r\n\r\nexport const HistoryNavigationWidgetContext = 'historyNavigationWidget';\r\nexport const HistoryNavigationEnablementContext = 'historyNavigationEnabled';\r\n\r\nfunction bindContextScopedWidget(contextKeyService: IContextKeyService, widget: IContextScopedWidget, contextKey: string): void {\r\n\tnew RawContextKey(contextKey, widget).bindTo(contextKeyService);\r\n}\r\n\r\nfunction createWidgetScopedContextKeyService(contextKeyService: IContextKeyService, widget: IContextScopedWidget): IContextKeyService {\r\n\treturn contextKeyService.createScoped(widget.target);\r\n}\r\n\r\nfunction getContextScopedWidget(contextKeyService: IContextKeyService, contextKey: string): T | undefined {\r\n\treturn contextKeyService.getContext(document.activeElement).getValue(contextKey);\r\n}\r\n\r\ninterface IContextScopedWidget {\r\n\treadonly target: IContextKeyServiceTarget;\r\n}\r\n\r\ninterface IContextScopedHistoryNavigationWidget extends IContextScopedWidget {\r\n\thistoryNavigator: IHistoryNavigationWidget;\r\n}\r\n\r\nexport function createAndBindHistoryNavigationWidgetScopedContextKeyService(contextKeyService: IContextKeyService, widget: IContextScopedHistoryNavigationWidget): { scopedContextKeyService: IContextKeyService, historyNavigationEnablement: IContextKey } {\r\n\tconst scopedContextKeyService = createWidgetScopedContextKeyService(contextKeyService, widget);\r\n\tbindContextScopedWidget(scopedContextKeyService, widget, HistoryNavigationWidgetContext);\r\n\tconst historyNavigationEnablement = new RawContextKey(HistoryNavigationEnablementContext, true).bindTo(scopedContextKeyService);\r\n\treturn { scopedContextKeyService, historyNavigationEnablement };\r\n}\r\n\r\nexport class ContextScopedFindInput extends FindInput {\r\n\r\n\tconstructor(container: HTMLElement | null, contextViewProvider: IContextViewProvider, options: IFindInputOptions,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService, showFindOptions: boolean = false\r\n\t) {\r\n\t\tsuper(container, contextViewProvider, showFindOptions, options);\r\n\t\tthis._register(createAndBindHistoryNavigationWidgetScopedContextKeyService(contextKeyService, { target: this.inputBox.element, historyNavigator: this.inputBox }).scopedContextKeyService);\r\n\t}\r\n}\r\n\r\nexport class ContextScopedReplaceInput extends ReplaceInput {\r\n\r\n\tconstructor(container: HTMLElement | null, contextViewProvider: IContextViewProvider | undefined, options: IReplaceInputOptions,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService, showReplaceOptions: boolean = false\r\n\t) {\r\n\t\tsuper(container, contextViewProvider, showReplaceOptions, options);\r\n\t\tthis._register(createAndBindHistoryNavigationWidgetScopedContextKeyService(contextKeyService, { target: this.inputBox.element, historyNavigator: this.inputBox }).scopedContextKeyService);\r\n\t}\r\n\r\n}\r\n\r\nKeybindingsRegistry.registerCommandAndKeybindingRule({\r\n\tid: 'history.showPrevious',\r\n\tweight: KeybindingWeight.WorkbenchContrib,\r\n\twhen: ContextKeyExpr.and(ContextKeyExpr.has(HistoryNavigationWidgetContext), ContextKeyExpr.equals(HistoryNavigationEnablementContext, true)),\r\n\tprimary: KeyCode.UpArrow,\r\n\tsecondary: [KeyMod.Alt | KeyCode.UpArrow],\r\n\thandler: (accessor, arg2) => {\r\n\t\tconst widget = getContextScopedWidget(accessor.get(IContextKeyService), HistoryNavigationWidgetContext);\r\n\t\tif (widget) {\r\n\t\t\tconst historyInputBox: IHistoryNavigationWidget = widget.historyNavigator;\r\n\t\t\thistoryInputBox.showPreviousValue();\r\n\t\t}\r\n\t}\r\n});\r\n\r\nKeybindingsRegistry.registerCommandAndKeybindingRule({\r\n\tid: 'history.showNext',\r\n\tweight: KeybindingWeight.WorkbenchContrib,\r\n\twhen: ContextKeyExpr.and(ContextKeyExpr.has(HistoryNavigationWidgetContext), ContextKeyExpr.equals(HistoryNavigationEnablementContext, true)),\r\n\tprimary: KeyCode.DownArrow,\r\n\tsecondary: [KeyMod.Alt | KeyCode.DownArrow],\r\n\thandler: (accessor, arg2) => {\r\n\t\tconst widget = getContextScopedWidget(accessor.get(IContextKeyService), HistoryNavigationWidgetContext);\r\n\t\tif (widget) {\r\n\t\t\tconst historyInputBox: IHistoryNavigationWidget = widget.historyNavigator;\r\n\t\t\thistoryInputBox.showNextValue();\r\n\t\t}\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IQuickPick, IQuickPickItem, IQuickNavigateConfiguration } from 'vs/platform/quickinput/common/quickInput';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { Registry } from 'vs/platform/registry/common/platform';\r\nimport { coalesce } from 'vs/base/common/arrays';\r\nimport { IDisposable, toDisposable } from 'vs/base/common/lifecycle';\r\nimport { ItemActivation } from 'vs/base/parts/quickinput/common/quickInput';\r\n\r\nexport interface IQuickAccessOptions {\r\n\r\n\t/**\r\n\t * Allows to enable quick navigate support in quick input.\r\n\t */\r\n\tquickNavigateConfiguration?: IQuickNavigateConfiguration;\r\n\r\n\t/**\r\n\t * Allows to configure a different item activation strategy.\r\n\t * By default the first item in the list will get activated.\r\n\t */\r\n\titemActivation?: ItemActivation;\r\n\r\n\t/**\r\n\t * Whether to take the input value as is and not restore it\r\n\t * from any existing value if quick access is visible.\r\n\t */\r\n\tpreserveValue?: boolean;\r\n}\r\n\r\nexport interface IQuickAccessController {\r\n\r\n\t/**\r\n\t * Open the quick access picker with the optional value prefilled.\r\n\t */\r\n\tshow(value?: string, options?: IQuickAccessOptions): void;\r\n}\r\n\r\nexport enum DefaultQuickAccessFilterValue {\r\n\r\n\t/**\r\n\t * Keep the value as it is given to quick access.\r\n\t */\r\n\tPRESERVE = 0,\r\n\r\n\t/**\r\n\t * Use the value that was used last time something was accepted from the picker.\r\n\t */\r\n\tLAST = 1\r\n}\r\n\r\nexport interface IQuickAccessProvider {\r\n\r\n\t/**\r\n\t * Allows to set a default filter value when the provider opens. This can be:\r\n\t * - `undefined` to not specify any default value\r\n\t * - `DefaultFilterValues.PRESERVE` to use the value that was last typed\r\n\t * - `string` for the actual value to use\r\n\t *\r\n\t * Note: the default filter will only be used if quick access was opened with\r\n\t * the exact prefix of the provider. Otherwise the filter value is preserved.\r\n\t */\r\n\treadonly defaultFilterValue?: string | DefaultQuickAccessFilterValue;\r\n\r\n\t/**\r\n\t * Called whenever a prefix was typed into quick pick that matches the provider.\r\n\t *\r\n\t * @param picker the picker to use for showing provider results. The picker is\r\n\t * automatically shown after the method returns, no need to call `show()`.\r\n\t * @param token providers have to check the cancellation token everytime after\r\n\t * a long running operation or from event handlers because it could be that the\r\n\t * picker has been closed or changed meanwhile. The token can be used to find out\r\n\t * that the picker was closed without picking an entry (e.g. was canceled by the user).\r\n\t * @return a disposable that will automatically be disposed when the picker\r\n\t * closes or is replaced by another picker.\r\n\t */\r\n\tprovide(picker: IQuickPick, token: CancellationToken): IDisposable;\r\n}\r\n\r\nexport interface IQuickAccessProviderHelp {\r\n\r\n\t/**\r\n\t * The prefix to show for the help entry. If not provided,\r\n\t * the prefix used for registration will be taken.\r\n\t */\r\n\tprefix?: string;\r\n\r\n\t/**\r\n\t * A description text to help understand the intent of the provider.\r\n\t */\r\n\tdescription: string;\r\n\r\n\t/**\r\n\t * Separation between provider for editors and global ones.\r\n\t */\r\n\tneedsEditor: boolean;\r\n}\r\n\r\nexport interface IQuickAccessProviderDescriptor {\r\n\r\n\t/**\r\n\t * The actual provider that will be instantiated as needed.\r\n\t */\r\n\treadonly ctor: { new(...services: any /* TS BrandedService but no clue how to type this properly */[]): IQuickAccessProvider };\r\n\r\n\t/**\r\n\t * The prefix for quick access picker to use the provider for.\r\n\t */\r\n\treadonly prefix: string;\r\n\r\n\t/**\r\n\t * A placeholder to use for the input field when the provider is active.\r\n\t * This will also be read out by screen readers and thus helps for\r\n\t * accessibility.\r\n\t */\r\n\treadonly placeholder?: string;\r\n\r\n\t/**\r\n\t * Documentation for the provider in the quick access help.\r\n\t */\r\n\treadonly helpEntries: IQuickAccessProviderHelp[];\r\n\r\n\t/**\r\n\t * A context key that will be set automatically when the\r\n\t * picker for the provider is showing.\r\n\t */\r\n\treadonly contextKey?: string;\r\n}\r\n\r\nexport const Extensions = {\r\n\tQuickaccess: 'workbench.contributions.quickaccess'\r\n};\r\n\r\nexport interface IQuickAccessRegistry {\r\n\r\n\t/**\r\n\t * Registers a quick access provider to the platform.\r\n\t */\r\n\tregisterQuickAccessProvider(provider: IQuickAccessProviderDescriptor): IDisposable;\r\n\r\n\t/**\r\n\t * Get all registered quick access providers.\r\n\t */\r\n\tgetQuickAccessProviders(): IQuickAccessProviderDescriptor[];\r\n\r\n\t/**\r\n\t * Get a specific quick access provider for a given prefix.\r\n\t */\r\n\tgetQuickAccessProvider(prefix: string): IQuickAccessProviderDescriptor | undefined;\r\n}\r\n\r\nexport class QuickAccessRegistry implements IQuickAccessRegistry {\r\n\tprivate providers: IQuickAccessProviderDescriptor[] = [];\r\n\tprivate defaultProvider: IQuickAccessProviderDescriptor | undefined = undefined;\r\n\r\n\tregisterQuickAccessProvider(provider: IQuickAccessProviderDescriptor): IDisposable {\r\n\r\n\t\t// Extract the default provider when no prefix is present\r\n\t\tif (provider.prefix.length === 0) {\r\n\t\t\tthis.defaultProvider = provider;\r\n\t\t} else {\r\n\t\t\tthis.providers.push(provider);\r\n\t\t}\r\n\r\n\t\t// sort the providers by decreasing prefix length, such that longer\r\n\t\t// prefixes take priority: 'ext' vs 'ext install' - the latter should win\r\n\t\tthis.providers.sort((providerA, providerB) => providerB.prefix.length - providerA.prefix.length);\r\n\r\n\t\treturn toDisposable(() => {\r\n\t\t\tthis.providers.splice(this.providers.indexOf(provider), 1);\r\n\r\n\t\t\tif (this.defaultProvider === provider) {\r\n\t\t\t\tthis.defaultProvider = undefined;\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tgetQuickAccessProviders(): IQuickAccessProviderDescriptor[] {\r\n\t\treturn coalesce([this.defaultProvider, ...this.providers]);\r\n\t}\r\n\r\n\tgetQuickAccessProvider(prefix: string): IQuickAccessProviderDescriptor | undefined {\r\n\t\tconst result = prefix ? (this.providers.find(provider => prefix.startsWith(provider.prefix)) || undefined) : undefined;\r\n\r\n\t\treturn result || this.defaultProvider;\r\n\t}\r\n}\r\n\r\nRegistry.add(Extensions.Quickaccess, new QuickAccessRegistry());\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IQuickPick, IQuickPickItem, IQuickInputService } from 'vs/platform/quickinput/common/quickInput';\r\nimport { IQuickAccessProvider, IQuickAccessRegistry, Extensions } from 'vs/platform/quickinput/common/quickAccess';\r\nimport { Registry } from 'vs/platform/registry/common/platform';\r\nimport { localize } from 'vs/nls';\r\nimport { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\r\n\r\ninterface IHelpQuickAccessPickItem extends IQuickPickItem {\r\n\tprefix: string;\r\n}\r\n\r\nexport class HelpQuickAccessProvider implements IQuickAccessProvider {\r\n\r\n\tstatic PREFIX = '?';\r\n\r\n\tprivate readonly registry = Registry.as(Extensions.Quickaccess);\r\n\r\n\tconstructor(@IQuickInputService private readonly quickInputService: IQuickInputService) { }\r\n\r\n\tprovide(picker: IQuickPick): IDisposable {\r\n\t\tconst disposables = new DisposableStore();\r\n\r\n\t\t// Open a picker with the selected value if picked\r\n\t\tdisposables.add(picker.onDidAccept(() => {\r\n\t\t\tconst [item] = picker.selectedItems;\r\n\t\t\tif (item) {\r\n\t\t\t\tthis.quickInputService.quickAccess.show(item.prefix, { preserveValue: true });\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\t// Also open a picker when we detect the user typed the exact\r\n\t\t// name of a provider (e.g. `?term` for terminals)\r\n\t\tdisposables.add(picker.onDidChangeValue(value => {\r\n\t\t\tconst providerDescriptor = this.registry.getQuickAccessProvider(value.substr(HelpQuickAccessProvider.PREFIX.length));\r\n\t\t\tif (providerDescriptor && providerDescriptor.prefix && providerDescriptor.prefix !== HelpQuickAccessProvider.PREFIX) {\r\n\t\t\t\tthis.quickInputService.quickAccess.show(providerDescriptor.prefix, { preserveValue: true });\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\t// Fill in all providers separated by editor/global scope\r\n\t\tconst { editorProviders, globalProviders } = this.getQuickAccessProviders();\r\n\t\tpicker.items = editorProviders.length === 0 || globalProviders.length === 0 ?\r\n\r\n\t\t\t// Without groups\r\n\t\t\t[\r\n\t\t\t\t...(editorProviders.length === 0 ? globalProviders : editorProviders)\r\n\t\t\t] :\r\n\r\n\t\t\t// With groups\r\n\t\t\t[\r\n\t\t\t\t{ label: localize('globalCommands', \"global commands\"), type: 'separator' },\r\n\t\t\t\t...globalProviders,\r\n\t\t\t\t{ label: localize('editorCommands', \"editor commands\"), type: 'separator' },\r\n\t\t\t\t...editorProviders\r\n\t\t\t];\r\n\r\n\t\treturn disposables;\r\n\t}\r\n\r\n\tprivate getQuickAccessProviders(): { editorProviders: IHelpQuickAccessPickItem[], globalProviders: IHelpQuickAccessPickItem[] } {\r\n\t\tconst globalProviders: IHelpQuickAccessPickItem[] = [];\r\n\t\tconst editorProviders: IHelpQuickAccessPickItem[] = [];\r\n\r\n\t\tfor (const provider of this.registry.getQuickAccessProviders().sort((providerA, providerB) => providerA.prefix.localeCompare(providerB.prefix))) {\r\n\t\t\tif (provider.prefix === HelpQuickAccessProvider.PREFIX) {\r\n\t\t\t\tcontinue; // exclude help which is already active\r\n\t\t\t}\r\n\r\n\t\t\tfor (const helpEntry of provider.helpEntries) {\r\n\t\t\t\tconst prefix = helpEntry.prefix || provider.prefix;\r\n\t\t\t\tconst label = prefix || '\\u2026' /* ... */;\r\n\r\n\t\t\t\t(helpEntry.needsEditor ? editorProviders : globalProviders).push({\r\n\t\t\t\t\tprefix,\r\n\t\t\t\t\tlabel,\r\n\t\t\t\t\tariaLabel: localize('helpPickAriaLabel', \"{0}, {1}\", label, helpEntry.description),\r\n\t\t\t\t\tdescription: helpEntry.description\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn { editorProviders, globalProviders };\r\n\t}\r\n}\r\n\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Registry } from 'vs/platform/registry/common/platform';\r\nimport { IQuickAccessRegistry, Extensions } from 'vs/platform/quickinput/common/quickAccess';\r\nimport { QuickHelpNLS } from 'vs/editor/common/standaloneStrings';\r\nimport { HelpQuickAccessProvider } from 'vs/platform/quickinput/browser/helpQuickAccess';\r\n\r\nRegistry.as(Extensions.Quickaccess).registerQuickAccessProvider({\r\n\tctor: HelpQuickAccessProvider,\r\n\tprefix: '',\r\n\thelpEntries: [{ description: QuickHelpNLS.helpQuickAccessActionLabel, needsEditor: true }]\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IQuickInputService, IQuickPick, IQuickPickItem, ItemActivation } from 'vs/platform/quickinput/common/quickInput';\r\nimport { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle';\r\nimport { IQuickAccessController, IQuickAccessProvider, IQuickAccessRegistry, Extensions, IQuickAccessProviderDescriptor, IQuickAccessOptions, DefaultQuickAccessFilterValue } from 'vs/platform/quickinput/common/quickAccess';\r\nimport { Registry } from 'vs/platform/registry/common/platform';\r\nimport { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';\r\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\r\nimport { once } from 'vs/base/common/functional';\r\n\r\nexport class QuickAccessController extends Disposable implements IQuickAccessController {\r\n\r\n\tprivate readonly registry = Registry.as(Extensions.Quickaccess);\r\n\tprivate readonly mapProviderToDescriptor = new Map();\r\n\r\n\tprivate readonly lastAcceptedPickerValues = new Map();\r\n\r\n\tprivate visibleQuickAccess: {\r\n\t\tpicker: IQuickPick,\r\n\t\tdescriptor: IQuickAccessProviderDescriptor | undefined,\r\n\t\tvalue: string\r\n\t} | undefined = undefined;\r\n\r\n\tconstructor(\r\n\t\t@IQuickInputService private readonly quickInputService: IQuickInputService,\r\n\t\t@IInstantiationService private readonly instantiationService: IInstantiationService\r\n\t) {\r\n\t\tsuper();\r\n\t}\r\n\r\n\tshow(value = '', options?: IQuickAccessOptions): void {\r\n\r\n\t\t// Find provider for the value to show\r\n\t\tconst [provider, descriptor] = this.getOrInstantiateProvider(value);\r\n\r\n\t\t// Return early if quick access is already showing on that same prefix\r\n\t\tconst visibleQuickAccess = this.visibleQuickAccess;\r\n\t\tconst visibleDescriptor = visibleQuickAccess?.descriptor;\r\n\t\tif (visibleQuickAccess && descriptor && visibleDescriptor === descriptor) {\r\n\r\n\t\t\t// Apply value only if it is more specific than the prefix\r\n\t\t\t// from the provider and we are not instructed to preserve\r\n\t\t\tif (value !== descriptor.prefix && !options?.preserveValue) {\r\n\t\t\t\tvisibleQuickAccess.picker.value = value;\r\n\t\t\t}\r\n\r\n\t\t\t// Always adjust selection\r\n\t\t\tthis.adjustValueSelection(visibleQuickAccess.picker, descriptor, options);\r\n\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// Rewrite the filter value based on certain rules unless disabled\r\n\t\tif (descriptor && !options?.preserveValue) {\r\n\t\t\tlet newValue: string | undefined = undefined;\r\n\r\n\t\t\t// If we have a visible provider with a value, take it's filter value but\r\n\t\t\t// rewrite to new provider prefix in case they differ\r\n\t\t\tif (visibleQuickAccess && visibleDescriptor && visibleDescriptor !== descriptor) {\r\n\t\t\t\tconst newValueCandidateWithoutPrefix = visibleQuickAccess.value.substr(visibleDescriptor.prefix.length);\r\n\t\t\t\tif (newValueCandidateWithoutPrefix) {\r\n\t\t\t\t\tnewValue = `${descriptor.prefix}${newValueCandidateWithoutPrefix}`;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// Otherwise, take a default value as instructed\r\n\t\t\tif (!newValue) {\r\n\t\t\t\tconst defaultFilterValue = provider?.defaultFilterValue;\r\n\t\t\t\tif (defaultFilterValue === DefaultQuickAccessFilterValue.LAST) {\r\n\t\t\t\t\tnewValue = this.lastAcceptedPickerValues.get(descriptor);\r\n\t\t\t\t} else if (typeof defaultFilterValue === 'string') {\r\n\t\t\t\t\tnewValue = `${descriptor.prefix}${defaultFilterValue}`;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (typeof newValue === 'string') {\r\n\t\t\t\tvalue = newValue;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Create a picker for the provider to use with the initial value\r\n\t\t// and adjust the filtering to exclude the prefix from filtering\r\n\t\tconst disposables = new DisposableStore();\r\n\t\tconst picker = disposables.add(this.quickInputService.createQuickPick());\r\n\t\tpicker.value = value;\r\n\t\tthis.adjustValueSelection(picker, descriptor, options);\r\n\t\tpicker.placeholder = descriptor?.placeholder;\r\n\t\tpicker.quickNavigate = options?.quickNavigateConfiguration;\r\n\t\tpicker.hideInput = !!picker.quickNavigate && !visibleQuickAccess; // only hide input if there was no picker opened already\r\n\t\tif (typeof options?.itemActivation === 'number' || options?.quickNavigateConfiguration) {\r\n\t\t\tpicker.itemActivation = options?.itemActivation ?? ItemActivation.SECOND /* quick nav is always second */;\r\n\t\t}\r\n\t\tpicker.contextKey = descriptor?.contextKey;\r\n\t\tpicker.filterValue = (value: string) => value.substring(descriptor ? descriptor.prefix.length : 0);\r\n\t\tif (descriptor?.placeholder) {\r\n\t\t\tpicker.ariaLabel = descriptor?.placeholder;\r\n\t\t}\r\n\r\n\t\t// Register listeners\r\n\t\tconst cancellationToken = this.registerPickerListeners(picker, provider, descriptor, value, disposables);\r\n\r\n\t\t// Ask provider to fill the picker as needed if we have one\r\n\t\tif (provider) {\r\n\t\t\tdisposables.add(provider.provide(picker, cancellationToken));\r\n\t\t}\r\n\r\n\t\t// Finally, show the picker. This is important because a provider\r\n\t\t// may not call this and then our disposables would leak that rely\r\n\t\t// on the onDidHide event.\r\n\t\tpicker.show();\r\n\t}\r\n\r\n\tprivate adjustValueSelection(picker: IQuickPick, descriptor?: IQuickAccessProviderDescriptor, options?: IQuickAccessOptions): void {\r\n\t\tlet valueSelection: [number, number];\r\n\r\n\t\t// Preserve: just always put the cursor at the end\r\n\t\tif (options?.preserveValue) {\r\n\t\t\tvalueSelection = [picker.value.length, picker.value.length];\r\n\t\t}\r\n\r\n\t\t// Otherwise: select the value up until the prefix\r\n\t\telse {\r\n\t\t\tvalueSelection = [descriptor?.prefix.length ?? 0, picker.value.length];\r\n\t\t}\r\n\r\n\t\tpicker.valueSelection = valueSelection;\r\n\t}\r\n\r\n\tprivate registerPickerListeners(picker: IQuickPick, provider: IQuickAccessProvider | undefined, descriptor: IQuickAccessProviderDescriptor | undefined, value: string, disposables: DisposableStore): CancellationToken {\r\n\r\n\t\t// Remember as last visible picker and clean up once picker get's disposed\r\n\t\tconst visibleQuickAccess = this.visibleQuickAccess = { picker, descriptor, value };\r\n\t\tdisposables.add(toDisposable(() => {\r\n\t\t\tif (visibleQuickAccess === this.visibleQuickAccess) {\r\n\t\t\t\tthis.visibleQuickAccess = undefined;\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\t// Whenever the value changes, check if the provider has\r\n\t\t// changed and if so - re-create the picker from the beginning\r\n\t\tdisposables.add(picker.onDidChangeValue(value => {\r\n\t\t\tconst [providerForValue] = this.getOrInstantiateProvider(value);\r\n\t\t\tif (providerForValue !== provider) {\r\n\t\t\t\tthis.show(value, { preserveValue: true } /* do not rewrite value from user typing! */);\r\n\t\t\t} else {\r\n\t\t\t\tvisibleQuickAccess.value = value; // remember the value in our visible one\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\t// Remember picker input for future use when accepting\r\n\t\tif (descriptor) {\r\n\t\t\tdisposables.add(picker.onDidAccept(() => {\r\n\t\t\t\tthis.lastAcceptedPickerValues.set(descriptor, picker.value);\r\n\t\t\t}));\r\n\t\t}\r\n\r\n\t\t// Create a cancellation token source that is valid as long as the\r\n\t\t// picker has not been closed without picking an item\r\n\t\tconst cts = disposables.add(new CancellationTokenSource());\r\n\t\tonce(picker.onDidHide)(() => {\r\n\t\t\tif (picker.selectedItems.length === 0) {\r\n\t\t\t\tcts.cancel();\r\n\t\t\t}\r\n\r\n\t\t\t// Start to dispose once picker hides\r\n\t\t\tdisposables.dispose();\r\n\t\t});\r\n\r\n\t\treturn cts.token;\r\n\t}\r\n\r\n\tprivate getOrInstantiateProvider(value: string): [IQuickAccessProvider | undefined, IQuickAccessProviderDescriptor | undefined] {\r\n\t\tconst providerDescriptor = this.registry.getQuickAccessProvider(value);\r\n\t\tif (!providerDescriptor) {\r\n\t\t\treturn [undefined, undefined];\r\n\t\t}\r\n\r\n\t\tlet provider = this.mapProviderToDescriptor.get(providerDescriptor);\r\n\t\tif (!provider) {\r\n\t\t\tprovider = this.instantiationService.createInstance(providerDescriptor.ctor);\r\n\t\t\tthis.mapProviderToDescriptor.set(providerDescriptor, provider);\r\n\t\t}\r\n\r\n\t\treturn [provider, providerDescriptor];\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { Event, Emitter, PauseableEmitter } from 'vs/base/common/event';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { isUndefinedOrNull } from 'vs/base/common/types';\r\nconst TARGET_KEY = '__$__targetStorageMarker';\r\n\r\nexport const IStorageService = createDecorator('storageService');\r\n\r\nexport enum WillSaveStateReason {\r\n\r\n\t/**\r\n\t * No specific reason to save state.\r\n\t */\r\n\tNONE,\r\n\r\n\t/**\r\n\t * A hint that the workbench is about to shutdown.\r\n\t */\r\n\tSHUTDOWN\r\n}\r\n\r\nexport interface IWillSaveStateEvent {\r\n\treason: WillSaveStateReason;\r\n}\r\n\r\nexport interface IStorageService {\r\n\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\t/**\r\n\t * Emitted when the storage is about to persist. This is the right time\r\n\t * to persist data to ensure it is stored before the application shuts\r\n\t * down.\r\n\t *\r\n\t * The will save state event allows to optionally ask for the reason of\r\n\t * saving the state, e.g. to find out if the state is saved due to a\r\n\t * shutdown.\r\n\t *\r\n\t * Note: this event may be fired many times, not only on shutdown to prevent\r\n\t * loss of state in situations where the shutdown is not sufficient to\r\n\t * persist the data properly.\r\n\t */\r\n\treadonly onWillSaveState: Event;\r\n\r\n\t/**\r\n\t * Retrieve an element stored with the given key from storage. Use\r\n\t * the provided `defaultValue` if the element is `null` or `undefined`.\r\n\t *\r\n\t * @param scope allows to define the scope of the storage operation\r\n\t * to either the current workspace only or all workspaces.\r\n\t */\r\n\tget(key: string, scope: StorageScope, fallbackValue: string): string;\r\n\tget(key: string, scope: StorageScope, fallbackValue?: string): string | undefined;\r\n\r\n\t/**\r\n\t * Retrieve an element stored with the given key from storage. Use\r\n\t * the provided `defaultValue` if the element is `null` or `undefined`.\r\n\t * The element will be converted to a `boolean`.\r\n\t *\r\n\t * @param scope allows to define the scope of the storage operation\r\n\t * to either the current workspace only or all workspaces.\r\n\t */\r\n\tgetBoolean(key: string, scope: StorageScope, fallbackValue: boolean): boolean;\r\n\tgetBoolean(key: string, scope: StorageScope, fallbackValue?: boolean): boolean | undefined;\r\n\r\n\t/**\r\n\t * Retrieve an element stored with the given key from storage. Use\r\n\t * the provided `defaultValue` if the element is `null` or `undefined`.\r\n\t * The element will be converted to a `number` using `parseInt` with a\r\n\t * base of `10`.\r\n\t *\r\n\t * @param scope allows to define the scope of the storage operation\r\n\t * to either the current workspace only or all workspaces.\r\n\t */\r\n\tgetNumber(key: string, scope: StorageScope, fallbackValue: number): number;\r\n\tgetNumber(key: string, scope: StorageScope, fallbackValue?: number): number | undefined;\r\n\r\n\t/**\r\n\t * Store a value under the given key to storage. The value will be\r\n\t * converted to a `string`. Storing either `undefined` or `null` will\r\n\t * remove the entry under the key.\r\n\t *\r\n\t * @param scope allows to define the scope of the storage operation\r\n\t * to either the current workspace only or all workspaces.\r\n\t *\r\n\t * @param target allows to define the target of the storage operation\r\n\t * to either the current machine or user.\r\n\t */\r\n\tstore(key: string, value: string | boolean | number | undefined | null, scope: StorageScope, target: StorageTarget): void;\r\n\r\n\t/**\r\n\t * Delete an element stored under the provided key from storage.\r\n\t *\r\n\t * The scope argument allows to define the scope of the storage\r\n\t * operation to either the current workspace only or all workspaces.\r\n\t */\r\n\tremove(key: string, scope: StorageScope): void;\r\n}\r\n\r\nexport const enum StorageScope {\r\n\r\n\t/**\r\n\t * The stored data will be scoped to all workspaces.\r\n\t */\r\n\tGLOBAL,\r\n\r\n\t/**\r\n\t * The stored data will be scoped to the current workspace.\r\n\t */\r\n\tWORKSPACE\r\n}\r\n\r\nexport const enum StorageTarget {\r\n\r\n\t/**\r\n\t * The stored data is user specific and applies across machines.\r\n\t */\r\n\tUSER,\r\n\r\n\t/**\r\n\t * The stored data is machine specific.\r\n\t */\r\n\tMACHINE\r\n}\r\n\r\nexport interface IStorageValueChangeEvent {\r\n\r\n\t/**\r\n\t * The scope for the storage entry that changed\r\n\t * or was removed.\r\n\t */\r\n\treadonly scope: StorageScope;\r\n\r\n\t/**\r\n\t * The `key` of the storage entry that was changed\r\n\t * or was removed.\r\n\t */\r\n\treadonly key: string;\r\n\r\n\t/**\r\n\t * The `target` can be `undefined` if a key is being\r\n\t * removed.\r\n\t */\r\n\treadonly target: StorageTarget | undefined;\r\n}\r\n\r\nexport interface IStorageTargetChangeEvent {\r\n\r\n\t/**\r\n\t * The scope for the target that changed. Listeners\r\n\t * should use `keys(scope, target)` to get an updated\r\n\t * list of keys for the given `scope` and `target`.\r\n\t */\r\n\treadonly scope: StorageScope;\r\n}\r\n\r\ninterface IKeyTargets {\r\n\t[key: string]: StorageTarget\r\n}\r\n\r\nexport abstract class AbstractStorageService extends Disposable implements IStorageService {\r\n\r\n\tdeclare readonly _serviceBrand: undefined;\r\n\r\n\tprivate readonly _onDidChangeValue = this._register(new PauseableEmitter());\r\n\r\n\tprivate readonly _onDidChangeTarget = this._register(new PauseableEmitter());\r\n\r\n\tprivate readonly _onWillSaveState = this._register(new Emitter());\r\n\treadonly onWillSaveState = this._onWillSaveState.event;\r\n\r\n\tprotected emitDidChangeValue(scope: StorageScope, key: string): void {\r\n\r\n\t\t// Specially handle `TARGET_KEY`\r\n\t\tif (key === TARGET_KEY) {\r\n\r\n\t\t\t// Clear our cached version which is now out of date\r\n\t\t\tif (scope === StorageScope.GLOBAL) {\r\n\t\t\t\tthis._globalKeyTargets = undefined;\r\n\t\t\t} else if (scope === StorageScope.WORKSPACE) {\r\n\t\t\t\tthis._workspaceKeyTargets = undefined;\r\n\t\t\t}\r\n\r\n\t\t\t// Emit as `didChangeTarget` event\r\n\t\t\tthis._onDidChangeTarget.fire({ scope });\r\n\t\t}\r\n\r\n\t\t// Emit any other key to outside\r\n\t\telse {\r\n\t\t\tthis._onDidChangeValue.fire({ scope, key, target: this.getKeyTargets(scope)[key] });\r\n\t\t}\r\n\t}\r\n\r\n\tstore(key: string, value: string | boolean | number | undefined | null, scope: StorageScope, target: StorageTarget): void {\r\n\r\n\t\t// We remove the key for undefined/null values\r\n\t\tif (isUndefinedOrNull(value)) {\r\n\t\t\tthis.remove(key, scope);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// Update our datastructures but send events only after\r\n\t\tthis.withPausedEmitters(() => {\r\n\r\n\t\t\t// Update key-target map\r\n\t\t\tthis.updateKeyTarget(key, scope, target);\r\n\r\n\t\t\t// Store actual value\r\n\t\t\tthis.doStore(key, value, scope);\r\n\t\t});\r\n\t}\r\n\r\n\tremove(key: string, scope: StorageScope): void {\r\n\r\n\t\t// Update our datastructures but send events only after\r\n\t\tthis.withPausedEmitters(() => {\r\n\r\n\t\t\t// Update key-target map\r\n\t\t\tthis.updateKeyTarget(key, scope, undefined);\r\n\r\n\t\t\t// Remove actual key\r\n\t\t\tthis.doRemove(key, scope);\r\n\t\t});\r\n\t}\r\n\r\n\tprivate withPausedEmitters(fn: Function): void {\r\n\r\n\t\t// Pause emitters\r\n\t\tthis._onDidChangeValue.pause();\r\n\t\tthis._onDidChangeTarget.pause();\r\n\r\n\t\ttry {\r\n\t\t\tfn();\r\n\t\t} finally {\r\n\r\n\t\t\t// Resume emitters\r\n\t\t\tthis._onDidChangeValue.resume();\r\n\t\t\tthis._onDidChangeTarget.resume();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate updateKeyTarget(key: string, scope: StorageScope, target: StorageTarget | undefined): void {\r\n\r\n\t\t// Add\r\n\t\tconst keyTargets = this.getKeyTargets(scope);\r\n\t\tif (typeof target === 'number') {\r\n\t\t\tif (keyTargets[key] !== target) {\r\n\t\t\t\tkeyTargets[key] = target;\r\n\t\t\t\tthis.doStore(TARGET_KEY, JSON.stringify(keyTargets), scope);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Remove\r\n\t\telse {\r\n\t\t\tif (typeof keyTargets[key] === 'number') {\r\n\t\t\t\tdelete keyTargets[key];\r\n\t\t\t\tthis.doStore(TARGET_KEY, JSON.stringify(keyTargets), scope);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _workspaceKeyTargets: IKeyTargets | undefined = undefined;\r\n\tprivate get workspaceKeyTargets(): IKeyTargets {\r\n\t\tif (!this._workspaceKeyTargets) {\r\n\t\t\tthis._workspaceKeyTargets = this.loadKeyTargets(StorageScope.WORKSPACE);\r\n\t\t}\r\n\r\n\t\treturn this._workspaceKeyTargets;\r\n\t}\r\n\r\n\tprivate _globalKeyTargets: IKeyTargets | undefined = undefined;\r\n\tprivate get globalKeyTargets(): IKeyTargets {\r\n\t\tif (!this._globalKeyTargets) {\r\n\t\t\tthis._globalKeyTargets = this.loadKeyTargets(StorageScope.GLOBAL);\r\n\t\t}\r\n\r\n\t\treturn this._globalKeyTargets;\r\n\t}\r\n\r\n\tprivate getKeyTargets(scope: StorageScope): IKeyTargets {\r\n\t\treturn scope === StorageScope.GLOBAL ? this.globalKeyTargets : this.workspaceKeyTargets;\r\n\t}\r\n\r\n\tprivate loadKeyTargets(scope: StorageScope): { [key: string]: StorageTarget } {\r\n\t\tconst keysRaw = this.get(TARGET_KEY, scope);\r\n\t\tif (keysRaw) {\r\n\t\t\ttry {\r\n\t\t\t\treturn JSON.parse(keysRaw);\r\n\t\t\t} catch (error) {\r\n\t\t\t\t// Fail gracefully\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn Object.create(null);\r\n\t}\r\n\r\n\t// --- abstract\r\n\r\n\tabstract get(key: string, scope: StorageScope, fallbackValue: string): string;\r\n\tabstract get(key: string, scope: StorageScope, fallbackValue?: string): string | undefined;\r\n\r\n\tabstract getBoolean(key: string, scope: StorageScope, fallbackValue: boolean): boolean;\r\n\tabstract getBoolean(key: string, scope: StorageScope, fallbackValue?: boolean): boolean | undefined;\r\n\r\n\tabstract getNumber(key: string, scope: StorageScope, fallbackValue: number): number;\r\n\tabstract getNumber(key: string, scope: StorageScope, fallbackValue?: number): number | undefined;\r\n\r\n\tprotected abstract doStore(key: string, value: string | boolean | number, scope: StorageScope): void;\r\n\r\n\tprotected abstract doRemove(key: string, scope: StorageScope): void;\r\n}\r\n\r\nexport class InMemoryStorageService extends AbstractStorageService {\r\n\r\n\tprivate readonly globalCache = new Map();\r\n\tprivate readonly workspaceCache = new Map();\r\n\r\n\tprivate getCache(scope: StorageScope): Map {\r\n\t\treturn scope === StorageScope.GLOBAL ? this.globalCache : this.workspaceCache;\r\n\t}\r\n\r\n\tget(key: string, scope: StorageScope, fallbackValue: string): string;\r\n\tget(key: string, scope: StorageScope, fallbackValue?: string): string | undefined {\r\n\t\tconst value = this.getCache(scope).get(key);\r\n\r\n\t\tif (isUndefinedOrNull(value)) {\r\n\t\t\treturn fallbackValue;\r\n\t\t}\r\n\r\n\t\treturn value;\r\n\t}\r\n\r\n\tgetBoolean(key: string, scope: StorageScope, fallbackValue: boolean): boolean;\r\n\tgetBoolean(key: string, scope: StorageScope, fallbackValue?: boolean): boolean | undefined {\r\n\t\tconst value = this.getCache(scope).get(key);\r\n\r\n\t\tif (isUndefinedOrNull(value)) {\r\n\t\t\treturn fallbackValue;\r\n\t\t}\r\n\r\n\t\treturn value === 'true';\r\n\t}\r\n\r\n\tgetNumber(key: string, scope: StorageScope, fallbackValue: number): number;\r\n\tgetNumber(key: string, scope: StorageScope, fallbackValue?: number): number | undefined {\r\n\t\tconst value = this.getCache(scope).get(key);\r\n\r\n\t\tif (isUndefinedOrNull(value)) {\r\n\t\t\treturn fallbackValue;\r\n\t\t}\r\n\r\n\t\treturn parseInt(value, 10);\r\n\t}\r\n\r\n\tprotected doStore(key: string, value: string | boolean | number, scope: StorageScope): void {\r\n\r\n\t\t// Otherwise, convert to String and store\r\n\t\tconst valueStr = String(value);\r\n\r\n\t\t// Return early if value already set\r\n\t\tconst currentValue = this.getCache(scope).get(key);\r\n\t\tif (currentValue === valueStr) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// Update in cache\r\n\t\tthis.getCache(scope).set(key, valueStr);\r\n\r\n\t\t// Events\r\n\t\tthis.emitDidChangeValue(scope, key);\r\n\t}\r\n\r\n\tprotected doRemove(key: string, scope: StorageScope): void {\r\n\t\tconst wasDeleted = this.getCache(scope).delete(key);\r\n\t\tif (!wasDeleted) {\r\n\t\t\treturn; // Return early if value already deleted\r\n\t\t}\r\n\r\n\t\t// Events\r\n\t\tthis.emitDidChangeValue(scope, key);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { registerSingleton } from 'vs/platform/instantiation/common/extensions';\r\nimport { CodeLensModel } from 'vs/editor/contrib/codelens/codelens';\r\nimport { LRUCache } from 'vs/base/common/map';\r\nimport { CodeLensProvider, CodeLensList, CodeLens } from 'vs/editor/common/modes';\r\nimport { IStorageService, StorageScope, StorageTarget, WillSaveStateReason } from 'vs/platform/storage/common/storage';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { runWhenIdle } from 'vs/base/common/async';\r\nimport { once } from 'vs/base/common/functional';\r\n\r\nexport const ICodeLensCache = createDecorator('ICodeLensCache');\r\n\r\nexport interface ICodeLensCache {\r\n\treadonly _serviceBrand: undefined;\r\n\tput(model: ITextModel, data: CodeLensModel): void;\r\n\tget(model: ITextModel): CodeLensModel | undefined;\r\n\tdelete(model: ITextModel): void;\r\n}\r\n\r\ninterface ISerializedCacheData {\r\n\tlineCount: number;\r\n\tlines: number[];\r\n}\r\n\r\nclass CacheItem {\r\n\r\n\tconstructor(\r\n\t\treadonly lineCount: number,\r\n\t\treadonly data: CodeLensModel\r\n\t) { }\r\n}\r\n\r\nexport class CodeLensCache implements ICodeLensCache {\r\n\r\n\tdeclare readonly _serviceBrand: undefined;\r\n\r\n\tprivate readonly _fakeProvider = new class implements CodeLensProvider {\r\n\t\tprovideCodeLenses(): CodeLensList {\r\n\t\t\tthrow new Error('not supported');\r\n\t\t}\r\n\t};\r\n\r\n\tprivate readonly _cache = new LRUCache(20, 0.75);\r\n\r\n\tconstructor(@IStorageService storageService: IStorageService) {\r\n\r\n\t\t// remove old data\r\n\t\tconst oldkey = 'codelens/cache';\r\n\t\trunWhenIdle(() => storageService.remove(oldkey, StorageScope.WORKSPACE));\r\n\r\n\t\t// restore lens data on start\r\n\t\tconst key = 'codelens/cache2';\r\n\t\tconst raw = storageService.get(key, StorageScope.WORKSPACE, '{}');\r\n\t\tthis._deserialize(raw);\r\n\r\n\t\t// store lens data on shutdown\r\n\t\tonce(storageService.onWillSaveState)(e => {\r\n\t\t\tif (e.reason === WillSaveStateReason.SHUTDOWN) {\r\n\t\t\t\tstorageService.store(key, this._serialize(), StorageScope.WORKSPACE, StorageTarget.MACHINE);\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tput(model: ITextModel, data: CodeLensModel): void {\r\n\t\t// create a copy of the model that is without command-ids\r\n\t\t// but with comand-labels\r\n\t\tconst copyItems = data.lenses.map(item => {\r\n\t\t\treturn {\r\n\t\t\t\trange: item.symbol.range,\r\n\t\t\t\tcommand: item.symbol.command && { id: '', title: item.symbol.command?.title },\r\n\t\t\t};\r\n\t\t});\r\n\t\tconst copyModel = new CodeLensModel();\r\n\t\tcopyModel.add({ lenses: copyItems, dispose: () => { } }, this._fakeProvider);\r\n\r\n\t\tconst item = new CacheItem(model.getLineCount(), copyModel);\r\n\t\tthis._cache.set(model.uri.toString(), item);\r\n\t}\r\n\r\n\tget(model: ITextModel) {\r\n\t\tconst item = this._cache.get(model.uri.toString());\r\n\t\treturn item && item.lineCount === model.getLineCount() ? item.data : undefined;\r\n\t}\r\n\r\n\tdelete(model: ITextModel): void {\r\n\t\tthis._cache.delete(model.uri.toString());\r\n\t}\r\n\r\n\t// --- persistence\r\n\r\n\tprivate _serialize(): string {\r\n\t\tconst data: Record = Object.create(null);\r\n\t\tfor (const [key, value] of this._cache) {\r\n\t\t\tconst lines = new Set();\r\n\t\t\tfor (const d of value.data.lenses) {\r\n\t\t\t\tlines.add(d.symbol.range.startLineNumber);\r\n\t\t\t}\r\n\t\t\tdata[key] = {\r\n\t\t\t\tlineCount: value.lineCount,\r\n\t\t\t\tlines: [...lines.values()]\r\n\t\t\t};\r\n\t\t}\r\n\t\treturn JSON.stringify(data);\r\n\t}\r\n\r\n\tprivate _deserialize(raw: string): void {\r\n\t\ttry {\r\n\t\t\tconst data: Record = JSON.parse(raw);\r\n\t\t\tfor (const key in data) {\r\n\t\t\t\tconst element = data[key];\r\n\t\t\t\tconst lenses: CodeLens[] = [];\r\n\t\t\t\tfor (const line of element.lines) {\r\n\t\t\t\t\tlenses.push({ range: new Range(line, 1, line, 11) });\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst model = new CodeLensModel();\r\n\t\t\t\tmodel.add({ lenses, dispose() { } }, this._fakeProvider);\r\n\t\t\t\tthis._cache.set(key, new CacheItem(element.lineCount, model));\r\n\t\t\t}\r\n\t\t} catch {\r\n\t\t\t// ignore...\r\n\t\t}\r\n\t}\r\n}\r\n\r\nregisterSingleton(ICodeLensCache, CodeLensCache);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\n\r\nimport { LRUCache, TernarySearchTree } from 'vs/base/common/map';\r\nimport { IStorageService, StorageScope, StorageTarget, WillSaveStateReason } from 'vs/platform/storage/common/storage';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { IPosition } from 'vs/editor/common/core/position';\r\nimport { CompletionItemKind, completionKindFromString } from 'vs/editor/common/modes';\r\nimport { DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { RunOnceScheduler } from 'vs/base/common/async';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\r\nimport { registerSingleton } from 'vs/platform/instantiation/common/extensions';\r\nimport { CompletionItem } from 'vs/editor/contrib/suggest/suggest';\r\nimport { IModeService } from 'vs/editor/common/services/modeService';\r\n\r\nexport abstract class Memory {\r\n\r\n\tconstructor(readonly name: MemMode) { }\r\n\r\n\tselect(model: ITextModel, pos: IPosition, items: CompletionItem[]): number {\r\n\t\tif (items.length === 0) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t\tlet topScore = items[0].score[0];\r\n\t\tfor (let i = 0; i < items.length; i++) {\r\n\t\t\tconst { score, completion: suggestion } = items[i];\r\n\t\t\tif (score[0] !== topScore) {\r\n\t\t\t\t// stop when leaving the group of top matches\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tif (suggestion.preselect) {\r\n\t\t\t\t// stop when seeing an auto-select-item\r\n\t\t\t\treturn i;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn 0;\r\n\t}\r\n\r\n\tabstract memorize(model: ITextModel, pos: IPosition, item: CompletionItem): void;\r\n\r\n\tabstract toJSON(): object | undefined;\r\n\r\n\tabstract fromJSON(data: object): void;\r\n}\r\n\r\nexport class NoMemory extends Memory {\r\n\r\n\tconstructor() {\r\n\t\tsuper('first');\r\n\t}\r\n\r\n\tmemorize(model: ITextModel, pos: IPosition, item: CompletionItem): void {\r\n\t\t// no-op\r\n\t}\r\n\r\n\ttoJSON() {\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tfromJSON() {\r\n\t\t//\r\n\t}\r\n}\r\n\r\nexport interface MemItem {\r\n\ttype: string | CompletionItemKind;\r\n\tinsertText: string;\r\n\ttouch: number;\r\n}\r\n\r\nexport class LRUMemory extends Memory {\r\n\r\n\tconstructor() {\r\n\t\tsuper('recentlyUsed');\r\n\t}\r\n\r\n\tprivate _cache = new LRUCache(300, 0.66);\r\n\tprivate _seq = 0;\r\n\r\n\tmemorize(model: ITextModel, pos: IPosition, item: CompletionItem): void {\r\n\t\tconst key = `${model.getLanguageIdentifier().language}/${item.textLabel}`;\r\n\t\tthis._cache.set(key, {\r\n\t\t\ttouch: this._seq++,\r\n\t\t\ttype: item.completion.kind,\r\n\t\t\tinsertText: item.completion.insertText\r\n\t\t});\r\n\t}\r\n\r\n\tselect(model: ITextModel, pos: IPosition, items: CompletionItem[]): number {\r\n\r\n\t\tif (items.length === 0) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tconst lineSuffix = model.getLineContent(pos.lineNumber).substr(pos.column - 10, pos.column - 1);\r\n\t\tif (/\\s$/.test(lineSuffix)) {\r\n\t\t\treturn super.select(model, pos, items);\r\n\t\t}\r\n\r\n\t\tlet topScore = items[0].score[0];\r\n\t\tlet indexPreselect = -1;\r\n\t\tlet indexRecency = -1;\r\n\t\tlet seq = -1;\r\n\t\tfor (let i = 0; i < items.length; i++) {\r\n\t\t\tif (items[i].score[0] !== topScore) {\r\n\t\t\t\t// consider only top items\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tconst key = `${model.getLanguageIdentifier().language}/${items[i].textLabel}`;\r\n\t\t\tconst item = this._cache.peek(key);\r\n\t\t\tif (item && item.touch > seq && item.type === items[i].completion.kind && item.insertText === items[i].completion.insertText) {\r\n\t\t\t\tseq = item.touch;\r\n\t\t\t\tindexRecency = i;\r\n\t\t\t}\r\n\t\t\tif (items[i].completion.preselect && indexPreselect === -1) {\r\n\t\t\t\t// stop when seeing an auto-select-item\r\n\t\t\t\treturn indexPreselect = i;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (indexRecency !== -1) {\r\n\t\t\treturn indexRecency;\r\n\t\t} else if (indexPreselect !== -1) {\r\n\t\t\treturn indexPreselect;\r\n\t\t} else {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t}\r\n\r\n\ttoJSON(): object {\r\n\t\treturn this._cache.toJSON();\r\n\t}\r\n\r\n\tfromJSON(data: [string, MemItem][]): void {\r\n\t\tthis._cache.clear();\r\n\t\tlet seq = 0;\r\n\t\tfor (const [key, value] of data) {\r\n\t\t\tvalue.touch = seq;\r\n\t\t\tvalue.type = typeof value.type === 'number' ? value.type : completionKindFromString(value.type);\r\n\t\t\tthis._cache.set(key, value);\r\n\t\t}\r\n\t\tthis._seq = this._cache.size;\r\n\t}\r\n}\r\n\r\n\r\nexport class PrefixMemory extends Memory {\r\n\r\n\tconstructor() {\r\n\t\tsuper('recentlyUsedByPrefix');\r\n\t}\r\n\r\n\tprivate _trie = TernarySearchTree.forStrings();\r\n\tprivate _seq = 0;\r\n\r\n\tmemorize(model: ITextModel, pos: IPosition, item: CompletionItem): void {\r\n\t\tconst { word } = model.getWordUntilPosition(pos);\r\n\t\tconst key = `${model.getLanguageIdentifier().language}/${word}`;\r\n\t\tthis._trie.set(key, {\r\n\t\t\ttype: item.completion.kind,\r\n\t\t\tinsertText: item.completion.insertText,\r\n\t\t\ttouch: this._seq++\r\n\t\t});\r\n\t}\r\n\r\n\tselect(model: ITextModel, pos: IPosition, items: CompletionItem[]): number {\r\n\t\tlet { word } = model.getWordUntilPosition(pos);\r\n\t\tif (!word) {\r\n\t\t\treturn super.select(model, pos, items);\r\n\t\t}\r\n\t\tlet key = `${model.getLanguageIdentifier().language}/${word}`;\r\n\t\tlet item = this._trie.get(key);\r\n\t\tif (!item) {\r\n\t\t\titem = this._trie.findSubstr(key);\r\n\t\t}\r\n\t\tif (item) {\r\n\t\t\tfor (let i = 0; i < items.length; i++) {\r\n\t\t\t\tlet { kind, insertText } = items[i].completion;\r\n\t\t\t\tif (kind === item.type && insertText === item.insertText) {\r\n\t\t\t\t\treturn i;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn super.select(model, pos, items);\r\n\t}\r\n\r\n\ttoJSON(): object {\r\n\r\n\t\tlet entries: [string, MemItem][] = [];\r\n\t\tthis._trie.forEach((value, key) => entries.push([key, value]));\r\n\r\n\t\t// sort by last recently used (touch), then\r\n\t\t// take the top 200 item and normalize their\r\n\t\t// touch\r\n\t\tentries\r\n\t\t\t.sort((a, b) => -(a[1].touch - b[1].touch))\r\n\t\t\t.forEach((value, i) => value[1].touch = i);\r\n\r\n\t\treturn entries.slice(0, 200);\r\n\t}\r\n\r\n\tfromJSON(data: [string, MemItem][]): void {\r\n\t\tthis._trie.clear();\r\n\t\tif (data.length > 0) {\r\n\t\t\tthis._seq = data[0][1].touch + 1;\r\n\t\t\tfor (const [key, value] of data) {\r\n\t\t\t\tvalue.type = typeof value.type === 'number' ? value.type : completionKindFromString(value.type);\r\n\t\t\t\tthis._trie.set(key, value);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport type MemMode = 'first' | 'recentlyUsed' | 'recentlyUsedByPrefix';\r\n\r\nexport class SuggestMemoryService implements ISuggestMemoryService {\r\n\r\n\tprivate static readonly _strategyCtors = new Map([\r\n\t\t['recentlyUsedByPrefix', PrefixMemory],\r\n\t\t['recentlyUsed', LRUMemory],\r\n\t\t['first', NoMemory]\r\n\t]);\r\n\r\n\tprivate static readonly _storagePrefix = 'suggest/memories';\r\n\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\r\n\tprivate readonly _persistSoon: RunOnceScheduler;\r\n\tprivate readonly _disposables = new DisposableStore();\r\n\r\n\tprivate _strategy?: Memory;\r\n\r\n\tconstructor(\r\n\t\t@IStorageService private readonly _storageService: IStorageService,\r\n\t\t@IModeService private readonly _modeService: IModeService,\r\n\t\t@IConfigurationService private readonly _configService: IConfigurationService,\r\n\t) {\r\n\t\tthis._persistSoon = new RunOnceScheduler(() => this._saveState(), 500);\r\n\t\tthis._disposables.add(_storageService.onWillSaveState(e => {\r\n\t\t\tif (e.reason === WillSaveStateReason.SHUTDOWN) {\r\n\t\t\t\tthis._saveState();\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._disposables.dispose();\r\n\t\tthis._persistSoon.dispose();\r\n\t}\r\n\r\n\tmemorize(model: ITextModel, pos: IPosition, item: CompletionItem): void {\r\n\t\tthis._withStrategy(model, pos).memorize(model, pos, item);\r\n\t\tthis._persistSoon.schedule();\r\n\t}\r\n\r\n\tselect(model: ITextModel, pos: IPosition, items: CompletionItem[]): number {\r\n\t\treturn this._withStrategy(model, pos).select(model, pos, items);\r\n\t}\r\n\r\n\tprivate _withStrategy(model: ITextModel, pos: IPosition): Memory {\r\n\r\n\t\tconst mode = this._configService.getValue('editor.suggestSelection', {\r\n\t\t\toverrideIdentifier: this._modeService.getLanguageIdentifier(model.getLanguageIdAtPosition(pos.lineNumber, pos.column))?.language,\r\n\t\t\tresource: model.uri\r\n\t\t});\r\n\r\n\t\tif (this._strategy?.name !== mode) {\r\n\r\n\t\t\tthis._saveState();\r\n\t\t\tconst ctor = SuggestMemoryService._strategyCtors.get(mode) || NoMemory;\r\n\t\t\tthis._strategy = new ctor();\r\n\r\n\t\t\ttry {\r\n\t\t\t\tconst share = this._configService.getValue('editor.suggest.shareSuggestSelections');\r\n\t\t\t\tconst scope = share ? StorageScope.GLOBAL : StorageScope.WORKSPACE;\r\n\t\t\t\tconst raw = this._storageService.get(`${SuggestMemoryService._storagePrefix}/${mode}`, scope);\r\n\t\t\t\tif (raw) {\r\n\t\t\t\t\tthis._strategy.fromJSON(JSON.parse(raw));\r\n\t\t\t\t}\r\n\t\t\t} catch (e) {\r\n\t\t\t\t// things can go wrong with JSON...\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this._strategy;\r\n\t}\r\n\r\n\tprivate _saveState() {\r\n\t\tif (this._strategy) {\r\n\t\t\tconst share = this._configService.getValue('editor.suggest.shareSuggestSelections');\r\n\t\t\tconst scope = share ? StorageScope.GLOBAL : StorageScope.WORKSPACE;\r\n\t\t\tconst raw = JSON.stringify(this._strategy);\r\n\t\t\tthis._storageService.store(`${SuggestMemoryService._storagePrefix}/${this._strategy.name}`, raw, scope, StorageTarget.MACHINE);\r\n\t\t}\r\n\t}\r\n}\r\n\r\n\r\nexport const ISuggestMemoryService = createDecorator('ISuggestMemories');\r\n\r\nexport interface ISuggestMemoryService {\r\n\treadonly _serviceBrand: undefined;\r\n\tmemorize(model: ITextModel, pos: IPosition, item: CompletionItem): void;\r\n\tselect(model: ITextModel, pos: IPosition, items: CompletionItem[]): number;\r\n}\r\n\r\nregisterSingleton(ISuggestMemoryService, SuggestMemoryService, true);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';\r\n\r\nexport const ITelemetryService = createDecorator('telemetryService');\r\n\r\nexport interface ITelemetryService {\r\n\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\tpublicLog2 = never, T extends GDPRClassification = never>(eventName: string, data?: StrictPropertyCheck, anonymizeFilePaths?: boolean): Promise;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { localize } from 'vs/nls';\r\nimport { IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';\r\nimport { PickerQuickAccessProvider, IPickerQuickAccessItem, IPickerQuickAccessProviderOptions } from 'vs/platform/quickinput/browser/pickerQuickAccess';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { DisposableStore, Disposable, IDisposable } from 'vs/base/common/lifecycle';\r\nimport { or, matchesPrefix, matchesWords, matchesContiguousSubString } from 'vs/base/common/filters';\r\nimport { withNullAsUndefined } from 'vs/base/common/types';\r\nimport { LRUCache } from 'vs/base/common/map';\r\nimport { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';\r\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\r\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\r\nimport { ICommandService } from 'vs/platform/commands/common/commands';\r\nimport { WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions';\r\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\r\nimport { isPromiseCanceledError } from 'vs/base/common/errors';\r\nimport { INotificationService } from 'vs/platform/notification/common/notification';\r\nimport { toErrorMessage } from 'vs/base/common/errorMessage';\r\n\r\nexport interface ICommandQuickPick extends IPickerQuickAccessItem {\r\n\tcommandId: string;\r\n\tcommandAlias?: string;\r\n}\r\n\r\nexport interface ICommandsQuickAccessOptions extends IPickerQuickAccessProviderOptions {\r\n\tshowAlias: boolean;\r\n}\r\n\r\nexport abstract class AbstractCommandsQuickAccessProvider extends PickerQuickAccessProvider implements IDisposable {\r\n\r\n\tstatic PREFIX = '>';\r\n\r\n\tprivate static WORD_FILTER = or(matchesPrefix, matchesWords, matchesContiguousSubString);\r\n\r\n\tprivate readonly commandsHistory = this._register(this.instantiationService.createInstance(CommandsHistory));\r\n\r\n\tconstructor(\r\n\t\tprotected options: ICommandsQuickAccessOptions,\r\n\t\t@IInstantiationService private readonly instantiationService: IInstantiationService,\r\n\t\t@IKeybindingService private readonly keybindingService: IKeybindingService,\r\n\t\t@ICommandService private readonly commandService: ICommandService,\r\n\t\t@ITelemetryService private readonly telemetryService: ITelemetryService,\r\n\t\t@INotificationService private readonly notificationService: INotificationService\r\n\t) {\r\n\t\tsuper(AbstractCommandsQuickAccessProvider.PREFIX, options);\r\n\t}\r\n\r\n\tprotected async getPicks(filter: string, disposables: DisposableStore, token: CancellationToken): Promise> {\r\n\r\n\t\t// Ask subclass for all command picks\r\n\t\tconst allCommandPicks = await this.getCommandPicks(disposables, token);\r\n\r\n\t\tif (token.isCancellationRequested) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\t// Filter\r\n\t\tconst filteredCommandPicks: ICommandQuickPick[] = [];\r\n\t\tfor (const commandPick of allCommandPicks) {\r\n\t\t\tconst labelHighlights = withNullAsUndefined(AbstractCommandsQuickAccessProvider.WORD_FILTER(filter, commandPick.label));\r\n\t\t\tconst aliasHighlights = commandPick.commandAlias ? withNullAsUndefined(AbstractCommandsQuickAccessProvider.WORD_FILTER(filter, commandPick.commandAlias)) : undefined;\r\n\r\n\t\t\t// Add if matching in label or alias\r\n\t\t\tif (labelHighlights || aliasHighlights) {\r\n\t\t\t\tcommandPick.highlights = {\r\n\t\t\t\t\tlabel: labelHighlights,\r\n\t\t\t\t\tdetail: this.options.showAlias ? aliasHighlights : undefined\r\n\t\t\t\t};\r\n\r\n\t\t\t\tfilteredCommandPicks.push(commandPick);\r\n\t\t\t}\r\n\r\n\t\t\t// Also add if we have a 100% command ID match\r\n\t\t\telse if (filter === commandPick.commandId) {\r\n\t\t\t\tfilteredCommandPicks.push(commandPick);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Add description to commands that have duplicate labels\r\n\t\tconst mapLabelToCommand = new Map();\r\n\t\tfor (const commandPick of filteredCommandPicks) {\r\n\t\t\tconst existingCommandForLabel = mapLabelToCommand.get(commandPick.label);\r\n\t\t\tif (existingCommandForLabel) {\r\n\t\t\t\tcommandPick.description = commandPick.commandId;\r\n\t\t\t\texistingCommandForLabel.description = existingCommandForLabel.commandId;\r\n\t\t\t} else {\r\n\t\t\t\tmapLabelToCommand.set(commandPick.label, commandPick);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Sort by MRU order and fallback to name otherwise\r\n\t\tfilteredCommandPicks.sort((commandPickA, commandPickB) => {\r\n\t\t\tconst commandACounter = this.commandsHistory.peek(commandPickA.commandId);\r\n\t\t\tconst commandBCounter = this.commandsHistory.peek(commandPickB.commandId);\r\n\r\n\t\t\tif (commandACounter && commandBCounter) {\r\n\t\t\t\treturn commandACounter > commandBCounter ? -1 : 1; // use more recently used command before older\r\n\t\t\t}\r\n\r\n\t\t\tif (commandACounter) {\r\n\t\t\t\treturn -1; // first command was used, so it wins over the non used one\r\n\t\t\t}\r\n\r\n\t\t\tif (commandBCounter) {\r\n\t\t\t\treturn 1; // other command was used so it wins over the command\r\n\t\t\t}\r\n\r\n\t\t\t// both commands were never used, so we sort by name\r\n\t\t\treturn commandPickA.label.localeCompare(commandPickB.label);\r\n\t\t});\r\n\r\n\t\tconst commandPicks: Array = [];\r\n\r\n\t\tlet addSeparator = false;\r\n\t\tfor (let i = 0; i < filteredCommandPicks.length; i++) {\r\n\t\t\tconst commandPick = filteredCommandPicks[i];\r\n\t\t\tconst keybinding = this.keybindingService.lookupKeybinding(commandPick.commandId);\r\n\t\t\tconst ariaLabel = keybinding ?\r\n\t\t\t\tlocalize('commandPickAriaLabelWithKeybinding', \"{0}, {1}\", commandPick.label, keybinding.getAriaLabel()) :\r\n\t\t\t\tcommandPick.label;\r\n\r\n\t\t\t// Separator: recently used\r\n\t\t\tif (i === 0 && this.commandsHistory.peek(commandPick.commandId)) {\r\n\t\t\t\tcommandPicks.push({ type: 'separator', label: localize('recentlyUsed', \"recently used\") });\r\n\t\t\t\taddSeparator = true;\r\n\t\t\t}\r\n\r\n\t\t\t// Separator: other commands\r\n\t\t\tif (i !== 0 && addSeparator && !this.commandsHistory.peek(commandPick.commandId)) {\r\n\t\t\t\tcommandPicks.push({ type: 'separator', label: localize('morecCommands', \"other commands\") });\r\n\t\t\t\taddSeparator = false; // only once\r\n\t\t\t}\r\n\r\n\t\t\t// Command\r\n\t\t\tcommandPicks.push({\r\n\t\t\t\t...commandPick,\r\n\t\t\t\tariaLabel,\r\n\t\t\t\tdetail: this.options.showAlias && commandPick.commandAlias !== commandPick.label ? commandPick.commandAlias : undefined,\r\n\t\t\t\tkeybinding,\r\n\t\t\t\taccept: async () => {\r\n\r\n\t\t\t\t\t// Add to history\r\n\t\t\t\t\tthis.commandsHistory.push(commandPick.commandId);\r\n\r\n\t\t\t\t\t// Telementry\r\n\t\t\t\t\tthis.telemetryService.publicLog2('workbenchActionExecuted', {\r\n\t\t\t\t\t\tid: commandPick.commandId,\r\n\t\t\t\t\t\tfrom: 'quick open'\r\n\t\t\t\t\t});\r\n\r\n\t\t\t\t\t// Run\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tawait this.commandService.executeCommand(commandPick.commandId);\r\n\t\t\t\t\t} catch (error) {\r\n\t\t\t\t\t\tif (!isPromiseCanceledError(error)) {\r\n\t\t\t\t\t\t\tthis.notificationService.error(localize('canNotRun', \"Command '{0}' resulted in an error ({1})\", commandPick.label, toErrorMessage(error)));\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\treturn commandPicks;\r\n\t}\r\n\r\n\t/**\r\n\t * Subclasses to provide the actual command entries.\r\n\t */\r\n\tprotected abstract getCommandPicks(disposables: DisposableStore, token: CancellationToken): Promise>;\r\n}\r\n\r\ninterface ISerializedCommandHistory {\r\n\tusesLRU?: boolean;\r\n\tentries: { key: string; value: number }[];\r\n}\r\n\r\ninterface ICommandsQuickAccessConfiguration {\r\n\tworkbench: {\r\n\t\tcommandPalette: {\r\n\t\t\thistory: number;\r\n\t\t\tpreserveInput: boolean;\r\n\t\t}\r\n\t};\r\n}\r\n\r\nexport class CommandsHistory extends Disposable {\r\n\r\n\tstatic readonly DEFAULT_COMMANDS_HISTORY_LENGTH = 50;\r\n\r\n\tprivate static readonly PREF_KEY_CACHE = 'commandPalette.mru.cache';\r\n\tprivate static readonly PREF_KEY_COUNTER = 'commandPalette.mru.counter';\r\n\r\n\tprivate static cache: LRUCache | undefined;\r\n\tprivate static counter = 1;\r\n\r\n\tprivate configuredCommandsHistoryLength = 0;\r\n\r\n\tconstructor(\r\n\t\t@IStorageService private readonly storageService: IStorageService,\r\n\t\t@IConfigurationService private readonly configurationService: IConfigurationService,\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\tthis.updateConfiguration();\r\n\t\tthis.load();\r\n\r\n\t\tthis.registerListeners();\r\n\t}\r\n\r\n\tprivate registerListeners(): void {\r\n\t\tthis._register(this.configurationService.onDidChangeConfiguration(() => this.updateConfiguration()));\r\n\t}\r\n\r\n\tprivate updateConfiguration(): void {\r\n\t\tthis.configuredCommandsHistoryLength = CommandsHistory.getConfiguredCommandHistoryLength(this.configurationService);\r\n\r\n\t\tif (CommandsHistory.cache && CommandsHistory.cache.limit !== this.configuredCommandsHistoryLength) {\r\n\t\t\tCommandsHistory.cache.limit = this.configuredCommandsHistoryLength;\r\n\r\n\t\t\tCommandsHistory.saveState(this.storageService);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate load(): void {\r\n\t\tconst raw = this.storageService.get(CommandsHistory.PREF_KEY_CACHE, StorageScope.GLOBAL);\r\n\t\tlet serializedCache: ISerializedCommandHistory | undefined;\r\n\t\tif (raw) {\r\n\t\t\ttry {\r\n\t\t\t\tserializedCache = JSON.parse(raw);\r\n\t\t\t} catch (error) {\r\n\t\t\t\t// invalid data\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst cache = CommandsHistory.cache = new LRUCache(this.configuredCommandsHistoryLength, 1);\r\n\t\tif (serializedCache) {\r\n\t\t\tlet entries: { key: string; value: number }[];\r\n\t\t\tif (serializedCache.usesLRU) {\r\n\t\t\t\tentries = serializedCache.entries;\r\n\t\t\t} else {\r\n\t\t\t\tentries = serializedCache.entries.sort((a, b) => a.value - b.value);\r\n\t\t\t}\r\n\t\t\tentries.forEach(entry => cache.set(entry.key, entry.value));\r\n\t\t}\r\n\r\n\t\tCommandsHistory.counter = this.storageService.getNumber(CommandsHistory.PREF_KEY_COUNTER, StorageScope.GLOBAL, CommandsHistory.counter);\r\n\t}\r\n\r\n\tpush(commandId: string): void {\r\n\t\tif (!CommandsHistory.cache) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tCommandsHistory.cache.set(commandId, CommandsHistory.counter++); // set counter to command\r\n\r\n\t\tCommandsHistory.saveState(this.storageService);\r\n\t}\r\n\r\n\tpeek(commandId: string): number | undefined {\r\n\t\treturn CommandsHistory.cache?.peek(commandId);\r\n\t}\r\n\r\n\tstatic saveState(storageService: IStorageService): void {\r\n\t\tif (!CommandsHistory.cache) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst serializedCache: ISerializedCommandHistory = { usesLRU: true, entries: [] };\r\n\t\tCommandsHistory.cache.forEach((value, key) => serializedCache.entries.push({ key, value }));\r\n\r\n\t\tstorageService.store(CommandsHistory.PREF_KEY_CACHE, JSON.stringify(serializedCache), StorageScope.GLOBAL, StorageTarget.USER);\r\n\t\tstorageService.store(CommandsHistory.PREF_KEY_COUNTER, CommandsHistory.counter, StorageScope.GLOBAL, StorageTarget.USER);\r\n\t}\r\n\r\n\tstatic getConfiguredCommandHistoryLength(configurationService: IConfigurationService): number {\r\n\t\tconst config = configurationService.getValue();\r\n\r\n\t\tconst configuredCommandHistoryLength = config.workbench?.commandPalette?.history;\r\n\t\tif (typeof configuredCommandHistoryLength === 'number') {\r\n\t\t\treturn configuredCommandHistoryLength;\r\n\t\t}\r\n\r\n\t\treturn CommandsHistory.DEFAULT_COMMANDS_HISTORY_LENGTH;\r\n\t}\r\n}\r\n\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { AbstractCommandsQuickAccessProvider, ICommandQuickPick, ICommandsQuickAccessOptions } from 'vs/platform/quickinput/browser/commandsQuickAccess';\r\nimport { IEditor } from 'vs/editor/common/editorCommon';\r\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\r\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\r\nimport { INotificationService } from 'vs/platform/notification/common/notification';\r\nimport { ICommandService } from 'vs/platform/commands/common/commands';\r\nimport { stripIcons } from 'vs/base/common/iconLabels';\r\n\r\nexport abstract class AbstractEditorCommandsQuickAccessProvider extends AbstractCommandsQuickAccessProvider {\r\n\r\n\tconstructor(\r\n\t\toptions: ICommandsQuickAccessOptions,\r\n\t\tinstantiationService: IInstantiationService,\r\n\t\tkeybindingService: IKeybindingService,\r\n\t\tcommandService: ICommandService,\r\n\t\ttelemetryService: ITelemetryService,\r\n\t\tnotificationService: INotificationService\r\n\t) {\r\n\t\tsuper(options, instantiationService, keybindingService, commandService, telemetryService, notificationService);\r\n\t}\r\n\r\n\t/**\r\n\t * Subclasses to provide the current active editor control.\r\n\t */\r\n\tprotected abstract activeTextEditorControl: IEditor | undefined;\r\n\r\n\tprotected getCodeEditorCommandPicks(): ICommandQuickPick[] {\r\n\t\tconst activeTextEditorControl = this.activeTextEditorControl;\r\n\t\tif (!activeTextEditorControl) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tconst editorCommandPicks: ICommandQuickPick[] = [];\r\n\t\tfor (const editorAction of activeTextEditorControl.getSupportedActions()) {\r\n\t\t\teditorCommandPicks.push({\r\n\t\t\t\tcommandId: editorAction.id,\r\n\t\t\t\tcommandAlias: editorAction.alias,\r\n\t\t\t\tlabel: stripIcons(editorAction.label) || editorAction.id,\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\treturn editorCommandPicks;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as platform from 'vs/platform/registry/common/platform';\r\nimport { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema';\r\nimport { Color, RGBA } from 'vs/base/common/color';\r\nimport { IColorTheme } from 'vs/platform/theme/common/themeService';\r\nimport { Event, Emitter } from 'vs/base/common/event';\r\nimport * as nls from 'vs/nls';\r\nimport { Extensions as JSONExtensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';\r\nimport { RunOnceScheduler } from 'vs/base/common/async';\r\n\r\n// ------ API types\r\n\r\nexport type ColorIdentifier = string;\r\n\r\nexport interface ColorContribution {\r\n\treadonly id: ColorIdentifier;\r\n\treadonly description: string;\r\n\treadonly defaults: ColorDefaults | null;\r\n\treadonly needsTransparency: boolean;\r\n\treadonly deprecationMessage: string | undefined;\r\n}\r\n\r\n\r\nexport interface ColorFunction {\r\n\t(theme: IColorTheme): Color | undefined;\r\n}\r\n\r\nexport interface ColorDefaults {\r\n\tlight: ColorValue | null;\r\n\tdark: ColorValue | null;\r\n\thc: ColorValue | null;\r\n}\r\n\r\n/**\r\n * A Color Value is either a color literal, a refence to other color or a derived color\r\n */\r\nexport type ColorValue = Color | string | ColorIdentifier | ColorFunction;\r\n\r\n// color registry\r\nexport const Extensions = {\r\n\tColorContribution: 'base.contributions.colors'\r\n};\r\n\r\nexport interface IColorRegistry {\r\n\r\n\t/**\r\n\t * Gets the default color of the given id\r\n\t */\r\n\tresolveDefaultColor(id: ColorIdentifier, theme: IColorTheme): Color | undefined;\r\n\r\n}\r\n\r\nclass ColorRegistry implements IColorRegistry {\r\n\r\n\tprivate readonly _onDidChangeSchema = new Emitter();\r\n\treadonly onDidChangeSchema: Event = this._onDidChangeSchema.event;\r\n\r\n\tprivate colorsById: { [key: string]: ColorContribution };\r\n\tprivate colorSchema: IJSONSchema & { properties: IJSONSchemaMap } = { type: 'object', properties: {} };\r\n\tprivate colorReferenceSchema: IJSONSchema & { enum: string[], enumDescriptions: string[] } = { type: 'string', enum: [], enumDescriptions: [] };\r\n\r\n\tconstructor() {\r\n\t\tthis.colorsById = {};\r\n\t}\r\n\r\n\tpublic registerColor(id: string, defaults: ColorDefaults | null, description: string, needsTransparency = false, deprecationMessage?: string): ColorIdentifier {\r\n\t\tlet colorContribution: ColorContribution = { id, description, defaults, needsTransparency, deprecationMessage };\r\n\t\tthis.colorsById[id] = colorContribution;\r\n\t\tlet propertySchema: IJSONSchema = { type: 'string', description, format: 'color-hex', defaultSnippets: [{ body: '${1:#ff0000}' }] };\r\n\t\tif (deprecationMessage) {\r\n\t\t\tpropertySchema.deprecationMessage = deprecationMessage;\r\n\t\t}\r\n\t\tthis.colorSchema.properties[id] = propertySchema;\r\n\t\tthis.colorReferenceSchema.enum.push(id);\r\n\t\tthis.colorReferenceSchema.enumDescriptions.push(description);\r\n\r\n\t\tthis._onDidChangeSchema.fire();\r\n\t\treturn id;\r\n\t}\r\n\r\n\tpublic resolveDefaultColor(id: ColorIdentifier, theme: IColorTheme): Color | undefined {\r\n\t\tconst colorDesc = this.colorsById[id];\r\n\t\tif (colorDesc && colorDesc.defaults) {\r\n\t\t\tconst colorValue = colorDesc.defaults[theme.type];\r\n\t\t\treturn resolveColorValue(colorValue, theme);\r\n\t\t}\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tpublic getColorSchema(): IJSONSchema {\r\n\t\treturn this.colorSchema;\r\n\t}\r\n\r\n\tpublic toString() {\r\n\t\tlet sorter = (a: string, b: string) => {\r\n\t\t\tlet cat1 = a.indexOf('.') === -1 ? 0 : 1;\r\n\t\t\tlet cat2 = b.indexOf('.') === -1 ? 0 : 1;\r\n\t\t\tif (cat1 !== cat2) {\r\n\t\t\t\treturn cat1 - cat2;\r\n\t\t\t}\r\n\t\t\treturn a.localeCompare(b);\r\n\t\t};\r\n\r\n\t\treturn Object.keys(this.colorsById).sort(sorter).map(k => `- \\`${k}\\`: ${this.colorsById[k].description}`).join('\\n');\r\n\t}\r\n\r\n}\r\n\r\nconst colorRegistry = new ColorRegistry();\r\nplatform.Registry.add(Extensions.ColorContribution, colorRegistry);\r\n\r\nexport function registerColor(id: string, defaults: ColorDefaults | null, description: string, needsTransparency?: boolean, deprecationMessage?: string): ColorIdentifier {\r\n\treturn colorRegistry.registerColor(id, defaults, description, needsTransparency, deprecationMessage);\r\n}\r\n\r\n// ----- base colors\r\n\r\nexport const foreground = registerColor('foreground', { dark: '#CCCCCC', light: '#616161', hc: '#FFFFFF' }, nls.localize('foreground', \"Overall foreground color. This color is only used if not overridden by a component.\"));\r\nexport const errorForeground = registerColor('errorForeground', { dark: '#F48771', light: '#A1260D', hc: '#F48771' }, nls.localize('errorForeground', \"Overall foreground color for error messages. This color is only used if not overridden by a component.\"));\r\nexport const iconForeground = registerColor('icon.foreground', { dark: '#C5C5C5', light: '#424242', hc: '#FFFFFF' }, nls.localize('iconForeground', \"The default color for icons in the workbench.\"));\r\n\r\nexport const focusBorder = registerColor('focusBorder', { dark: '#007FD4', light: '#0090F1', hc: '#F38518' }, nls.localize('focusBorder', \"Overall border color for focused elements. This color is only used if not overridden by a component.\"));\r\n\r\nexport const contrastBorder = registerColor('contrastBorder', { light: null, dark: null, hc: '#6FC3DF' }, nls.localize('contrastBorder', \"An extra border around elements to separate them from others for greater contrast.\"));\r\nexport const activeContrastBorder = registerColor('contrastActiveBorder', { light: null, dark: null, hc: focusBorder }, nls.localize('activeContrastBorder', \"An extra border around active elements to separate them from others for greater contrast.\"));\r\nexport const textLinkForeground = registerColor('textLink.foreground', { light: '#006AB1', dark: '#3794FF', hc: '#3794FF' }, nls.localize('textLinkForeground', \"Foreground color for links in text.\"));\r\nexport const textCodeBlockBackground = registerColor('textCodeBlock.background', { light: '#dcdcdc66', dark: '#0a0a0a66', hc: Color.black }, nls.localize('textCodeBlockBackground', \"Background color for code blocks in text.\"));\r\n\r\n// ----- widgets\r\nexport const widgetShadow = registerColor('widget.shadow', { dark: transparent(Color.black, .36), light: transparent(Color.black, .16), hc: null }, nls.localize('widgetShadow', 'Shadow color of widgets such as find/replace inside the editor.'));\r\n\r\nexport const inputBackground = registerColor('input.background', { dark: '#3C3C3C', light: Color.white, hc: Color.black }, nls.localize('inputBoxBackground', \"Input box background.\"));\r\nexport const inputForeground = registerColor('input.foreground', { dark: foreground, light: foreground, hc: foreground }, nls.localize('inputBoxForeground', \"Input box foreground.\"));\r\nexport const inputBorder = registerColor('input.border', { dark: null, light: null, hc: contrastBorder }, nls.localize('inputBoxBorder', \"Input box border.\"));\r\nexport const inputActiveOptionBorder = registerColor('inputOption.activeBorder', { dark: '#007ACC00', light: '#007ACC00', hc: contrastBorder }, nls.localize('inputBoxActiveOptionBorder', \"Border color of activated options in input fields.\"));\r\nexport const inputActiveOptionBackground = registerColor('inputOption.activeBackground', { dark: transparent(focusBorder, 0.4), light: transparent(focusBorder, 0.2), hc: Color.transparent }, nls.localize('inputOption.activeBackground', \"Background color of activated options in input fields.\"));\r\nexport const inputActiveOptionForeground = registerColor('inputOption.activeForeground', { dark: Color.white, light: Color.black, hc: null }, nls.localize('inputOption.activeForeground', \"Foreground color of activated options in input fields.\"));\r\n\r\nexport const inputValidationInfoBackground = registerColor('inputValidation.infoBackground', { dark: '#063B49', light: '#D6ECF2', hc: Color.black }, nls.localize('inputValidationInfoBackground', \"Input validation background color for information severity.\"));\r\nexport const inputValidationInfoForeground = registerColor('inputValidation.infoForeground', { dark: null, light: null, hc: null }, nls.localize('inputValidationInfoForeground', \"Input validation foreground color for information severity.\"));\r\nexport const inputValidationInfoBorder = registerColor('inputValidation.infoBorder', { dark: '#007acc', light: '#007acc', hc: contrastBorder }, nls.localize('inputValidationInfoBorder', \"Input validation border color for information severity.\"));\r\nexport const inputValidationWarningBackground = registerColor('inputValidation.warningBackground', { dark: '#352A05', light: '#F6F5D2', hc: Color.black }, nls.localize('inputValidationWarningBackground', \"Input validation background color for warning severity.\"));\r\nexport const inputValidationWarningForeground = registerColor('inputValidation.warningForeground', { dark: null, light: null, hc: null }, nls.localize('inputValidationWarningForeground', \"Input validation foreground color for warning severity.\"));\r\nexport const inputValidationWarningBorder = registerColor('inputValidation.warningBorder', { dark: '#B89500', light: '#B89500', hc: contrastBorder }, nls.localize('inputValidationWarningBorder', \"Input validation border color for warning severity.\"));\r\nexport const inputValidationErrorBackground = registerColor('inputValidation.errorBackground', { dark: '#5A1D1D', light: '#F2DEDE', hc: Color.black }, nls.localize('inputValidationErrorBackground', \"Input validation background color for error severity.\"));\r\nexport const inputValidationErrorForeground = registerColor('inputValidation.errorForeground', { dark: null, light: null, hc: null }, nls.localize('inputValidationErrorForeground', \"Input validation foreground color for error severity.\"));\r\nexport const inputValidationErrorBorder = registerColor('inputValidation.errorBorder', { dark: '#BE1100', light: '#BE1100', hc: contrastBorder }, nls.localize('inputValidationErrorBorder', \"Input validation border color for error severity.\"));\r\n\r\nexport const selectBackground = registerColor('dropdown.background', { dark: '#3C3C3C', light: Color.white, hc: Color.black }, nls.localize('dropdownBackground', \"Dropdown background.\"));\r\nexport const selectForeground = registerColor('dropdown.foreground', { dark: '#F0F0F0', light: null, hc: Color.white }, nls.localize('dropdownForeground', \"Dropdown foreground.\"));\r\n\r\nexport const buttonForeground = registerColor('button.foreground', { dark: Color.white, light: Color.white, hc: Color.white }, nls.localize('buttonForeground', \"Button foreground color.\"));\r\nexport const buttonBackground = registerColor('button.background', { dark: '#0E639C', light: '#007ACC', hc: null }, nls.localize('buttonBackground', \"Button background color.\"));\r\nexport const buttonHoverBackground = registerColor('button.hoverBackground', { dark: lighten(buttonBackground, 0.2), light: darken(buttonBackground, 0.2), hc: null }, nls.localize('buttonHoverBackground', \"Button background color when hovering.\"));\r\n\r\nexport const badgeBackground = registerColor('badge.background', { dark: '#4D4D4D', light: '#C4C4C4', hc: Color.black }, nls.localize('badgeBackground', \"Badge background color. Badges are small information labels, e.g. for search results count.\"));\r\nexport const badgeForeground = registerColor('badge.foreground', { dark: Color.white, light: '#333', hc: Color.white }, nls.localize('badgeForeground', \"Badge foreground color. Badges are small information labels, e.g. for search results count.\"));\r\n\r\nexport const scrollbarShadow = registerColor('scrollbar.shadow', { dark: '#000000', light: '#DDDDDD', hc: null }, nls.localize('scrollbarShadow', \"Scrollbar shadow to indicate that the view is scrolled.\"));\r\nexport const scrollbarSliderBackground = registerColor('scrollbarSlider.background', { dark: Color.fromHex('#797979').transparent(0.4), light: Color.fromHex('#646464').transparent(0.4), hc: transparent(contrastBorder, 0.6) }, nls.localize('scrollbarSliderBackground', \"Scrollbar slider background color.\"));\r\nexport const scrollbarSliderHoverBackground = registerColor('scrollbarSlider.hoverBackground', { dark: Color.fromHex('#646464').transparent(0.7), light: Color.fromHex('#646464').transparent(0.7), hc: transparent(contrastBorder, 0.8) }, nls.localize('scrollbarSliderHoverBackground', \"Scrollbar slider background color when hovering.\"));\r\nexport const scrollbarSliderActiveBackground = registerColor('scrollbarSlider.activeBackground', { dark: Color.fromHex('#BFBFBF').transparent(0.4), light: Color.fromHex('#000000').transparent(0.6), hc: contrastBorder }, nls.localize('scrollbarSliderActiveBackground', \"Scrollbar slider background color when clicked on.\"));\r\n\r\nexport const progressBarBackground = registerColor('progressBar.background', { dark: Color.fromHex('#0E70C0'), light: Color.fromHex('#0E70C0'), hc: contrastBorder }, nls.localize('progressBarBackground', \"Background color of the progress bar that can show for long running operations.\"));\r\n\r\nexport const editorErrorBackground = registerColor('editorError.background', { dark: null, light: null, hc: null }, nls.localize('editorError.background', 'Background color of error text in the editor. The color must not be opaque so as not to hide underlying decorations.'), true);\r\nexport const editorErrorForeground = registerColor('editorError.foreground', { dark: '#F48771', light: '#E51400', hc: null }, nls.localize('editorError.foreground', 'Foreground color of error squigglies in the editor.'));\r\nexport const editorErrorBorder = registerColor('editorError.border', { dark: null, light: null, hc: Color.fromHex('#E47777').transparent(0.8) }, nls.localize('errorBorder', 'Border color of error boxes in the editor.'));\r\n\r\nexport const editorWarningBackground = registerColor('editorWarning.background', { dark: null, light: null, hc: null }, nls.localize('editorWarning.background', 'Background color of warning text in the editor. The color must not be opaque so as not to hide underlying decorations.'), true);\r\nexport const editorWarningForeground = registerColor('editorWarning.foreground', { dark: '#CCA700', light: '#E9A700', hc: null }, nls.localize('editorWarning.foreground', 'Foreground color of warning squigglies in the editor.'));\r\nexport const editorWarningBorder = registerColor('editorWarning.border', { dark: null, light: null, hc: Color.fromHex('#FFCC00').transparent(0.8) }, nls.localize('warningBorder', 'Border color of warning boxes in the editor.'));\r\n\r\nexport const editorInfoBackground = registerColor('editorInfo.background', { dark: null, light: null, hc: null }, nls.localize('editorInfo.background', 'Background color of info text in the editor. The color must not be opaque so as not to hide underlying decorations.'), true);\r\nexport const editorInfoForeground = registerColor('editorInfo.foreground', { dark: '#75BEFF', light: '#75BEFF', hc: null }, nls.localize('editorInfo.foreground', 'Foreground color of info squigglies in the editor.'));\r\nexport const editorInfoBorder = registerColor('editorInfo.border', { dark: null, light: null, hc: Color.fromHex('#75BEFF').transparent(0.8) }, nls.localize('infoBorder', 'Border color of info boxes in the editor.'));\r\n\r\nexport const editorHintForeground = registerColor('editorHint.foreground', { dark: Color.fromHex('#eeeeee').transparent(0.7), light: '#6c6c6c', hc: null }, nls.localize('editorHint.foreground', 'Foreground color of hint squigglies in the editor.'));\r\nexport const editorHintBorder = registerColor('editorHint.border', { dark: null, light: null, hc: Color.fromHex('#eeeeee').transparent(0.8) }, nls.localize('hintBorder', 'Border color of hint boxes in the editor.'));\r\n\r\n/**\r\n * Editor background color.\r\n * Because of bug https://monacotools.visualstudio.com/DefaultCollection/Monaco/_workitems/edit/13254\r\n * we are *not* using the color white (or #ffffff, rgba(255,255,255)) but something very close to white.\r\n */\r\nexport const editorBackground = registerColor('editor.background', { light: '#fffffe', dark: '#1E1E1E', hc: Color.black }, nls.localize('editorBackground', \"Editor background color.\"));\r\n\r\n/**\r\n * Editor foreground color.\r\n */\r\nexport const editorForeground = registerColor('editor.foreground', { light: '#333333', dark: '#BBBBBB', hc: Color.white }, nls.localize('editorForeground', \"Editor default foreground color.\"));\r\n\r\n/**\r\n * Editor widgets\r\n */\r\nexport const editorWidgetBackground = registerColor('editorWidget.background', { dark: '#252526', light: '#F3F3F3', hc: '#0C141F' }, nls.localize('editorWidgetBackground', 'Background color of editor widgets, such as find/replace.'));\r\nexport const editorWidgetForeground = registerColor('editorWidget.foreground', { dark: foreground, light: foreground, hc: foreground }, nls.localize('editorWidgetForeground', 'Foreground color of editor widgets, such as find/replace.'));\r\n\r\nexport const editorWidgetBorder = registerColor('editorWidget.border', { dark: '#454545', light: '#C8C8C8', hc: contrastBorder }, nls.localize('editorWidgetBorder', 'Border color of editor widgets. The color is only used if the widget chooses to have a border and if the color is not overridden by a widget.'));\r\n\r\nexport const editorWidgetResizeBorder = registerColor('editorWidget.resizeBorder', { light: null, dark: null, hc: null }, nls.localize('editorWidgetResizeBorder', \"Border color of the resize bar of editor widgets. The color is only used if the widget chooses to have a resize border and if the color is not overridden by a widget.\"));\r\n\r\n/**\r\n * Quick pick widget\r\n */\r\nexport const quickInputBackground = registerColor('quickInput.background', { dark: editorWidgetBackground, light: editorWidgetBackground, hc: editorWidgetBackground }, nls.localize('pickerBackground', \"Quick picker background color. The quick picker widget is the container for pickers like the command palette.\"));\r\nexport const quickInputForeground = registerColor('quickInput.foreground', { dark: editorWidgetForeground, light: editorWidgetForeground, hc: editorWidgetForeground }, nls.localize('pickerForeground', \"Quick picker foreground color. The quick picker widget is the container for pickers like the command palette.\"));\r\nexport const quickInputTitleBackground = registerColor('quickInputTitle.background', { dark: new Color(new RGBA(255, 255, 255, 0.105)), light: new Color(new RGBA(0, 0, 0, 0.06)), hc: '#000000' }, nls.localize('pickerTitleBackground', \"Quick picker title background color. The quick picker widget is the container for pickers like the command palette.\"));\r\nexport const pickerGroupForeground = registerColor('pickerGroup.foreground', { dark: '#3794FF', light: '#0066BF', hc: Color.white }, nls.localize('pickerGroupForeground', \"Quick picker color for grouping labels.\"));\r\nexport const pickerGroupBorder = registerColor('pickerGroup.border', { dark: '#3F3F46', light: '#CCCEDB', hc: Color.white }, nls.localize('pickerGroupBorder', \"Quick picker color for grouping borders.\"));\r\n\r\n/**\r\n * Editor selection colors.\r\n */\r\nexport const editorSelectionBackground = registerColor('editor.selectionBackground', { light: '#ADD6FF', dark: '#264F78', hc: '#f3f518' }, nls.localize('editorSelectionBackground', \"Color of the editor selection.\"));\r\nexport const editorSelectionForeground = registerColor('editor.selectionForeground', { light: null, dark: null, hc: '#000000' }, nls.localize('editorSelectionForeground', \"Color of the selected text for high contrast.\"));\r\nexport const editorInactiveSelection = registerColor('editor.inactiveSelectionBackground', { light: transparent(editorSelectionBackground, 0.5), dark: transparent(editorSelectionBackground, 0.5), hc: transparent(editorSelectionBackground, 0.5) }, nls.localize('editorInactiveSelection', \"Color of the selection in an inactive editor. The color must not be opaque so as not to hide underlying decorations.\"), true);\r\nexport const editorSelectionHighlight = registerColor('editor.selectionHighlightBackground', { light: lessProminent(editorSelectionBackground, editorBackground, 0.3, 0.6), dark: lessProminent(editorSelectionBackground, editorBackground, 0.3, 0.6), hc: null }, nls.localize('editorSelectionHighlight', 'Color for regions with the same content as the selection. The color must not be opaque so as not to hide underlying decorations.'), true);\r\nexport const editorSelectionHighlightBorder = registerColor('editor.selectionHighlightBorder', { light: null, dark: null, hc: activeContrastBorder }, nls.localize('editorSelectionHighlightBorder', \"Border color for regions with the same content as the selection.\"));\r\n\r\n\r\n/**\r\n * Editor find match colors.\r\n */\r\nexport const editorFindMatch = registerColor('editor.findMatchBackground', { light: '#A8AC94', dark: '#515C6A', hc: null }, nls.localize('editorFindMatch', \"Color of the current search match.\"));\r\nexport const editorFindMatchHighlight = registerColor('editor.findMatchHighlightBackground', { light: '#EA5C0055', dark: '#EA5C0055', hc: null }, nls.localize('findMatchHighlight', \"Color of the other search matches. The color must not be opaque so as not to hide underlying decorations.\"), true);\r\nexport const editorFindRangeHighlight = registerColor('editor.findRangeHighlightBackground', { dark: '#3a3d4166', light: '#b4b4b44d', hc: null }, nls.localize('findRangeHighlight', \"Color of the range limiting the search. The color must not be opaque so as not to hide underlying decorations.\"), true);\r\nexport const editorFindMatchBorder = registerColor('editor.findMatchBorder', { light: null, dark: null, hc: activeContrastBorder }, nls.localize('editorFindMatchBorder', \"Border color of the current search match.\"));\r\nexport const editorFindMatchHighlightBorder = registerColor('editor.findMatchHighlightBorder', { light: null, dark: null, hc: activeContrastBorder }, nls.localize('findMatchHighlightBorder', \"Border color of the other search matches.\"));\r\nexport const editorFindRangeHighlightBorder = registerColor('editor.findRangeHighlightBorder', { dark: null, light: null, hc: transparent(activeContrastBorder, 0.4) }, nls.localize('findRangeHighlightBorder', \"Border color of the range limiting the search. The color must not be opaque so as not to hide underlying decorations.\"), true);\r\n\r\n/**\r\n * Editor hover\r\n */\r\nexport const editorHoverHighlight = registerColor('editor.hoverHighlightBackground', { light: '#ADD6FF26', dark: '#264f7840', hc: '#ADD6FF26' }, nls.localize('hoverHighlight', 'Highlight below the word for which a hover is shown. The color must not be opaque so as not to hide underlying decorations.'), true);\r\nexport const editorHoverBackground = registerColor('editorHoverWidget.background', { light: editorWidgetBackground, dark: editorWidgetBackground, hc: editorWidgetBackground }, nls.localize('hoverBackground', 'Background color of the editor hover.'));\r\nexport const editorHoverForeground = registerColor('editorHoverWidget.foreground', { light: editorWidgetForeground, dark: editorWidgetForeground, hc: editorWidgetForeground }, nls.localize('hoverForeground', 'Foreground color of the editor hover.'));\r\nexport const editorHoverBorder = registerColor('editorHoverWidget.border', { light: editorWidgetBorder, dark: editorWidgetBorder, hc: editorWidgetBorder }, nls.localize('hoverBorder', 'Border color of the editor hover.'));\r\nexport const editorHoverStatusBarBackground = registerColor('editorHoverWidget.statusBarBackground', { dark: lighten(editorHoverBackground, 0.2), light: darken(editorHoverBackground, 0.05), hc: editorWidgetBackground }, nls.localize('statusBarBackground', \"Background color of the editor hover status bar.\"));\r\n/**\r\n * Editor link colors\r\n */\r\nexport const editorActiveLinkForeground = registerColor('editorLink.activeForeground', { dark: '#4E94CE', light: Color.blue, hc: Color.cyan }, nls.localize('activeLinkForeground', 'Color of active links.'));\r\n\r\n/**\r\n * Inline hints\r\n */\r\nexport const editorInlineHintForeground = registerColor('editorInlineHint.foreground', { dark: editorWidgetBackground, light: editorWidgetForeground, hc: editorWidgetBackground }, nls.localize('editorInlineHintForeground', 'Foreground color of inline hints'));\r\nexport const editorInlineHintBackground = registerColor('editorInlineHint.background', { dark: editorWidgetForeground, light: editorWidgetBackground, hc: editorWidgetForeground }, nls.localize('editorInlineHintBackground', 'Background color of inline hints'));\r\n\r\n/**\r\n * Editor lighbulb icon colors\r\n */\r\nexport const editorLightBulbForeground = registerColor('editorLightBulb.foreground', { dark: '#FFCC00', light: '#DDB100', hc: '#FFCC00' }, nls.localize('editorLightBulbForeground', \"The color used for the lightbulb actions icon.\"));\r\nexport const editorLightBulbAutoFixForeground = registerColor('editorLightBulbAutoFix.foreground', { dark: '#75BEFF', light: '#007ACC', hc: '#75BEFF' }, nls.localize('editorLightBulbAutoFixForeground', \"The color used for the lightbulb auto fix actions icon.\"));\r\n\r\n/**\r\n * Diff Editor Colors\r\n */\r\nexport const defaultInsertColor = new Color(new RGBA(155, 185, 85, 0.2));\r\nexport const defaultRemoveColor = new Color(new RGBA(255, 0, 0, 0.2));\r\n\r\nexport const diffInserted = registerColor('diffEditor.insertedTextBackground', { dark: defaultInsertColor, light: defaultInsertColor, hc: null }, nls.localize('diffEditorInserted', 'Background color for text that got inserted. The color must not be opaque so as not to hide underlying decorations.'), true);\r\nexport const diffRemoved = registerColor('diffEditor.removedTextBackground', { dark: defaultRemoveColor, light: defaultRemoveColor, hc: null }, nls.localize('diffEditorRemoved', 'Background color for text that got removed. The color must not be opaque so as not to hide underlying decorations.'), true);\r\n\r\nexport const diffInsertedOutline = registerColor('diffEditor.insertedTextBorder', { dark: null, light: null, hc: '#33ff2eff' }, nls.localize('diffEditorInsertedOutline', 'Outline color for the text that got inserted.'));\r\nexport const diffRemovedOutline = registerColor('diffEditor.removedTextBorder', { dark: null, light: null, hc: '#FF008F' }, nls.localize('diffEditorRemovedOutline', 'Outline color for text that got removed.'));\r\n\r\nexport const diffBorder = registerColor('diffEditor.border', { dark: null, light: null, hc: contrastBorder }, nls.localize('diffEditorBorder', 'Border color between the two text editors.'));\r\nexport const diffDiagonalFill = registerColor('diffEditor.diagonalFill', { dark: '#cccccc33', light: '#22222233', hc: null }, nls.localize('diffDiagonalFill', \"Color of the diff editor's diagonal fill. The diagonal fill is used in side-by-side diff views.\"));\r\n\r\n/**\r\n * List and tree colors\r\n */\r\nexport const listFocusBackground = registerColor('list.focusBackground', { dark: '#062F4A', light: '#D6EBFF', hc: null }, nls.localize('listFocusBackground', \"List/Tree background color for the focused item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.\"));\r\nexport const listFocusForeground = registerColor('list.focusForeground', { dark: null, light: null, hc: null }, nls.localize('listFocusForeground', \"List/Tree foreground color for the focused item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.\"));\r\nexport const listActiveSelectionBackground = registerColor('list.activeSelectionBackground', { dark: '#094771', light: '#0060C0', hc: null }, nls.localize('listActiveSelectionBackground', \"List/Tree background color for the selected item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.\"));\r\nexport const listActiveSelectionForeground = registerColor('list.activeSelectionForeground', { dark: Color.white, light: Color.white, hc: null }, nls.localize('listActiveSelectionForeground', \"List/Tree foreground color for the selected item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.\"));\r\nexport const listInactiveSelectionBackground = registerColor('list.inactiveSelectionBackground', { dark: '#37373D', light: '#E4E6F1', hc: null }, nls.localize('listInactiveSelectionBackground', \"List/Tree background color for the selected item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.\"));\r\nexport const listInactiveSelectionForeground = registerColor('list.inactiveSelectionForeground', { dark: null, light: null, hc: null }, nls.localize('listInactiveSelectionForeground', \"List/Tree foreground color for the selected item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.\"));\r\nexport const listInactiveFocusBackground = registerColor('list.inactiveFocusBackground', { dark: null, light: null, hc: null }, nls.localize('listInactiveFocusBackground', \"List/Tree background color for the focused item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.\"));\r\nexport const listHoverBackground = registerColor('list.hoverBackground', { dark: '#2A2D2E', light: '#F0F0F0', hc: null }, nls.localize('listHoverBackground', \"List/Tree background when hovering over items using the mouse.\"));\r\nexport const listHoverForeground = registerColor('list.hoverForeground', { dark: null, light: null, hc: null }, nls.localize('listHoverForeground', \"List/Tree foreground when hovering over items using the mouse.\"));\r\nexport const listDropBackground = registerColor('list.dropBackground', { dark: listFocusBackground, light: listFocusBackground, hc: null }, nls.localize('listDropBackground', \"List/Tree drag and drop background when moving items around using the mouse.\"));\r\nexport const listHighlightForeground = registerColor('list.highlightForeground', { dark: '#0097fb', light: '#0066BF', hc: focusBorder }, nls.localize('highlight', 'List/Tree foreground color of the match highlights when searching inside the list/tree.'));\r\nexport const listFilterWidgetBackground = registerColor('listFilterWidget.background', { light: '#efc1ad', dark: '#653723', hc: Color.black }, nls.localize('listFilterWidgetBackground', 'Background color of the type filter widget in lists and trees.'));\r\nexport const listFilterWidgetOutline = registerColor('listFilterWidget.outline', { dark: Color.transparent, light: Color.transparent, hc: '#f38518' }, nls.localize('listFilterWidgetOutline', 'Outline color of the type filter widget in lists and trees.'));\r\nexport const listFilterWidgetNoMatchesOutline = registerColor('listFilterWidget.noMatchesOutline', { dark: '#BE1100', light: '#BE1100', hc: contrastBorder }, nls.localize('listFilterWidgetNoMatchesOutline', 'Outline color of the type filter widget in lists and trees, when there are no matches.'));\r\nexport const treeIndentGuidesStroke = registerColor('tree.indentGuidesStroke', { dark: '#585858', light: '#a9a9a9', hc: '#a9a9a9' }, nls.localize('treeIndentGuidesStroke', \"Tree stroke color for the indentation guides.\"));\r\n\r\n/**\r\n * Menu colors\r\n */\r\nexport const menuBorder = registerColor('menu.border', { dark: null, light: null, hc: contrastBorder }, nls.localize('menuBorder', \"Border color of menus.\"));\r\nexport const menuForeground = registerColor('menu.foreground', { dark: selectForeground, light: foreground, hc: selectForeground }, nls.localize('menuForeground', \"Foreground color of menu items.\"));\r\nexport const menuBackground = registerColor('menu.background', { dark: selectBackground, light: selectBackground, hc: selectBackground }, nls.localize('menuBackground', \"Background color of menu items.\"));\r\nexport const menuSelectionForeground = registerColor('menu.selectionForeground', { dark: listActiveSelectionForeground, light: listActiveSelectionForeground, hc: listActiveSelectionForeground }, nls.localize('menuSelectionForeground', \"Foreground color of the selected menu item in menus.\"));\r\nexport const menuSelectionBackground = registerColor('menu.selectionBackground', { dark: listActiveSelectionBackground, light: listActiveSelectionBackground, hc: listActiveSelectionBackground }, nls.localize('menuSelectionBackground', \"Background color of the selected menu item in menus.\"));\r\nexport const menuSelectionBorder = registerColor('menu.selectionBorder', { dark: null, light: null, hc: activeContrastBorder }, nls.localize('menuSelectionBorder', \"Border color of the selected menu item in menus.\"));\r\nexport const menuSeparatorBackground = registerColor('menu.separatorBackground', { dark: '#BBBBBB', light: '#888888', hc: contrastBorder }, nls.localize('menuSeparatorBackground', \"Color of a separator menu item in menus.\"));\r\n\r\n/**\r\n * Snippet placeholder colors\r\n */\r\nexport const snippetTabstopHighlightBackground = registerColor('editor.snippetTabstopHighlightBackground', { dark: new Color(new RGBA(124, 124, 124, 0.3)), light: new Color(new RGBA(10, 50, 100, 0.2)), hc: new Color(new RGBA(124, 124, 124, 0.3)) }, nls.localize('snippetTabstopHighlightBackground', \"Highlight background color of a snippet tabstop.\"));\r\nexport const snippetTabstopHighlightBorder = registerColor('editor.snippetTabstopHighlightBorder', { dark: null, light: null, hc: null }, nls.localize('snippetTabstopHighlightBorder', \"Highlight border color of a snippet tabstop.\"));\r\nexport const snippetFinalTabstopHighlightBackground = registerColor('editor.snippetFinalTabstopHighlightBackground', { dark: null, light: null, hc: null }, nls.localize('snippetFinalTabstopHighlightBackground', \"Highlight background color of the final tabstop of a snippet.\"));\r\nexport const snippetFinalTabstopHighlightBorder = registerColor('editor.snippetFinalTabstopHighlightBorder', { dark: '#525252', light: new Color(new RGBA(10, 50, 100, 0.5)), hc: '#525252' }, nls.localize('snippetFinalTabstopHighlightBorder', \"Highlight border color of the final tabstop of a snippet.\"));\r\n\r\nexport const overviewRulerFindMatchForeground = registerColor('editorOverviewRuler.findMatchForeground', { dark: '#d186167e', light: '#d186167e', hc: '#AB5A00' }, nls.localize('overviewRulerFindMatchForeground', 'Overview ruler marker color for find matches. The color must not be opaque so as not to hide underlying decorations.'), true);\r\n\r\nexport const overviewRulerSelectionHighlightForeground = registerColor('editorOverviewRuler.selectionHighlightForeground', { dark: '#A0A0A0CC', light: '#A0A0A0CC', hc: '#A0A0A0CC' }, nls.localize('overviewRulerSelectionHighlightForeground', 'Overview ruler marker color for selection highlights. The color must not be opaque so as not to hide underlying decorations.'), true);\r\n\r\nexport const minimapFindMatch = registerColor('minimap.findMatchHighlight', { light: '#d18616', dark: '#d18616', hc: '#AB5A00' }, nls.localize('minimapFindMatchHighlight', 'Minimap marker color for find matches.'), true);\r\nexport const minimapSelection = registerColor('minimap.selectionHighlight', { light: '#ADD6FF', dark: '#264F78', hc: '#ffffff' }, nls.localize('minimapSelectionHighlight', 'Minimap marker color for the editor selection.'), true);\r\nexport const minimapError = registerColor('minimap.errorHighlight', { dark: new Color(new RGBA(255, 18, 18, 0.7)), light: new Color(new RGBA(255, 18, 18, 0.7)), hc: new Color(new RGBA(255, 50, 50, 1)) }, nls.localize('minimapError', 'Minimap marker color for errors.'));\r\nexport const minimapWarning = registerColor('minimap.warningHighlight', { dark: editorWarningForeground, light: editorWarningForeground, hc: editorWarningBorder }, nls.localize('overviewRuleWarning', 'Minimap marker color for warnings.'));\r\nexport const minimapBackground = registerColor('minimap.background', { dark: null, light: null, hc: null }, nls.localize('minimapBackground', \"Minimap background color.\"));\r\n\r\nexport const minimapSliderBackground = registerColor('minimapSlider.background', { light: transparent(scrollbarSliderBackground, 0.5), dark: transparent(scrollbarSliderBackground, 0.5), hc: transparent(scrollbarSliderBackground, 0.5) }, nls.localize('minimapSliderBackground', \"Minimap slider background color.\"));\r\nexport const minimapSliderHoverBackground = registerColor('minimapSlider.hoverBackground', { light: transparent(scrollbarSliderHoverBackground, 0.5), dark: transparent(scrollbarSliderHoverBackground, 0.5), hc: transparent(scrollbarSliderHoverBackground, 0.5) }, nls.localize('minimapSliderHoverBackground', \"Minimap slider background color when hovering.\"));\r\nexport const minimapSliderActiveBackground = registerColor('minimapSlider.activeBackground', { light: transparent(scrollbarSliderActiveBackground, 0.5), dark: transparent(scrollbarSliderActiveBackground, 0.5), hc: transparent(scrollbarSliderActiveBackground, 0.5) }, nls.localize('minimapSliderActiveBackground', \"Minimap slider background color when clicked on.\"));\r\n\r\nexport const problemsErrorIconForeground = registerColor('problemsErrorIcon.foreground', { dark: editorErrorForeground, light: editorErrorForeground, hc: editorErrorForeground }, nls.localize('problemsErrorIconForeground', \"The color used for the problems error icon.\"));\r\nexport const problemsWarningIconForeground = registerColor('problemsWarningIcon.foreground', { dark: editorWarningForeground, light: editorWarningForeground, hc: editorWarningForeground }, nls.localize('problemsWarningIconForeground', \"The color used for the problems warning icon.\"));\r\nexport const problemsInfoIconForeground = registerColor('problemsInfoIcon.foreground', { dark: editorInfoForeground, light: editorInfoForeground, hc: editorInfoForeground }, nls.localize('problemsInfoIconForeground', \"The color used for the problems info icon.\"));\r\n\r\n// ----- color functions\r\n\r\nexport function darken(colorValue: ColorValue, factor: number): ColorFunction {\r\n\treturn (theme) => {\r\n\t\tlet color = resolveColorValue(colorValue, theme);\r\n\t\tif (color) {\r\n\t\t\treturn color.darken(factor);\r\n\t\t}\r\n\t\treturn undefined;\r\n\t};\r\n}\r\n\r\nexport function lighten(colorValue: ColorValue, factor: number): ColorFunction {\r\n\treturn (theme) => {\r\n\t\tlet color = resolveColorValue(colorValue, theme);\r\n\t\tif (color) {\r\n\t\t\treturn color.lighten(factor);\r\n\t\t}\r\n\t\treturn undefined;\r\n\t};\r\n}\r\n\r\nexport function transparent(colorValue: ColorValue, factor: number): ColorFunction {\r\n\treturn (theme) => {\r\n\t\tlet color = resolveColorValue(colorValue, theme);\r\n\t\tif (color) {\r\n\t\t\treturn color.transparent(factor);\r\n\t\t}\r\n\t\treturn undefined;\r\n\t};\r\n}\r\n\r\nexport function oneOf(...colorValues: ColorValue[]): ColorFunction {\r\n\treturn (theme) => {\r\n\t\tfor (let colorValue of colorValues) {\r\n\t\t\tlet color = resolveColorValue(colorValue, theme);\r\n\t\t\tif (color) {\r\n\t\t\t\treturn color;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn undefined;\r\n\t};\r\n}\r\n\r\nfunction lessProminent(colorValue: ColorValue, backgroundColorValue: ColorValue, factor: number, transparency: number): ColorFunction {\r\n\treturn (theme) => {\r\n\t\tlet from = resolveColorValue(colorValue, theme);\r\n\t\tif (from) {\r\n\t\t\tlet backgroundColor = resolveColorValue(backgroundColorValue, theme);\r\n\t\t\tif (backgroundColor) {\r\n\t\t\t\tif (from.isDarkerThan(backgroundColor)) {\r\n\t\t\t\t\treturn Color.getLighterColor(from, backgroundColor, factor).transparent(transparency);\r\n\t\t\t\t}\r\n\t\t\t\treturn Color.getDarkerColor(from, backgroundColor, factor).transparent(transparency);\r\n\t\t\t}\r\n\t\t\treturn from.transparent(factor * transparency);\r\n\t\t}\r\n\t\treturn undefined;\r\n\t};\r\n}\r\n\r\n// ----- implementation\r\n\r\n/**\r\n * @param colorValue Resolve a color value in the context of a theme\r\n */\r\nexport function resolveColorValue(colorValue: ColorValue | null, theme: IColorTheme): Color | undefined {\r\n\tif (colorValue === null) {\r\n\t\treturn undefined;\r\n\t} else if (typeof colorValue === 'string') {\r\n\t\tif (colorValue[0] === '#') {\r\n\t\t\treturn Color.fromHex(colorValue);\r\n\t\t}\r\n\t\treturn theme.getColor(colorValue);\r\n\t} else if (colorValue instanceof Color) {\r\n\t\treturn colorValue;\r\n\t} else if (typeof colorValue === 'function') {\r\n\t\treturn colorValue(theme);\r\n\t}\r\n\treturn undefined;\r\n}\r\n\r\nexport const workbenchColorsSchemaId = 'vscode://schemas/workbench-colors';\r\n\r\nlet schemaRegistry = platform.Registry.as(JSONExtensions.JSONContribution);\r\nschemaRegistry.registerSchema(workbenchColorsSchemaId, colorRegistry.getColorSchema());\r\n\r\nconst delayer = new RunOnceScheduler(() => schemaRegistry.notifySchemaChanged(workbenchColorsSchemaId), 200);\r\ncolorRegistry.onDidChangeSchema(() => {\r\n\tif (!delayer.isScheduled()) {\r\n\t\tdelayer.schedule();\r\n\t}\r\n});\r\n\r\n// setTimeout(_ => console.log(colorRegistry.toString()), 5000);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService';\r\nimport { ColorIdentifier, contrastBorder, listFocusBackground, listFocusForeground, listActiveSelectionBackground, listActiveSelectionForeground, listInactiveSelectionForeground, listInactiveSelectionBackground, listInactiveFocusBackground, listHoverBackground, listHoverForeground, listDropBackground, widgetShadow, activeContrastBorder, badgeBackground, badgeForeground, menuForeground, menuBackground, menuSelectionForeground, menuSelectionBackground, menuSelectionBorder, menuBorder, menuSeparatorBackground, darken, listFilterWidgetOutline, listFilterWidgetNoMatchesOutline, listFilterWidgetBackground, treeIndentGuidesStroke, ColorValue, resolveColorValue } from 'vs/platform/theme/common/colorRegistry';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { IThemable, styleFn } from 'vs/base/common/styler';\r\n\r\nexport interface IStyleOverrides {\r\n\t[color: string]: ColorIdentifier | undefined;\r\n}\r\n\r\nexport interface IColorMapping {\r\n\t[optionsKey: string]: ColorValue | undefined;\r\n}\r\n\r\nexport interface IComputedStyles {\r\n\t[color: string]: Color | undefined;\r\n}\r\n\r\nexport function computeStyles(theme: IColorTheme, styleMap: IColorMapping): IComputedStyles {\r\n\tconst styles = Object.create(null) as IComputedStyles;\r\n\tfor (let key in styleMap) {\r\n\t\tconst value = styleMap[key];\r\n\t\tif (value) {\r\n\t\t\tstyles[key] = resolveColorValue(value, theme);\r\n\t\t}\r\n\t}\r\n\r\n\treturn styles;\r\n}\r\n\r\nexport function attachStyler(themeService: IThemeService, styleMap: T, widgetOrCallback: IThemable | styleFn): IDisposable {\r\n\tfunction applyStyles(theme: IColorTheme): void {\r\n\t\tconst styles = computeStyles(themeService.getColorTheme(), styleMap);\r\n\r\n\t\tif (typeof widgetOrCallback === 'function') {\r\n\t\t\twidgetOrCallback(styles);\r\n\t\t} else {\r\n\t\t\twidgetOrCallback.style(styles);\r\n\t\t}\r\n\t}\r\n\r\n\tapplyStyles(themeService.getColorTheme());\r\n\r\n\treturn themeService.onDidColorThemeChange(applyStyles);\r\n}\r\n\r\nexport interface IBadgeStyleOverrides extends IStyleOverrides {\r\n\tbadgeBackground?: ColorIdentifier;\r\n\tbadgeForeground?: ColorIdentifier;\r\n}\r\n\r\nexport function attachBadgeStyler(widget: IThemable, themeService: IThemeService, style?: IBadgeStyleOverrides): IDisposable {\r\n\treturn attachStyler(themeService, {\r\n\t\tbadgeBackground: (style && style.badgeBackground) || badgeBackground,\r\n\t\tbadgeForeground: (style && style.badgeForeground) || badgeForeground,\r\n\t\tbadgeBorder: contrastBorder\r\n\t} as IBadgeStyleOverrides, widget);\r\n}\r\n\r\nexport function attachListStyler(widget: IThemable, themeService: IThemeService, overrides?: IColorMapping): IDisposable {\r\n\treturn attachStyler(themeService, { ...defaultListStyles, ...(overrides || {}) }, widget);\r\n}\r\n\r\nexport const defaultListStyles: IColorMapping = {\r\n\tlistFocusBackground: listFocusBackground,\r\n\tlistFocusForeground: listFocusForeground,\r\n\tlistActiveSelectionBackground: darken(listActiveSelectionBackground, 0.1),\r\n\tlistActiveSelectionForeground: listActiveSelectionForeground,\r\n\tlistFocusAndSelectionBackground: listActiveSelectionBackground,\r\n\tlistFocusAndSelectionForeground: listActiveSelectionForeground,\r\n\tlistInactiveSelectionBackground: listInactiveSelectionBackground,\r\n\tlistInactiveSelectionForeground: listInactiveSelectionForeground,\r\n\tlistInactiveFocusBackground: listInactiveFocusBackground,\r\n\tlistHoverBackground: listHoverBackground,\r\n\tlistHoverForeground: listHoverForeground,\r\n\tlistDropBackground: listDropBackground,\r\n\tlistFocusOutline: activeContrastBorder,\r\n\tlistSelectionOutline: activeContrastBorder,\r\n\tlistHoverOutline: activeContrastBorder,\r\n\tlistFilterWidgetBackground: listFilterWidgetBackground,\r\n\tlistFilterWidgetOutline: listFilterWidgetOutline,\r\n\tlistFilterWidgetNoMatchesOutline: listFilterWidgetNoMatchesOutline,\r\n\tlistMatchesShadow: widgetShadow,\r\n\ttreeIndentGuidesStroke: treeIndentGuidesStroke\r\n};\r\n\r\nexport interface IMenuStyleOverrides extends IColorMapping {\r\n\tshadowColor?: ColorIdentifier;\r\n\tborderColor?: ColorIdentifier;\r\n\tforegroundColor?: ColorIdentifier;\r\n\tbackgroundColor?: ColorIdentifier;\r\n\tselectionForegroundColor?: ColorIdentifier;\r\n\tselectionBackgroundColor?: ColorIdentifier;\r\n\tselectionBorderColor?: ColorIdentifier;\r\n\tseparatorColor?: ColorIdentifier;\r\n}\r\n\r\nexport const defaultMenuStyles = {\r\n\tshadowColor: widgetShadow,\r\n\tborderColor: menuBorder,\r\n\tforegroundColor: menuForeground,\r\n\tbackgroundColor: menuBackground,\r\n\tselectionForegroundColor: menuSelectionForeground,\r\n\tselectionBackgroundColor: menuSelectionBackground,\r\n\tselectionBorderColor: menuSelectionBorder,\r\n\tseparatorColor: menuSeparatorBackground\r\n};\r\n\r\nexport function attachMenuStyler(widget: IThemable, themeService: IThemeService, style?: IMenuStyleOverrides): IDisposable {\r\n\treturn attachStyler(themeService, { ...defaultMenuStyles, ...style }, widget);\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./contextMenuHandler';\r\n\r\nimport { ActionRunner, IRunEvent, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions';\r\nimport { combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { Menu } from 'vs/base/browser/ui/menu/menu';\r\nimport { IContextViewService } from 'vs/platform/contextview/browser/contextView';\r\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\r\nimport { INotificationService } from 'vs/platform/notification/common/notification';\r\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\r\nimport { IThemeService } from 'vs/platform/theme/common/themeService';\r\nimport { IContextMenuDelegate } from 'vs/base/browser/contextmenu';\r\nimport { EventType, $, isHTMLElement } from 'vs/base/browser/dom';\r\nimport { attachMenuStyler } from 'vs/platform/theme/common/styler';\r\nimport { domEvent } from 'vs/base/browser/event';\r\nimport { StandardMouseEvent } from 'vs/base/browser/mouseEvent';\r\n\r\nexport interface IContextMenuHandlerOptions {\r\n\tblockMouse: boolean;\r\n}\r\n\r\nexport class ContextMenuHandler {\r\n\tprivate focusToReturn: HTMLElement | null = null;\r\n\tprivate block: HTMLElement | null = null;\r\n\tprivate options: IContextMenuHandlerOptions = { blockMouse: true };\r\n\r\n\tconstructor(\r\n\t\tprivate contextViewService: IContextViewService,\r\n\t\tprivate telemetryService: ITelemetryService,\r\n\t\tprivate notificationService: INotificationService,\r\n\t\tprivate keybindingService: IKeybindingService,\r\n\t\tprivate themeService: IThemeService\r\n\t) { }\r\n\r\n\tconfigure(options: IContextMenuHandlerOptions): void {\r\n\t\tthis.options = options;\r\n\t}\r\n\r\n\tshowContextMenu(delegate: IContextMenuDelegate): void {\r\n\t\tconst actions = delegate.getActions();\r\n\t\tif (!actions.length) {\r\n\t\t\treturn; // Don't render an empty context menu\r\n\t\t}\r\n\r\n\t\tthis.focusToReturn = document.activeElement as HTMLElement;\r\n\r\n\t\tlet menu: Menu | undefined;\r\n\r\n\t\tlet shadowRootElement = isHTMLElement(delegate.domForShadowRoot) ? delegate.domForShadowRoot : undefined;\r\n\t\tthis.contextViewService.showContextView({\r\n\t\t\tgetAnchor: () => delegate.getAnchor(),\r\n\t\t\tcanRelayout: false,\r\n\t\t\tanchorAlignment: delegate.anchorAlignment,\r\n\t\t\tanchorAxisAlignment: delegate.anchorAxisAlignment,\r\n\r\n\t\t\trender: (container) => {\r\n\t\t\t\tlet className = delegate.getMenuClassName ? delegate.getMenuClassName() : '';\r\n\r\n\t\t\t\tif (className) {\r\n\t\t\t\t\tcontainer.className += ' ' + className;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Render invisible div to block mouse interaction in the rest of the UI\r\n\t\t\t\tif (this.options.blockMouse) {\r\n\t\t\t\t\tthis.block = container.appendChild($('.context-view-block'));\r\n\t\t\t\t\tthis.block.style.position = 'fixed';\r\n\t\t\t\t\tthis.block.style.cursor = 'initial';\r\n\t\t\t\t\tthis.block.style.left = '0';\r\n\t\t\t\t\tthis.block.style.top = '0';\r\n\t\t\t\t\tthis.block.style.width = '100%';\r\n\t\t\t\t\tthis.block.style.height = '100%';\r\n\t\t\t\t\tthis.block.style.zIndex = '-1';\r\n\t\t\t\t\tdomEvent(this.block, EventType.MOUSE_DOWN)((e: MouseEvent) => e.stopPropagation());\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst menuDisposables = new DisposableStore();\r\n\r\n\t\t\t\tconst actionRunner = delegate.actionRunner || new ActionRunner();\r\n\t\t\t\tactionRunner.onBeforeRun(this.onActionRun, this, menuDisposables);\r\n\t\t\t\tactionRunner.onDidRun(this.onDidActionRun, this, menuDisposables);\r\n\t\t\t\tmenu = new Menu(container, actions, {\r\n\t\t\t\t\tactionViewItemProvider: delegate.getActionViewItem,\r\n\t\t\t\t\tcontext: delegate.getActionsContext ? delegate.getActionsContext() : null,\r\n\t\t\t\t\tactionRunner,\r\n\t\t\t\t\tgetKeyBinding: delegate.getKeyBinding ? delegate.getKeyBinding : action => this.keybindingService.lookupKeybinding(action.id)\r\n\t\t\t\t});\r\n\r\n\t\t\t\tmenuDisposables.add(attachMenuStyler(menu, this.themeService));\r\n\r\n\t\t\t\tmenu.onDidCancel(() => this.contextViewService.hideContextView(true), null, menuDisposables);\r\n\t\t\t\tmenu.onDidBlur(() => this.contextViewService.hideContextView(true), null, menuDisposables);\r\n\t\t\t\tdomEvent(window, EventType.BLUR)(() => { this.contextViewService.hideContextView(true); }, null, menuDisposables);\r\n\t\t\t\tdomEvent(window, EventType.MOUSE_DOWN)((e: MouseEvent) => {\r\n\t\t\t\t\tif (e.defaultPrevented) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tlet event = new StandardMouseEvent(e);\r\n\t\t\t\t\tlet element: HTMLElement | null = event.target;\r\n\r\n\t\t\t\t\t// Don't do anything as we are likely creating a context menu\r\n\t\t\t\t\tif (event.rightButton) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\twhile (element) {\r\n\t\t\t\t\t\tif (element === container) {\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\telement = element.parentElement;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tthis.contextViewService.hideContextView(true);\r\n\t\t\t\t}, null, menuDisposables);\r\n\r\n\t\t\t\treturn combinedDisposable(menuDisposables, menu);\r\n\t\t\t},\r\n\r\n\t\t\tfocus: () => {\r\n\t\t\t\tif (menu) {\r\n\t\t\t\t\tmenu.focus(!!delegate.autoSelectFirstItem);\r\n\t\t\t\t}\r\n\t\t\t},\r\n\r\n\t\t\tonHide: (didCancel?: boolean) => {\r\n\t\t\t\tif (delegate.onHide) {\r\n\t\t\t\t\tdelegate.onHide(!!didCancel);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (this.block) {\r\n\t\t\t\t\tthis.block.remove();\r\n\t\t\t\t\tthis.block = null;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (this.focusToReturn) {\r\n\t\t\t\t\tthis.focusToReturn.focus();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}, shadowRootElement, !!shadowRootElement);\r\n\t}\r\n\r\n\tprivate onActionRun(e: IRunEvent): void {\r\n\t\tif (this.telemetryService) {\r\n\t\t\tthis.telemetryService.publicLog2('workbenchActionExecuted', { id: e.action.id, from: 'contextMenu' });\r\n\t\t}\r\n\r\n\t\tthis.contextViewService.hideContextView(false);\r\n\r\n\t\t// Restore focus here\r\n\t\tif (this.focusToReturn) {\r\n\t\t\tthis.focusToReturn.focus();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate onDidActionRun(e: IRunEvent): void {\r\n\t\tif (e.error) {\r\n\t\t\tthis.notificationService.error(e.error);\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\n/**\r\n * Color scheme used by the OS and by color themes.\r\n */\r\nexport enum ColorScheme {\r\n\tDARK = 'dark',\r\n\tLIGHT = 'light',\r\n\tHIGH_CONTRAST = 'hc'\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as browser from 'vs/base/browser/browser';\r\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport { IVisibleLine } from 'vs/editor/browser/view/viewLayer';\r\nimport { RangeUtil } from 'vs/editor/browser/viewParts/lines/rangeUtil';\r\nimport { IStringBuilder } from 'vs/editor/common/core/stringBuilder';\r\nimport { IConfiguration } from 'vs/editor/common/editorCommon';\r\nimport { HorizontalRange, VisibleRanges } from 'vs/editor/common/view/renderingContext';\r\nimport { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations';\r\nimport { CharacterMapping, ForeignElementType, RenderLineInput, renderViewLine, LineRange } from 'vs/editor/common/viewLayout/viewLineRenderer';\r\nimport { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';\r\nimport { InlineDecorationType } from 'vs/editor/common/viewModel/viewModel';\r\nimport { ColorScheme } from 'vs/platform/theme/common/theme';\r\nimport { EditorOption, EditorFontLigatures } from 'vs/editor/common/config/editorOptions';\r\n\r\nconst canUseFastRenderedViewLine = (function () {\r\n\tif (platform.isNative) {\r\n\t\t// In VSCode we know very well when the zoom level changes\r\n\t\treturn true;\r\n\t}\r\n\r\n\tif (platform.isLinux || browser.isFirefox || browser.isSafari) {\r\n\t\t// On Linux, it appears that zooming affects char widths (in pixels), which is unexpected.\r\n\t\t// --\r\n\t\t// Even though we read character widths correctly, having read them at a specific zoom level\r\n\t\t// does not mean they are the same at the current zoom level.\r\n\t\t// --\r\n\t\t// This could be improved if we ever figure out how to get an event when browsers zoom,\r\n\t\t// but until then we have to stick with reading client rects.\r\n\t\t// --\r\n\t\t// The same has been observed with Firefox on Windows7\r\n\t\t// --\r\n\t\t// The same has been oversved with Safari\r\n\t\treturn false;\r\n\t}\r\n\r\n\treturn true;\r\n})();\r\n\r\nlet monospaceAssumptionsAreValid = true;\r\n\r\nconst alwaysRenderInlineSelection = (browser.isEdgeLegacy);\r\n\r\nexport class DomReadingContext {\r\n\r\n\tprivate readonly _domNode: HTMLElement;\r\n\tprivate _clientRectDeltaLeft: number;\r\n\tprivate _clientRectDeltaLeftRead: boolean;\r\n\tpublic get clientRectDeltaLeft(): number {\r\n\t\tif (!this._clientRectDeltaLeftRead) {\r\n\t\t\tthis._clientRectDeltaLeftRead = true;\r\n\t\t\tthis._clientRectDeltaLeft = this._domNode.getBoundingClientRect().left;\r\n\t\t}\r\n\t\treturn this._clientRectDeltaLeft;\r\n\t}\r\n\r\n\tpublic readonly endNode: HTMLElement;\r\n\r\n\tconstructor(domNode: HTMLElement, endNode: HTMLElement) {\r\n\t\tthis._domNode = domNode;\r\n\t\tthis._clientRectDeltaLeft = 0;\r\n\t\tthis._clientRectDeltaLeftRead = false;\r\n\t\tthis.endNode = endNode;\r\n\t}\r\n\r\n}\r\n\r\nexport class ViewLineOptions {\r\n\tpublic readonly themeType: ColorScheme;\r\n\tpublic readonly renderWhitespace: 'none' | 'boundary' | 'selection' | 'trailing' | 'all';\r\n\tpublic readonly renderControlCharacters: boolean;\r\n\tpublic readonly spaceWidth: number;\r\n\tpublic readonly middotWidth: number;\r\n\tpublic readonly wsmiddotWidth: number;\r\n\tpublic readonly useMonospaceOptimizations: boolean;\r\n\tpublic readonly canUseHalfwidthRightwardsArrow: boolean;\r\n\tpublic readonly lineHeight: number;\r\n\tpublic readonly stopRenderingLineAfter: number;\r\n\tpublic readonly fontLigatures: string;\r\n\r\n\tconstructor(config: IConfiguration, themeType: ColorScheme) {\r\n\t\tthis.themeType = themeType;\r\n\t\tconst options = config.options;\r\n\t\tconst fontInfo = options.get(EditorOption.fontInfo);\r\n\t\tthis.renderWhitespace = options.get(EditorOption.renderWhitespace);\r\n\t\tthis.renderControlCharacters = options.get(EditorOption.renderControlCharacters);\r\n\t\tthis.spaceWidth = fontInfo.spaceWidth;\r\n\t\tthis.middotWidth = fontInfo.middotWidth;\r\n\t\tthis.wsmiddotWidth = fontInfo.wsmiddotWidth;\r\n\t\tthis.useMonospaceOptimizations = (\r\n\t\t\tfontInfo.isMonospace\r\n\t\t\t&& !options.get(EditorOption.disableMonospaceOptimizations)\r\n\t\t);\r\n\t\tthis.canUseHalfwidthRightwardsArrow = fontInfo.canUseHalfwidthRightwardsArrow;\r\n\t\tthis.lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tthis.stopRenderingLineAfter = options.get(EditorOption.stopRenderingLineAfter);\r\n\t\tthis.fontLigatures = options.get(EditorOption.fontLigatures);\r\n\t}\r\n\r\n\tpublic equals(other: ViewLineOptions): boolean {\r\n\t\treturn (\r\n\t\t\tthis.themeType === other.themeType\r\n\t\t\t&& this.renderWhitespace === other.renderWhitespace\r\n\t\t\t&& this.renderControlCharacters === other.renderControlCharacters\r\n\t\t\t&& this.spaceWidth === other.spaceWidth\r\n\t\t\t&& this.middotWidth === other.middotWidth\r\n\t\t\t&& this.wsmiddotWidth === other.wsmiddotWidth\r\n\t\t\t&& this.useMonospaceOptimizations === other.useMonospaceOptimizations\r\n\t\t\t&& this.canUseHalfwidthRightwardsArrow === other.canUseHalfwidthRightwardsArrow\r\n\t\t\t&& this.lineHeight === other.lineHeight\r\n\t\t\t&& this.stopRenderingLineAfter === other.stopRenderingLineAfter\r\n\t\t\t&& this.fontLigatures === other.fontLigatures\r\n\t\t);\r\n\t}\r\n}\r\n\r\nexport class ViewLine implements IVisibleLine {\r\n\r\n\tpublic static readonly CLASS_NAME = 'view-line';\r\n\r\n\tprivate _options: ViewLineOptions;\r\n\tprivate _isMaybeInvalid: boolean;\r\n\tprivate _renderedViewLine: IRenderedViewLine | null;\r\n\r\n\tconstructor(options: ViewLineOptions) {\r\n\t\tthis._options = options;\r\n\t\tthis._isMaybeInvalid = true;\r\n\t\tthis._renderedViewLine = null;\r\n\t}\r\n\r\n\t// --- begin IVisibleLineData\r\n\r\n\tpublic getDomNode(): HTMLElement | null {\r\n\t\tif (this._renderedViewLine && this._renderedViewLine.domNode) {\r\n\t\t\treturn this._renderedViewLine.domNode.domNode;\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\tpublic setDomNode(domNode: HTMLElement): void {\r\n\t\tif (this._renderedViewLine) {\r\n\t\t\tthis._renderedViewLine.domNode = createFastDomNode(domNode);\r\n\t\t} else {\r\n\t\t\tthrow new Error('I have no rendered view line to set the dom node to...');\r\n\t\t}\r\n\t}\r\n\r\n\tpublic onContentChanged(): void {\r\n\t\tthis._isMaybeInvalid = true;\r\n\t}\r\n\tpublic onTokensChanged(): void {\r\n\t\tthis._isMaybeInvalid = true;\r\n\t}\r\n\tpublic onDecorationsChanged(): void {\r\n\t\tthis._isMaybeInvalid = true;\r\n\t}\r\n\tpublic onOptionsChanged(newOptions: ViewLineOptions): void {\r\n\t\tthis._isMaybeInvalid = true;\r\n\t\tthis._options = newOptions;\r\n\t}\r\n\tpublic onSelectionChanged(): boolean {\r\n\t\tif (alwaysRenderInlineSelection || this._options.themeType === ColorScheme.HIGH_CONTRAST || this._options.renderWhitespace === 'selection') {\r\n\t\t\tthis._isMaybeInvalid = true;\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic renderLine(lineNumber: number, deltaTop: number, viewportData: ViewportData, sb: IStringBuilder): boolean {\r\n\t\tif (this._isMaybeInvalid === false) {\r\n\t\t\t// it appears that nothing relevant has changed\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tthis._isMaybeInvalid = false;\r\n\r\n\t\tconst lineData = viewportData.getViewLineRenderingData(lineNumber);\r\n\t\tconst options = this._options;\r\n\t\tconst actualInlineDecorations = LineDecoration.filter(lineData.inlineDecorations, lineNumber, lineData.minColumn, lineData.maxColumn);\r\n\r\n\t\t// Only send selection information when needed for rendering whitespace\r\n\t\tlet selectionsOnLine: LineRange[] | null = null;\r\n\t\tif (alwaysRenderInlineSelection || options.themeType === ColorScheme.HIGH_CONTRAST || this._options.renderWhitespace === 'selection') {\r\n\t\t\tconst selections = viewportData.selections;\r\n\t\t\tfor (const selection of selections) {\r\n\r\n\t\t\t\tif (selection.endLineNumber < lineNumber || selection.startLineNumber > lineNumber) {\r\n\t\t\t\t\t// Selection does not intersect line\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst startColumn = (selection.startLineNumber === lineNumber ? selection.startColumn : lineData.minColumn);\r\n\t\t\t\tconst endColumn = (selection.endLineNumber === lineNumber ? selection.endColumn : lineData.maxColumn);\r\n\r\n\t\t\t\tif (startColumn < endColumn) {\r\n\t\t\t\t\tif (options.themeType === ColorScheme.HIGH_CONTRAST || this._options.renderWhitespace !== 'selection') {\r\n\t\t\t\t\t\tactualInlineDecorations.push(new LineDecoration(startColumn, endColumn, 'inline-selected-text', InlineDecorationType.Regular));\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tif (!selectionsOnLine) {\r\n\t\t\t\t\t\t\tselectionsOnLine = [];\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tselectionsOnLine.push(new LineRange(startColumn - 1, endColumn - 1));\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst renderLineInput = new RenderLineInput(\r\n\t\t\toptions.useMonospaceOptimizations,\r\n\t\t\toptions.canUseHalfwidthRightwardsArrow,\r\n\t\t\tlineData.content,\r\n\t\t\tlineData.continuesWithWrappedLine,\r\n\t\t\tlineData.isBasicASCII,\r\n\t\t\tlineData.containsRTL,\r\n\t\t\tlineData.minColumn - 1,\r\n\t\t\tlineData.tokens,\r\n\t\t\tactualInlineDecorations,\r\n\t\t\tlineData.tabSize,\r\n\t\t\tlineData.startVisibleColumn,\r\n\t\t\toptions.spaceWidth,\r\n\t\t\toptions.middotWidth,\r\n\t\t\toptions.wsmiddotWidth,\r\n\t\t\toptions.stopRenderingLineAfter,\r\n\t\t\toptions.renderWhitespace,\r\n\t\t\toptions.renderControlCharacters,\r\n\t\t\toptions.fontLigatures !== EditorFontLigatures.OFF,\r\n\t\t\tselectionsOnLine\r\n\t\t);\r\n\r\n\t\tif (this._renderedViewLine && this._renderedViewLine.input.equals(renderLineInput)) {\r\n\t\t\t// no need to do anything, we have the same render input\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tsb.appendASCIIString('
    ');\r\n\r\n\t\tconst output = renderViewLine(renderLineInput, sb);\r\n\r\n\t\tsb.appendASCIIString('
    ');\r\n\r\n\t\tlet renderedViewLine: IRenderedViewLine | null = null;\r\n\t\tif (monospaceAssumptionsAreValid && canUseFastRenderedViewLine && lineData.isBasicASCII && options.useMonospaceOptimizations && output.containsForeignElements === ForeignElementType.None) {\r\n\t\t\tif (lineData.content.length < 300 && renderLineInput.lineTokens.getCount() < 100) {\r\n\t\t\t\t// Browser rounding errors have been observed in Chrome and IE, so using the fast\r\n\t\t\t\t// view line only for short lines. Please test before removing the length check...\r\n\t\t\t\t// ---\r\n\t\t\t\t// Another rounding error has been observed on Linux in VSCode, where width\r\n\t\t\t\t// rounding errors add up to an observable large number...\r\n\t\t\t\t// ---\r\n\t\t\t\t// Also see another example of rounding errors on Windows in\r\n\t\t\t\t// https://github.com/microsoft/vscode/issues/33178\r\n\t\t\t\trenderedViewLine = new FastRenderedViewLine(\r\n\t\t\t\t\tthis._renderedViewLine ? this._renderedViewLine.domNode : null,\r\n\t\t\t\t\trenderLineInput,\r\n\t\t\t\t\toutput.characterMapping\r\n\t\t\t\t);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!renderedViewLine) {\r\n\t\t\trenderedViewLine = createRenderedLine(\r\n\t\t\t\tthis._renderedViewLine ? this._renderedViewLine.domNode : null,\r\n\t\t\t\trenderLineInput,\r\n\t\t\t\toutput.characterMapping,\r\n\t\t\t\toutput.containsRTL,\r\n\t\t\t\toutput.containsForeignElements\r\n\t\t\t);\r\n\t\t}\r\n\r\n\t\tthis._renderedViewLine = renderedViewLine;\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic layoutLine(lineNumber: number, deltaTop: number): void {\r\n\t\tif (this._renderedViewLine && this._renderedViewLine.domNode) {\r\n\t\t\tthis._renderedViewLine.domNode.setTop(deltaTop);\r\n\t\t\tthis._renderedViewLine.domNode.setHeight(this._options.lineHeight);\r\n\t\t}\r\n\t}\r\n\r\n\t// --- end IVisibleLineData\r\n\r\n\tpublic getWidth(): number {\r\n\t\tif (!this._renderedViewLine) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t\treturn this._renderedViewLine.getWidth();\r\n\t}\r\n\r\n\tpublic getWidthIsFast(): boolean {\r\n\t\tif (!this._renderedViewLine) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn this._renderedViewLine.getWidthIsFast();\r\n\t}\r\n\r\n\tpublic needsMonospaceFontCheck(): boolean {\r\n\t\tif (!this._renderedViewLine) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn (this._renderedViewLine instanceof FastRenderedViewLine);\r\n\t}\r\n\r\n\tpublic monospaceAssumptionsAreValid(): boolean {\r\n\t\tif (!this._renderedViewLine) {\r\n\t\t\treturn monospaceAssumptionsAreValid;\r\n\t\t}\r\n\t\tif (this._renderedViewLine instanceof FastRenderedViewLine) {\r\n\t\t\treturn this._renderedViewLine.monospaceAssumptionsAreValid();\r\n\t\t}\r\n\t\treturn monospaceAssumptionsAreValid;\r\n\t}\r\n\r\n\tpublic onMonospaceAssumptionsInvalidated(): void {\r\n\t\tif (this._renderedViewLine && this._renderedViewLine instanceof FastRenderedViewLine) {\r\n\t\t\tthis._renderedViewLine = this._renderedViewLine.toSlowRenderedLine();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getVisibleRangesForRange(startColumn: number, endColumn: number, context: DomReadingContext): VisibleRanges | null {\r\n\t\tif (!this._renderedViewLine) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tstartColumn = startColumn | 0; // @perf\r\n\t\tendColumn = endColumn | 0; // @perf\r\n\r\n\t\tstartColumn = Math.min(this._renderedViewLine.input.lineContent.length + 1, Math.max(1, startColumn));\r\n\t\tendColumn = Math.min(this._renderedViewLine.input.lineContent.length + 1, Math.max(1, endColumn));\r\n\r\n\t\tconst stopRenderingLineAfter = this._renderedViewLine.input.stopRenderingLineAfter | 0; // @perf\r\n\t\tlet outsideRenderedLine = false;\r\n\r\n\t\tif (stopRenderingLineAfter !== -1 && startColumn > stopRenderingLineAfter + 1 && endColumn > stopRenderingLineAfter + 1) {\r\n\t\t\t// This range is obviously not visible\r\n\t\t\toutsideRenderedLine = true;\r\n\t\t}\r\n\r\n\t\tif (stopRenderingLineAfter !== -1 && startColumn > stopRenderingLineAfter + 1) {\r\n\t\t\tstartColumn = stopRenderingLineAfter + 1;\r\n\t\t}\r\n\r\n\t\tif (stopRenderingLineAfter !== -1 && endColumn > stopRenderingLineAfter + 1) {\r\n\t\t\tendColumn = stopRenderingLineAfter + 1;\r\n\t\t}\r\n\r\n\t\tconst horizontalRanges = this._renderedViewLine.getVisibleRangesForRange(startColumn, endColumn, context);\r\n\t\tif (horizontalRanges && horizontalRanges.length > 0) {\r\n\t\t\treturn new VisibleRanges(outsideRenderedLine, horizontalRanges);\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic getColumnOfNodeOffset(lineNumber: number, spanNode: HTMLElement, offset: number): number {\r\n\t\tif (!this._renderedViewLine) {\r\n\t\t\treturn 1;\r\n\t\t}\r\n\t\treturn this._renderedViewLine.getColumnOfNodeOffset(lineNumber, spanNode, offset);\r\n\t}\r\n}\r\n\r\ninterface IRenderedViewLine {\r\n\tdomNode: FastDomNode | null;\r\n\treadonly input: RenderLineInput;\r\n\tgetWidth(): number;\r\n\tgetWidthIsFast(): boolean;\r\n\tgetVisibleRangesForRange(startColumn: number, endColumn: number, context: DomReadingContext): HorizontalRange[] | null;\r\n\tgetColumnOfNodeOffset(lineNumber: number, spanNode: HTMLElement, offset: number): number;\r\n}\r\n\r\n/**\r\n * A rendered line which is guaranteed to contain only regular ASCII and is rendered with a monospace font.\r\n */\r\nclass FastRenderedViewLine implements IRenderedViewLine {\r\n\r\n\tpublic domNode: FastDomNode | null;\r\n\tpublic readonly input: RenderLineInput;\r\n\r\n\tprivate readonly _characterMapping: CharacterMapping;\r\n\tprivate readonly _charWidth: number;\r\n\r\n\tconstructor(domNode: FastDomNode | null, renderLineInput: RenderLineInput, characterMapping: CharacterMapping) {\r\n\t\tthis.domNode = domNode;\r\n\t\tthis.input = renderLineInput;\r\n\r\n\t\tthis._characterMapping = characterMapping;\r\n\t\tthis._charWidth = renderLineInput.spaceWidth;\r\n\t}\r\n\r\n\tpublic getWidth(): number {\r\n\t\treturn this._getCharPosition(this._characterMapping.length);\r\n\t}\r\n\r\n\tpublic getWidthIsFast(): boolean {\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic monospaceAssumptionsAreValid(): boolean {\r\n\t\tif (!this.domNode) {\r\n\t\t\treturn monospaceAssumptionsAreValid;\r\n\t\t}\r\n\t\tconst expectedWidth = this.getWidth();\r\n\t\tconst actualWidth = (this.domNode.domNode.firstChild).offsetWidth;\r\n\t\tif (Math.abs(expectedWidth - actualWidth) >= 2) {\r\n\t\t\t// more than 2px off\r\n\t\t\tconsole.warn(`monospace assumptions have been violated, therefore disabling monospace optimizations!`);\r\n\t\t\tmonospaceAssumptionsAreValid = false;\r\n\t\t}\r\n\t\treturn monospaceAssumptionsAreValid;\r\n\t}\r\n\r\n\tpublic toSlowRenderedLine(): RenderedViewLine {\r\n\t\treturn createRenderedLine(this.domNode, this.input, this._characterMapping, false, ForeignElementType.None);\r\n\t}\r\n\r\n\tpublic getVisibleRangesForRange(startColumn: number, endColumn: number, context: DomReadingContext): HorizontalRange[] | null {\r\n\t\tconst startPosition = this._getCharPosition(startColumn);\r\n\t\tconst endPosition = this._getCharPosition(endColumn);\r\n\t\treturn [new HorizontalRange(startPosition, endPosition - startPosition)];\r\n\t}\r\n\r\n\tprivate _getCharPosition(column: number): number {\r\n\t\tconst charOffset = this._characterMapping.getAbsoluteOffsets();\r\n\t\tif (charOffset.length === 0) {\r\n\t\t\t// No characters on this line\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t\treturn Math.round(this._charWidth * charOffset[column - 1]);\r\n\t}\r\n\r\n\tpublic getColumnOfNodeOffset(lineNumber: number, spanNode: HTMLElement, offset: number): number {\r\n\t\tconst spanNodeTextContentLength = spanNode.textContent!.length;\r\n\r\n\t\tlet spanIndex = -1;\r\n\t\twhile (spanNode) {\r\n\t\t\tspanNode = spanNode.previousSibling;\r\n\t\t\tspanIndex++;\r\n\t\t}\r\n\r\n\t\tconst charOffset = this._characterMapping.partDataToCharOffset(spanIndex, spanNodeTextContentLength, offset);\r\n\t\treturn charOffset + 1;\r\n\t}\r\n}\r\n\r\n/**\r\n * Every time we render a line, we save what we have rendered in an instance of this class.\r\n */\r\nclass RenderedViewLine implements IRenderedViewLine {\r\n\r\n\tpublic domNode: FastDomNode | null;\r\n\tpublic readonly input: RenderLineInput;\r\n\r\n\tprotected readonly _characterMapping: CharacterMapping;\r\n\tprivate readonly _isWhitespaceOnly: boolean;\r\n\tprivate readonly _containsForeignElements: ForeignElementType;\r\n\tprivate _cachedWidth: number;\r\n\r\n\t/**\r\n\t * This is a map that is used only when the line is guaranteed to have no RTL text.\r\n\t */\r\n\tprivate readonly _pixelOffsetCache: Int32Array | null;\r\n\r\n\tconstructor(domNode: FastDomNode | null, renderLineInput: RenderLineInput, characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: ForeignElementType) {\r\n\t\tthis.domNode = domNode;\r\n\t\tthis.input = renderLineInput;\r\n\t\tthis._characterMapping = characterMapping;\r\n\t\tthis._isWhitespaceOnly = /^\\s*$/.test(renderLineInput.lineContent);\r\n\t\tthis._containsForeignElements = containsForeignElements;\r\n\t\tthis._cachedWidth = -1;\r\n\r\n\t\tthis._pixelOffsetCache = null;\r\n\t\tif (!containsRTL || this._characterMapping.length === 0 /* the line is empty */) {\r\n\t\t\tthis._pixelOffsetCache = new Int32Array(Math.max(2, this._characterMapping.length + 1));\r\n\t\t\tfor (let column = 0, len = this._characterMapping.length; column <= len; column++) {\r\n\t\t\t\tthis._pixelOffsetCache[column] = -1;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t// --- Reading from the DOM methods\r\n\r\n\tprotected _getReadingTarget(myDomNode: FastDomNode): HTMLElement {\r\n\t\treturn myDomNode.domNode.firstChild;\r\n\t}\r\n\r\n\t/**\r\n\t * Width of the line in pixels\r\n\t */\r\n\tpublic getWidth(): number {\r\n\t\tif (!this.domNode) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t\tif (this._cachedWidth === -1) {\r\n\t\t\tthis._cachedWidth = this._getReadingTarget(this.domNode).offsetWidth;\r\n\t\t}\r\n\t\treturn this._cachedWidth;\r\n\t}\r\n\r\n\tpublic getWidthIsFast(): boolean {\r\n\t\tif (this._cachedWidth === -1) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t * Visible ranges for a model range\r\n\t */\r\n\tpublic getVisibleRangesForRange(startColumn: number, endColumn: number, context: DomReadingContext): HorizontalRange[] | null {\r\n\t\tif (!this.domNode) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tif (this._pixelOffsetCache !== null) {\r\n\t\t\t// the text is LTR\r\n\t\t\tconst startOffset = this._readPixelOffset(this.domNode, startColumn, context);\r\n\t\t\tif (startOffset === -1) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\r\n\t\t\tconst endOffset = this._readPixelOffset(this.domNode, endColumn, context);\r\n\t\t\tif (endOffset === -1) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\r\n\t\t\treturn [new HorizontalRange(startOffset, endOffset - startOffset)];\r\n\t\t}\r\n\r\n\t\treturn this._readVisibleRangesForRange(this.domNode, startColumn, endColumn, context);\r\n\t}\r\n\r\n\tprotected _readVisibleRangesForRange(domNode: FastDomNode, startColumn: number, endColumn: number, context: DomReadingContext): HorizontalRange[] | null {\r\n\t\tif (startColumn === endColumn) {\r\n\t\t\tconst pixelOffset = this._readPixelOffset(domNode, startColumn, context);\r\n\t\t\tif (pixelOffset === -1) {\r\n\t\t\t\treturn null;\r\n\t\t\t} else {\r\n\t\t\t\treturn [new HorizontalRange(pixelOffset, 0)];\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\treturn this._readRawVisibleRangesForRange(domNode, startColumn, endColumn, context);\r\n\t\t}\r\n\t}\r\n\r\n\tprotected _readPixelOffset(domNode: FastDomNode, column: number, context: DomReadingContext): number {\r\n\t\tif (this._characterMapping.length === 0) {\r\n\t\t\t// This line has no content\r\n\t\t\tif (this._containsForeignElements === ForeignElementType.None) {\r\n\t\t\t\t// We can assume the line is really empty\r\n\t\t\t\treturn 0;\r\n\t\t\t}\r\n\t\t\tif (this._containsForeignElements === ForeignElementType.After) {\r\n\t\t\t\t// We have foreign elements after the (empty) line\r\n\t\t\t\treturn 0;\r\n\t\t\t}\r\n\t\t\tif (this._containsForeignElements === ForeignElementType.Before) {\r\n\t\t\t\t// We have foreign elements before the (empty) line\r\n\t\t\t\treturn this.getWidth();\r\n\t\t\t}\r\n\t\t\t// We have foreign elements before & after the (empty) line\r\n\t\t\tconst readingTarget = this._getReadingTarget(domNode);\r\n\t\t\tif (readingTarget.firstChild) {\r\n\t\t\t\treturn (readingTarget.firstChild).offsetWidth;\r\n\t\t\t} else {\r\n\t\t\t\treturn 0;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (this._pixelOffsetCache !== null) {\r\n\t\t\t// the text is LTR\r\n\r\n\t\t\tconst cachedPixelOffset = this._pixelOffsetCache[column];\r\n\t\t\tif (cachedPixelOffset !== -1) {\r\n\t\t\t\treturn cachedPixelOffset;\r\n\t\t\t}\r\n\r\n\t\t\tconst result = this._actualReadPixelOffset(domNode, column, context);\r\n\t\t\tthis._pixelOffsetCache[column] = result;\r\n\t\t\treturn result;\r\n\t\t}\r\n\r\n\t\treturn this._actualReadPixelOffset(domNode, column, context);\r\n\t}\r\n\r\n\tprivate _actualReadPixelOffset(domNode: FastDomNode, column: number, context: DomReadingContext): number {\r\n\t\tif (this._characterMapping.length === 0) {\r\n\t\t\t// This line has no content\r\n\t\t\tconst r = RangeUtil.readHorizontalRanges(this._getReadingTarget(domNode), 0, 0, 0, 0, context.clientRectDeltaLeft, context.endNode);\r\n\t\t\tif (!r || r.length === 0) {\r\n\t\t\t\treturn -1;\r\n\t\t\t}\r\n\t\t\treturn r[0].left;\r\n\t\t}\r\n\r\n\t\tif (column === this._characterMapping.length && this._isWhitespaceOnly && this._containsForeignElements === ForeignElementType.None) {\r\n\t\t\t// This branch helps in the case of whitespace only lines which have a width set\r\n\t\t\treturn this.getWidth();\r\n\t\t}\r\n\r\n\t\tconst partData = this._characterMapping.charOffsetToPartData(column - 1);\r\n\t\tconst partIndex = CharacterMapping.getPartIndex(partData);\r\n\t\tconst charOffsetInPart = CharacterMapping.getCharIndex(partData);\r\n\r\n\t\tconst r = RangeUtil.readHorizontalRanges(this._getReadingTarget(domNode), partIndex, charOffsetInPart, partIndex, charOffsetInPart, context.clientRectDeltaLeft, context.endNode);\r\n\t\tif (!r || r.length === 0) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\tconst result = r[0].left;\r\n\t\tif (this.input.isBasicASCII) {\r\n\t\t\tconst charOffset = this._characterMapping.getAbsoluteOffsets();\r\n\t\t\tconst expectedResult = Math.round(this.input.spaceWidth * charOffset[column - 1]);\r\n\t\t\tif (Math.abs(expectedResult - result) <= 1) {\r\n\t\t\t\treturn expectedResult;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate _readRawVisibleRangesForRange(domNode: FastDomNode, startColumn: number, endColumn: number, context: DomReadingContext): HorizontalRange[] | null {\r\n\r\n\t\tif (startColumn === 1 && endColumn === this._characterMapping.length) {\r\n\t\t\t// This branch helps IE with bidi text & gives a performance boost to other browsers when reading visible ranges for an entire line\r\n\r\n\t\t\treturn [new HorizontalRange(0, this.getWidth())];\r\n\t\t}\r\n\r\n\t\tconst startPartData = this._characterMapping.charOffsetToPartData(startColumn - 1);\r\n\t\tconst startPartIndex = CharacterMapping.getPartIndex(startPartData);\r\n\t\tconst startCharOffsetInPart = CharacterMapping.getCharIndex(startPartData);\r\n\r\n\t\tconst endPartData = this._characterMapping.charOffsetToPartData(endColumn - 1);\r\n\t\tconst endPartIndex = CharacterMapping.getPartIndex(endPartData);\r\n\t\tconst endCharOffsetInPart = CharacterMapping.getCharIndex(endPartData);\r\n\r\n\t\treturn RangeUtil.readHorizontalRanges(this._getReadingTarget(domNode), startPartIndex, startCharOffsetInPart, endPartIndex, endCharOffsetInPart, context.clientRectDeltaLeft, context.endNode);\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the column for the text found at a specific offset inside a rendered dom node\r\n\t */\r\n\tpublic getColumnOfNodeOffset(lineNumber: number, spanNode: HTMLElement, offset: number): number {\r\n\t\tconst spanNodeTextContentLength = spanNode.textContent!.length;\r\n\r\n\t\tlet spanIndex = -1;\r\n\t\twhile (spanNode) {\r\n\t\t\tspanNode = spanNode.previousSibling;\r\n\t\t\tspanIndex++;\r\n\t\t}\r\n\r\n\t\tconst charOffset = this._characterMapping.partDataToCharOffset(spanIndex, spanNodeTextContentLength, offset);\r\n\t\treturn charOffset + 1;\r\n\t}\r\n}\r\n\r\nclass WebKitRenderedViewLine extends RenderedViewLine {\r\n\tprotected _readVisibleRangesForRange(domNode: FastDomNode, startColumn: number, endColumn: number, context: DomReadingContext): HorizontalRange[] | null {\r\n\t\tconst output = super._readVisibleRangesForRange(domNode, startColumn, endColumn, context);\r\n\r\n\t\tif (!output || output.length === 0 || startColumn === endColumn || (startColumn === 1 && endColumn === this._characterMapping.length)) {\r\n\t\t\treturn output;\r\n\t\t}\r\n\r\n\t\t// WebKit is buggy and returns an expanded range (to contain words in some cases)\r\n\t\t// The last client rect is enlarged (I think)\r\n\t\tif (!this.input.containsRTL) {\r\n\t\t\t// This is an attempt to patch things up\r\n\t\t\t// Find position of last column\r\n\t\t\tconst endPixelOffset = this._readPixelOffset(domNode, endColumn, context);\r\n\t\t\tif (endPixelOffset !== -1) {\r\n\t\t\t\tconst lastRange = output[output.length - 1];\r\n\t\t\t\tif (lastRange.left < endPixelOffset) {\r\n\t\t\t\t\t// Trim down the width of the last visible range to not go after the last column's position\r\n\t\t\t\t\tlastRange.width = endPixelOffset - lastRange.left;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn output;\r\n\t}\r\n}\r\n\r\nconst createRenderedLine: (domNode: FastDomNode | null, renderLineInput: RenderLineInput, characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: ForeignElementType) => RenderedViewLine = (function () {\r\n\tif (browser.isWebKit) {\r\n\t\treturn createWebKitRenderedLine;\r\n\t}\r\n\treturn createNormalRenderedLine;\r\n})();\r\n\r\nfunction createWebKitRenderedLine(domNode: FastDomNode | null, renderLineInput: RenderLineInput, characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: ForeignElementType): RenderedViewLine {\r\n\treturn new WebKitRenderedViewLine(domNode, renderLineInput, characterMapping, containsRTL, containsForeignElements);\r\n}\r\n\r\nfunction createNormalRenderedLine(domNode: FastDomNode | null, renderLineInput: RenderLineInput, characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: ForeignElementType): RenderedViewLine {\r\n\treturn new RenderedViewLine(domNode, renderLineInput, characterMapping, containsRTL, containsForeignElements);\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as browser from 'vs/base/browser/browser';\r\nimport { IPointerHandlerHelper } from 'vs/editor/browser/controller/mouseHandler';\r\nimport { IMouseTarget, MouseTargetType } from 'vs/editor/browser/editorBrowser';\r\nimport { ClientCoordinates, EditorMouseEvent, EditorPagePosition, PageCoordinates } from 'vs/editor/browser/editorDom';\r\nimport { PartFingerprint, PartFingerprints } from 'vs/editor/browser/view/viewPart';\r\nimport { ViewLine } from 'vs/editor/browser/viewParts/lines/viewLine';\r\nimport { IViewCursorRenderData } from 'vs/editor/browser/viewParts/viewCursors/viewCursor';\r\nimport { EditorLayoutInfo, EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range as EditorRange } from 'vs/editor/common/core/range';\r\nimport { HorizontalPosition } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport { IViewModel } from 'vs/editor/common/viewModel/viewModel';\r\nimport { CursorColumns } from 'vs/editor/common/controller/cursorCommon';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { AtomicTabMoveOperations, Direction } from 'vs/editor/common/controller/cursorAtomicMoveOperations';\r\n\r\nexport interface IViewZoneData {\r\n\tviewZoneId: string;\r\n\tpositionBefore: Position | null;\r\n\tpositionAfter: Position | null;\r\n\tposition: Position;\r\n\tafterLineNumber: number;\r\n}\r\n\r\nexport interface IMarginData {\r\n\tisAfterLines: boolean;\r\n\tglyphMarginLeft: number;\r\n\tglyphMarginWidth: number;\r\n\tlineNumbersWidth: number;\r\n\toffsetX: number;\r\n}\r\n\r\nexport interface IEmptyContentData {\r\n\tisAfterLines: boolean;\r\n\thorizontalDistanceToText?: number;\r\n}\r\n\r\ninterface IETextRange {\r\n\ttext: string;\r\n\tcollapse(start?: boolean): void;\r\n\tduplicate(): IETextRange;\r\n\tmoveToElementText(element: Element): void;\r\n\tmoveToPoint(x: number, y: number): void;\r\n\tparentElement(): Element;\r\n\tsetEndPoint(how: string, SourceRange: IETextRange): void;\r\n}\r\n\r\ndeclare const IETextRange: {\r\n\tprototype: IETextRange;\r\n\tnew(): IETextRange;\r\n};\r\n\r\ninterface IHitTestResult {\r\n\tposition: Position | null;\r\n\thitTarget: Element | null;\r\n}\r\n\r\nexport class PointerHandlerLastRenderData {\r\n\tconstructor(\r\n\t\tpublic readonly lastViewCursorsRenderData: IViewCursorRenderData[],\r\n\t\tpublic readonly lastTextareaPosition: Position | null\r\n\t) { }\r\n}\r\n\r\nexport class MouseTarget implements IMouseTarget {\r\n\r\n\tpublic readonly element: Element | null;\r\n\tpublic readonly type: MouseTargetType;\r\n\tpublic readonly mouseColumn: number;\r\n\tpublic readonly position: Position | null;\r\n\tpublic readonly range: EditorRange | null;\r\n\tpublic readonly detail: any;\r\n\r\n\tconstructor(element: Element | null, type: MouseTargetType, mouseColumn: number = 0, position: Position | null = null, range: EditorRange | null = null, detail: any = null) {\r\n\t\tthis.element = element;\r\n\t\tthis.type = type;\r\n\t\tthis.mouseColumn = mouseColumn;\r\n\t\tthis.position = position;\r\n\t\tif (!range && position) {\r\n\t\t\trange = new EditorRange(position.lineNumber, position.column, position.lineNumber, position.column);\r\n\t\t}\r\n\t\tthis.range = range;\r\n\t\tthis.detail = detail;\r\n\t}\r\n\r\n\tprivate static _typeToString(type: MouseTargetType): string {\r\n\t\tif (type === MouseTargetType.TEXTAREA) {\r\n\t\t\treturn 'TEXTAREA';\r\n\t\t}\r\n\t\tif (type === MouseTargetType.GUTTER_GLYPH_MARGIN) {\r\n\t\t\treturn 'GUTTER_GLYPH_MARGIN';\r\n\t\t}\r\n\t\tif (type === MouseTargetType.GUTTER_LINE_NUMBERS) {\r\n\t\t\treturn 'GUTTER_LINE_NUMBERS';\r\n\t\t}\r\n\t\tif (type === MouseTargetType.GUTTER_LINE_DECORATIONS) {\r\n\t\t\treturn 'GUTTER_LINE_DECORATIONS';\r\n\t\t}\r\n\t\tif (type === MouseTargetType.GUTTER_VIEW_ZONE) {\r\n\t\t\treturn 'GUTTER_VIEW_ZONE';\r\n\t\t}\r\n\t\tif (type === MouseTargetType.CONTENT_TEXT) {\r\n\t\t\treturn 'CONTENT_TEXT';\r\n\t\t}\r\n\t\tif (type === MouseTargetType.CONTENT_EMPTY) {\r\n\t\t\treturn 'CONTENT_EMPTY';\r\n\t\t}\r\n\t\tif (type === MouseTargetType.CONTENT_VIEW_ZONE) {\r\n\t\t\treturn 'CONTENT_VIEW_ZONE';\r\n\t\t}\r\n\t\tif (type === MouseTargetType.CONTENT_WIDGET) {\r\n\t\t\treturn 'CONTENT_WIDGET';\r\n\t\t}\r\n\t\tif (type === MouseTargetType.OVERVIEW_RULER) {\r\n\t\t\treturn 'OVERVIEW_RULER';\r\n\t\t}\r\n\t\tif (type === MouseTargetType.SCROLLBAR) {\r\n\t\t\treturn 'SCROLLBAR';\r\n\t\t}\r\n\t\tif (type === MouseTargetType.OVERLAY_WIDGET) {\r\n\t\t\treturn 'OVERLAY_WIDGET';\r\n\t\t}\r\n\t\treturn 'UNKNOWN';\r\n\t}\r\n\r\n\tpublic static toString(target: IMouseTarget): string {\r\n\t\treturn this._typeToString(target.type) + ': ' + target.position + ' - ' + target.range + ' - ' + target.detail;\r\n\t}\r\n\r\n\tpublic toString(): string {\r\n\t\treturn MouseTarget.toString(this);\r\n\t}\r\n}\r\n\r\nclass ElementPath {\r\n\r\n\tpublic static isTextArea(path: Uint8Array): boolean {\r\n\t\treturn (\r\n\t\t\tpath.length === 2\r\n\t\t\t&& path[0] === PartFingerprint.OverflowGuard\r\n\t\t\t&& path[1] === PartFingerprint.TextArea\r\n\t\t);\r\n\t}\r\n\r\n\tpublic static isChildOfViewLines(path: Uint8Array): boolean {\r\n\t\treturn (\r\n\t\t\tpath.length >= 4\r\n\t\t\t&& path[0] === PartFingerprint.OverflowGuard\r\n\t\t\t&& path[3] === PartFingerprint.ViewLines\r\n\t\t);\r\n\t}\r\n\r\n\tpublic static isStrictChildOfViewLines(path: Uint8Array): boolean {\r\n\t\treturn (\r\n\t\t\tpath.length > 4\r\n\t\t\t&& path[0] === PartFingerprint.OverflowGuard\r\n\t\t\t&& path[3] === PartFingerprint.ViewLines\r\n\t\t);\r\n\t}\r\n\r\n\tpublic static isChildOfScrollableElement(path: Uint8Array): boolean {\r\n\t\treturn (\r\n\t\t\tpath.length >= 2\r\n\t\t\t&& path[0] === PartFingerprint.OverflowGuard\r\n\t\t\t&& path[1] === PartFingerprint.ScrollableElement\r\n\t\t);\r\n\t}\r\n\r\n\tpublic static isChildOfMinimap(path: Uint8Array): boolean {\r\n\t\treturn (\r\n\t\t\tpath.length >= 2\r\n\t\t\t&& path[0] === PartFingerprint.OverflowGuard\r\n\t\t\t&& path[1] === PartFingerprint.Minimap\r\n\t\t);\r\n\t}\r\n\r\n\tpublic static isChildOfContentWidgets(path: Uint8Array): boolean {\r\n\t\treturn (\r\n\t\t\tpath.length >= 4\r\n\t\t\t&& path[0] === PartFingerprint.OverflowGuard\r\n\t\t\t&& path[3] === PartFingerprint.ContentWidgets\r\n\t\t);\r\n\t}\r\n\r\n\tpublic static isChildOfOverflowingContentWidgets(path: Uint8Array): boolean {\r\n\t\treturn (\r\n\t\t\tpath.length >= 1\r\n\t\t\t&& path[0] === PartFingerprint.OverflowingContentWidgets\r\n\t\t);\r\n\t}\r\n\r\n\tpublic static isChildOfOverlayWidgets(path: Uint8Array): boolean {\r\n\t\treturn (\r\n\t\t\tpath.length >= 2\r\n\t\t\t&& path[0] === PartFingerprint.OverflowGuard\r\n\t\t\t&& path[1] === PartFingerprint.OverlayWidgets\r\n\t\t);\r\n\t}\r\n}\r\n\r\nexport class HitTestContext {\r\n\r\n\tpublic readonly model: IViewModel;\r\n\tpublic readonly layoutInfo: EditorLayoutInfo;\r\n\tpublic readonly viewDomNode: HTMLElement;\r\n\tpublic readonly lineHeight: number;\r\n\tpublic readonly stickyTabStops: boolean;\r\n\tpublic readonly typicalHalfwidthCharacterWidth: number;\r\n\tpublic readonly lastRenderData: PointerHandlerLastRenderData;\r\n\r\n\tprivate readonly _context: ViewContext;\r\n\tprivate readonly _viewHelper: IPointerHandlerHelper;\r\n\r\n\tconstructor(context: ViewContext, viewHelper: IPointerHandlerHelper, lastRenderData: PointerHandlerLastRenderData) {\r\n\t\tthis.model = context.model;\r\n\t\tconst options = context.configuration.options;\r\n\t\tthis.layoutInfo = options.get(EditorOption.layoutInfo);\r\n\t\tthis.viewDomNode = viewHelper.viewDomNode;\r\n\t\tthis.lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tthis.stickyTabStops = options.get(EditorOption.stickyTabStops);\r\n\t\tthis.typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth;\r\n\t\tthis.lastRenderData = lastRenderData;\r\n\t\tthis._context = context;\r\n\t\tthis._viewHelper = viewHelper;\r\n\t}\r\n\r\n\tpublic getZoneAtCoord(mouseVerticalOffset: number): IViewZoneData | null {\r\n\t\treturn HitTestContext.getZoneAtCoord(this._context, mouseVerticalOffset);\r\n\t}\r\n\r\n\tpublic static getZoneAtCoord(context: ViewContext, mouseVerticalOffset: number): IViewZoneData | null {\r\n\t\t// The target is either a view zone or the empty space after the last view-line\r\n\t\tconst viewZoneWhitespace = context.viewLayout.getWhitespaceAtVerticalOffset(mouseVerticalOffset);\r\n\r\n\t\tif (viewZoneWhitespace) {\r\n\t\t\tconst viewZoneMiddle = viewZoneWhitespace.verticalOffset + viewZoneWhitespace.height / 2;\r\n\t\t\tconst lineCount = context.model.getLineCount();\r\n\t\t\tlet positionBefore: Position | null = null;\r\n\t\t\tlet position: Position | null;\r\n\t\t\tlet positionAfter: Position | null = null;\r\n\r\n\t\t\tif (viewZoneWhitespace.afterLineNumber !== lineCount) {\r\n\t\t\t\t// There are more lines after this view zone\r\n\t\t\t\tpositionAfter = new Position(viewZoneWhitespace.afterLineNumber + 1, 1);\r\n\t\t\t}\r\n\t\t\tif (viewZoneWhitespace.afterLineNumber > 0) {\r\n\t\t\t\t// There are more lines above this view zone\r\n\t\t\t\tpositionBefore = new Position(viewZoneWhitespace.afterLineNumber, context.model.getLineMaxColumn(viewZoneWhitespace.afterLineNumber));\r\n\t\t\t}\r\n\r\n\t\t\tif (positionAfter === null) {\r\n\t\t\t\tposition = positionBefore;\r\n\t\t\t} else if (positionBefore === null) {\r\n\t\t\t\tposition = positionAfter;\r\n\t\t\t} else if (mouseVerticalOffset < viewZoneMiddle) {\r\n\t\t\t\tposition = positionBefore;\r\n\t\t\t} else {\r\n\t\t\t\tposition = positionAfter;\r\n\t\t\t}\r\n\r\n\t\t\treturn {\r\n\t\t\t\tviewZoneId: viewZoneWhitespace.id,\r\n\t\t\t\tafterLineNumber: viewZoneWhitespace.afterLineNumber,\r\n\t\t\t\tpositionBefore: positionBefore,\r\n\t\t\t\tpositionAfter: positionAfter,\r\n\t\t\t\tposition: position!\r\n\t\t\t};\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic getFullLineRangeAtCoord(mouseVerticalOffset: number): { range: EditorRange; isAfterLines: boolean; } {\r\n\t\tif (this._context.viewLayout.isAfterLines(mouseVerticalOffset)) {\r\n\t\t\t// Below the last line\r\n\t\t\tconst lineNumber = this._context.model.getLineCount();\r\n\t\t\tconst maxLineColumn = this._context.model.getLineMaxColumn(lineNumber);\r\n\t\t\treturn {\r\n\t\t\t\trange: new EditorRange(lineNumber, maxLineColumn, lineNumber, maxLineColumn),\r\n\t\t\t\tisAfterLines: true\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tconst lineNumber = this._context.viewLayout.getLineNumberAtVerticalOffset(mouseVerticalOffset);\r\n\t\tconst maxLineColumn = this._context.model.getLineMaxColumn(lineNumber);\r\n\t\treturn {\r\n\t\t\trange: new EditorRange(lineNumber, 1, lineNumber, maxLineColumn),\r\n\t\t\tisAfterLines: false\r\n\t\t};\r\n\t}\r\n\r\n\tpublic getLineNumberAtVerticalOffset(mouseVerticalOffset: number): number {\r\n\t\treturn this._context.viewLayout.getLineNumberAtVerticalOffset(mouseVerticalOffset);\r\n\t}\r\n\r\n\tpublic isAfterLines(mouseVerticalOffset: number): boolean {\r\n\t\treturn this._context.viewLayout.isAfterLines(mouseVerticalOffset);\r\n\t}\r\n\r\n\tpublic isInTopPadding(mouseVerticalOffset: number): boolean {\r\n\t\treturn this._context.viewLayout.isInTopPadding(mouseVerticalOffset);\r\n\t}\r\n\r\n\tpublic isInBottomPadding(mouseVerticalOffset: number): boolean {\r\n\t\treturn this._context.viewLayout.isInBottomPadding(mouseVerticalOffset);\r\n\t}\r\n\r\n\tpublic getVerticalOffsetForLineNumber(lineNumber: number): number {\r\n\t\treturn this._context.viewLayout.getVerticalOffsetForLineNumber(lineNumber);\r\n\t}\r\n\r\n\tpublic findAttribute(element: Element, attr: string): string | null {\r\n\t\treturn HitTestContext._findAttribute(element, attr, this._viewHelper.viewDomNode);\r\n\t}\r\n\r\n\tprivate static _findAttribute(element: Element, attr: string, stopAt: Element): string | null {\r\n\t\twhile (element && element !== document.body) {\r\n\t\t\tif (element.hasAttribute && element.hasAttribute(attr)) {\r\n\t\t\t\treturn element.getAttribute(attr);\r\n\t\t\t}\r\n\t\t\tif (element === stopAt) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t\telement = element.parentNode;\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic getLineWidth(lineNumber: number): number {\r\n\t\treturn this._viewHelper.getLineWidth(lineNumber);\r\n\t}\r\n\r\n\tpublic visibleRangeForPosition(lineNumber: number, column: number): HorizontalPosition | null {\r\n\t\treturn this._viewHelper.visibleRangeForPosition(lineNumber, column);\r\n\t}\r\n\r\n\tpublic getPositionFromDOMInfo(spanNode: HTMLElement, offset: number): Position | null {\r\n\t\treturn this._viewHelper.getPositionFromDOMInfo(spanNode, offset);\r\n\t}\r\n\r\n\tpublic getCurrentScrollTop(): number {\r\n\t\treturn this._context.viewLayout.getCurrentScrollTop();\r\n\t}\r\n\r\n\tpublic getCurrentScrollLeft(): number {\r\n\t\treturn this._context.viewLayout.getCurrentScrollLeft();\r\n\t}\r\n}\r\n\r\nabstract class BareHitTestRequest {\r\n\r\n\tpublic readonly editorPos: EditorPagePosition;\r\n\tpublic readonly pos: PageCoordinates;\r\n\tpublic readonly mouseVerticalOffset: number;\r\n\tpublic readonly isInMarginArea: boolean;\r\n\tpublic readonly isInContentArea: boolean;\r\n\tpublic readonly mouseContentHorizontalOffset: number;\r\n\r\n\tprotected readonly mouseColumn: number;\r\n\r\n\tconstructor(ctx: HitTestContext, editorPos: EditorPagePosition, pos: PageCoordinates) {\r\n\t\tthis.editorPos = editorPos;\r\n\t\tthis.pos = pos;\r\n\r\n\t\tthis.mouseVerticalOffset = Math.max(0, ctx.getCurrentScrollTop() + pos.y - editorPos.y);\r\n\t\tthis.mouseContentHorizontalOffset = ctx.getCurrentScrollLeft() + pos.x - editorPos.x - ctx.layoutInfo.contentLeft;\r\n\t\tthis.isInMarginArea = (pos.x - editorPos.x < ctx.layoutInfo.contentLeft && pos.x - editorPos.x >= ctx.layoutInfo.glyphMarginLeft);\r\n\t\tthis.isInContentArea = !this.isInMarginArea;\r\n\t\tthis.mouseColumn = Math.max(0, MouseTargetFactory._getMouseColumn(this.mouseContentHorizontalOffset, ctx.typicalHalfwidthCharacterWidth));\r\n\t}\r\n}\r\n\r\nclass HitTestRequest extends BareHitTestRequest {\r\n\tprivate readonly _ctx: HitTestContext;\r\n\tpublic readonly target: Element | null;\r\n\tpublic readonly targetPath: Uint8Array;\r\n\r\n\tconstructor(ctx: HitTestContext, editorPos: EditorPagePosition, pos: PageCoordinates, target: Element | null) {\r\n\t\tsuper(ctx, editorPos, pos);\r\n\t\tthis._ctx = ctx;\r\n\r\n\t\tif (target) {\r\n\t\t\tthis.target = target;\r\n\t\t\tthis.targetPath = PartFingerprints.collect(target, ctx.viewDomNode);\r\n\t\t} else {\r\n\t\t\tthis.target = null;\r\n\t\t\tthis.targetPath = new Uint8Array(0);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic toString(): string {\r\n\t\treturn `pos(${this.pos.x},${this.pos.y}), editorPos(${this.editorPos.x},${this.editorPos.y}), mouseVerticalOffset: ${this.mouseVerticalOffset}, mouseContentHorizontalOffset: ${this.mouseContentHorizontalOffset}\\n\\ttarget: ${this.target ? (this.target).outerHTML : null}`;\r\n\t}\r\n\r\n\tpublic fulfill(type: MouseTargetType, position: Position | null = null, range: EditorRange | null = null, detail: any = null): MouseTarget {\r\n\t\tlet mouseColumn = this.mouseColumn;\r\n\t\tif (position && position.column < this._ctx.model.getLineMaxColumn(position.lineNumber)) {\r\n\t\t\t// Most likely, the line contains foreign decorations...\r\n\t\t\tmouseColumn = CursorColumns.visibleColumnFromColumn(this._ctx.model.getLineContent(position.lineNumber), position.column, this._ctx.model.getTextModelOptions().tabSize) + 1;\r\n\t\t}\r\n\t\treturn new MouseTarget(this.target, type, mouseColumn, position, range, detail);\r\n\t}\r\n\r\n\tpublic withTarget(target: Element | null): HitTestRequest {\r\n\t\treturn new HitTestRequest(this._ctx, this.editorPos, this.pos, target);\r\n\t}\r\n}\r\n\r\ninterface ResolvedHitTestRequest extends HitTestRequest {\r\n\treadonly target: Element;\r\n}\r\n\r\nconst EMPTY_CONTENT_AFTER_LINES: IEmptyContentData = { isAfterLines: true };\r\n\r\nfunction createEmptyContentDataInLines(horizontalDistanceToText: number): IEmptyContentData {\r\n\treturn {\r\n\t\tisAfterLines: false,\r\n\t\thorizontalDistanceToText: horizontalDistanceToText\r\n\t};\r\n}\r\n\r\nexport class MouseTargetFactory {\r\n\r\n\tprivate readonly _context: ViewContext;\r\n\tprivate readonly _viewHelper: IPointerHandlerHelper;\r\n\r\n\tconstructor(context: ViewContext, viewHelper: IPointerHandlerHelper) {\r\n\t\tthis._context = context;\r\n\t\tthis._viewHelper = viewHelper;\r\n\t}\r\n\r\n\tpublic mouseTargetIsWidget(e: EditorMouseEvent): boolean {\r\n\t\tconst t = e.target;\r\n\t\tconst path = PartFingerprints.collect(t, this._viewHelper.viewDomNode);\r\n\r\n\t\t// Is it a content widget?\r\n\t\tif (ElementPath.isChildOfContentWidgets(path) || ElementPath.isChildOfOverflowingContentWidgets(path)) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\t// Is it an overlay widget?\r\n\t\tif (ElementPath.isChildOfOverlayWidgets(path)) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic createMouseTarget(lastRenderData: PointerHandlerLastRenderData, editorPos: EditorPagePosition, pos: PageCoordinates, target: HTMLElement | null): IMouseTarget {\r\n\t\tconst ctx = new HitTestContext(this._context, this._viewHelper, lastRenderData);\r\n\t\tconst request = new HitTestRequest(ctx, editorPos, pos, target);\r\n\t\ttry {\r\n\t\t\tconst r = MouseTargetFactory._createMouseTarget(ctx, request, false);\r\n\t\t\t// console.log(r.toString());\r\n\t\t\treturn r;\r\n\t\t} catch (err) {\r\n\t\t\t// console.log(err);\r\n\t\t\treturn request.fulfill(MouseTargetType.UNKNOWN);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static _createMouseTarget(ctx: HitTestContext, request: HitTestRequest, domHitTestExecuted: boolean): MouseTarget {\r\n\r\n\t\t// console.log(`${domHitTestExecuted ? '=>' : ''}CAME IN REQUEST: ${request}`);\r\n\r\n\t\t// First ensure the request has a target\r\n\t\tif (request.target === null) {\r\n\t\t\tif (domHitTestExecuted) {\r\n\t\t\t\t// Still no target... and we have already executed hit test...\r\n\t\t\t\treturn request.fulfill(MouseTargetType.UNKNOWN);\r\n\t\t\t}\r\n\r\n\t\t\tconst hitTestResult = MouseTargetFactory._doHitTest(ctx, request);\r\n\r\n\t\t\tif (hitTestResult.position) {\r\n\t\t\t\treturn MouseTargetFactory.createMouseTargetFromHitTestPosition(ctx, request, hitTestResult.position.lineNumber, hitTestResult.position.column);\r\n\t\t\t}\r\n\r\n\t\t\treturn this._createMouseTarget(ctx, request.withTarget(hitTestResult.hitTarget), true);\r\n\t\t}\r\n\r\n\t\t// we know for a fact that request.target is not null\r\n\t\tconst resolvedRequest = request;\r\n\r\n\t\tlet result: MouseTarget | null = null;\r\n\r\n\t\tresult = result || MouseTargetFactory._hitTestContentWidget(ctx, resolvedRequest);\r\n\t\tresult = result || MouseTargetFactory._hitTestOverlayWidget(ctx, resolvedRequest);\r\n\t\tresult = result || MouseTargetFactory._hitTestMinimap(ctx, resolvedRequest);\r\n\t\tresult = result || MouseTargetFactory._hitTestScrollbarSlider(ctx, resolvedRequest);\r\n\t\tresult = result || MouseTargetFactory._hitTestViewZone(ctx, resolvedRequest);\r\n\t\tresult = result || MouseTargetFactory._hitTestMargin(ctx, resolvedRequest);\r\n\t\tresult = result || MouseTargetFactory._hitTestViewCursor(ctx, resolvedRequest);\r\n\t\tresult = result || MouseTargetFactory._hitTestTextArea(ctx, resolvedRequest);\r\n\t\tresult = result || MouseTargetFactory._hitTestViewLines(ctx, resolvedRequest, domHitTestExecuted);\r\n\t\tresult = result || MouseTargetFactory._hitTestScrollbar(ctx, resolvedRequest);\r\n\r\n\t\treturn (result || request.fulfill(MouseTargetType.UNKNOWN));\r\n\t}\r\n\r\n\tprivate static _hitTestContentWidget(ctx: HitTestContext, request: ResolvedHitTestRequest): MouseTarget | null {\r\n\t\t// Is it a content widget?\r\n\t\tif (ElementPath.isChildOfContentWidgets(request.targetPath) || ElementPath.isChildOfOverflowingContentWidgets(request.targetPath)) {\r\n\t\t\tconst widgetId = ctx.findAttribute(request.target, 'widgetId');\r\n\t\t\tif (widgetId) {\r\n\t\t\t\treturn request.fulfill(MouseTargetType.CONTENT_WIDGET, null, null, widgetId);\r\n\t\t\t} else {\r\n\t\t\t\treturn request.fulfill(MouseTargetType.UNKNOWN);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate static _hitTestOverlayWidget(ctx: HitTestContext, request: ResolvedHitTestRequest): MouseTarget | null {\r\n\t\t// Is it an overlay widget?\r\n\t\tif (ElementPath.isChildOfOverlayWidgets(request.targetPath)) {\r\n\t\t\tconst widgetId = ctx.findAttribute(request.target, 'widgetId');\r\n\t\t\tif (widgetId) {\r\n\t\t\t\treturn request.fulfill(MouseTargetType.OVERLAY_WIDGET, null, null, widgetId);\r\n\t\t\t} else {\r\n\t\t\t\treturn request.fulfill(MouseTargetType.UNKNOWN);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate static _hitTestViewCursor(ctx: HitTestContext, request: ResolvedHitTestRequest): MouseTarget | null {\r\n\r\n\t\tif (request.target) {\r\n\t\t\t// Check if we've hit a painted cursor\r\n\t\t\tconst lastViewCursorsRenderData = ctx.lastRenderData.lastViewCursorsRenderData;\r\n\r\n\t\t\tfor (const d of lastViewCursorsRenderData) {\r\n\r\n\t\t\t\tif (request.target === d.domNode) {\r\n\t\t\t\t\treturn request.fulfill(MouseTargetType.CONTENT_TEXT, d.position);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (request.isInContentArea) {\r\n\t\t\t// Edge has a bug when hit-testing the exact position of a cursor,\r\n\t\t\t// instead of returning the correct dom node, it returns the\r\n\t\t\t// first or last rendered view line dom node, therefore help it out\r\n\t\t\t// and first check if we are on top of a cursor\r\n\r\n\t\t\tconst lastViewCursorsRenderData = ctx.lastRenderData.lastViewCursorsRenderData;\r\n\t\t\tconst mouseContentHorizontalOffset = request.mouseContentHorizontalOffset;\r\n\t\t\tconst mouseVerticalOffset = request.mouseVerticalOffset;\r\n\r\n\t\t\tfor (const d of lastViewCursorsRenderData) {\r\n\r\n\t\t\t\tif (mouseContentHorizontalOffset < d.contentLeft) {\r\n\t\t\t\t\t// mouse position is to the left of the cursor\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\tif (mouseContentHorizontalOffset > d.contentLeft + d.width) {\r\n\t\t\t\t\t// mouse position is to the right of the cursor\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst cursorVerticalOffset = ctx.getVerticalOffsetForLineNumber(d.position.lineNumber);\r\n\r\n\t\t\t\tif (\r\n\t\t\t\t\tcursorVerticalOffset <= mouseVerticalOffset\r\n\t\t\t\t\t&& mouseVerticalOffset <= cursorVerticalOffset + d.height\r\n\t\t\t\t) {\r\n\t\t\t\t\treturn request.fulfill(MouseTargetType.CONTENT_TEXT, d.position);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate static _hitTestViewZone(ctx: HitTestContext, request: ResolvedHitTestRequest): MouseTarget | null {\r\n\t\tconst viewZoneData = ctx.getZoneAtCoord(request.mouseVerticalOffset);\r\n\t\tif (viewZoneData) {\r\n\t\t\tconst mouseTargetType = (request.isInContentArea ? MouseTargetType.CONTENT_VIEW_ZONE : MouseTargetType.GUTTER_VIEW_ZONE);\r\n\t\t\treturn request.fulfill(mouseTargetType, viewZoneData.position, null, viewZoneData);\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate static _hitTestTextArea(ctx: HitTestContext, request: ResolvedHitTestRequest): MouseTarget | null {\r\n\t\t// Is it the textarea?\r\n\t\tif (ElementPath.isTextArea(request.targetPath)) {\r\n\t\t\tif (ctx.lastRenderData.lastTextareaPosition) {\r\n\t\t\t\treturn request.fulfill(MouseTargetType.CONTENT_TEXT, ctx.lastRenderData.lastTextareaPosition);\r\n\t\t\t}\r\n\t\t\treturn request.fulfill(MouseTargetType.TEXTAREA, ctx.lastRenderData.lastTextareaPosition);\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate static _hitTestMargin(ctx: HitTestContext, request: ResolvedHitTestRequest): MouseTarget | null {\r\n\t\tif (request.isInMarginArea) {\r\n\t\t\tconst res = ctx.getFullLineRangeAtCoord(request.mouseVerticalOffset);\r\n\t\t\tconst pos = res.range.getStartPosition();\r\n\t\t\tlet offset = Math.abs(request.pos.x - request.editorPos.x);\r\n\t\t\tconst detail: IMarginData = {\r\n\t\t\t\tisAfterLines: res.isAfterLines,\r\n\t\t\t\tglyphMarginLeft: ctx.layoutInfo.glyphMarginLeft,\r\n\t\t\t\tglyphMarginWidth: ctx.layoutInfo.glyphMarginWidth,\r\n\t\t\t\tlineNumbersWidth: ctx.layoutInfo.lineNumbersWidth,\r\n\t\t\t\toffsetX: offset\r\n\t\t\t};\r\n\r\n\t\t\toffset -= ctx.layoutInfo.glyphMarginLeft;\r\n\r\n\t\t\tif (offset <= ctx.layoutInfo.glyphMarginWidth) {\r\n\t\t\t\t// On the glyph margin\r\n\t\t\t\treturn request.fulfill(MouseTargetType.GUTTER_GLYPH_MARGIN, pos, res.range, detail);\r\n\t\t\t}\r\n\t\t\toffset -= ctx.layoutInfo.glyphMarginWidth;\r\n\r\n\t\t\tif (offset <= ctx.layoutInfo.lineNumbersWidth) {\r\n\t\t\t\t// On the line numbers\r\n\t\t\t\treturn request.fulfill(MouseTargetType.GUTTER_LINE_NUMBERS, pos, res.range, detail);\r\n\t\t\t}\r\n\t\t\toffset -= ctx.layoutInfo.lineNumbersWidth;\r\n\r\n\t\t\t// On the line decorations\r\n\t\t\treturn request.fulfill(MouseTargetType.GUTTER_LINE_DECORATIONS, pos, res.range, detail);\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate static _hitTestViewLines(ctx: HitTestContext, request: ResolvedHitTestRequest, domHitTestExecuted: boolean): MouseTarget | null {\r\n\t\tif (!ElementPath.isChildOfViewLines(request.targetPath)) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (ctx.isInTopPadding(request.mouseVerticalOffset)) {\r\n\t\t\treturn request.fulfill(MouseTargetType.CONTENT_EMPTY, new Position(1, 1), undefined, EMPTY_CONTENT_AFTER_LINES);\r\n\t\t}\r\n\r\n\t\t// Check if it is below any lines and any view zones\r\n\t\tif (ctx.isAfterLines(request.mouseVerticalOffset) || ctx.isInBottomPadding(request.mouseVerticalOffset)) {\r\n\t\t\t// This most likely indicates it happened after the last view-line\r\n\t\t\tconst lineCount = ctx.model.getLineCount();\r\n\t\t\tconst maxLineColumn = ctx.model.getLineMaxColumn(lineCount);\r\n\t\t\treturn request.fulfill(MouseTargetType.CONTENT_EMPTY, new Position(lineCount, maxLineColumn), undefined, EMPTY_CONTENT_AFTER_LINES);\r\n\t\t}\r\n\r\n\t\tif (domHitTestExecuted) {\r\n\t\t\t// Check if we are hitting a view-line (can happen in the case of inline decorations on empty lines)\r\n\t\t\t// See https://github.com/microsoft/vscode/issues/46942\r\n\t\t\tif (ElementPath.isStrictChildOfViewLines(request.targetPath)) {\r\n\t\t\t\tconst lineNumber = ctx.getLineNumberAtVerticalOffset(request.mouseVerticalOffset);\r\n\t\t\t\tif (ctx.model.getLineLength(lineNumber) === 0) {\r\n\t\t\t\t\tconst lineWidth = ctx.getLineWidth(lineNumber);\r\n\t\t\t\t\tconst detail = createEmptyContentDataInLines(request.mouseContentHorizontalOffset - lineWidth);\r\n\t\t\t\t\treturn request.fulfill(MouseTargetType.CONTENT_EMPTY, new Position(lineNumber, 1), undefined, detail);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst lineWidth = ctx.getLineWidth(lineNumber);\r\n\t\t\t\tif (request.mouseContentHorizontalOffset >= lineWidth) {\r\n\t\t\t\t\tconst detail = createEmptyContentDataInLines(request.mouseContentHorizontalOffset - lineWidth);\r\n\t\t\t\t\tconst pos = new Position(lineNumber, ctx.model.getLineMaxColumn(lineNumber));\r\n\t\t\t\t\treturn request.fulfill(MouseTargetType.CONTENT_EMPTY, pos, undefined, detail);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// We have already executed hit test...\r\n\t\t\treturn request.fulfill(MouseTargetType.UNKNOWN);\r\n\t\t}\r\n\r\n\t\tconst hitTestResult = MouseTargetFactory._doHitTest(ctx, request);\r\n\r\n\t\tif (hitTestResult.position) {\r\n\t\t\treturn MouseTargetFactory.createMouseTargetFromHitTestPosition(ctx, request, hitTestResult.position.lineNumber, hitTestResult.position.column);\r\n\t\t}\r\n\r\n\t\treturn this._createMouseTarget(ctx, request.withTarget(hitTestResult.hitTarget), true);\r\n\t}\r\n\r\n\tprivate static _hitTestMinimap(ctx: HitTestContext, request: ResolvedHitTestRequest): MouseTarget | null {\r\n\t\tif (ElementPath.isChildOfMinimap(request.targetPath)) {\r\n\t\t\tconst possibleLineNumber = ctx.getLineNumberAtVerticalOffset(request.mouseVerticalOffset);\r\n\t\t\tconst maxColumn = ctx.model.getLineMaxColumn(possibleLineNumber);\r\n\t\t\treturn request.fulfill(MouseTargetType.SCROLLBAR, new Position(possibleLineNumber, maxColumn));\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate static _hitTestScrollbarSlider(ctx: HitTestContext, request: ResolvedHitTestRequest): MouseTarget | null {\r\n\t\tif (ElementPath.isChildOfScrollableElement(request.targetPath)) {\r\n\t\t\tif (request.target && request.target.nodeType === 1) {\r\n\t\t\t\tconst className = request.target.className;\r\n\t\t\t\tif (className && /\\b(slider|scrollbar)\\b/.test(className)) {\r\n\t\t\t\t\tconst possibleLineNumber = ctx.getLineNumberAtVerticalOffset(request.mouseVerticalOffset);\r\n\t\t\t\t\tconst maxColumn = ctx.model.getLineMaxColumn(possibleLineNumber);\r\n\t\t\t\t\treturn request.fulfill(MouseTargetType.SCROLLBAR, new Position(possibleLineNumber, maxColumn));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate static _hitTestScrollbar(ctx: HitTestContext, request: ResolvedHitTestRequest): MouseTarget | null {\r\n\t\t// Is it the overview ruler?\r\n\t\t// Is it a child of the scrollable element?\r\n\t\tif (ElementPath.isChildOfScrollableElement(request.targetPath)) {\r\n\t\t\tconst possibleLineNumber = ctx.getLineNumberAtVerticalOffset(request.mouseVerticalOffset);\r\n\t\t\tconst maxColumn = ctx.model.getLineMaxColumn(possibleLineNumber);\r\n\t\t\treturn request.fulfill(MouseTargetType.SCROLLBAR, new Position(possibleLineNumber, maxColumn));\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic getMouseColumn(editorPos: EditorPagePosition, pos: PageCoordinates): number {\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\t\tconst mouseContentHorizontalOffset = this._context.viewLayout.getCurrentScrollLeft() + pos.x - editorPos.x - layoutInfo.contentLeft;\r\n\t\treturn MouseTargetFactory._getMouseColumn(mouseContentHorizontalOffset, options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth);\r\n\t}\r\n\r\n\tpublic static _getMouseColumn(mouseContentHorizontalOffset: number, typicalHalfwidthCharacterWidth: number): number {\r\n\t\tif (mouseContentHorizontalOffset < 0) {\r\n\t\t\treturn 1;\r\n\t\t}\r\n\t\tconst chars = Math.round(mouseContentHorizontalOffset / typicalHalfwidthCharacterWidth);\r\n\t\treturn (chars + 1);\r\n\t}\r\n\r\n\tprivate static createMouseTargetFromHitTestPosition(ctx: HitTestContext, request: HitTestRequest, lineNumber: number, column: number): MouseTarget {\r\n\t\tconst pos = new Position(lineNumber, column);\r\n\r\n\t\tconst lineWidth = ctx.getLineWidth(lineNumber);\r\n\r\n\t\tif (request.mouseContentHorizontalOffset > lineWidth) {\r\n\t\t\tif (browser.isEdgeLegacy && pos.column === 1) {\r\n\t\t\t\t// See https://github.com/microsoft/vscode/issues/10875\r\n\t\t\t\tconst detail = createEmptyContentDataInLines(request.mouseContentHorizontalOffset - lineWidth);\r\n\t\t\t\treturn request.fulfill(MouseTargetType.CONTENT_EMPTY, new Position(lineNumber, ctx.model.getLineMaxColumn(lineNumber)), undefined, detail);\r\n\t\t\t}\r\n\t\t\tconst detail = createEmptyContentDataInLines(request.mouseContentHorizontalOffset - lineWidth);\r\n\t\t\treturn request.fulfill(MouseTargetType.CONTENT_EMPTY, pos, undefined, detail);\r\n\t\t}\r\n\r\n\t\tconst visibleRange = ctx.visibleRangeForPosition(lineNumber, column);\r\n\r\n\t\tif (!visibleRange) {\r\n\t\t\treturn request.fulfill(MouseTargetType.UNKNOWN, pos);\r\n\t\t}\r\n\r\n\t\tconst columnHorizontalOffset = visibleRange.left;\r\n\r\n\t\tif (request.mouseContentHorizontalOffset === columnHorizontalOffset) {\r\n\t\t\treturn request.fulfill(MouseTargetType.CONTENT_TEXT, pos);\r\n\t\t}\r\n\r\n\t\t// Let's define a, b, c and check if the offset is in between them...\r\n\t\tinterface OffsetColumn { offset: number; column: number; }\r\n\r\n\t\tconst points: OffsetColumn[] = [];\r\n\t\tpoints.push({ offset: visibleRange.left, column: column });\r\n\t\tif (column > 1) {\r\n\t\t\tconst visibleRange = ctx.visibleRangeForPosition(lineNumber, column - 1);\r\n\t\t\tif (visibleRange) {\r\n\t\t\t\tpoints.push({ offset: visibleRange.left, column: column - 1 });\r\n\t\t\t}\r\n\t\t}\r\n\t\tconst lineMaxColumn = ctx.model.getLineMaxColumn(lineNumber);\r\n\t\tif (column < lineMaxColumn) {\r\n\t\t\tconst visibleRange = ctx.visibleRangeForPosition(lineNumber, column + 1);\r\n\t\t\tif (visibleRange) {\r\n\t\t\t\tpoints.push({ offset: visibleRange.left, column: column + 1 });\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpoints.sort((a, b) => a.offset - b.offset);\r\n\r\n\t\tfor (let i = 1; i < points.length; i++) {\r\n\t\t\tconst prev = points[i - 1];\r\n\t\t\tconst curr = points[i];\r\n\t\t\tif (prev.offset <= request.mouseContentHorizontalOffset && request.mouseContentHorizontalOffset <= curr.offset) {\r\n\t\t\t\tconst rng = new EditorRange(lineNumber, prev.column, lineNumber, curr.column);\r\n\t\t\t\treturn request.fulfill(MouseTargetType.CONTENT_TEXT, pos, rng);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn request.fulfill(MouseTargetType.CONTENT_TEXT, pos);\r\n\t}\r\n\r\n\t/**\r\n\t * Most probably WebKit browsers and Edge\r\n\t */\r\n\tprivate static _doHitTestWithCaretRangeFromPoint(ctx: HitTestContext, request: BareHitTestRequest): IHitTestResult {\r\n\r\n\t\t// In Chrome, especially on Linux it is possible to click between lines,\r\n\t\t// so try to adjust the `hity` below so that it lands in the center of a line\r\n\t\tconst lineNumber = ctx.getLineNumberAtVerticalOffset(request.mouseVerticalOffset);\r\n\t\tconst lineVerticalOffset = ctx.getVerticalOffsetForLineNumber(lineNumber);\r\n\t\tconst lineCenteredVerticalOffset = lineVerticalOffset + Math.floor(ctx.lineHeight / 2);\r\n\t\tlet adjustedPageY = request.pos.y + (lineCenteredVerticalOffset - request.mouseVerticalOffset);\r\n\r\n\t\tif (adjustedPageY <= request.editorPos.y) {\r\n\t\t\tadjustedPageY = request.editorPos.y + 1;\r\n\t\t}\r\n\t\tif (adjustedPageY >= request.editorPos.y + ctx.layoutInfo.height) {\r\n\t\t\tadjustedPageY = request.editorPos.y + ctx.layoutInfo.height - 1;\r\n\t\t}\r\n\r\n\t\tconst adjustedPage = new PageCoordinates(request.pos.x, adjustedPageY);\r\n\r\n\t\tconst r = this._actualDoHitTestWithCaretRangeFromPoint(ctx, adjustedPage.toClientCoordinates());\r\n\t\tif (r.position) {\r\n\t\t\treturn r;\r\n\t\t}\r\n\r\n\t\t// Also try to hit test without the adjustment (for the edge cases that we are near the top or bottom)\r\n\t\treturn this._actualDoHitTestWithCaretRangeFromPoint(ctx, request.pos.toClientCoordinates());\r\n\t}\r\n\r\n\tprivate static _actualDoHitTestWithCaretRangeFromPoint(ctx: HitTestContext, coords: ClientCoordinates): IHitTestResult {\r\n\t\tconst shadowRoot = dom.getShadowRoot(ctx.viewDomNode);\r\n\t\tlet range: Range;\r\n\t\tif (shadowRoot) {\r\n\t\t\tif (typeof shadowRoot.caretRangeFromPoint === 'undefined') {\r\n\t\t\t\trange = shadowCaretRangeFromPoint(shadowRoot, coords.clientX, coords.clientY);\r\n\t\t\t} else {\r\n\t\t\t\trange = shadowRoot.caretRangeFromPoint(coords.clientX, coords.clientY);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\trange = document.caretRangeFromPoint(coords.clientX, coords.clientY);\r\n\t\t}\r\n\r\n\t\tif (!range || !range.startContainer) {\r\n\t\t\treturn {\r\n\t\t\t\tposition: null,\r\n\t\t\t\thitTarget: null\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\t// Chrome always hits a TEXT_NODE, while Edge sometimes hits a token span\r\n\t\tconst startContainer = range.startContainer;\r\n\t\tlet hitTarget: HTMLElement | null = null;\r\n\r\n\t\tif (startContainer.nodeType === startContainer.TEXT_NODE) {\r\n\t\t\t// startContainer is expected to be the token text\r\n\t\t\tconst parent1 = startContainer.parentNode; // expected to be the token span\r\n\t\t\tconst parent2 = parent1 ? parent1.parentNode : null; // expected to be the view line container span\r\n\t\t\tconst parent3 = parent2 ? parent2.parentNode : null; // expected to be the view line div\r\n\t\t\tconst parent3ClassName = parent3 && parent3.nodeType === parent3.ELEMENT_NODE ? (parent3).className : null;\r\n\r\n\t\t\tif (parent3ClassName === ViewLine.CLASS_NAME) {\r\n\t\t\t\tconst p = ctx.getPositionFromDOMInfo(parent1, range.startOffset);\r\n\t\t\t\treturn {\r\n\t\t\t\t\tposition: p,\r\n\t\t\t\t\thitTarget: null\r\n\t\t\t\t};\r\n\t\t\t} else {\r\n\t\t\t\thitTarget = startContainer.parentNode;\r\n\t\t\t}\r\n\t\t} else if (startContainer.nodeType === startContainer.ELEMENT_NODE) {\r\n\t\t\t// startContainer is expected to be the token span\r\n\t\t\tconst parent1 = startContainer.parentNode; // expected to be the view line container span\r\n\t\t\tconst parent2 = parent1 ? parent1.parentNode : null; // expected to be the view line div\r\n\t\t\tconst parent2ClassName = parent2 && parent2.nodeType === parent2.ELEMENT_NODE ? (parent2).className : null;\r\n\r\n\t\t\tif (parent2ClassName === ViewLine.CLASS_NAME) {\r\n\t\t\t\tconst p = ctx.getPositionFromDOMInfo(startContainer, (startContainer).textContent!.length);\r\n\t\t\t\treturn {\r\n\t\t\t\t\tposition: p,\r\n\t\t\t\t\thitTarget: null\r\n\t\t\t\t};\r\n\t\t\t} else {\r\n\t\t\t\thitTarget = startContainer;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tposition: null,\r\n\t\t\thitTarget: hitTarget\r\n\t\t};\r\n\t}\r\n\r\n\t/**\r\n\t * Most probably Gecko\r\n\t */\r\n\tprivate static _doHitTestWithCaretPositionFromPoint(ctx: HitTestContext, coords: ClientCoordinates): IHitTestResult {\r\n\t\tconst hitResult: { offsetNode: Node; offset: number; } = (document).caretPositionFromPoint(coords.clientX, coords.clientY);\r\n\r\n\t\tif (hitResult.offsetNode.nodeType === hitResult.offsetNode.TEXT_NODE) {\r\n\t\t\t// offsetNode is expected to be the token text\r\n\t\t\tconst parent1 = hitResult.offsetNode.parentNode; // expected to be the token span\r\n\t\t\tconst parent2 = parent1 ? parent1.parentNode : null; // expected to be the view line container span\r\n\t\t\tconst parent3 = parent2 ? parent2.parentNode : null; // expected to be the view line div\r\n\t\t\tconst parent3ClassName = parent3 && parent3.nodeType === parent3.ELEMENT_NODE ? (parent3).className : null;\r\n\r\n\t\t\tif (parent3ClassName === ViewLine.CLASS_NAME) {\r\n\t\t\t\tconst p = ctx.getPositionFromDOMInfo(hitResult.offsetNode.parentNode, hitResult.offset);\r\n\t\t\t\treturn {\r\n\t\t\t\t\tposition: p,\r\n\t\t\t\t\thitTarget: null\r\n\t\t\t\t};\r\n\t\t\t} else {\r\n\t\t\t\treturn {\r\n\t\t\t\t\tposition: null,\r\n\t\t\t\t\thitTarget: hitResult.offsetNode.parentNode\r\n\t\t\t\t};\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// For inline decorations, Gecko sometimes returns the `` of the line and the offset is the `` with the inline decoration\r\n\t\t// Some other times, it returns the `` with the inline decoration\r\n\t\tif (hitResult.offsetNode.nodeType === hitResult.offsetNode.ELEMENT_NODE) {\r\n\t\t\tconst parent1 = hitResult.offsetNode.parentNode;\r\n\t\t\tconst parent1ClassName = parent1 && parent1.nodeType === parent1.ELEMENT_NODE ? (parent1).className : null;\r\n\t\t\tconst parent2 = parent1 ? parent1.parentNode : null;\r\n\t\t\tconst parent2ClassName = parent2 && parent2.nodeType === parent2.ELEMENT_NODE ? (parent2).className : null;\r\n\r\n\t\t\tif (parent1ClassName === ViewLine.CLASS_NAME) {\r\n\t\t\t\t// it returned the `` of the line and the offset is the `` with the inline decoration\r\n\t\t\t\tconst tokenSpan = hitResult.offsetNode.childNodes[Math.min(hitResult.offset, hitResult.offsetNode.childNodes.length - 1)];\r\n\t\t\t\tif (tokenSpan) {\r\n\t\t\t\t\tconst p = ctx.getPositionFromDOMInfo(tokenSpan, 0);\r\n\t\t\t\t\treturn {\r\n\t\t\t\t\t\tposition: p,\r\n\t\t\t\t\t\thitTarget: null\r\n\t\t\t\t\t};\r\n\t\t\t\t}\r\n\t\t\t} else if (parent2ClassName === ViewLine.CLASS_NAME) {\r\n\t\t\t\t// it returned the `` with the inline decoration\r\n\t\t\t\tconst p = ctx.getPositionFromDOMInfo(hitResult.offsetNode, 0);\r\n\t\t\t\treturn {\r\n\t\t\t\t\tposition: p,\r\n\t\t\t\t\thitTarget: null\r\n\t\t\t\t};\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tposition: null,\r\n\t\t\thitTarget: hitResult.offsetNode\r\n\t\t};\r\n\t}\r\n\r\n\t/**\r\n\t * Most probably IE\r\n\t */\r\n\tprivate static _doHitTestWithMoveToPoint(ctx: HitTestContext, coords: ClientCoordinates): IHitTestResult {\r\n\t\tlet resultPosition: Position | null = null;\r\n\t\tlet resultHitTarget: Element | null = null;\r\n\r\n\t\tconst textRange: IETextRange = (document.body).createTextRange();\r\n\t\ttry {\r\n\t\t\ttextRange.moveToPoint(coords.clientX, coords.clientY);\r\n\t\t} catch (err) {\r\n\t\t\treturn {\r\n\t\t\t\tposition: null,\r\n\t\t\t\thitTarget: null\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\ttextRange.collapse(true);\r\n\r\n\t\t// Now, let's do our best to figure out what we hit :)\r\n\t\tconst parentElement = textRange ? textRange.parentElement() : null;\r\n\t\tconst parent1 = parentElement ? parentElement.parentNode : null;\r\n\t\tconst parent2 = parent1 ? parent1.parentNode : null;\r\n\r\n\t\tconst parent2ClassName = parent2 && parent2.nodeType === parent2.ELEMENT_NODE ? (parent2).className : '';\r\n\r\n\t\tif (parent2ClassName === ViewLine.CLASS_NAME) {\r\n\t\t\tconst rangeToContainEntireSpan = textRange.duplicate();\r\n\t\t\trangeToContainEntireSpan.moveToElementText(parentElement!);\r\n\t\t\trangeToContainEntireSpan.setEndPoint('EndToStart', textRange);\r\n\r\n\t\t\tresultPosition = ctx.getPositionFromDOMInfo(parentElement, rangeToContainEntireSpan.text.length);\r\n\t\t\t// Move range out of the span node, IE doesn't like having many ranges in\r\n\t\t\t// the same spot and will act badly for lines containing dashes ('-')\r\n\t\t\trangeToContainEntireSpan.moveToElementText(ctx.viewDomNode);\r\n\t\t} else {\r\n\t\t\t// Looks like we've hit the hover or something foreign\r\n\t\t\tresultHitTarget = parentElement;\r\n\t\t}\r\n\r\n\t\t// Move range out of the span node, IE doesn't like having many ranges in\r\n\t\t// the same spot and will act badly for lines containing dashes ('-')\r\n\t\ttextRange.moveToElementText(ctx.viewDomNode);\r\n\r\n\t\treturn {\r\n\t\t\tposition: resultPosition,\r\n\t\t\thitTarget: resultHitTarget\r\n\t\t};\r\n\t}\r\n\r\n\tprivate static _snapToSoftTabBoundary(position: Position, viewModel: IViewModel): Position {\r\n\t\tconst lineContent = viewModel.getLineContent(position.lineNumber);\r\n\t\tconst { tabSize } = viewModel.getTextModelOptions();\r\n\t\tconst newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, position.column - 1, tabSize, Direction.Nearest);\r\n\t\tif (newPosition !== -1) {\r\n\t\t\treturn new Position(position.lineNumber, newPosition + 1);\r\n\t\t}\r\n\t\treturn position;\r\n\t}\r\n\r\n\tprivate static _doHitTest(ctx: HitTestContext, request: BareHitTestRequest): IHitTestResult {\r\n\t\t// State of the art (18.10.2012):\r\n\t\t// The spec says browsers should support document.caretPositionFromPoint, but nobody implemented it (http://dev.w3.org/csswg/cssom-view/)\r\n\t\t// Gecko:\r\n\t\t// - they tried to implement it once, but failed: https://bugzilla.mozilla.org/show_bug.cgi?id=654352\r\n\t\t// - however, they do give out rangeParent/rangeOffset properties on mouse events\r\n\t\t// Webkit:\r\n\t\t// - they have implemented a previous version of the spec which was using document.caretRangeFromPoint\r\n\t\t// IE:\r\n\t\t// - they have a proprietary method on ranges, moveToPoint: https://msdn.microsoft.com/en-us/library/ie/ms536632(v=vs.85).aspx\r\n\r\n\t\t// 24.08.2016: Edge has added WebKit's document.caretRangeFromPoint, but it is quite buggy\r\n\t\t// - when hit testing the cursor it returns the first or the last line in the viewport\r\n\t\t// - it inconsistently hits text nodes or span nodes, while WebKit only hits text nodes\r\n\t\t// - when toggling render whitespace on, and hit testing in the empty content after a line, it always hits offset 0 of the first span of the line\r\n\r\n\t\t// Thank you browsers for making this so 'easy' :)\r\n\r\n\t\tlet result: IHitTestResult;\r\n\t\tif (typeof document.caretRangeFromPoint === 'function') {\r\n\t\t\tresult = this._doHitTestWithCaretRangeFromPoint(ctx, request);\r\n\t\t} else if ((document).caretPositionFromPoint) {\r\n\t\t\tresult = this._doHitTestWithCaretPositionFromPoint(ctx, request.pos.toClientCoordinates());\r\n\t\t} else if ((document.body).createTextRange) {\r\n\t\t\tresult = this._doHitTestWithMoveToPoint(ctx, request.pos.toClientCoordinates());\r\n\t\t} else {\r\n\t\t\tresult = {\r\n\t\t\t\tposition: null,\r\n\t\t\t\thitTarget: null\r\n\t\t\t};\r\n\t\t}\r\n\t\t// Snap to the nearest soft tab boundary if atomic soft tabs are enabled.\r\n\t\tif (result.position && ctx.stickyTabStops) {\r\n\t\t\tresult.position = this._snapToSoftTabBoundary(result.position, ctx.model);\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n}\r\n\r\nexport function shadowCaretRangeFromPoint(shadowRoot: ShadowRoot, x: number, y: number): Range {\r\n\tconst range = document.createRange();\r\n\r\n\t// Get the element under the point\r\n\tlet el: Element | null = shadowRoot.elementFromPoint(x, y);\r\n\r\n\tif (el !== null) {\r\n\t\t// Get the last child of the element until its firstChild is a text node\r\n\t\t// This assumes that the pointer is on the right of the line, out of the tokens\r\n\t\t// and that we want to get the offset of the last token of the line\r\n\t\twhile (el && el.firstChild && el.firstChild.nodeType !== el.firstChild.TEXT_NODE && el.lastChild && el.lastChild.firstChild) {\r\n\t\t\tel = el.lastChild;\r\n\t\t}\r\n\r\n\t\t// Grab its rect\r\n\t\tconst rect = el.getBoundingClientRect();\r\n\r\n\t\t// And its font\r\n\t\tconst font = window.getComputedStyle(el, null).getPropertyValue('font');\r\n\r\n\t\t// And also its txt content\r\n\t\tconst text = (el as any).innerText;\r\n\r\n\t\t// Position the pixel cursor at the left of the element\r\n\t\tlet pixelCursor = rect.left;\r\n\t\tlet offset = 0;\r\n\t\tlet step: number;\r\n\r\n\t\t// If the point is on the right of the box put the cursor after the last character\r\n\t\tif (x > rect.left + rect.width) {\r\n\t\t\toffset = text.length;\r\n\t\t} else {\r\n\t\t\tconst charWidthReader = CharWidthReader.getInstance();\r\n\t\t\t// Goes through all the characters of the innerText, and checks if the x of the point\r\n\t\t\t// belongs to the character.\r\n\t\t\tfor (let i = 0; i < text.length + 1; i++) {\r\n\t\t\t\t// The step is half the width of the character\r\n\t\t\t\tstep = charWidthReader.getCharWidth(text.charAt(i), font) / 2;\r\n\t\t\t\t// Move to the center of the character\r\n\t\t\t\tpixelCursor += step;\r\n\t\t\t\t// If the x of the point is smaller that the position of the cursor, the point is over that character\r\n\t\t\t\tif (x < pixelCursor) {\r\n\t\t\t\t\toffset = i;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\t// Move between the current character and the next\r\n\t\t\t\tpixelCursor += step;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Creates a range with the text node of the element and set the offset found\r\n\t\trange.setStart(el.firstChild!, offset);\r\n\t\trange.setEnd(el.firstChild!, offset);\r\n\t}\r\n\r\n\treturn range;\r\n}\r\n\r\nclass CharWidthReader {\r\n\tprivate static _INSTANCE: CharWidthReader | null = null;\r\n\r\n\tpublic static getInstance(): CharWidthReader {\r\n\t\tif (!CharWidthReader._INSTANCE) {\r\n\t\t\tCharWidthReader._INSTANCE = new CharWidthReader();\r\n\t\t}\r\n\t\treturn CharWidthReader._INSTANCE;\r\n\t}\r\n\r\n\tprivate readonly _cache: { [cacheKey: string]: number; };\r\n\tprivate readonly _canvas: HTMLCanvasElement;\r\n\r\n\tprivate constructor() {\r\n\t\tthis._cache = {};\r\n\t\tthis._canvas = document.createElement('canvas');\r\n\t}\r\n\r\n\tpublic getCharWidth(char: string, font: string): number {\r\n\t\tconst cacheKey = char + font;\r\n\t\tif (this._cache[cacheKey]) {\r\n\t\t\treturn this._cache[cacheKey];\r\n\t\t}\r\n\r\n\t\tconst context = this._canvas.getContext('2d')!;\r\n\t\tcontext.font = font;\r\n\t\tconst metrics = context.measureText(char);\r\n\t\tconst width = metrics.width;\r\n\t\tthis._cache[cacheKey] = width;\r\n\t\treturn width;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { StandardWheelEvent, IMouseWheelEvent } from 'vs/base/browser/mouseEvent';\r\nimport { TimeoutTimer } from 'vs/base/common/async';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport { HitTestContext, IViewZoneData, MouseTarget, MouseTargetFactory, PointerHandlerLastRenderData } from 'vs/editor/browser/controller/mouseTarget';\r\nimport { IMouseTarget, MouseTargetType } from 'vs/editor/browser/editorBrowser';\r\nimport { ClientCoordinates, EditorMouseEvent, EditorMouseEventFactory, GlobalEditorMouseMoveMonitor, createEditorPagePosition } from 'vs/editor/browser/editorDom';\r\nimport { ViewController } from 'vs/editor/browser/view/viewController';\r\nimport { EditorZoom } from 'vs/editor/common/config/editorZoom';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { HorizontalPosition } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\n/**\r\n * Merges mouse events when mouse move events are throttled\r\n */\r\nexport function createMouseMoveEventMerger(mouseTargetFactory: MouseTargetFactory | null) {\r\n\treturn function (lastEvent: EditorMouseEvent | null, currentEvent: EditorMouseEvent): EditorMouseEvent {\r\n\t\tlet targetIsWidget = false;\r\n\t\tif (mouseTargetFactory) {\r\n\t\t\ttargetIsWidget = mouseTargetFactory.mouseTargetIsWidget(currentEvent);\r\n\t\t}\r\n\t\tif (!targetIsWidget) {\r\n\t\t\tcurrentEvent.preventDefault();\r\n\t\t}\r\n\t\treturn currentEvent;\r\n\t};\r\n}\r\n\r\nexport interface IPointerHandlerHelper {\r\n\tviewDomNode: HTMLElement;\r\n\tlinesContentDomNode: HTMLElement;\r\n\r\n\tfocusTextArea(): void;\r\n\r\n\t/**\r\n\t * Get the last rendered information for cursors & textarea.\r\n\t */\r\n\tgetLastRenderData(): PointerHandlerLastRenderData;\r\n\r\n\tshouldSuppressMouseDownOnViewZone(viewZoneId: string): boolean;\r\n\tshouldSuppressMouseDownOnWidget(widgetId: string): boolean;\r\n\r\n\t/**\r\n\t * Decode a position from a rendered dom node\r\n\t */\r\n\tgetPositionFromDOMInfo(spanNode: HTMLElement, offset: number): Position | null;\r\n\r\n\tvisibleRangeForPosition(lineNumber: number, column: number): HorizontalPosition | null;\r\n\tgetLineWidth(lineNumber: number): number;\r\n}\r\n\r\nexport class MouseHandler extends ViewEventHandler {\r\n\r\n\tstatic readonly MOUSE_MOVE_MINIMUM_TIME = 100; // ms\r\n\r\n\tprotected _context: ViewContext;\r\n\tprotected viewController: ViewController;\r\n\tprotected viewHelper: IPointerHandlerHelper;\r\n\tprotected mouseTargetFactory: MouseTargetFactory;\r\n\tprotected readonly _mouseDownOperation: MouseDownOperation;\r\n\tprivate lastMouseLeaveTime: number;\r\n\r\n\tconstructor(context: ViewContext, viewController: ViewController, viewHelper: IPointerHandlerHelper) {\r\n\t\tsuper();\r\n\r\n\t\tthis._context = context;\r\n\t\tthis.viewController = viewController;\r\n\t\tthis.viewHelper = viewHelper;\r\n\t\tthis.mouseTargetFactory = new MouseTargetFactory(this._context, viewHelper);\r\n\r\n\t\tthis._mouseDownOperation = this._register(new MouseDownOperation(\r\n\t\t\tthis._context,\r\n\t\t\tthis.viewController,\r\n\t\t\tthis.viewHelper,\r\n\t\t\t(e, testEventTarget) => this._createMouseTarget(e, testEventTarget),\r\n\t\t\t(e) => this._getMouseColumn(e)\r\n\t\t));\r\n\r\n\t\tthis.lastMouseLeaveTime = -1;\r\n\r\n\t\tconst mouseEvents = new EditorMouseEventFactory(this.viewHelper.viewDomNode);\r\n\r\n\t\tthis._register(mouseEvents.onContextMenu(this.viewHelper.viewDomNode, (e) => this._onContextMenu(e, true)));\r\n\r\n\t\tthis._register(mouseEvents.onMouseMoveThrottled(this.viewHelper.viewDomNode,\r\n\t\t\t(e) => this._onMouseMove(e),\r\n\t\t\tcreateMouseMoveEventMerger(this.mouseTargetFactory), MouseHandler.MOUSE_MOVE_MINIMUM_TIME));\r\n\r\n\t\tthis._register(mouseEvents.onMouseUp(this.viewHelper.viewDomNode, (e) => this._onMouseUp(e)));\r\n\r\n\t\tthis._register(mouseEvents.onMouseLeave(this.viewHelper.viewDomNode, (e) => this._onMouseLeave(e)));\r\n\r\n\t\tthis._register(mouseEvents.onMouseDown(this.viewHelper.viewDomNode, (e) => this._onMouseDown(e)));\r\n\r\n\t\tconst onMouseWheel = (browserEvent: IMouseWheelEvent) => {\r\n\t\t\tthis.viewController.emitMouseWheel(browserEvent);\r\n\r\n\t\t\tif (!this._context.configuration.options.get(EditorOption.mouseWheelZoom)) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tconst e = new StandardWheelEvent(browserEvent);\r\n\t\t\tconst doMouseWheelZoom = (\r\n\t\t\t\tplatform.isMacintosh\r\n\t\t\t\t\t? (browserEvent.metaKey && !browserEvent.ctrlKey && !browserEvent.shiftKey && !browserEvent.altKey)\r\n\t\t\t\t\t: (browserEvent.ctrlKey && !browserEvent.metaKey && !browserEvent.shiftKey && !browserEvent.altKey)\r\n\t\t\t);\r\n\t\t\tif (doMouseWheelZoom) {\r\n\t\t\t\tconst zoomLevel: number = EditorZoom.getZoomLevel();\r\n\t\t\t\tconst delta = e.deltaY > 0 ? 1 : -1;\r\n\t\t\t\tEditorZoom.setZoomLevel(zoomLevel + delta);\r\n\t\t\t\te.preventDefault();\r\n\t\t\t\te.stopPropagation();\r\n\t\t\t}\r\n\t\t};\r\n\t\tthis._register(dom.addDisposableListener(this.viewHelper.viewDomNode, dom.EventType.MOUSE_WHEEL, onMouseWheel, { capture: true, passive: false }));\r\n\r\n\t\tthis._context.addEventHandler(this);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._context.removeEventHandler(this);\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\t// --- begin event handlers\r\n\tpublic onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {\r\n\t\tthis._mouseDownOperation.onCursorStateChanged(e);\r\n\t\treturn false;\r\n\t}\r\n\tpublic onFocusChanged(e: viewEvents.ViewFocusChangedEvent): boolean {\r\n\t\treturn false;\r\n\t}\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\tthis._mouseDownOperation.onScrollChanged();\r\n\t\treturn false;\r\n\t}\r\n\t// --- end event handlers\r\n\r\n\tpublic getTargetAtClientPoint(clientX: number, clientY: number): IMouseTarget | null {\r\n\t\tconst clientPos = new ClientCoordinates(clientX, clientY);\r\n\t\tconst pos = clientPos.toPageCoordinates();\r\n\t\tconst editorPos = createEditorPagePosition(this.viewHelper.viewDomNode);\r\n\r\n\t\tif (pos.y < editorPos.y || pos.y > editorPos.y + editorPos.height || pos.x < editorPos.x || pos.x > editorPos.x + editorPos.width) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\treturn this.mouseTargetFactory.createMouseTarget(this.viewHelper.getLastRenderData(), editorPos, pos, null);\r\n\t}\r\n\r\n\tprotected _createMouseTarget(e: EditorMouseEvent, testEventTarget: boolean): IMouseTarget {\r\n\t\treturn this.mouseTargetFactory.createMouseTarget(this.viewHelper.getLastRenderData(), e.editorPos, e.pos, testEventTarget ? e.target : null);\r\n\t}\r\n\r\n\tprivate _getMouseColumn(e: EditorMouseEvent): number {\r\n\t\treturn this.mouseTargetFactory.getMouseColumn(e.editorPos, e.pos);\r\n\t}\r\n\r\n\tprotected _onContextMenu(e: EditorMouseEvent, testEventTarget: boolean): void {\r\n\t\tthis.viewController.emitContextMenu({\r\n\t\t\tevent: e,\r\n\t\t\ttarget: this._createMouseTarget(e, testEventTarget)\r\n\t\t});\r\n\t}\r\n\r\n\tpublic _onMouseMove(e: EditorMouseEvent): void {\r\n\t\tif (this._mouseDownOperation.isActive()) {\r\n\t\t\t// In selection/drag operation\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst actualMouseMoveTime = e.timestamp;\r\n\t\tif (actualMouseMoveTime < this.lastMouseLeaveTime) {\r\n\t\t\t// Due to throttling, this event occurred before the mouse left the editor, therefore ignore it.\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.viewController.emitMouseMove({\r\n\t\t\tevent: e,\r\n\t\t\ttarget: this._createMouseTarget(e, true)\r\n\t\t});\r\n\t}\r\n\r\n\tpublic _onMouseLeave(e: EditorMouseEvent): void {\r\n\t\tthis.lastMouseLeaveTime = (new Date()).getTime();\r\n\t\tthis.viewController.emitMouseLeave({\r\n\t\t\tevent: e,\r\n\t\t\ttarget: null\r\n\t\t});\r\n\t}\r\n\r\n\tpublic _onMouseUp(e: EditorMouseEvent): void {\r\n\t\tthis.viewController.emitMouseUp({\r\n\t\t\tevent: e,\r\n\t\t\ttarget: this._createMouseTarget(e, true)\r\n\t\t});\r\n\t}\r\n\r\n\tpublic _onMouseDown(e: EditorMouseEvent): void {\r\n\t\tconst t = this._createMouseTarget(e, true);\r\n\r\n\t\tconst targetIsContent = (t.type === MouseTargetType.CONTENT_TEXT || t.type === MouseTargetType.CONTENT_EMPTY);\r\n\t\tconst targetIsGutter = (t.type === MouseTargetType.GUTTER_GLYPH_MARGIN || t.type === MouseTargetType.GUTTER_LINE_NUMBERS || t.type === MouseTargetType.GUTTER_LINE_DECORATIONS);\r\n\t\tconst targetIsLineNumbers = (t.type === MouseTargetType.GUTTER_LINE_NUMBERS);\r\n\t\tconst selectOnLineNumbers = this._context.configuration.options.get(EditorOption.selectOnLineNumbers);\r\n\t\tconst targetIsViewZone = (t.type === MouseTargetType.CONTENT_VIEW_ZONE || t.type === MouseTargetType.GUTTER_VIEW_ZONE);\r\n\t\tconst targetIsWidget = (t.type === MouseTargetType.CONTENT_WIDGET);\r\n\r\n\t\tlet shouldHandle = e.leftButton || e.middleButton;\r\n\t\tif (platform.isMacintosh && e.leftButton && e.ctrlKey) {\r\n\t\t\tshouldHandle = false;\r\n\t\t}\r\n\r\n\t\tconst focus = () => {\r\n\t\t\te.preventDefault();\r\n\t\t\tthis.viewHelper.focusTextArea();\r\n\t\t};\r\n\r\n\t\tif (shouldHandle && (targetIsContent || (targetIsLineNumbers && selectOnLineNumbers))) {\r\n\t\t\tfocus();\r\n\t\t\tthis._mouseDownOperation.start(t.type, e);\r\n\r\n\t\t} else if (targetIsGutter) {\r\n\t\t\t// Do not steal focus\r\n\t\t\te.preventDefault();\r\n\t\t} else if (targetIsViewZone) {\r\n\t\t\tconst viewZoneData = t.detail;\r\n\t\t\tif (this.viewHelper.shouldSuppressMouseDownOnViewZone(viewZoneData.viewZoneId)) {\r\n\t\t\t\tfocus();\r\n\t\t\t\tthis._mouseDownOperation.start(t.type, e);\r\n\t\t\t\te.preventDefault();\r\n\t\t\t}\r\n\t\t} else if (targetIsWidget && this.viewHelper.shouldSuppressMouseDownOnWidget(t.detail)) {\r\n\t\t\tfocus();\r\n\t\t\te.preventDefault();\r\n\t\t}\r\n\r\n\t\tthis.viewController.emitMouseDown({\r\n\t\t\tevent: e,\r\n\t\t\ttarget: t\r\n\t\t});\r\n\t}\r\n}\r\n\r\nclass MouseDownOperation extends Disposable {\r\n\r\n\tprivate readonly _context: ViewContext;\r\n\tprivate readonly _viewController: ViewController;\r\n\tprivate readonly _viewHelper: IPointerHandlerHelper;\r\n\tprivate readonly _createMouseTarget: (e: EditorMouseEvent, testEventTarget: boolean) => IMouseTarget;\r\n\tprivate readonly _getMouseColumn: (e: EditorMouseEvent) => number;\r\n\r\n\tprivate readonly _mouseMoveMonitor: GlobalEditorMouseMoveMonitor;\r\n\tprivate readonly _onScrollTimeout: TimeoutTimer;\r\n\tprivate readonly _mouseState: MouseDownState;\r\n\r\n\tprivate _currentSelection: Selection;\r\n\tprivate _isActive: boolean;\r\n\tprivate _lastMouseEvent: EditorMouseEvent | null;\r\n\r\n\tconstructor(\r\n\t\tcontext: ViewContext,\r\n\t\tviewController: ViewController,\r\n\t\tviewHelper: IPointerHandlerHelper,\r\n\t\tcreateMouseTarget: (e: EditorMouseEvent, testEventTarget: boolean) => IMouseTarget,\r\n\t\tgetMouseColumn: (e: EditorMouseEvent) => number\r\n\t) {\r\n\t\tsuper();\r\n\t\tthis._context = context;\r\n\t\tthis._viewController = viewController;\r\n\t\tthis._viewHelper = viewHelper;\r\n\t\tthis._createMouseTarget = createMouseTarget;\r\n\t\tthis._getMouseColumn = getMouseColumn;\r\n\r\n\t\tthis._mouseMoveMonitor = this._register(new GlobalEditorMouseMoveMonitor(this._viewHelper.viewDomNode));\r\n\t\tthis._onScrollTimeout = this._register(new TimeoutTimer());\r\n\t\tthis._mouseState = new MouseDownState();\r\n\r\n\t\tthis._currentSelection = new Selection(1, 1, 1, 1);\r\n\t\tthis._isActive = false;\r\n\t\tthis._lastMouseEvent = null;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tpublic isActive(): boolean {\r\n\t\treturn this._isActive;\r\n\t}\r\n\r\n\tprivate _onMouseDownThenMove(e: EditorMouseEvent): void {\r\n\t\tthis._lastMouseEvent = e;\r\n\t\tthis._mouseState.setModifiers(e);\r\n\r\n\t\tconst position = this._findMousePosition(e, true);\r\n\t\tif (!position) {\r\n\t\t\t// Ignoring because position is unknown\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this._mouseState.isDragAndDrop) {\r\n\t\t\tthis._viewController.emitMouseDrag({\r\n\t\t\t\tevent: e,\r\n\t\t\t\ttarget: position\r\n\t\t\t});\r\n\t\t} else {\r\n\t\t\tthis._dispatchMouse(position, true);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic start(targetType: MouseTargetType, e: EditorMouseEvent): void {\r\n\t\tthis._lastMouseEvent = e;\r\n\r\n\t\tthis._mouseState.setStartedOnLineNumbers(targetType === MouseTargetType.GUTTER_LINE_NUMBERS);\r\n\t\tthis._mouseState.setStartButtons(e);\r\n\t\tthis._mouseState.setModifiers(e);\r\n\t\tconst position = this._findMousePosition(e, true);\r\n\t\tif (!position || !position.position) {\r\n\t\t\t// Ignoring because position is unknown\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._mouseState.trySetCount(e.detail, position.position);\r\n\r\n\t\t// Overwrite the detail of the MouseEvent, as it will be sent out in an event and contributions might rely on it.\r\n\t\te.detail = this._mouseState.count;\r\n\r\n\t\tconst options = this._context.configuration.options;\r\n\r\n\t\tif (!options.get(EditorOption.readOnly)\r\n\t\t\t&& options.get(EditorOption.dragAndDrop)\r\n\t\t\t&& !options.get(EditorOption.columnSelection)\r\n\t\t\t&& !this._mouseState.altKey // we don't support multiple mouse\r\n\t\t\t&& e.detail < 2 // only single click on a selection can work\r\n\t\t\t&& !this._isActive // the mouse is not down yet\r\n\t\t\t&& !this._currentSelection.isEmpty() // we don't drag single cursor\r\n\t\t\t&& (position.type === MouseTargetType.CONTENT_TEXT) // single click on text\r\n\t\t\t&& position.position && this._currentSelection.containsPosition(position.position) // single click on a selection\r\n\t\t) {\r\n\t\t\tthis._mouseState.isDragAndDrop = true;\r\n\t\t\tthis._isActive = true;\r\n\r\n\t\t\tthis._mouseMoveMonitor.startMonitoring(\r\n\t\t\t\te.target,\r\n\t\t\t\te.buttons,\r\n\t\t\t\tcreateMouseMoveEventMerger(null),\r\n\t\t\t\t(e) => this._onMouseDownThenMove(e),\r\n\t\t\t\t(browserEvent?: MouseEvent | KeyboardEvent) => {\r\n\t\t\t\t\tconst position = this._findMousePosition(this._lastMouseEvent!, true);\r\n\r\n\t\t\t\t\tif (browserEvent && browserEvent instanceof KeyboardEvent) {\r\n\t\t\t\t\t\t// cancel\r\n\t\t\t\t\t\tthis._viewController.emitMouseDropCanceled();\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tthis._viewController.emitMouseDrop({\r\n\t\t\t\t\t\t\tevent: this._lastMouseEvent!,\r\n\t\t\t\t\t\t\ttarget: (position ? this._createMouseTarget(this._lastMouseEvent!, true) : null) // Ignoring because position is unknown, e.g., Content View Zone\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tthis._stop();\r\n\t\t\t\t}\r\n\t\t\t);\r\n\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._mouseState.isDragAndDrop = false;\r\n\t\tthis._dispatchMouse(position, e.shiftKey);\r\n\r\n\t\tif (!this._isActive) {\r\n\t\t\tthis._isActive = true;\r\n\t\t\tthis._mouseMoveMonitor.startMonitoring(\r\n\t\t\t\te.target,\r\n\t\t\t\te.buttons,\r\n\t\t\t\tcreateMouseMoveEventMerger(null),\r\n\t\t\t\t(e) => this._onMouseDownThenMove(e),\r\n\t\t\t\t() => this._stop()\r\n\t\t\t);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _stop(): void {\r\n\t\tthis._isActive = false;\r\n\t\tthis._onScrollTimeout.cancel();\r\n\t}\r\n\r\n\tpublic onScrollChanged(): void {\r\n\t\tif (!this._isActive) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._onScrollTimeout.setIfNotSet(() => {\r\n\t\t\tif (!this._lastMouseEvent) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tconst position = this._findMousePosition(this._lastMouseEvent, false);\r\n\t\t\tif (!position) {\r\n\t\t\t\t// Ignoring because position is unknown\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (this._mouseState.isDragAndDrop) {\r\n\t\t\t\t// Ignoring because users are dragging the text\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tthis._dispatchMouse(position, true);\r\n\t\t}, 10);\r\n\t}\r\n\r\n\tpublic onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): void {\r\n\t\tthis._currentSelection = e.selections[0];\r\n\t}\r\n\r\n\tprivate _getPositionOutsideEditor(e: EditorMouseEvent): MouseTarget | null {\r\n\t\tconst editorContent = e.editorPos;\r\n\t\tconst model = this._context.model;\r\n\t\tconst viewLayout = this._context.viewLayout;\r\n\r\n\t\tconst mouseColumn = this._getMouseColumn(e);\r\n\r\n\t\tif (e.posy < editorContent.y) {\r\n\t\t\tconst verticalOffset = Math.max(viewLayout.getCurrentScrollTop() - (editorContent.y - e.posy), 0);\r\n\t\t\tconst viewZoneData = HitTestContext.getZoneAtCoord(this._context, verticalOffset);\r\n\t\t\tif (viewZoneData) {\r\n\t\t\t\tconst newPosition = this._helpPositionJumpOverViewZone(viewZoneData);\r\n\t\t\t\tif (newPosition) {\r\n\t\t\t\t\treturn new MouseTarget(null, MouseTargetType.OUTSIDE_EDITOR, mouseColumn, newPosition);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tconst aboveLineNumber = viewLayout.getLineNumberAtVerticalOffset(verticalOffset);\r\n\t\t\treturn new MouseTarget(null, MouseTargetType.OUTSIDE_EDITOR, mouseColumn, new Position(aboveLineNumber, 1));\r\n\t\t}\r\n\r\n\t\tif (e.posy > editorContent.y + editorContent.height) {\r\n\t\t\tconst verticalOffset = viewLayout.getCurrentScrollTop() + (e.posy - editorContent.y);\r\n\t\t\tconst viewZoneData = HitTestContext.getZoneAtCoord(this._context, verticalOffset);\r\n\t\t\tif (viewZoneData) {\r\n\t\t\t\tconst newPosition = this._helpPositionJumpOverViewZone(viewZoneData);\r\n\t\t\t\tif (newPosition) {\r\n\t\t\t\t\treturn new MouseTarget(null, MouseTargetType.OUTSIDE_EDITOR, mouseColumn, newPosition);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tconst belowLineNumber = viewLayout.getLineNumberAtVerticalOffset(verticalOffset);\r\n\t\t\treturn new MouseTarget(null, MouseTargetType.OUTSIDE_EDITOR, mouseColumn, new Position(belowLineNumber, model.getLineMaxColumn(belowLineNumber)));\r\n\t\t}\r\n\r\n\t\tconst possibleLineNumber = viewLayout.getLineNumberAtVerticalOffset(viewLayout.getCurrentScrollTop() + (e.posy - editorContent.y));\r\n\r\n\t\tif (e.posx < editorContent.x) {\r\n\t\t\treturn new MouseTarget(null, MouseTargetType.OUTSIDE_EDITOR, mouseColumn, new Position(possibleLineNumber, 1));\r\n\t\t}\r\n\r\n\t\tif (e.posx > editorContent.x + editorContent.width) {\r\n\t\t\treturn new MouseTarget(null, MouseTargetType.OUTSIDE_EDITOR, mouseColumn, new Position(possibleLineNumber, model.getLineMaxColumn(possibleLineNumber)));\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate _findMousePosition(e: EditorMouseEvent, testEventTarget: boolean): MouseTarget | null {\r\n\t\tconst positionOutsideEditor = this._getPositionOutsideEditor(e);\r\n\t\tif (positionOutsideEditor) {\r\n\t\t\treturn positionOutsideEditor;\r\n\t\t}\r\n\r\n\t\tconst t = this._createMouseTarget(e, testEventTarget);\r\n\t\tconst hintedPosition = t.position;\r\n\t\tif (!hintedPosition) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (t.type === MouseTargetType.CONTENT_VIEW_ZONE || t.type === MouseTargetType.GUTTER_VIEW_ZONE) {\r\n\t\t\tconst newPosition = this._helpPositionJumpOverViewZone(t.detail);\r\n\t\t\tif (newPosition) {\r\n\t\t\t\treturn new MouseTarget(t.element, t.type, t.mouseColumn, newPosition, null, t.detail);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn t;\r\n\t}\r\n\r\n\tprivate _helpPositionJumpOverViewZone(viewZoneData: IViewZoneData): Position | null {\r\n\t\t// Force position on view zones to go above or below depending on where selection started from\r\n\t\tconst selectionStart = new Position(this._currentSelection.selectionStartLineNumber, this._currentSelection.selectionStartColumn);\r\n\t\tconst positionBefore = viewZoneData.positionBefore;\r\n\t\tconst positionAfter = viewZoneData.positionAfter;\r\n\r\n\t\tif (positionBefore && positionAfter) {\r\n\t\t\tif (positionBefore.isBefore(selectionStart)) {\r\n\t\t\t\treturn positionBefore;\r\n\t\t\t} else {\r\n\t\t\t\treturn positionAfter;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate _dispatchMouse(position: MouseTarget, inSelectionMode: boolean): void {\r\n\t\tif (!position.position) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._viewController.dispatchMouse({\r\n\t\t\tposition: position.position,\r\n\t\t\tmouseColumn: position.mouseColumn,\r\n\t\t\tstartedOnLineNumbers: this._mouseState.startedOnLineNumbers,\r\n\r\n\t\t\tinSelectionMode: inSelectionMode,\r\n\t\t\tmouseDownCount: this._mouseState.count,\r\n\t\t\taltKey: this._mouseState.altKey,\r\n\t\t\tctrlKey: this._mouseState.ctrlKey,\r\n\t\t\tmetaKey: this._mouseState.metaKey,\r\n\t\t\tshiftKey: this._mouseState.shiftKey,\r\n\r\n\t\t\tleftButton: this._mouseState.leftButton,\r\n\t\t\tmiddleButton: this._mouseState.middleButton,\r\n\t\t});\r\n\t}\r\n}\r\n\r\nclass MouseDownState {\r\n\r\n\tprivate static readonly CLEAR_MOUSE_DOWN_COUNT_TIME = 400; // ms\r\n\r\n\tprivate _altKey: boolean;\r\n\tpublic get altKey(): boolean { return this._altKey; }\r\n\r\n\tprivate _ctrlKey: boolean;\r\n\tpublic get ctrlKey(): boolean { return this._ctrlKey; }\r\n\r\n\tprivate _metaKey: boolean;\r\n\tpublic get metaKey(): boolean { return this._metaKey; }\r\n\r\n\tprivate _shiftKey: boolean;\r\n\tpublic get shiftKey(): boolean { return this._shiftKey; }\r\n\r\n\tprivate _leftButton: boolean;\r\n\tpublic get leftButton(): boolean { return this._leftButton; }\r\n\r\n\tprivate _middleButton: boolean;\r\n\tpublic get middleButton(): boolean { return this._middleButton; }\r\n\r\n\tprivate _startedOnLineNumbers: boolean;\r\n\tpublic get startedOnLineNumbers(): boolean { return this._startedOnLineNumbers; }\r\n\r\n\tprivate _lastMouseDownPosition: Position | null;\r\n\tprivate _lastMouseDownPositionEqualCount: number;\r\n\tprivate _lastMouseDownCount: number;\r\n\tprivate _lastSetMouseDownCountTime: number;\r\n\tpublic isDragAndDrop: boolean;\r\n\r\n\tconstructor() {\r\n\t\tthis._altKey = false;\r\n\t\tthis._ctrlKey = false;\r\n\t\tthis._metaKey = false;\r\n\t\tthis._shiftKey = false;\r\n\t\tthis._leftButton = false;\r\n\t\tthis._middleButton = false;\r\n\t\tthis._startedOnLineNumbers = false;\r\n\t\tthis._lastMouseDownPosition = null;\r\n\t\tthis._lastMouseDownPositionEqualCount = 0;\r\n\t\tthis._lastMouseDownCount = 0;\r\n\t\tthis._lastSetMouseDownCountTime = 0;\r\n\t\tthis.isDragAndDrop = false;\r\n\t}\r\n\r\n\tpublic get count(): number {\r\n\t\treturn this._lastMouseDownCount;\r\n\t}\r\n\r\n\tpublic setModifiers(source: EditorMouseEvent) {\r\n\t\tthis._altKey = source.altKey;\r\n\t\tthis._ctrlKey = source.ctrlKey;\r\n\t\tthis._metaKey = source.metaKey;\r\n\t\tthis._shiftKey = source.shiftKey;\r\n\t}\r\n\r\n\tpublic setStartButtons(source: EditorMouseEvent) {\r\n\t\tthis._leftButton = source.leftButton;\r\n\t\tthis._middleButton = source.middleButton;\r\n\t}\r\n\r\n\tpublic setStartedOnLineNumbers(startedOnLineNumbers: boolean): void {\r\n\t\tthis._startedOnLineNumbers = startedOnLineNumbers;\r\n\t}\r\n\r\n\tpublic trySetCount(setMouseDownCount: number, newMouseDownPosition: Position): void {\r\n\t\t// a. Invalidate multiple clicking if too much time has passed (will be hit by IE because the detail field of mouse events contains garbage in IE10)\r\n\t\tconst currentTime = (new Date()).getTime();\r\n\t\tif (currentTime - this._lastSetMouseDownCountTime > MouseDownState.CLEAR_MOUSE_DOWN_COUNT_TIME) {\r\n\t\t\tsetMouseDownCount = 1;\r\n\t\t}\r\n\t\tthis._lastSetMouseDownCountTime = currentTime;\r\n\r\n\t\t// b. Ensure that we don't jump from single click to triple click in one go (will be hit by IE because the detail field of mouse events contains garbage in IE10)\r\n\t\tif (setMouseDownCount > this._lastMouseDownCount + 1) {\r\n\t\t\tsetMouseDownCount = this._lastMouseDownCount + 1;\r\n\t\t}\r\n\r\n\t\t// c. Invalidate multiple clicking if the logical position is different\r\n\t\tif (this._lastMouseDownPosition && this._lastMouseDownPosition.equals(newMouseDownPosition)) {\r\n\t\t\tthis._lastMouseDownPositionEqualCount++;\r\n\t\t} else {\r\n\t\t\tthis._lastMouseDownPositionEqualCount = 1;\r\n\t\t}\r\n\t\tthis._lastMouseDownPosition = newMouseDownPosition;\r\n\r\n\t\t// Finally set the lastMouseDownCount\r\n\t\tthis._lastMouseDownCount = Math.min(setMouseDownCount, this._lastMouseDownPositionEqualCount);\r\n\t}\r\n\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport { EventType, Gesture, GestureEvent } from 'vs/base/browser/touch';\r\nimport { IDisposable, Disposable } from 'vs/base/common/lifecycle';\r\nimport { IPointerHandlerHelper, MouseHandler, createMouseMoveEventMerger } from 'vs/editor/browser/controller/mouseHandler';\r\nimport { IMouseTarget } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorMouseEvent, EditorPointerEventFactory } from 'vs/editor/browser/editorDom';\r\nimport { ViewController } from 'vs/editor/browser/view/viewController';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport { BrowserFeatures } from 'vs/base/browser/canIUse';\r\n\r\ninterface IThrottledGestureEvent {\r\n\ttranslationX: number;\r\n\ttranslationY: number;\r\n}\r\n\r\nfunction gestureChangeEventMerger(lastEvent: IThrottledGestureEvent | null, currentEvent: MSGestureEvent): IThrottledGestureEvent {\r\n\tconst r = {\r\n\t\ttranslationY: currentEvent.translationY,\r\n\t\ttranslationX: currentEvent.translationX\r\n\t};\r\n\tif (lastEvent) {\r\n\t\tr.translationY += lastEvent.translationY;\r\n\t\tr.translationX += lastEvent.translationX;\r\n\t}\r\n\treturn r;\r\n}\r\n\r\n/**\r\n * Basically Edge but should be modified to handle any pointerEnabled, even without support of MSGesture\r\n */\r\nclass StandardPointerHandler extends MouseHandler implements IDisposable {\r\n\r\n\tprivate _lastPointerType: string;\r\n\tprivate _installGestureHandlerTimeout: number;\r\n\r\n\tconstructor(context: ViewContext, viewController: ViewController, viewHelper: IPointerHandlerHelper) {\r\n\t\tsuper(context, viewController, viewHelper);\r\n\r\n\t\tthis.viewHelper.linesContentDomNode.style.touchAction = 'none';\r\n\r\n\t\t// TODO@Alex -> this expects that the view is added in 100 ms, might not be the case\r\n\t\t// This handler should be added when the dom node is in the dom tree\r\n\t\tthis._installGestureHandlerTimeout = window.setTimeout(() => {\r\n\t\t\tthis._installGestureHandlerTimeout = -1;\r\n\r\n\t\t\t// TODO@Alex: replace the usage of MSGesture here with something that works across all browsers\r\n\t\t\tif (window.MSGesture) {\r\n\t\t\t\tconst touchGesture = new MSGesture();\r\n\t\t\t\tconst penGesture = new MSGesture();\r\n\t\t\t\ttouchGesture.target = this.viewHelper.linesContentDomNode;\r\n\t\t\t\tpenGesture.target = this.viewHelper.linesContentDomNode;\r\n\t\t\t\tthis.viewHelper.linesContentDomNode.addEventListener('pointerdown', (e: PointerEvent) => {\r\n\t\t\t\t\tconst pointerType = e.pointerType;\r\n\t\t\t\t\tif (pointerType === 'mouse') {\r\n\t\t\t\t\t\tthis._lastPointerType = 'mouse';\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t} else if (pointerType === 'touch') {\r\n\t\t\t\t\t\tthis._lastPointerType = 'touch';\r\n\t\t\t\t\t\ttouchGesture.addPointer(e.pointerId);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tthis._lastPointerType = 'pen';\r\n\t\t\t\t\t\tpenGesture.addPointer(e.pointerId);\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t\tthis._register(dom.addDisposableThrottledListener(this.viewHelper.linesContentDomNode, 'MSGestureChange', (e) => this._onGestureChange(e), gestureChangeEventMerger));\r\n\t\t\t\tthis._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, 'MSGestureTap', (e) => this._onCaptureGestureTap(e), true));\r\n\t\t\t}\r\n\t\t}, 100);\r\n\t\tthis._lastPointerType = 'mouse';\r\n\t}\r\n\r\n\tpublic _onMouseDown(e: EditorMouseEvent): void {\r\n\t\tif (this._lastPointerType === 'mouse') {\r\n\t\t\tsuper._onMouseDown(e);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _onCaptureGestureTap(rawEvent: MSGestureEvent): void {\r\n\t\tconst e = new EditorMouseEvent(rawEvent, this.viewHelper.viewDomNode);\r\n\t\tconst t = this._createMouseTarget(e, false);\r\n\t\tif (t.position) {\r\n\t\t\tthis.viewController.moveTo(t.position);\r\n\t\t}\r\n\t\t// IE does not want to focus when coming in from the browser's address bar\r\n\t\tif ((e.browserEvent).fromElement) {\r\n\t\t\te.preventDefault();\r\n\t\t\tthis.viewHelper.focusTextArea();\r\n\t\t} else {\r\n\t\t\t// TODO@Alex -> cancel this is focus is lost\r\n\t\t\tsetTimeout(() => {\r\n\t\t\t\tthis.viewHelper.focusTextArea();\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _onGestureChange(e: IThrottledGestureEvent): void {\r\n\t\tthis._context.model.deltaScrollNow(-e.translationX, -e.translationY);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\twindow.clearTimeout(this._installGestureHandlerTimeout);\r\n\t\tsuper.dispose();\r\n\t}\r\n}\r\n\r\n/**\r\n * Currently only tested on iOS 13/ iPadOS.\r\n */\r\nexport class PointerEventHandler extends MouseHandler {\r\n\tprivate _lastPointerType: string;\r\n\tconstructor(context: ViewContext, viewController: ViewController, viewHelper: IPointerHandlerHelper) {\r\n\t\tsuper(context, viewController, viewHelper);\r\n\r\n\t\tthis._register(Gesture.addTarget(this.viewHelper.linesContentDomNode));\r\n\t\tthis._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Tap, (e) => this.onTap(e)));\r\n\t\tthis._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Change, (e) => this.onChange(e)));\r\n\t\tthis._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Contextmenu, (e: MouseEvent) => this._onContextMenu(new EditorMouseEvent(e, this.viewHelper.viewDomNode), false)));\r\n\r\n\t\tthis._lastPointerType = 'mouse';\r\n\r\n\t\tthis._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, 'pointerdown', (e: any) => {\r\n\t\t\tconst pointerType = e.pointerType;\r\n\t\t\tif (pointerType === 'mouse') {\r\n\t\t\t\tthis._lastPointerType = 'mouse';\r\n\t\t\t\treturn;\r\n\t\t\t} else if (pointerType === 'touch') {\r\n\t\t\t\tthis._lastPointerType = 'touch';\r\n\t\t\t} else {\r\n\t\t\t\tthis._lastPointerType = 'pen';\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\t// PonterEvents\r\n\t\tconst pointerEvents = new EditorPointerEventFactory(this.viewHelper.viewDomNode);\r\n\r\n\t\tthis._register(pointerEvents.onPointerMoveThrottled(this.viewHelper.viewDomNode,\r\n\t\t\t(e) => this._onMouseMove(e),\r\n\t\t\tcreateMouseMoveEventMerger(this.mouseTargetFactory), MouseHandler.MOUSE_MOVE_MINIMUM_TIME));\r\n\t\tthis._register(pointerEvents.onPointerUp(this.viewHelper.viewDomNode, (e) => this._onMouseUp(e)));\r\n\t\tthis._register(pointerEvents.onPointerLeave(this.viewHelper.viewDomNode, (e) => this._onMouseLeave(e)));\r\n\t\tthis._register(pointerEvents.onPointerDown(this.viewHelper.viewDomNode, (e) => this._onMouseDown(e)));\r\n\t}\r\n\r\n\tprivate onTap(event: GestureEvent): void {\r\n\t\tif (!event.initialTarget || !this.viewHelper.linesContentDomNode.contains(event.initialTarget)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tevent.preventDefault();\r\n\t\tthis.viewHelper.focusTextArea();\r\n\t\tconst target = this._createMouseTarget(new EditorMouseEvent(event, this.viewHelper.viewDomNode), false);\r\n\r\n\t\tif (target.position) {\r\n\t\t\t// this.viewController.moveTo(target.position);\r\n\t\t\tthis.viewController.dispatchMouse({\r\n\t\t\t\tposition: target.position,\r\n\t\t\t\tmouseColumn: target.position.column,\r\n\t\t\t\tstartedOnLineNumbers: false,\r\n\t\t\t\tmouseDownCount: event.tapCount,\r\n\t\t\t\tinSelectionMode: false,\r\n\t\t\t\taltKey: false,\r\n\t\t\t\tctrlKey: false,\r\n\t\t\t\tmetaKey: false,\r\n\t\t\t\tshiftKey: false,\r\n\r\n\t\t\t\tleftButton: false,\r\n\t\t\t\tmiddleButton: false,\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tprivate onChange(e: GestureEvent): void {\r\n\t\tif (this._lastPointerType === 'touch') {\r\n\t\t\tthis._context.model.deltaScrollNow(-e.translationX, -e.translationY);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic _onMouseDown(e: EditorMouseEvent): void {\r\n\t\tif ((e.browserEvent as any).pointerType === 'touch') {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tsuper._onMouseDown(e);\r\n\t}\r\n}\r\n\r\nclass TouchHandler extends MouseHandler {\r\n\r\n\tconstructor(context: ViewContext, viewController: ViewController, viewHelper: IPointerHandlerHelper) {\r\n\t\tsuper(context, viewController, viewHelper);\r\n\r\n\t\tthis._register(Gesture.addTarget(this.viewHelper.linesContentDomNode));\r\n\r\n\t\tthis._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Tap, (e) => this.onTap(e)));\r\n\t\tthis._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Change, (e) => this.onChange(e)));\r\n\t\tthis._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Contextmenu, (e: MouseEvent) => this._onContextMenu(new EditorMouseEvent(e, this.viewHelper.viewDomNode), false)));\r\n\t}\r\n\r\n\tprivate onTap(event: GestureEvent): void {\r\n\t\tevent.preventDefault();\r\n\r\n\t\tthis.viewHelper.focusTextArea();\r\n\r\n\t\tconst target = this._createMouseTarget(new EditorMouseEvent(event, this.viewHelper.viewDomNode), false);\r\n\r\n\t\tif (target.position) {\r\n\t\t\tthis.viewController.moveTo(target.position);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate onChange(e: GestureEvent): void {\r\n\t\tthis._context.model.deltaScrollNow(-e.translationX, -e.translationY);\r\n\t}\r\n}\r\n\r\nexport class PointerHandler extends Disposable {\r\n\tprivate readonly handler: MouseHandler;\r\n\r\n\tconstructor(context: ViewContext, viewController: ViewController, viewHelper: IPointerHandlerHelper) {\r\n\t\tsuper();\r\n\t\tif ((platform.isIOS && BrowserFeatures.pointerEvents)) {\r\n\t\t\tthis.handler = this._register(new PointerEventHandler(context, viewController, viewHelper));\r\n\t\t} else if (window.TouchEvent) {\r\n\t\t\tthis.handler = this._register(new TouchHandler(context, viewController, viewHelper));\r\n\t\t} else if (window.navigator.pointerEnabled || window.PointerEvent) {\r\n\t\t\tthis.handler = this._register(new StandardPointerHandler(context, viewController, viewHelper));\r\n\t\t} else {\r\n\t\t\tthis.handler = this._register(new MouseHandler(context, viewController, viewHelper));\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getTargetAtClientPoint(clientX: number, clientY: number): IMouseTarget | null {\r\n\t\treturn this.handler.getTargetAtClientPoint(clientX, clientY);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { MouseTarget } from 'vs/editor/browser/controller/mouseTarget';\r\nimport { IEditorMouseEvent, IMouseTarget, IPartialEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { ICoordinatesConverter } from 'vs/editor/common/viewModel/viewModel';\r\nimport { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';\r\n\r\nexport interface EventCallback {\r\n\t(event: T): void;\r\n}\r\n\r\nexport class ViewUserInputEvents {\r\n\r\n\tpublic onKeyDown: EventCallback | null = null;\r\n\tpublic onKeyUp: EventCallback | null = null;\r\n\tpublic onContextMenu: EventCallback | null = null;\r\n\tpublic onMouseMove: EventCallback | null = null;\r\n\tpublic onMouseLeave: EventCallback | null = null;\r\n\tpublic onMouseDown: EventCallback | null = null;\r\n\tpublic onMouseUp: EventCallback | null = null;\r\n\tpublic onMouseDrag: EventCallback | null = null;\r\n\tpublic onMouseDrop: EventCallback | null = null;\r\n\tpublic onMouseDropCanceled: EventCallback | null = null;\r\n\tpublic onMouseWheel: EventCallback | null = null;\r\n\r\n\tprivate readonly _coordinatesConverter: ICoordinatesConverter;\r\n\r\n\tconstructor(coordinatesConverter: ICoordinatesConverter) {\r\n\t\tthis._coordinatesConverter = coordinatesConverter;\r\n\t}\r\n\r\n\tpublic emitKeyDown(e: IKeyboardEvent): void {\r\n\t\tif (this.onKeyDown) {\r\n\t\t\tthis.onKeyDown(e);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic emitKeyUp(e: IKeyboardEvent): void {\r\n\t\tif (this.onKeyUp) {\r\n\t\t\tthis.onKeyUp(e);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic emitContextMenu(e: IEditorMouseEvent): void {\r\n\t\tif (this.onContextMenu) {\r\n\t\t\tthis.onContextMenu(this._convertViewToModelMouseEvent(e));\r\n\t\t}\r\n\t}\r\n\r\n\tpublic emitMouseMove(e: IEditorMouseEvent): void {\r\n\t\tif (this.onMouseMove) {\r\n\t\t\tthis.onMouseMove(this._convertViewToModelMouseEvent(e));\r\n\t\t}\r\n\t}\r\n\r\n\tpublic emitMouseLeave(e: IPartialEditorMouseEvent): void {\r\n\t\tif (this.onMouseLeave) {\r\n\t\t\tthis.onMouseLeave(this._convertViewToModelMouseEvent(e));\r\n\t\t}\r\n\t}\r\n\r\n\tpublic emitMouseDown(e: IEditorMouseEvent): void {\r\n\t\tif (this.onMouseDown) {\r\n\t\t\tthis.onMouseDown(this._convertViewToModelMouseEvent(e));\r\n\t\t}\r\n\t}\r\n\r\n\tpublic emitMouseUp(e: IEditorMouseEvent): void {\r\n\t\tif (this.onMouseUp) {\r\n\t\t\tthis.onMouseUp(this._convertViewToModelMouseEvent(e));\r\n\t\t}\r\n\t}\r\n\r\n\tpublic emitMouseDrag(e: IEditorMouseEvent): void {\r\n\t\tif (this.onMouseDrag) {\r\n\t\t\tthis.onMouseDrag(this._convertViewToModelMouseEvent(e));\r\n\t\t}\r\n\t}\r\n\r\n\tpublic emitMouseDrop(e: IPartialEditorMouseEvent): void {\r\n\t\tif (this.onMouseDrop) {\r\n\t\t\tthis.onMouseDrop(this._convertViewToModelMouseEvent(e));\r\n\t\t}\r\n\t}\r\n\r\n\tpublic emitMouseDropCanceled(): void {\r\n\t\tif (this.onMouseDropCanceled) {\r\n\t\t\tthis.onMouseDropCanceled();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic emitMouseWheel(e: IMouseWheelEvent): void {\r\n\t\tif (this.onMouseWheel) {\r\n\t\t\tthis.onMouseWheel(e);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _convertViewToModelMouseEvent(e: IEditorMouseEvent): IEditorMouseEvent;\r\n\tprivate _convertViewToModelMouseEvent(e: IPartialEditorMouseEvent): IPartialEditorMouseEvent;\r\n\tprivate _convertViewToModelMouseEvent(e: IEditorMouseEvent | IPartialEditorMouseEvent): IEditorMouseEvent | IPartialEditorMouseEvent {\r\n\t\tif (e.target) {\r\n\t\t\treturn {\r\n\t\t\t\tevent: e.event,\r\n\t\t\t\ttarget: this._convertViewToModelMouseTarget(e.target)\r\n\t\t\t};\r\n\t\t}\r\n\t\treturn e;\r\n\t}\r\n\r\n\tprivate _convertViewToModelMouseTarget(target: IMouseTarget): IMouseTarget {\r\n\t\treturn ViewUserInputEvents.convertViewToModelMouseTarget(target, this._coordinatesConverter);\r\n\t}\r\n\r\n\tpublic static convertViewToModelMouseTarget(target: IMouseTarget, coordinatesConverter: ICoordinatesConverter): IMouseTarget {\r\n\t\treturn new ExternalMouseTarget(\r\n\t\t\ttarget.element,\r\n\t\t\ttarget.type,\r\n\t\t\ttarget.mouseColumn,\r\n\t\t\ttarget.position ? coordinatesConverter.convertViewPositionToModelPosition(target.position) : null,\r\n\t\t\ttarget.range ? coordinatesConverter.convertViewRangeToModelRange(target.range) : null,\r\n\t\t\ttarget.detail\r\n\t\t);\r\n\t}\r\n}\r\n\r\nclass ExternalMouseTarget implements IMouseTarget {\r\n\r\n\tpublic readonly element: Element | null;\r\n\tpublic readonly type: MouseTargetType;\r\n\tpublic readonly mouseColumn: number;\r\n\tpublic readonly position: Position | null;\r\n\tpublic readonly range: Range | null;\r\n\tpublic readonly detail: any;\r\n\r\n\tconstructor(element: Element | null, type: MouseTargetType, mouseColumn: number, position: Position | null, range: Range | null, detail: any) {\r\n\t\tthis.element = element;\r\n\t\tthis.type = type;\r\n\t\tthis.mouseColumn = mouseColumn;\r\n\t\tthis.position = position;\r\n\t\tthis.range = range;\r\n\t\tthis.detail = detail;\r\n\t}\r\n\r\n\tpublic toString(): string {\r\n\t\treturn MouseTarget.toString(this);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./viewLines';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport { FastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { RunOnceScheduler } from 'vs/base/common/async';\r\nimport { Configuration } from 'vs/editor/browser/config/configuration';\r\nimport { IVisibleLinesHost, VisibleLinesCollection } from 'vs/editor/browser/view/viewLayer';\r\nimport { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/view/viewPart';\r\nimport { DomReadingContext, ViewLine, ViewLineOptions } from 'vs/editor/browser/viewParts/lines/viewLine';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { ScrollType } from 'vs/editor/common/editorCommon';\r\nimport { IViewLines, LineVisibleRanges, VisibleRanges, HorizontalPosition } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';\r\nimport { Viewport } from 'vs/editor/common/viewModel/viewModel';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { Constants } from 'vs/base/common/uint';\r\nimport { MOUSE_CURSOR_TEXT_CSS_CLASS_NAME } from 'vs/base/browser/ui/mouseCursor/mouseCursor';\r\n\r\nclass LastRenderedData {\r\n\r\n\tprivate _currentVisibleRange: Range;\r\n\r\n\tconstructor() {\r\n\t\tthis._currentVisibleRange = new Range(1, 1, 1, 1);\r\n\t}\r\n\r\n\tpublic getCurrentVisibleRange(): Range {\r\n\t\treturn this._currentVisibleRange;\r\n\t}\r\n\r\n\tpublic setCurrentVisibleRange(currentVisibleRange: Range): void {\r\n\t\tthis._currentVisibleRange = currentVisibleRange;\r\n\t}\r\n}\r\n\r\nclass HorizontalRevealRangeRequest {\r\n\tpublic readonly type = 'range';\r\n\tpublic readonly minLineNumber: number;\r\n\tpublic readonly maxLineNumber: number;\r\n\r\n\tconstructor(\r\n\t\tpublic readonly lineNumber: number,\r\n\t\tpublic readonly startColumn: number,\r\n\t\tpublic readonly endColumn: number,\r\n\t\tpublic readonly startScrollTop: number,\r\n\t\tpublic readonly stopScrollTop: number,\r\n\t\tpublic readonly scrollType: ScrollType\r\n\t) {\r\n\t\tthis.minLineNumber = lineNumber;\r\n\t\tthis.maxLineNumber = lineNumber;\r\n\t}\r\n}\r\n\r\nclass HorizontalRevealSelectionsRequest {\r\n\tpublic readonly type = 'selections';\r\n\tpublic readonly minLineNumber: number;\r\n\tpublic readonly maxLineNumber: number;\r\n\r\n\tconstructor(\r\n\t\tpublic readonly selections: Selection[],\r\n\t\tpublic readonly startScrollTop: number,\r\n\t\tpublic readonly stopScrollTop: number,\r\n\t\tpublic readonly scrollType: ScrollType\r\n\t) {\r\n\t\tlet minLineNumber = selections[0].startLineNumber;\r\n\t\tlet maxLineNumber = selections[0].endLineNumber;\r\n\t\tfor (let i = 1, len = selections.length; i < len; i++) {\r\n\t\t\tconst selection = selections[i];\r\n\t\t\tminLineNumber = Math.min(minLineNumber, selection.startLineNumber);\r\n\t\t\tmaxLineNumber = Math.max(maxLineNumber, selection.endLineNumber);\r\n\t\t}\r\n\t\tthis.minLineNumber = minLineNumber;\r\n\t\tthis.maxLineNumber = maxLineNumber;\r\n\t}\r\n}\r\n\r\ntype HorizontalRevealRequest = HorizontalRevealRangeRequest | HorizontalRevealSelectionsRequest;\r\n\r\nexport class ViewLines extends ViewPart implements IVisibleLinesHost, IViewLines {\r\n\t/**\r\n\t * Adds this amount of pixels to the right of lines (no-one wants to type near the edge of the viewport)\r\n\t */\r\n\tprivate static readonly HORIZONTAL_EXTRA_PX = 30;\r\n\r\n\tprivate readonly _linesContent: FastDomNode;\r\n\tprivate readonly _textRangeRestingSpot: HTMLElement;\r\n\tprivate readonly _visibleLines: VisibleLinesCollection;\r\n\tprivate readonly domNode: FastDomNode;\r\n\r\n\t// --- config\r\n\tprivate _lineHeight: number;\r\n\tprivate _typicalHalfwidthCharacterWidth: number;\r\n\tprivate _isViewportWrapping: boolean;\r\n\tprivate _revealHorizontalRightPadding: number;\r\n\tprivate _cursorSurroundingLines: number;\r\n\tprivate _cursorSurroundingLinesStyle: 'default' | 'all';\r\n\tprivate _canUseLayerHinting: boolean;\r\n\tprivate _viewLineOptions: ViewLineOptions;\r\n\r\n\t// --- width\r\n\tprivate _maxLineWidth: number;\r\n\tprivate readonly _asyncUpdateLineWidths: RunOnceScheduler;\r\n\tprivate readonly _asyncCheckMonospaceFontAssumptions: RunOnceScheduler;\r\n\r\n\tprivate _horizontalRevealRequest: HorizontalRevealRequest | null;\r\n\tprivate readonly _lastRenderedData: LastRenderedData;\r\n\r\n\tconstructor(context: ViewContext, linesContent: FastDomNode) {\r\n\t\tsuper(context);\r\n\t\tthis._linesContent = linesContent;\r\n\t\tthis._textRangeRestingSpot = document.createElement('div');\r\n\t\tthis._visibleLines = new VisibleLinesCollection(this);\r\n\t\tthis.domNode = this._visibleLines.domNode;\r\n\r\n\t\tconst conf = this._context.configuration;\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst fontInfo = options.get(EditorOption.fontInfo);\r\n\t\tconst wrappingInfo = options.get(EditorOption.wrappingInfo);\r\n\r\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tthis._typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth;\r\n\t\tthis._isViewportWrapping = wrappingInfo.isViewportWrapping;\r\n\t\tthis._revealHorizontalRightPadding = options.get(EditorOption.revealHorizontalRightPadding);\r\n\t\tthis._cursorSurroundingLines = options.get(EditorOption.cursorSurroundingLines);\r\n\t\tthis._cursorSurroundingLinesStyle = options.get(EditorOption.cursorSurroundingLinesStyle);\r\n\t\tthis._canUseLayerHinting = !options.get(EditorOption.disableLayerHinting);\r\n\t\tthis._viewLineOptions = new ViewLineOptions(conf, this._context.theme.type);\r\n\r\n\t\tPartFingerprints.write(this.domNode, PartFingerprint.ViewLines);\r\n\t\tthis.domNode.setClassName(`view-lines ${MOUSE_CURSOR_TEXT_CSS_CLASS_NAME}`);\r\n\t\tConfiguration.applyFontInfo(this.domNode, fontInfo);\r\n\r\n\t\t// --- width & height\r\n\t\tthis._maxLineWidth = 0;\r\n\t\tthis._asyncUpdateLineWidths = new RunOnceScheduler(() => {\r\n\t\t\tthis._updateLineWidthsSlow();\r\n\t\t}, 200);\r\n\t\tthis._asyncCheckMonospaceFontAssumptions = new RunOnceScheduler(() => {\r\n\t\t\tthis._checkMonospaceFontAssumptions();\r\n\t\t}, 2000);\r\n\r\n\t\tthis._lastRenderedData = new LastRenderedData();\r\n\r\n\t\tthis._horizontalRevealRequest = null;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._asyncUpdateLineWidths.dispose();\r\n\t\tthis._asyncCheckMonospaceFontAssumptions.dispose();\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tpublic getDomNode(): FastDomNode {\r\n\t\treturn this.domNode;\r\n\t}\r\n\r\n\t// ---- begin IVisibleLinesHost\r\n\r\n\tpublic createVisibleLine(): ViewLine {\r\n\t\treturn new ViewLine(this._viewLineOptions);\r\n\t}\r\n\r\n\t// ---- end IVisibleLinesHost\r\n\r\n\t// ---- begin view event handlers\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tthis._visibleLines.onConfigurationChanged(e);\r\n\t\tif (e.hasChanged(EditorOption.wrappingInfo)) {\r\n\t\t\tthis._maxLineWidth = 0;\r\n\t\t}\r\n\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst fontInfo = options.get(EditorOption.fontInfo);\r\n\t\tconst wrappingInfo = options.get(EditorOption.wrappingInfo);\r\n\r\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tthis._typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth;\r\n\t\tthis._isViewportWrapping = wrappingInfo.isViewportWrapping;\r\n\t\tthis._revealHorizontalRightPadding = options.get(EditorOption.revealHorizontalRightPadding);\r\n\t\tthis._cursorSurroundingLines = options.get(EditorOption.cursorSurroundingLines);\r\n\t\tthis._cursorSurroundingLinesStyle = options.get(EditorOption.cursorSurroundingLinesStyle);\r\n\t\tthis._canUseLayerHinting = !options.get(EditorOption.disableLayerHinting);\r\n\t\tConfiguration.applyFontInfo(this.domNode, fontInfo);\r\n\r\n\t\tthis._onOptionsMaybeChanged();\r\n\r\n\t\tif (e.hasChanged(EditorOption.layoutInfo)) {\r\n\t\t\tthis._maxLineWidth = 0;\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\tprivate _onOptionsMaybeChanged(): boolean {\r\n\t\tconst conf = this._context.configuration;\r\n\r\n\t\tconst newViewLineOptions = new ViewLineOptions(conf, this._context.theme.type);\r\n\t\tif (!this._viewLineOptions.equals(newViewLineOptions)) {\r\n\t\t\tthis._viewLineOptions = newViewLineOptions;\r\n\r\n\t\t\tconst startLineNumber = this._visibleLines.getStartLineNumber();\r\n\t\t\tconst endLineNumber = this._visibleLines.getEndLineNumber();\r\n\t\t\tfor (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {\r\n\t\t\t\tconst line = this._visibleLines.getVisibleLine(lineNumber);\r\n\t\t\t\tline.onOptionsChanged(this._viewLineOptions);\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\t}\r\n\tpublic onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {\r\n\t\tconst rendStartLineNumber = this._visibleLines.getStartLineNumber();\r\n\t\tconst rendEndLineNumber = this._visibleLines.getEndLineNumber();\r\n\t\tlet r = false;\r\n\t\tfor (let lineNumber = rendStartLineNumber; lineNumber <= rendEndLineNumber; lineNumber++) {\r\n\t\t\tr = this._visibleLines.getVisibleLine(lineNumber).onSelectionChanged() || r;\r\n\t\t}\r\n\t\treturn r;\r\n\t}\r\n\tpublic onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {\r\n\t\tif (true/*e.inlineDecorationsChanged*/) {\r\n\t\t\tconst rendStartLineNumber = this._visibleLines.getStartLineNumber();\r\n\t\t\tconst rendEndLineNumber = this._visibleLines.getEndLineNumber();\r\n\t\t\tfor (let lineNumber = rendStartLineNumber; lineNumber <= rendEndLineNumber; lineNumber++) {\r\n\t\t\t\tthis._visibleLines.getVisibleLine(lineNumber).onDecorationsChanged();\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\tpublic onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\r\n\t\tconst shouldRender = this._visibleLines.onFlushed(e);\r\n\t\tthis._maxLineWidth = 0;\r\n\t\treturn shouldRender;\r\n\t}\r\n\tpublic onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\r\n\t\treturn this._visibleLines.onLinesChanged(e);\r\n\t}\r\n\tpublic onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\r\n\t\treturn this._visibleLines.onLinesDeleted(e);\r\n\t}\r\n\tpublic onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\r\n\t\treturn this._visibleLines.onLinesInserted(e);\r\n\t}\r\n\tpublic onRevealRangeRequest(e: viewEvents.ViewRevealRangeRequestEvent): boolean {\r\n\t\t// Using the future viewport here in order to handle multiple\r\n\t\t// incoming reveal range requests that might all desire to be animated\r\n\t\tconst desiredScrollTop = this._computeScrollTopToRevealRange(this._context.viewLayout.getFutureViewport(), e.source, e.range, e.selections, e.verticalType);\r\n\r\n\t\tif (desiredScrollTop === -1) {\r\n\t\t\t// marker to abort the reveal range request\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\t// validate the new desired scroll top\r\n\t\tlet newScrollPosition = this._context.viewLayout.validateScrollPosition({ scrollTop: desiredScrollTop });\r\n\r\n\t\tif (e.revealHorizontal) {\r\n\t\t\tif (e.range && e.range.startLineNumber !== e.range.endLineNumber) {\r\n\t\t\t\t// Two or more lines? => scroll to base (That's how you see most of the two lines)\r\n\t\t\t\tnewScrollPosition = {\r\n\t\t\t\t\tscrollTop: newScrollPosition.scrollTop,\r\n\t\t\t\t\tscrollLeft: 0\r\n\t\t\t\t};\r\n\t\t\t} else if (e.range) {\r\n\t\t\t\t// We don't necessarily know the horizontal offset of this range since the line might not be in the view...\r\n\t\t\t\tthis._horizontalRevealRequest = new HorizontalRevealRangeRequest(e.range.startLineNumber, e.range.startColumn, e.range.endColumn, this._context.viewLayout.getCurrentScrollTop(), newScrollPosition.scrollTop, e.scrollType);\r\n\t\t\t} else if (e.selections && e.selections.length > 0) {\r\n\t\t\t\tthis._horizontalRevealRequest = new HorizontalRevealSelectionsRequest(e.selections, this._context.viewLayout.getCurrentScrollTop(), newScrollPosition.scrollTop, e.scrollType);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tthis._horizontalRevealRequest = null;\r\n\t\t}\r\n\r\n\t\tconst scrollTopDelta = Math.abs(this._context.viewLayout.getCurrentScrollTop() - newScrollPosition.scrollTop);\r\n\t\tconst scrollType = (scrollTopDelta <= this._lineHeight ? ScrollType.Immediate : e.scrollType);\r\n\t\tthis._context.model.setScrollPosition(newScrollPosition, scrollType);\r\n\r\n\t\treturn true;\r\n\t}\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\tif (this._horizontalRevealRequest && e.scrollLeftChanged) {\r\n\t\t\t// cancel any outstanding horizontal reveal request if someone else scrolls horizontally.\r\n\t\t\tthis._horizontalRevealRequest = null;\r\n\t\t}\r\n\t\tif (this._horizontalRevealRequest && e.scrollTopChanged) {\r\n\t\t\tconst min = Math.min(this._horizontalRevealRequest.startScrollTop, this._horizontalRevealRequest.stopScrollTop);\r\n\t\t\tconst max = Math.max(this._horizontalRevealRequest.startScrollTop, this._horizontalRevealRequest.stopScrollTop);\r\n\t\t\tif (e.scrollTop < min || e.scrollTop > max) {\r\n\t\t\t\t// cancel any outstanding horizontal reveal request if someone else scrolls vertically.\r\n\t\t\t\tthis._horizontalRevealRequest = null;\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis.domNode.setWidth(e.scrollWidth);\r\n\t\treturn this._visibleLines.onScrollChanged(e) || true;\r\n\t}\r\n\r\n\tpublic onTokensChanged(e: viewEvents.ViewTokensChangedEvent): boolean {\r\n\t\treturn this._visibleLines.onTokensChanged(e);\r\n\t}\r\n\tpublic onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\r\n\t\tthis._context.model.setMaxLineWidth(this._maxLineWidth);\r\n\t\treturn this._visibleLines.onZonesChanged(e);\r\n\t}\r\n\tpublic onThemeChanged(e: viewEvents.ViewThemeChangedEvent): boolean {\r\n\t\treturn this._onOptionsMaybeChanged();\r\n\t}\r\n\r\n\t// ---- end view event handlers\r\n\r\n\t// ----------- HELPERS FOR OTHERS\r\n\r\n\tpublic getPositionFromDOMInfo(spanNode: HTMLElement, offset: number): Position | null {\r\n\t\tconst viewLineDomNode = this._getViewLineDomNode(spanNode);\r\n\t\tif (viewLineDomNode === null) {\r\n\t\t\t// Couldn't find view line node\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tconst lineNumber = this._getLineNumberFor(viewLineDomNode);\r\n\r\n\t\tif (lineNumber === -1) {\r\n\t\t\t// Couldn't find view line node\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (lineNumber < 1 || lineNumber > this._context.model.getLineCount()) {\r\n\t\t\t// lineNumber is outside range\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (this._context.model.getLineMaxColumn(lineNumber) === 1) {\r\n\t\t\t// Line is empty\r\n\t\t\treturn new Position(lineNumber, 1);\r\n\t\t}\r\n\r\n\t\tconst rendStartLineNumber = this._visibleLines.getStartLineNumber();\r\n\t\tconst rendEndLineNumber = this._visibleLines.getEndLineNumber();\r\n\t\tif (lineNumber < rendStartLineNumber || lineNumber > rendEndLineNumber) {\r\n\t\t\t// Couldn't find line\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet column = this._visibleLines.getVisibleLine(lineNumber).getColumnOfNodeOffset(lineNumber, spanNode, offset);\r\n\t\tconst minColumn = this._context.model.getLineMinColumn(lineNumber);\r\n\t\tif (column < minColumn) {\r\n\t\t\tcolumn = minColumn;\r\n\t\t}\r\n\t\treturn new Position(lineNumber, column);\r\n\t}\r\n\r\n\tprivate _getViewLineDomNode(node: HTMLElement | null): HTMLElement | null {\r\n\t\twhile (node && node.nodeType === 1) {\r\n\t\t\tif (node.className === ViewLine.CLASS_NAME) {\r\n\t\t\t\treturn node;\r\n\t\t\t}\r\n\t\t\tnode = node.parentElement;\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\t/**\r\n\t * @returns the line number of this view line dom node.\r\n\t */\r\n\tprivate _getLineNumberFor(domNode: HTMLElement): number {\r\n\t\tconst startLineNumber = this._visibleLines.getStartLineNumber();\r\n\t\tconst endLineNumber = this._visibleLines.getEndLineNumber();\r\n\t\tfor (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {\r\n\t\t\tconst line = this._visibleLines.getVisibleLine(lineNumber);\r\n\t\t\tif (domNode === line.getDomNode()) {\r\n\t\t\t\treturn lineNumber;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn -1;\r\n\t}\r\n\r\n\tpublic getLineWidth(lineNumber: number): number {\r\n\t\tconst rendStartLineNumber = this._visibleLines.getStartLineNumber();\r\n\t\tconst rendEndLineNumber = this._visibleLines.getEndLineNumber();\r\n\t\tif (lineNumber < rendStartLineNumber || lineNumber > rendEndLineNumber) {\r\n\t\t\t// Couldn't find line\r\n\t\t\treturn -1;\r\n\t\t}\r\n\r\n\t\treturn this._visibleLines.getVisibleLine(lineNumber).getWidth();\r\n\t}\r\n\r\n\tpublic linesVisibleRangesForRange(_range: Range, includeNewLines: boolean): LineVisibleRanges[] | null {\r\n\t\tif (this.shouldRender()) {\r\n\t\t\t// Cannot read from the DOM because it is dirty\r\n\t\t\t// i.e. the model & the dom are out of sync, so I'd be reading something stale\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst originalEndLineNumber = _range.endLineNumber;\r\n\t\tconst range = Range.intersectRanges(_range, this._lastRenderedData.getCurrentVisibleRange());\r\n\t\tif (!range) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet visibleRanges: LineVisibleRanges[] = [], visibleRangesLen = 0;\r\n\t\tconst domReadingContext = new DomReadingContext(this.domNode.domNode, this._textRangeRestingSpot);\r\n\r\n\t\tlet nextLineModelLineNumber: number = 0;\r\n\t\tif (includeNewLines) {\r\n\t\t\tnextLineModelLineNumber = this._context.model.coordinatesConverter.convertViewPositionToModelPosition(new Position(range.startLineNumber, 1)).lineNumber;\r\n\t\t}\r\n\r\n\t\tconst rendStartLineNumber = this._visibleLines.getStartLineNumber();\r\n\t\tconst rendEndLineNumber = this._visibleLines.getEndLineNumber();\r\n\t\tfor (let lineNumber = range.startLineNumber; lineNumber <= range.endLineNumber; lineNumber++) {\r\n\r\n\t\t\tif (lineNumber < rendStartLineNumber || lineNumber > rendEndLineNumber) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tconst startColumn = lineNumber === range.startLineNumber ? range.startColumn : 1;\r\n\t\t\tconst endColumn = lineNumber === range.endLineNumber ? range.endColumn : this._context.model.getLineMaxColumn(lineNumber);\r\n\t\t\tconst visibleRangesForLine = this._visibleLines.getVisibleLine(lineNumber).getVisibleRangesForRange(startColumn, endColumn, domReadingContext);\r\n\r\n\t\t\tif (!visibleRangesForLine) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (includeNewLines && lineNumber < originalEndLineNumber) {\r\n\t\t\t\tconst currentLineModelLineNumber = nextLineModelLineNumber;\r\n\t\t\t\tnextLineModelLineNumber = this._context.model.coordinatesConverter.convertViewPositionToModelPosition(new Position(lineNumber + 1, 1)).lineNumber;\r\n\r\n\t\t\t\tif (currentLineModelLineNumber !== nextLineModelLineNumber) {\r\n\t\t\t\t\tvisibleRangesForLine.ranges[visibleRangesForLine.ranges.length - 1].width += this._typicalHalfwidthCharacterWidth;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tvisibleRanges[visibleRangesLen++] = new LineVisibleRanges(visibleRangesForLine.outsideRenderedLine, lineNumber, visibleRangesForLine.ranges);\r\n\t\t}\r\n\r\n\t\tif (visibleRangesLen === 0) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\treturn visibleRanges;\r\n\t}\r\n\r\n\tprivate _visibleRangesForLineRange(lineNumber: number, startColumn: number, endColumn: number): VisibleRanges | null {\r\n\t\tif (this.shouldRender()) {\r\n\t\t\t// Cannot read from the DOM because it is dirty\r\n\t\t\t// i.e. the model & the dom are out of sync, so I'd be reading something stale\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (lineNumber < this._visibleLines.getStartLineNumber() || lineNumber > this._visibleLines.getEndLineNumber()) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\treturn this._visibleLines.getVisibleLine(lineNumber).getVisibleRangesForRange(startColumn, endColumn, new DomReadingContext(this.domNode.domNode, this._textRangeRestingSpot));\r\n\t}\r\n\r\n\tpublic visibleRangeForPosition(position: Position): HorizontalPosition | null {\r\n\t\tconst visibleRanges = this._visibleRangesForLineRange(position.lineNumber, position.column, position.column);\r\n\t\tif (!visibleRanges) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn new HorizontalPosition(visibleRanges.outsideRenderedLine, visibleRanges.ranges[0].left);\r\n\t}\r\n\r\n\t// --- implementation\r\n\r\n\tpublic updateLineWidths(): void {\r\n\t\tthis._updateLineWidths(false);\r\n\t}\r\n\r\n\t/**\r\n\t * Updates the max line width if it is fast to compute.\r\n\t * Returns true if all lines were taken into account.\r\n\t * Returns false if some lines need to be reevaluated (in a slow fashion).\r\n\t */\r\n\tprivate _updateLineWidthsFast(): boolean {\r\n\t\treturn this._updateLineWidths(true);\r\n\t}\r\n\r\n\tprivate _updateLineWidthsSlow(): void {\r\n\t\tthis._updateLineWidths(false);\r\n\t}\r\n\r\n\tprivate _updateLineWidths(fast: boolean): boolean {\r\n\t\tconst rendStartLineNumber = this._visibleLines.getStartLineNumber();\r\n\t\tconst rendEndLineNumber = this._visibleLines.getEndLineNumber();\r\n\r\n\t\tlet localMaxLineWidth = 1;\r\n\t\tlet allWidthsComputed = true;\r\n\t\tfor (let lineNumber = rendStartLineNumber; lineNumber <= rendEndLineNumber; lineNumber++) {\r\n\t\t\tconst visibleLine = this._visibleLines.getVisibleLine(lineNumber);\r\n\r\n\t\t\tif (fast && !visibleLine.getWidthIsFast()) {\r\n\t\t\t\t// Cannot compute width in a fast way for this line\r\n\t\t\t\tallWidthsComputed = false;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tlocalMaxLineWidth = Math.max(localMaxLineWidth, visibleLine.getWidth());\r\n\t\t}\r\n\r\n\t\tif (allWidthsComputed && rendStartLineNumber === 1 && rendEndLineNumber === this._context.model.getLineCount()) {\r\n\t\t\t// we know the max line width for all the lines\r\n\t\t\tthis._maxLineWidth = 0;\r\n\t\t}\r\n\r\n\t\tthis._ensureMaxLineWidth(localMaxLineWidth);\r\n\r\n\t\treturn allWidthsComputed;\r\n\t}\r\n\r\n\tprivate _checkMonospaceFontAssumptions(): void {\r\n\t\t// Problems with monospace assumptions are more apparent for longer lines,\r\n\t\t// as small rounding errors start to sum up, so we will select the longest\r\n\t\t// line for a closer inspection\r\n\t\tlet longestLineNumber = -1;\r\n\t\tlet longestWidth = -1;\r\n\t\tconst rendStartLineNumber = this._visibleLines.getStartLineNumber();\r\n\t\tconst rendEndLineNumber = this._visibleLines.getEndLineNumber();\r\n\t\tfor (let lineNumber = rendStartLineNumber; lineNumber <= rendEndLineNumber; lineNumber++) {\r\n\t\t\tconst visibleLine = this._visibleLines.getVisibleLine(lineNumber);\r\n\t\t\tif (visibleLine.needsMonospaceFontCheck()) {\r\n\t\t\t\tconst lineWidth = visibleLine.getWidth();\r\n\t\t\t\tif (lineWidth > longestWidth) {\r\n\t\t\t\t\tlongestWidth = lineWidth;\r\n\t\t\t\t\tlongestLineNumber = lineNumber;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (longestLineNumber === -1) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!this._visibleLines.getVisibleLine(longestLineNumber).monospaceAssumptionsAreValid()) {\r\n\t\t\tfor (let lineNumber = rendStartLineNumber; lineNumber <= rendEndLineNumber; lineNumber++) {\r\n\t\t\t\tconst visibleLine = this._visibleLines.getVisibleLine(lineNumber);\r\n\t\t\t\tvisibleLine.onMonospaceAssumptionsInvalidated();\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic prepareRender(): void {\r\n\t\tthrow new Error('Not supported');\r\n\t}\r\n\r\n\tpublic render(): void {\r\n\t\tthrow new Error('Not supported');\r\n\t}\r\n\r\n\tpublic renderText(viewportData: ViewportData): void {\r\n\t\t// (1) render lines - ensures lines are in the DOM\r\n\t\tthis._visibleLines.renderLines(viewportData);\r\n\t\tthis._lastRenderedData.setCurrentVisibleRange(viewportData.visibleRange);\r\n\t\tthis.domNode.setWidth(this._context.viewLayout.getScrollWidth());\r\n\t\tthis.domNode.setHeight(Math.min(this._context.viewLayout.getScrollHeight(), 1000000));\r\n\r\n\t\t// (2) compute horizontal scroll position:\r\n\t\t// - this must happen after the lines are in the DOM since it might need a line that rendered just now\r\n\t\t// - it might change `scrollWidth` and `scrollLeft`\r\n\t\tif (this._horizontalRevealRequest) {\r\n\r\n\t\t\tconst horizontalRevealRequest = this._horizontalRevealRequest;\r\n\r\n\t\t\t// Check that we have the line that contains the horizontal range in the viewport\r\n\t\t\tif (viewportData.startLineNumber <= horizontalRevealRequest.minLineNumber && horizontalRevealRequest.maxLineNumber <= viewportData.endLineNumber) {\r\n\r\n\t\t\t\tthis._horizontalRevealRequest = null;\r\n\r\n\t\t\t\t// allow `visibleRangesForRange2` to work\r\n\t\t\t\tthis.onDidRender();\r\n\r\n\t\t\t\t// compute new scroll position\r\n\t\t\t\tconst newScrollLeft = this._computeScrollLeftToReveal(horizontalRevealRequest);\r\n\r\n\t\t\t\tif (newScrollLeft) {\r\n\t\t\t\t\tif (!this._isViewportWrapping) {\r\n\t\t\t\t\t\t// ensure `scrollWidth` is large enough\r\n\t\t\t\t\t\tthis._ensureMaxLineWidth(newScrollLeft.maxHorizontalOffset);\r\n\t\t\t\t\t}\r\n\t\t\t\t\t// set `scrollLeft`\r\n\t\t\t\t\tthis._context.model.setScrollPosition({\r\n\t\t\t\t\t\tscrollLeft: newScrollLeft.scrollLeft\r\n\t\t\t\t\t}, horizontalRevealRequest.scrollType);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Update max line width (not so important, it is just so the horizontal scrollbar doesn't get too small)\r\n\t\tif (!this._updateLineWidthsFast()) {\r\n\t\t\t// Computing the width of some lines would be slow => delay it\r\n\t\t\tthis._asyncUpdateLineWidths.schedule();\r\n\t\t}\r\n\r\n\t\tif (platform.isLinux && !this._asyncCheckMonospaceFontAssumptions.isScheduled()) {\r\n\t\t\tconst rendStartLineNumber = this._visibleLines.getStartLineNumber();\r\n\t\t\tconst rendEndLineNumber = this._visibleLines.getEndLineNumber();\r\n\t\t\tfor (let lineNumber = rendStartLineNumber; lineNumber <= rendEndLineNumber; lineNumber++) {\r\n\t\t\t\tconst visibleLine = this._visibleLines.getVisibleLine(lineNumber);\r\n\t\t\t\tif (visibleLine.needsMonospaceFontCheck()) {\r\n\t\t\t\t\tthis._asyncCheckMonospaceFontAssumptions.schedule();\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// (3) handle scrolling\r\n\t\tthis._linesContent.setLayerHinting(this._canUseLayerHinting);\r\n\t\tthis._linesContent.setContain('strict');\r\n\t\tconst adjustedScrollTop = this._context.viewLayout.getCurrentScrollTop() - viewportData.bigNumbersDelta;\r\n\t\tthis._linesContent.setTop(-adjustedScrollTop);\r\n\t\tthis._linesContent.setLeft(-this._context.viewLayout.getCurrentScrollLeft());\r\n\t}\r\n\r\n\t// --- width\r\n\r\n\tprivate _ensureMaxLineWidth(lineWidth: number): void {\r\n\t\tconst iLineWidth = Math.ceil(lineWidth);\r\n\t\tif (this._maxLineWidth < iLineWidth) {\r\n\t\t\tthis._maxLineWidth = iLineWidth;\r\n\t\t\tthis._context.model.setMaxLineWidth(this._maxLineWidth);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _computeScrollTopToRevealRange(viewport: Viewport, source: string | null | undefined, range: Range | null, selections: Selection[] | null, verticalType: viewEvents.VerticalRevealType): number {\r\n\t\tconst viewportStartY = viewport.top;\r\n\t\tconst viewportHeight = viewport.height;\r\n\t\tconst viewportEndY = viewportStartY + viewportHeight;\r\n\t\tlet boxIsSingleRange: boolean;\r\n\t\tlet boxStartY: number;\r\n\t\tlet boxEndY: number;\r\n\r\n\t\t// Have a box that includes one extra line height (for the horizontal scrollbar)\r\n\t\tif (selections && selections.length > 0) {\r\n\t\t\tlet minLineNumber = selections[0].startLineNumber;\r\n\t\t\tlet maxLineNumber = selections[0].endLineNumber;\r\n\t\t\tfor (let i = 1, len = selections.length; i < len; i++) {\r\n\t\t\t\tconst selection = selections[i];\r\n\t\t\t\tminLineNumber = Math.min(minLineNumber, selection.startLineNumber);\r\n\t\t\t\tmaxLineNumber = Math.max(maxLineNumber, selection.endLineNumber);\r\n\t\t\t}\r\n\t\t\tboxIsSingleRange = false;\r\n\t\t\tboxStartY = this._context.viewLayout.getVerticalOffsetForLineNumber(minLineNumber);\r\n\t\t\tboxEndY = this._context.viewLayout.getVerticalOffsetForLineNumber(maxLineNumber) + this._lineHeight;\r\n\t\t} else if (range) {\r\n\t\t\tboxIsSingleRange = true;\r\n\t\t\tboxStartY = this._context.viewLayout.getVerticalOffsetForLineNumber(range.startLineNumber);\r\n\t\t\tboxEndY = this._context.viewLayout.getVerticalOffsetForLineNumber(range.endLineNumber) + this._lineHeight;\r\n\t\t} else {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\r\n\t\tconst shouldIgnoreScrollOff = source === 'mouse' && this._cursorSurroundingLinesStyle === 'default';\r\n\r\n\t\tif (!shouldIgnoreScrollOff) {\r\n\t\t\tconst context = Math.min((viewportHeight / this._lineHeight) / 2, this._cursorSurroundingLines);\r\n\t\t\tboxStartY -= context * this._lineHeight;\r\n\t\t\tboxEndY += Math.max(0, (context - 1)) * this._lineHeight;\r\n\t\t}\r\n\r\n\t\tif (verticalType === viewEvents.VerticalRevealType.Simple || verticalType === viewEvents.VerticalRevealType.Bottom) {\r\n\t\t\t// Reveal one line more when the last line would be covered by the scrollbar - arrow down case or revealing a line explicitly at bottom\r\n\t\t\tboxEndY += this._lineHeight;\r\n\t\t}\r\n\r\n\t\tlet newScrollTop: number;\r\n\r\n\t\tif (boxEndY - boxStartY > viewportHeight) {\r\n\t\t\t// the box is larger than the viewport ... scroll to its top\r\n\t\t\tif (!boxIsSingleRange) {\r\n\t\t\t\t// do not reveal multiple cursors if there are more than fit the viewport\r\n\t\t\t\treturn -1;\r\n\t\t\t}\r\n\t\t\tnewScrollTop = boxStartY;\r\n\t\t} else if (verticalType === viewEvents.VerticalRevealType.NearTop || verticalType === viewEvents.VerticalRevealType.NearTopIfOutsideViewport) {\r\n\t\t\tif (verticalType === viewEvents.VerticalRevealType.NearTopIfOutsideViewport && viewportStartY <= boxStartY && boxEndY <= viewportEndY) {\r\n\t\t\t\t// Box is already in the viewport... do nothing\r\n\t\t\t\tnewScrollTop = viewportStartY;\r\n\t\t\t} else {\r\n\t\t\t\t// We want a gap that is 20% of the viewport, but with a minimum of 5 lines\r\n\t\t\t\tconst desiredGapAbove = Math.max(5 * this._lineHeight, viewportHeight * 0.2);\r\n\t\t\t\t// Try to scroll just above the box with the desired gap\r\n\t\t\t\tconst desiredScrollTop = boxStartY - desiredGapAbove;\r\n\t\t\t\t// But ensure that the box is not pushed out of viewport\r\n\t\t\t\tconst minScrollTop = boxEndY - viewportHeight;\r\n\t\t\t\tnewScrollTop = Math.max(minScrollTop, desiredScrollTop);\r\n\t\t\t}\r\n\t\t} else if (verticalType === viewEvents.VerticalRevealType.Center || verticalType === viewEvents.VerticalRevealType.CenterIfOutsideViewport) {\r\n\t\t\tif (verticalType === viewEvents.VerticalRevealType.CenterIfOutsideViewport && viewportStartY <= boxStartY && boxEndY <= viewportEndY) {\r\n\t\t\t\t// Box is already in the viewport... do nothing\r\n\t\t\t\tnewScrollTop = viewportStartY;\r\n\t\t\t} else {\r\n\t\t\t\t// Box is outside the viewport... center it\r\n\t\t\t\tconst boxMiddleY = (boxStartY + boxEndY) / 2;\r\n\t\t\t\tnewScrollTop = Math.max(0, boxMiddleY - viewportHeight / 2);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tnewScrollTop = this._computeMinimumScrolling(viewportStartY, viewportEndY, boxStartY, boxEndY, verticalType === viewEvents.VerticalRevealType.Top, verticalType === viewEvents.VerticalRevealType.Bottom);\r\n\t\t}\r\n\r\n\t\treturn newScrollTop;\r\n\t}\r\n\r\n\tprivate _computeScrollLeftToReveal(horizontalRevealRequest: HorizontalRevealRequest): { scrollLeft: number; maxHorizontalOffset: number; } | null {\r\n\r\n\t\tconst viewport = this._context.viewLayout.getCurrentViewport();\r\n\t\tconst viewportStartX = viewport.left;\r\n\t\tconst viewportEndX = viewportStartX + viewport.width;\r\n\r\n\t\tlet boxStartX = Constants.MAX_SAFE_SMALL_INTEGER;\r\n\t\tlet boxEndX = 0;\r\n\t\tif (horizontalRevealRequest.type === 'range') {\r\n\t\t\tconst visibleRanges = this._visibleRangesForLineRange(horizontalRevealRequest.lineNumber, horizontalRevealRequest.startColumn, horizontalRevealRequest.endColumn);\r\n\t\t\tif (!visibleRanges) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t\tfor (const visibleRange of visibleRanges.ranges) {\r\n\t\t\t\tboxStartX = Math.min(boxStartX, visibleRange.left);\r\n\t\t\t\tboxEndX = Math.max(boxEndX, visibleRange.left + visibleRange.width);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tfor (const selection of horizontalRevealRequest.selections) {\r\n\t\t\t\tif (selection.startLineNumber !== selection.endLineNumber) {\r\n\t\t\t\t\treturn null;\r\n\t\t\t\t}\r\n\t\t\t\tconst visibleRanges = this._visibleRangesForLineRange(selection.startLineNumber, selection.startColumn, selection.endColumn);\r\n\t\t\t\tif (!visibleRanges) {\r\n\t\t\t\t\treturn null;\r\n\t\t\t\t}\r\n\t\t\t\tfor (const visibleRange of visibleRanges.ranges) {\r\n\t\t\t\t\tboxStartX = Math.min(boxStartX, visibleRange.left);\r\n\t\t\t\t\tboxEndX = Math.max(boxEndX, visibleRange.left + visibleRange.width);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tboxStartX = Math.max(0, boxStartX - ViewLines.HORIZONTAL_EXTRA_PX);\r\n\t\tboxEndX += this._revealHorizontalRightPadding;\r\n\r\n\t\tif (horizontalRevealRequest.type === 'selections' && boxEndX - boxStartX > viewport.width) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst newScrollLeft = this._computeMinimumScrolling(viewportStartX, viewportEndX, boxStartX, boxEndX);\r\n\t\treturn {\r\n\t\t\tscrollLeft: newScrollLeft,\r\n\t\t\tmaxHorizontalOffset: boxEndX\r\n\t\t};\r\n\t}\r\n\r\n\tprivate _computeMinimumScrolling(viewportStart: number, viewportEnd: number, boxStart: number, boxEnd: number, revealAtStart?: boolean, revealAtEnd?: boolean): number {\r\n\t\tviewportStart = viewportStart | 0;\r\n\t\tviewportEnd = viewportEnd | 0;\r\n\t\tboxStart = boxStart | 0;\r\n\t\tboxEnd = boxEnd | 0;\r\n\t\trevealAtStart = !!revealAtStart;\r\n\t\trevealAtEnd = !!revealAtEnd;\r\n\r\n\t\tconst viewportLength = viewportEnd - viewportStart;\r\n\t\tconst boxLength = boxEnd - boxStart;\r\n\r\n\t\tif (boxLength < viewportLength) {\r\n\t\t\t// The box would fit in the viewport\r\n\r\n\t\t\tif (revealAtStart) {\r\n\t\t\t\treturn boxStart;\r\n\t\t\t}\r\n\r\n\t\t\tif (revealAtEnd) {\r\n\t\t\t\treturn Math.max(0, boxEnd - viewportLength);\r\n\t\t\t}\r\n\r\n\t\t\tif (boxStart < viewportStart) {\r\n\t\t\t\t// The box is above the viewport\r\n\t\t\t\treturn boxStart;\r\n\t\t\t} else if (boxEnd > viewportEnd) {\r\n\t\t\t\t// The box is below the viewport\r\n\t\t\t\treturn Math.max(0, boxEnd - viewportLength);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\t// The box would not fit in the viewport\r\n\t\t\t// Reveal the beginning of the box\r\n\t\t\treturn boxStart;\r\n\t\t}\r\n\r\n\t\treturn viewportStart;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { IDisposable, toDisposable, Disposable } from 'vs/base/common/lifecycle';\r\nimport * as platform from 'vs/platform/registry/common/platform';\r\nimport { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry';\r\nimport { Event, Emitter } from 'vs/base/common/event';\r\nimport { IEnvironmentService } from 'vs/platform/environment/common/environment';\r\nimport { ColorScheme } from 'vs/platform/theme/common/theme';\r\nimport { CSSIcon } from 'vs/base/common/codicons';\r\n\r\nexport const IThemeService = createDecorator('themeService');\r\n\r\nexport interface ThemeColor {\r\n\tid: string;\r\n}\r\n\r\nexport namespace ThemeColor {\r\n\texport function isThemeColor(obj: any): obj is ThemeColor {\r\n\t\treturn obj && typeof obj === 'object' && typeof (obj).id === 'string';\r\n\t}\r\n}\r\n\r\nexport function themeColorFromId(id: ColorIdentifier) {\r\n\treturn { id };\r\n}\r\n\r\n// theme icon\r\nexport interface ThemeIcon {\r\n\treadonly id: string;\r\n\treadonly color?: ThemeColor;\r\n}\r\n\r\nexport namespace ThemeIcon {\r\n\texport function isThemeIcon(obj: any): obj is ThemeIcon {\r\n\t\treturn obj && typeof obj === 'object' && typeof (obj).id === 'string' && (typeof (obj).color === 'undefined' || ThemeColor.isThemeColor((obj).color));\r\n\t}\r\n\r\n\tconst _regexFromString = /^\\$\\(([a-z.]+\\/)?([a-z-~]+)\\)$/i;\r\n\r\n\texport function fromString(str: string): ThemeIcon | undefined {\r\n\t\tconst match = _regexFromString.exec(str);\r\n\t\tif (!match) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\t\tlet [, owner, name] = match;\r\n\t\tif (!owner || owner === 'codicon/') {\r\n\t\t\treturn { id: name };\r\n\t\t}\r\n\t\treturn { id: owner + name };\r\n\t}\r\n\r\n\texport function modify(icon: ThemeIcon, modifier: 'disabled' | 'spin' | undefined): ThemeIcon {\r\n\t\tlet id = icon.id;\r\n\t\tconst tildeIndex = id.lastIndexOf('~');\r\n\t\tif (tildeIndex !== -1) {\r\n\t\t\tid = id.substring(0, tildeIndex);\r\n\t\t}\r\n\t\tif (modifier) {\r\n\t\t\tid = `${id}~${modifier}`;\r\n\t\t}\r\n\t\treturn { id };\r\n\t}\r\n\r\n\texport function isEqual(ti1: ThemeIcon, ti2: ThemeIcon): boolean {\r\n\t\treturn ti1.id === ti2.id && ti1.color?.id === ti2.color?.id;\r\n\t}\r\n\r\n\texport const asClassNameArray: (icon: ThemeIcon) => string[] = CSSIcon.asClassNameArray;\r\n\texport const asClassName: (icon: ThemeIcon) => string = CSSIcon.asClassName;\r\n\texport const asCSSSelector: (icon: ThemeIcon) => string = CSSIcon.asCSSSelector;\r\n}\r\n\r\nexport function getThemeTypeSelector(type: ColorScheme): string {\r\n\tswitch (type) {\r\n\t\tcase ColorScheme.DARK: return 'vs-dark';\r\n\t\tcase ColorScheme.HIGH_CONTRAST: return 'hc-black';\r\n\t\tdefault: return 'vs';\r\n\t}\r\n}\r\n\r\nexport interface ITokenStyle {\r\n\treadonly foreground?: number;\r\n\treadonly bold?: boolean;\r\n\treadonly underline?: boolean;\r\n\treadonly italic?: boolean;\r\n}\r\n\r\nexport interface IColorTheme {\r\n\r\n\treadonly type: ColorScheme;\r\n\r\n\t/**\r\n\t * Resolves the color of the given color identifier. If the theme does not\r\n\t * specify the color, the default color is returned unless useDefault is set to false.\r\n\t * @param color the id of the color\r\n\t * @param useDefault specifies if the default color should be used. If not set, the default is used.\r\n\t */\r\n\tgetColor(color: ColorIdentifier, useDefault?: boolean): Color | undefined;\r\n\r\n\t/**\r\n\t * Returns whether the theme defines a value for the color. If not, that means the\r\n\t * default color will be used.\r\n\t */\r\n\tdefines(color: ColorIdentifier): boolean;\r\n\r\n\t/**\r\n\t * Returns the token style for a given classification. The result uses the MetadataConsts format\r\n\t */\r\n\tgetTokenStyleMetadata(type: string, modifiers: string[], modelLanguage: string): ITokenStyle | undefined;\r\n\r\n\t/**\r\n\t * Defines whether semantic highlighting should be enabled for the theme.\r\n\t */\r\n\treadonly semanticHighlighting: boolean;\r\n}\r\n\r\nexport interface IFileIconTheme {\r\n\treadonly hasFileIcons: boolean;\r\n\treadonly hasFolderIcons: boolean;\r\n\treadonly hidesExplorerArrows: boolean;\r\n}\r\n\r\nexport interface ICssStyleCollector {\r\n\taddRule(rule: string): void;\r\n}\r\n\r\nexport interface IThemingParticipant {\r\n\t(theme: IColorTheme, collector: ICssStyleCollector, environment: IEnvironmentService): void;\r\n}\r\n\r\nexport interface IThemeService {\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\tgetColorTheme(): IColorTheme;\r\n\r\n\treadonly onDidColorThemeChange: Event;\r\n\r\n\tgetFileIconTheme(): IFileIconTheme;\r\n\r\n}\r\n\r\n// static theming participant\r\nexport const Extensions = {\r\n\tThemingContribution: 'base.contributions.theming'\r\n};\r\n\r\nexport interface IThemingRegistry {\r\n\r\n\tgetThemingParticipants(): IThemingParticipant[];\r\n}\r\n\r\nclass ThemingRegistry implements IThemingRegistry {\r\n\tprivate themingParticipants: IThemingParticipant[] = [];\r\n\tprivate readonly onThemingParticipantAddedEmitter: Emitter;\r\n\r\n\tconstructor() {\r\n\t\tthis.themingParticipants = [];\r\n\t\tthis.onThemingParticipantAddedEmitter = new Emitter();\r\n\t}\r\n\r\n\tpublic onColorThemeChange(participant: IThemingParticipant): IDisposable {\r\n\t\tthis.themingParticipants.push(participant);\r\n\t\tthis.onThemingParticipantAddedEmitter.fire(participant);\r\n\t\treturn toDisposable(() => {\r\n\t\t\tconst idx = this.themingParticipants.indexOf(participant);\r\n\t\t\tthis.themingParticipants.splice(idx, 1);\r\n\t\t});\r\n\t}\r\n\r\n\tpublic getThemingParticipants(): IThemingParticipant[] {\r\n\t\treturn this.themingParticipants;\r\n\t}\r\n}\r\n\r\nlet themingRegistry = new ThemingRegistry();\r\nplatform.Registry.add(Extensions.ThemingContribution, themingRegistry);\r\n\r\nexport function registerThemingParticipant(participant: IThemingParticipant): IDisposable {\r\n\treturn themingRegistry.onColorThemeChange(participant);\r\n}\r\n\r\n/**\r\n * Utility base class for all themable components.\r\n */\r\nexport class Themable extends Disposable {\r\n\tprotected theme: IColorTheme;\r\n\r\n\tconstructor(\r\n\t\tprotected themeService: IThemeService\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\tthis.theme = themeService.getColorTheme();\r\n\r\n\t\t// Hook up to theme changes\r\n\t\tthis._register(this.themeService.onDidColorThemeChange(theme => this.onThemeChange(theme)));\r\n\t}\r\n\r\n\tprotected onThemeChange(theme: IColorTheme): void {\r\n\t\tthis.theme = theme;\r\n\r\n\t\tthis.updateStyles();\r\n\t}\r\n\r\n\tprotected updateStyles(): void {\r\n\t\t// Subclasses to override\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { AbstractCodeEditorService } from 'vs/editor/browser/services/abstractCodeEditorService';\r\nimport { IContentDecorationRenderOptions, IDecorationRenderOptions, IThemeDecorationRenderOptions, isThemeColor } from 'vs/editor/common/editorCommon';\r\nimport { IModelDecorationOptions, IModelDecorationOverviewRulerOptions, OverviewRulerLane, TrackedRangeStickiness } from 'vs/editor/common/model';\r\nimport { IResourceEditorInput } from 'vs/platform/editor/common/editor';\r\nimport { IColorTheme, IThemeService, ThemeColor } from 'vs/platform/theme/common/themeService';\r\n\r\nexport class RefCountedStyleSheet {\r\n\r\n\tprivate readonly _parent: CodeEditorServiceImpl;\r\n\tprivate readonly _editorId: string;\r\n\tprivate readonly _styleSheet: HTMLStyleElement;\r\n\tprivate _refCount: number;\r\n\r\n\tconstructor(parent: CodeEditorServiceImpl, editorId: string, styleSheet: HTMLStyleElement) {\r\n\t\tthis._parent = parent;\r\n\t\tthis._editorId = editorId;\r\n\t\tthis._styleSheet = styleSheet;\r\n\t\tthis._refCount = 0;\r\n\t}\r\n\r\n\tpublic ref(): void {\r\n\t\tthis._refCount++;\r\n\t}\r\n\r\n\tpublic unref(): void {\r\n\t\tthis._refCount--;\r\n\t\tif (this._refCount === 0) {\r\n\t\t\tthis._styleSheet.parentNode?.removeChild(this._styleSheet);\r\n\t\t\tthis._parent._removeEditorStyleSheets(this._editorId);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic insertRule(rule: string, index?: number): void {\r\n\t\tconst sheet = this._styleSheet.sheet;\r\n\t\tsheet.insertRule(rule, index);\r\n\t}\r\n\r\n\tpublic removeRulesContainingSelector(ruleName: string): void {\r\n\t\tdom.removeCSSRulesContainingSelector(ruleName, this._styleSheet);\r\n\t}\r\n}\r\n\r\nexport class GlobalStyleSheet {\r\n\tprivate readonly _styleSheet: HTMLStyleElement;\r\n\r\n\tconstructor(styleSheet: HTMLStyleElement) {\r\n\t\tthis._styleSheet = styleSheet;\r\n\t}\r\n\r\n\tpublic ref(): void {\r\n\t}\r\n\r\n\tpublic unref(): void {\r\n\t}\r\n\r\n\tpublic insertRule(rule: string, index?: number): void {\r\n\t\tconst sheet = this._styleSheet.sheet;\r\n\t\tsheet.insertRule(rule, index);\r\n\t}\r\n\r\n\tpublic removeRulesContainingSelector(ruleName: string): void {\r\n\t\tdom.removeCSSRulesContainingSelector(ruleName, this._styleSheet);\r\n\t}\r\n}\r\n\r\nexport abstract class CodeEditorServiceImpl extends AbstractCodeEditorService {\r\n\r\n\tprivate _globalStyleSheet: GlobalStyleSheet | null;\r\n\tprivate readonly _decorationOptionProviders = new Map();\r\n\tprivate readonly _editorStyleSheets = new Map();\r\n\tprivate readonly _themeService: IThemeService;\r\n\r\n\tconstructor(@IThemeService themeService: IThemeService, styleSheet: GlobalStyleSheet | null = null) {\r\n\t\tsuper();\r\n\t\tthis._globalStyleSheet = styleSheet ? styleSheet : null;\r\n\t\tthis._themeService = themeService;\r\n\t}\r\n\r\n\tprivate _getOrCreateGlobalStyleSheet(): GlobalStyleSheet {\r\n\t\tif (!this._globalStyleSheet) {\r\n\t\t\tthis._globalStyleSheet = new GlobalStyleSheet(dom.createStyleSheet());\r\n\t\t}\r\n\t\treturn this._globalStyleSheet;\r\n\t}\r\n\r\n\tprivate _getOrCreateStyleSheet(editor: ICodeEditor | undefined): GlobalStyleSheet | RefCountedStyleSheet {\r\n\t\tif (!editor) {\r\n\t\t\treturn this._getOrCreateGlobalStyleSheet();\r\n\t\t}\r\n\t\tconst domNode = editor.getContainerDomNode();\r\n\t\tif (!dom.isInShadowDOM(domNode)) {\r\n\t\t\treturn this._getOrCreateGlobalStyleSheet();\r\n\t\t}\r\n\t\tconst editorId = editor.getId();\r\n\t\tif (!this._editorStyleSheets.has(editorId)) {\r\n\t\t\tconst refCountedStyleSheet = new RefCountedStyleSheet(this, editorId, dom.createStyleSheet(domNode));\r\n\t\t\tthis._editorStyleSheets.set(editorId, refCountedStyleSheet);\r\n\t\t}\r\n\t\treturn this._editorStyleSheets.get(editorId)!;\r\n\t}\r\n\r\n\t_removeEditorStyleSheets(editorId: string): void {\r\n\t\tthis._editorStyleSheets.delete(editorId);\r\n\t}\r\n\r\n\tpublic registerDecorationType(key: string, options: IDecorationRenderOptions, parentTypeKey?: string, editor?: ICodeEditor): void {\r\n\t\tlet provider = this._decorationOptionProviders.get(key);\r\n\t\tif (!provider) {\r\n\t\t\tconst styleSheet = this._getOrCreateStyleSheet(editor);\r\n\t\t\tconst providerArgs: ProviderArguments = {\r\n\t\t\t\tstyleSheet: styleSheet,\r\n\t\t\t\tkey: key,\r\n\t\t\t\tparentTypeKey: parentTypeKey,\r\n\t\t\t\toptions: options || Object.create(null)\r\n\t\t\t};\r\n\t\t\tif (!parentTypeKey) {\r\n\t\t\t\tprovider = new DecorationTypeOptionsProvider(this._themeService, styleSheet, providerArgs);\r\n\t\t\t} else {\r\n\t\t\t\tprovider = new DecorationSubTypeOptionsProvider(this._themeService, styleSheet, providerArgs);\r\n\t\t\t}\r\n\t\t\tthis._decorationOptionProviders.set(key, provider);\r\n\t\t\tthis._onDecorationTypeRegistered.fire(key);\r\n\t\t}\r\n\t\tprovider.refCount++;\r\n\t}\r\n\r\n\tpublic removeDecorationType(key: string): void {\r\n\t\tconst provider = this._decorationOptionProviders.get(key);\r\n\t\tif (provider) {\r\n\t\t\tprovider.refCount--;\r\n\t\t\tif (provider.refCount <= 0) {\r\n\t\t\t\tthis._decorationOptionProviders.delete(key);\r\n\t\t\t\tprovider.dispose();\r\n\t\t\t\tthis.listCodeEditors().forEach((ed) => ed.removeDecorations(key));\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic resolveDecorationOptions(decorationTypeKey: string, writable: boolean): IModelDecorationOptions {\r\n\t\tconst provider = this._decorationOptionProviders.get(decorationTypeKey);\r\n\t\tif (!provider) {\r\n\t\t\tthrow new Error('Unknown decoration type key: ' + decorationTypeKey);\r\n\t\t}\r\n\t\treturn provider.getOptions(this, writable);\r\n\t}\r\n\r\n\tabstract getActiveCodeEditor(): ICodeEditor | null;\r\n\tabstract openCodeEditor(input: IResourceEditorInput, source: ICodeEditor | null, sideBySide?: boolean): Promise;\r\n}\r\n\r\ninterface IModelDecorationOptionsProvider extends IDisposable {\r\n\trefCount: number;\r\n\tgetOptions(codeEditorService: AbstractCodeEditorService, writable: boolean): IModelDecorationOptions;\r\n}\r\n\r\nexport class DecorationSubTypeOptionsProvider implements IModelDecorationOptionsProvider {\r\n\r\n\tprivate readonly _styleSheet: GlobalStyleSheet | RefCountedStyleSheet;\r\n\tpublic refCount: number;\r\n\r\n\tprivate readonly _parentTypeKey: string | undefined;\r\n\tprivate _beforeContentRules: DecorationCSSRules | null;\r\n\tprivate _afterContentRules: DecorationCSSRules | null;\r\n\r\n\tconstructor(themeService: IThemeService, styleSheet: GlobalStyleSheet | RefCountedStyleSheet, providerArgs: ProviderArguments) {\r\n\t\tthis._styleSheet = styleSheet;\r\n\t\tthis._styleSheet.ref();\r\n\t\tthis._parentTypeKey = providerArgs.parentTypeKey;\r\n\t\tthis.refCount = 0;\r\n\r\n\t\tthis._beforeContentRules = new DecorationCSSRules(ModelDecorationCSSRuleType.BeforeContentClassName, providerArgs, themeService);\r\n\t\tthis._afterContentRules = new DecorationCSSRules(ModelDecorationCSSRuleType.AfterContentClassName, providerArgs, themeService);\r\n\t}\r\n\r\n\tpublic getOptions(codeEditorService: AbstractCodeEditorService, writable: boolean): IModelDecorationOptions {\r\n\t\tconst options = codeEditorService.resolveDecorationOptions(this._parentTypeKey, true);\r\n\t\tif (this._beforeContentRules) {\r\n\t\t\toptions.beforeContentClassName = this._beforeContentRules.className;\r\n\t\t}\r\n\t\tif (this._afterContentRules) {\r\n\t\t\toptions.afterContentClassName = this._afterContentRules.className;\r\n\t\t}\r\n\t\treturn options;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tif (this._beforeContentRules) {\r\n\t\t\tthis._beforeContentRules.dispose();\r\n\t\t\tthis._beforeContentRules = null;\r\n\t\t}\r\n\t\tif (this._afterContentRules) {\r\n\t\t\tthis._afterContentRules.dispose();\r\n\t\t\tthis._afterContentRules = null;\r\n\t\t}\r\n\t\tthis._styleSheet.unref();\r\n\t}\r\n}\r\n\r\ninterface ProviderArguments {\r\n\tstyleSheet: GlobalStyleSheet | RefCountedStyleSheet;\r\n\tkey: string;\r\n\tparentTypeKey?: string;\r\n\toptions: IDecorationRenderOptions;\r\n}\r\n\r\n\r\nexport class DecorationTypeOptionsProvider implements IModelDecorationOptionsProvider {\r\n\r\n\tprivate readonly _disposables = new DisposableStore();\r\n\tprivate readonly _styleSheet: GlobalStyleSheet | RefCountedStyleSheet;\r\n\tpublic refCount: number;\r\n\r\n\tpublic className: string | undefined;\r\n\tpublic inlineClassName: string | undefined;\r\n\tpublic inlineClassNameAffectsLetterSpacing: boolean | undefined;\r\n\tpublic beforeContentClassName: string | undefined;\r\n\tpublic afterContentClassName: string | undefined;\r\n\tpublic glyphMarginClassName: string | undefined;\r\n\tpublic isWholeLine: boolean;\r\n\tpublic overviewRuler: IModelDecorationOverviewRulerOptions | undefined;\r\n\tpublic stickiness: TrackedRangeStickiness | undefined;\r\n\r\n\tconstructor(themeService: IThemeService, styleSheet: GlobalStyleSheet | RefCountedStyleSheet, providerArgs: ProviderArguments) {\r\n\t\tthis._styleSheet = styleSheet;\r\n\t\tthis._styleSheet.ref();\r\n\t\tthis.refCount = 0;\r\n\r\n\t\tconst createCSSRules = (type: ModelDecorationCSSRuleType) => {\r\n\t\t\tconst rules = new DecorationCSSRules(type, providerArgs, themeService);\r\n\t\t\tthis._disposables.add(rules);\r\n\t\t\tif (rules.hasContent) {\r\n\t\t\t\treturn rules.className;\r\n\t\t\t}\r\n\t\t\treturn undefined;\r\n\t\t};\r\n\t\tconst createInlineCSSRules = (type: ModelDecorationCSSRuleType) => {\r\n\t\t\tconst rules = new DecorationCSSRules(type, providerArgs, themeService);\r\n\t\t\tthis._disposables.add(rules);\r\n\t\t\tif (rules.hasContent) {\r\n\t\t\t\treturn { className: rules.className, hasLetterSpacing: rules.hasLetterSpacing };\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t};\r\n\r\n\t\tthis.className = createCSSRules(ModelDecorationCSSRuleType.ClassName);\r\n\t\tconst inlineData = createInlineCSSRules(ModelDecorationCSSRuleType.InlineClassName);\r\n\t\tif (inlineData) {\r\n\t\t\tthis.inlineClassName = inlineData.className;\r\n\t\t\tthis.inlineClassNameAffectsLetterSpacing = inlineData.hasLetterSpacing;\r\n\t\t}\r\n\t\tthis.beforeContentClassName = createCSSRules(ModelDecorationCSSRuleType.BeforeContentClassName);\r\n\t\tthis.afterContentClassName = createCSSRules(ModelDecorationCSSRuleType.AfterContentClassName);\r\n\t\tthis.glyphMarginClassName = createCSSRules(ModelDecorationCSSRuleType.GlyphMarginClassName);\r\n\r\n\t\tconst options = providerArgs.options;\r\n\t\tthis.isWholeLine = Boolean(options.isWholeLine);\r\n\t\tthis.stickiness = options.rangeBehavior;\r\n\r\n\t\tconst lightOverviewRulerColor = options.light && options.light.overviewRulerColor || options.overviewRulerColor;\r\n\t\tconst darkOverviewRulerColor = options.dark && options.dark.overviewRulerColor || options.overviewRulerColor;\r\n\t\tif (\r\n\t\t\ttypeof lightOverviewRulerColor !== 'undefined'\r\n\t\t\t|| typeof darkOverviewRulerColor !== 'undefined'\r\n\t\t) {\r\n\t\t\tthis.overviewRuler = {\r\n\t\t\t\tcolor: lightOverviewRulerColor || darkOverviewRulerColor,\r\n\t\t\t\tdarkColor: darkOverviewRulerColor || lightOverviewRulerColor,\r\n\t\t\t\tposition: options.overviewRulerLane || OverviewRulerLane.Center\r\n\t\t\t};\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getOptions(codeEditorService: AbstractCodeEditorService, writable: boolean): IModelDecorationOptions {\r\n\t\tif (!writable) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\treturn {\r\n\t\t\tinlineClassName: this.inlineClassName,\r\n\t\t\tbeforeContentClassName: this.beforeContentClassName,\r\n\t\t\tafterContentClassName: this.afterContentClassName,\r\n\t\t\tclassName: this.className,\r\n\t\t\tglyphMarginClassName: this.glyphMarginClassName,\r\n\t\t\tisWholeLine: this.isWholeLine,\r\n\t\t\toverviewRuler: this.overviewRuler,\r\n\t\t\tstickiness: this.stickiness\r\n\t\t};\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._disposables.dispose();\r\n\t\tthis._styleSheet.unref();\r\n\t}\r\n}\r\n\r\n\r\nconst _CSS_MAP: { [prop: string]: string; } = {\r\n\tcolor: 'color:{0} !important;',\r\n\topacity: 'opacity:{0};',\r\n\tbackgroundColor: 'background-color:{0};',\r\n\r\n\toutline: 'outline:{0};',\r\n\toutlineColor: 'outline-color:{0};',\r\n\toutlineStyle: 'outline-style:{0};',\r\n\toutlineWidth: 'outline-width:{0};',\r\n\r\n\tborder: 'border:{0};',\r\n\tborderColor: 'border-color:{0};',\r\n\tborderRadius: 'border-radius:{0};',\r\n\tborderSpacing: 'border-spacing:{0};',\r\n\tborderStyle: 'border-style:{0};',\r\n\tborderWidth: 'border-width:{0};',\r\n\r\n\tfontStyle: 'font-style:{0};',\r\n\tfontWeight: 'font-weight:{0};',\r\n\tfontSize: 'font-size:{0};',\r\n\tfontFamily: 'font-family:{0};',\r\n\ttextDecoration: 'text-decoration:{0};',\r\n\tcursor: 'cursor:{0};',\r\n\tletterSpacing: 'letter-spacing:{0};',\r\n\r\n\tgutterIconPath: 'background:{0} center center no-repeat;',\r\n\tgutterIconSize: 'background-size:{0};',\r\n\r\n\tcontentText: 'content:\\'{0}\\';',\r\n\tcontentIconPath: 'content:{0};',\r\n\tmargin: 'margin:{0};',\r\n\tpadding: 'padding:{0};',\r\n\twidth: 'width:{0};',\r\n\theight: 'height:{0};'\r\n};\r\n\r\n\r\nclass DecorationCSSRules {\r\n\r\n\tprivate _theme: IColorTheme;\r\n\tprivate readonly _className: string;\r\n\tprivate readonly _unThemedSelector: string;\r\n\tprivate _hasContent: boolean;\r\n\tprivate _hasLetterSpacing: boolean;\r\n\tprivate readonly _ruleType: ModelDecorationCSSRuleType;\r\n\tprivate _themeListener: IDisposable | null;\r\n\tprivate readonly _providerArgs: ProviderArguments;\r\n\tprivate _usesThemeColors: boolean;\r\n\r\n\tconstructor(ruleType: ModelDecorationCSSRuleType, providerArgs: ProviderArguments, themeService: IThemeService) {\r\n\t\tthis._theme = themeService.getColorTheme();\r\n\t\tthis._ruleType = ruleType;\r\n\t\tthis._providerArgs = providerArgs;\r\n\t\tthis._usesThemeColors = false;\r\n\t\tthis._hasContent = false;\r\n\t\tthis._hasLetterSpacing = false;\r\n\r\n\t\tlet className = CSSNameHelper.getClassName(this._providerArgs.key, ruleType);\r\n\t\tif (this._providerArgs.parentTypeKey) {\r\n\t\t\tclassName = className + ' ' + CSSNameHelper.getClassName(this._providerArgs.parentTypeKey, ruleType);\r\n\t\t}\r\n\t\tthis._className = className;\r\n\r\n\t\tthis._unThemedSelector = CSSNameHelper.getSelector(this._providerArgs.key, this._providerArgs.parentTypeKey, ruleType);\r\n\r\n\t\tthis._buildCSS();\r\n\r\n\t\tif (this._usesThemeColors) {\r\n\t\t\tthis._themeListener = themeService.onDidColorThemeChange(theme => {\r\n\t\t\t\tthis._theme = themeService.getColorTheme();\r\n\t\t\t\tthis._removeCSS();\r\n\t\t\t\tthis._buildCSS();\r\n\t\t\t});\r\n\t\t} else {\r\n\t\t\tthis._themeListener = null;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic dispose() {\r\n\t\tif (this._hasContent) {\r\n\t\t\tthis._removeCSS();\r\n\t\t\tthis._hasContent = false;\r\n\t\t}\r\n\t\tif (this._themeListener) {\r\n\t\t\tthis._themeListener.dispose();\r\n\t\t\tthis._themeListener = null;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic get hasContent(): boolean {\r\n\t\treturn this._hasContent;\r\n\t}\r\n\r\n\tpublic get hasLetterSpacing(): boolean {\r\n\t\treturn this._hasLetterSpacing;\r\n\t}\r\n\r\n\tpublic get className(): string {\r\n\t\treturn this._className;\r\n\t}\r\n\r\n\tprivate _buildCSS(): void {\r\n\t\tconst options = this._providerArgs.options;\r\n\t\tlet unthemedCSS: string, lightCSS: string, darkCSS: string;\r\n\t\tswitch (this._ruleType) {\r\n\t\t\tcase ModelDecorationCSSRuleType.ClassName:\r\n\t\t\t\tunthemedCSS = this.getCSSTextForModelDecorationClassName(options);\r\n\t\t\t\tlightCSS = this.getCSSTextForModelDecorationClassName(options.light);\r\n\t\t\t\tdarkCSS = this.getCSSTextForModelDecorationClassName(options.dark);\r\n\t\t\t\tbreak;\r\n\t\t\tcase ModelDecorationCSSRuleType.InlineClassName:\r\n\t\t\t\tunthemedCSS = this.getCSSTextForModelDecorationInlineClassName(options);\r\n\t\t\t\tlightCSS = this.getCSSTextForModelDecorationInlineClassName(options.light);\r\n\t\t\t\tdarkCSS = this.getCSSTextForModelDecorationInlineClassName(options.dark);\r\n\t\t\t\tbreak;\r\n\t\t\tcase ModelDecorationCSSRuleType.GlyphMarginClassName:\r\n\t\t\t\tunthemedCSS = this.getCSSTextForModelDecorationGlyphMarginClassName(options);\r\n\t\t\t\tlightCSS = this.getCSSTextForModelDecorationGlyphMarginClassName(options.light);\r\n\t\t\t\tdarkCSS = this.getCSSTextForModelDecorationGlyphMarginClassName(options.dark);\r\n\t\t\t\tbreak;\r\n\t\t\tcase ModelDecorationCSSRuleType.BeforeContentClassName:\r\n\t\t\t\tunthemedCSS = this.getCSSTextForModelDecorationContentClassName(options.before);\r\n\t\t\t\tlightCSS = this.getCSSTextForModelDecorationContentClassName(options.light && options.light.before);\r\n\t\t\t\tdarkCSS = this.getCSSTextForModelDecorationContentClassName(options.dark && options.dark.before);\r\n\t\t\t\tbreak;\r\n\t\t\tcase ModelDecorationCSSRuleType.AfterContentClassName:\r\n\t\t\t\tunthemedCSS = this.getCSSTextForModelDecorationContentClassName(options.after);\r\n\t\t\t\tlightCSS = this.getCSSTextForModelDecorationContentClassName(options.light && options.light.after);\r\n\t\t\t\tdarkCSS = this.getCSSTextForModelDecorationContentClassName(options.dark && options.dark.after);\r\n\t\t\t\tbreak;\r\n\t\t\tdefault:\r\n\t\t\t\tthrow new Error('Unknown rule type: ' + this._ruleType);\r\n\t\t}\r\n\t\tconst sheet = this._providerArgs.styleSheet;\r\n\r\n\t\tlet hasContent = false;\r\n\t\tif (unthemedCSS.length > 0) {\r\n\t\t\tsheet.insertRule(`${this._unThemedSelector} {${unthemedCSS}}`, 0);\r\n\t\t\thasContent = true;\r\n\t\t}\r\n\t\tif (lightCSS.length > 0) {\r\n\t\t\tsheet.insertRule(`.vs${this._unThemedSelector} {${lightCSS}}`, 0);\r\n\t\t\thasContent = true;\r\n\t\t}\r\n\t\tif (darkCSS.length > 0) {\r\n\t\t\tsheet.insertRule(`.vs-dark${this._unThemedSelector}, .hc-black${this._unThemedSelector} {${darkCSS}}`, 0);\r\n\t\t\thasContent = true;\r\n\t\t}\r\n\t\tthis._hasContent = hasContent;\r\n\t}\r\n\r\n\tprivate _removeCSS(): void {\r\n\t\tthis._providerArgs.styleSheet.removeRulesContainingSelector(this._unThemedSelector);\r\n\t}\r\n\r\n\t/**\r\n\t * Build the CSS for decorations styled via `className`.\r\n\t */\r\n\tprivate getCSSTextForModelDecorationClassName(opts: IThemeDecorationRenderOptions | undefined): string {\r\n\t\tif (!opts) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\tconst cssTextArr: string[] = [];\r\n\t\tthis.collectCSSText(opts, ['backgroundColor'], cssTextArr);\r\n\t\tthis.collectCSSText(opts, ['outline', 'outlineColor', 'outlineStyle', 'outlineWidth'], cssTextArr);\r\n\t\tthis.collectBorderSettingsCSSText(opts, cssTextArr);\r\n\t\treturn cssTextArr.join('');\r\n\t}\r\n\r\n\t/**\r\n\t * Build the CSS for decorations styled via `inlineClassName`.\r\n\t */\r\n\tprivate getCSSTextForModelDecorationInlineClassName(opts: IThemeDecorationRenderOptions | undefined): string {\r\n\t\tif (!opts) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\tconst cssTextArr: string[] = [];\r\n\t\tthis.collectCSSText(opts, ['fontStyle', 'fontWeight', 'textDecoration', 'cursor', 'color', 'opacity', 'letterSpacing'], cssTextArr);\r\n\t\tif (opts.letterSpacing) {\r\n\t\t\tthis._hasLetterSpacing = true;\r\n\t\t}\r\n\t\treturn cssTextArr.join('');\r\n\t}\r\n\r\n\t/**\r\n\t * Build the CSS for decorations styled before or after content.\r\n\t */\r\n\tprivate getCSSTextForModelDecorationContentClassName(opts: IContentDecorationRenderOptions | undefined): string {\r\n\t\tif (!opts) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\tconst cssTextArr: string[] = [];\r\n\r\n\t\tif (typeof opts !== 'undefined') {\r\n\t\t\tthis.collectBorderSettingsCSSText(opts, cssTextArr);\r\n\t\t\tif (typeof opts.contentIconPath !== 'undefined') {\r\n\t\t\t\tcssTextArr.push(strings.format(_CSS_MAP.contentIconPath, dom.asCSSUrl(URI.revive(opts.contentIconPath))));\r\n\t\t\t}\r\n\t\t\tif (typeof opts.contentText === 'string') {\r\n\t\t\t\tconst truncated = opts.contentText.match(/^.*$/m)![0]; // only take first line\r\n\t\t\t\tconst escaped = truncated.replace(/['\\\\]/g, '\\\\$&');\r\n\r\n\t\t\t\tcssTextArr.push(strings.format(_CSS_MAP.contentText, escaped));\r\n\t\t\t}\r\n\t\t\tthis.collectCSSText(opts, ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily', 'textDecoration', 'color', 'opacity', 'backgroundColor', 'margin', 'padding'], cssTextArr);\r\n\t\t\tif (this.collectCSSText(opts, ['width', 'height'], cssTextArr)) {\r\n\t\t\t\tcssTextArr.push('display:inline-block;');\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn cssTextArr.join('');\r\n\t}\r\n\r\n\t/**\r\n\t * Build the CSS for decorations styled via `glpyhMarginClassName`.\r\n\t */\r\n\tprivate getCSSTextForModelDecorationGlyphMarginClassName(opts: IThemeDecorationRenderOptions | undefined): string {\r\n\t\tif (!opts) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\tconst cssTextArr: string[] = [];\r\n\r\n\t\tif (typeof opts.gutterIconPath !== 'undefined') {\r\n\t\t\tcssTextArr.push(strings.format(_CSS_MAP.gutterIconPath, dom.asCSSUrl(URI.revive(opts.gutterIconPath))));\r\n\t\t\tif (typeof opts.gutterIconSize !== 'undefined') {\r\n\t\t\t\tcssTextArr.push(strings.format(_CSS_MAP.gutterIconSize, opts.gutterIconSize));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn cssTextArr.join('');\r\n\t}\r\n\r\n\tprivate collectBorderSettingsCSSText(opts: any, cssTextArr: string[]): boolean {\r\n\t\tif (this.collectCSSText(opts, ['border', 'borderColor', 'borderRadius', 'borderSpacing', 'borderStyle', 'borderWidth'], cssTextArr)) {\r\n\t\t\tcssTextArr.push(strings.format('box-sizing: border-box;'));\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tprivate collectCSSText(opts: any, properties: string[], cssTextArr: string[]): boolean {\r\n\t\tconst lenBefore = cssTextArr.length;\r\n\t\tfor (let property of properties) {\r\n\t\t\tconst value = this.resolveValue(opts[property]);\r\n\t\t\tif (typeof value === 'string') {\r\n\t\t\t\tcssTextArr.push(strings.format(_CSS_MAP[property], value));\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn cssTextArr.length !== lenBefore;\r\n\t}\r\n\r\n\tprivate resolveValue(value: string | ThemeColor): string {\r\n\t\tif (isThemeColor(value)) {\r\n\t\t\tthis._usesThemeColors = true;\r\n\t\t\tconst color = this._theme.getColor(value.id);\r\n\t\t\tif (color) {\r\n\t\t\t\treturn color.toString();\r\n\t\t\t}\r\n\t\t\treturn 'transparent';\r\n\t\t}\r\n\t\treturn value;\r\n\t}\r\n}\r\n\r\nconst enum ModelDecorationCSSRuleType {\r\n\tClassName = 0,\r\n\tInlineClassName = 1,\r\n\tGlyphMarginClassName = 2,\r\n\tBeforeContentClassName = 3,\r\n\tAfterContentClassName = 4\r\n}\r\n\r\nclass CSSNameHelper {\r\n\r\n\tpublic static getClassName(key: string, type: ModelDecorationCSSRuleType): string {\r\n\t\treturn 'ced-' + key + '-' + type;\r\n\t}\r\n\r\n\tpublic static getSelector(key: string, parentKey: string | undefined, ruleType: ModelDecorationCSSRuleType): string {\r\n\t\tlet selector = '.monaco-editor .' + this.getClassName(key, ruleType);\r\n\t\tif (parentKey) {\r\n\t\t\tselector = selector + '.' + this.getClassName(parentKey, ruleType);\r\n\t\t}\r\n\t\tif (ruleType === ModelDecorationCSSRuleType.BeforeContentClassName) {\r\n\t\t\tselector += '::before';\r\n\t\t} else if (ruleType === ModelDecorationCSSRuleType.AfterContentClassName) {\r\n\t\t\tselector += '::after';\r\n\t\t}\r\n\t\treturn selector;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { IMouseEvent } from 'vs/base/browser/mouseEvent';\r\nimport { IOverviewRulerLayoutInfo, SmoothScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';\r\nimport { ScrollableElementChangeOptions, ScrollableElementCreationOptions } from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';\r\nimport { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/view/viewPart';\r\nimport { INewScrollPosition, ScrollType } from 'vs/editor/common/editorCommon';\r\nimport { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { getThemeTypeSelector } from 'vs/platform/theme/common/themeService';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\nexport class EditorScrollbar extends ViewPart {\r\n\r\n\tprivate readonly scrollbar: SmoothScrollableElement;\r\n\tprivate readonly scrollbarDomNode: FastDomNode;\r\n\r\n\tconstructor(\r\n\t\tcontext: ViewContext,\r\n\t\tlinesContent: FastDomNode,\r\n\t\tviewDomNode: FastDomNode,\r\n\t\toverflowGuardDomNode: FastDomNode\r\n\t) {\r\n\t\tsuper(context);\r\n\r\n\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst scrollbar = options.get(EditorOption.scrollbar);\r\n\t\tconst mouseWheelScrollSensitivity = options.get(EditorOption.mouseWheelScrollSensitivity);\r\n\t\tconst fastScrollSensitivity = options.get(EditorOption.fastScrollSensitivity);\r\n\t\tconst scrollPredominantAxis = options.get(EditorOption.scrollPredominantAxis);\r\n\r\n\t\tconst scrollbarOptions: ScrollableElementCreationOptions = {\r\n\t\t\tlistenOnDomNode: viewDomNode.domNode,\r\n\t\t\tclassName: 'editor-scrollable' + ' ' + getThemeTypeSelector(context.theme.type),\r\n\t\t\tuseShadows: false,\r\n\t\t\tlazyRender: true,\r\n\r\n\t\t\tvertical: scrollbar.vertical,\r\n\t\t\thorizontal: scrollbar.horizontal,\r\n\t\t\tverticalHasArrows: scrollbar.verticalHasArrows,\r\n\t\t\thorizontalHasArrows: scrollbar.horizontalHasArrows,\r\n\t\t\tverticalScrollbarSize: scrollbar.verticalScrollbarSize,\r\n\t\t\tverticalSliderSize: scrollbar.verticalSliderSize,\r\n\t\t\thorizontalScrollbarSize: scrollbar.horizontalScrollbarSize,\r\n\t\t\thorizontalSliderSize: scrollbar.horizontalSliderSize,\r\n\t\t\thandleMouseWheel: scrollbar.handleMouseWheel,\r\n\t\t\talwaysConsumeMouseWheel: scrollbar.alwaysConsumeMouseWheel,\r\n\t\t\tarrowSize: scrollbar.arrowSize,\r\n\t\t\tmouseWheelScrollSensitivity: mouseWheelScrollSensitivity,\r\n\t\t\tfastScrollSensitivity: fastScrollSensitivity,\r\n\t\t\tscrollPredominantAxis: scrollPredominantAxis,\r\n\t\t\tscrollByPage: scrollbar.scrollByPage,\r\n\t\t};\r\n\r\n\t\tthis.scrollbar = this._register(new SmoothScrollableElement(linesContent.domNode, scrollbarOptions, this._context.viewLayout.getScrollable()));\r\n\t\tPartFingerprints.write(this.scrollbar.getDomNode(), PartFingerprint.ScrollableElement);\r\n\r\n\t\tthis.scrollbarDomNode = createFastDomNode(this.scrollbar.getDomNode());\r\n\t\tthis.scrollbarDomNode.setPosition('absolute');\r\n\t\tthis._setLayout();\r\n\r\n\t\t// When having a zone widget that calls .focus() on one of its dom elements,\r\n\t\t// the browser will try desperately to reveal that dom node, unexpectedly\r\n\t\t// changing the .scrollTop of this.linesContent\r\n\r\n\t\tconst onBrowserDesperateReveal = (domNode: HTMLElement, lookAtScrollTop: boolean, lookAtScrollLeft: boolean) => {\r\n\t\t\tconst newScrollPosition: INewScrollPosition = {};\r\n\r\n\t\t\tif (lookAtScrollTop) {\r\n\t\t\t\tconst deltaTop = domNode.scrollTop;\r\n\t\t\t\tif (deltaTop) {\r\n\t\t\t\t\tnewScrollPosition.scrollTop = this._context.viewLayout.getCurrentScrollTop() + deltaTop;\r\n\t\t\t\t\tdomNode.scrollTop = 0;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (lookAtScrollLeft) {\r\n\t\t\t\tconst deltaLeft = domNode.scrollLeft;\r\n\t\t\t\tif (deltaLeft) {\r\n\t\t\t\t\tnewScrollPosition.scrollLeft = this._context.viewLayout.getCurrentScrollLeft() + deltaLeft;\r\n\t\t\t\t\tdomNode.scrollLeft = 0;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tthis._context.model.setScrollPosition(newScrollPosition, ScrollType.Immediate);\r\n\t\t};\r\n\r\n\t\t// I've seen this happen both on the view dom node & on the lines content dom node.\r\n\t\tthis._register(dom.addDisposableListener(viewDomNode.domNode, 'scroll', (e: Event) => onBrowserDesperateReveal(viewDomNode.domNode, true, true)));\r\n\t\tthis._register(dom.addDisposableListener(linesContent.domNode, 'scroll', (e: Event) => onBrowserDesperateReveal(linesContent.domNode, true, false)));\r\n\t\tthis._register(dom.addDisposableListener(overflowGuardDomNode.domNode, 'scroll', (e: Event) => onBrowserDesperateReveal(overflowGuardDomNode.domNode, true, false)));\r\n\t\tthis._register(dom.addDisposableListener(this.scrollbarDomNode.domNode, 'scroll', (e: Event) => onBrowserDesperateReveal(this.scrollbarDomNode.domNode, true, false)));\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tprivate _setLayout(): void {\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\r\n\t\tthis.scrollbarDomNode.setLeft(layoutInfo.contentLeft);\r\n\r\n\t\tconst minimap = options.get(EditorOption.minimap);\r\n\t\tconst side = minimap.side;\r\n\t\tif (side === 'right') {\r\n\t\t\tthis.scrollbarDomNode.setWidth(layoutInfo.contentWidth + layoutInfo.minimap.minimapWidth);\r\n\t\t} else {\r\n\t\t\tthis.scrollbarDomNode.setWidth(layoutInfo.contentWidth);\r\n\t\t}\r\n\t\tthis.scrollbarDomNode.setHeight(layoutInfo.height);\r\n\t}\r\n\r\n\tpublic getOverviewRulerLayoutInfo(): IOverviewRulerLayoutInfo {\r\n\t\treturn this.scrollbar.getOverviewRulerLayoutInfo();\r\n\t}\r\n\r\n\tpublic getDomNode(): FastDomNode {\r\n\t\treturn this.scrollbarDomNode;\r\n\t}\r\n\r\n\tpublic delegateVerticalScrollbarMouseDown(browserEvent: IMouseEvent): void {\r\n\t\tthis.scrollbar.delegateVerticalScrollbarMouseDown(browserEvent);\r\n\t}\r\n\r\n\t// --- begin event handlers\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tif (\r\n\t\t\te.hasChanged(EditorOption.scrollbar)\r\n\t\t\t|| e.hasChanged(EditorOption.mouseWheelScrollSensitivity)\r\n\t\t\t|| e.hasChanged(EditorOption.fastScrollSensitivity)\r\n\t\t) {\r\n\t\t\tconst options = this._context.configuration.options;\r\n\t\t\tconst scrollbar = options.get(EditorOption.scrollbar);\r\n\t\t\tconst mouseWheelScrollSensitivity = options.get(EditorOption.mouseWheelScrollSensitivity);\r\n\t\t\tconst fastScrollSensitivity = options.get(EditorOption.fastScrollSensitivity);\r\n\t\t\tconst scrollPredominantAxis = options.get(EditorOption.scrollPredominantAxis);\r\n\t\t\tconst newOpts: ScrollableElementChangeOptions = {\r\n\t\t\t\thandleMouseWheel: scrollbar.handleMouseWheel,\r\n\t\t\t\tmouseWheelScrollSensitivity: mouseWheelScrollSensitivity,\r\n\t\t\t\tfastScrollSensitivity: fastScrollSensitivity,\r\n\t\t\t\tscrollPredominantAxis: scrollPredominantAxis\r\n\t\t\t};\r\n\t\t\tthis.scrollbar.updateOptions(newOpts);\r\n\t\t}\r\n\t\tif (e.hasChanged(EditorOption.layoutInfo)) {\r\n\t\t\tthis._setLayout();\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onThemeChanged(e: viewEvents.ViewThemeChangedEvent): boolean {\r\n\t\tthis.scrollbar.updateClassName('editor-scrollable' + ' ' + getThemeTypeSelector(this._context.theme.type));\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// --- end event handlers\r\n\r\n\tpublic prepareRender(ctx: RenderingContext): void {\r\n\t\t// Nothing to do\r\n\t}\r\n\r\n\tpublic render(ctx: RestrictedRenderingContext): void {\r\n\t\tthis.scrollbar.renderNow();\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./minimap';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { GlobalMouseMoveMonitor, IStandardMouseMoveEventData, standardMouseMoveMerger } from 'vs/base/browser/globalMouseMoveMonitor';\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport { IDisposable, Disposable } from 'vs/base/common/lifecycle';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { ILine, RenderedLinesCollection } from 'vs/editor/browser/view/viewLayer';\r\nimport { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/view/viewPart';\r\nimport { RenderMinimap, EditorOption, MINIMAP_GUTTER_WIDTH, EditorLayoutInfoComputer } from 'vs/editor/common/config/editorOptions';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { RGBA8 } from 'vs/editor/common/core/rgba';\r\nimport { IConfiguration, ScrollType } from 'vs/editor/common/editorCommon';\r\nimport { ColorId } from 'vs/editor/common/modes';\r\nimport { MinimapCharRenderer } from 'vs/editor/browser/viewParts/minimap/minimapCharRenderer';\r\nimport { Constants } from 'vs/editor/browser/viewParts/minimap/minimapCharSheet';\r\nimport { MinimapTokensColorTracker } from 'vs/editor/common/viewModel/minimapTokensColorTracker';\r\nimport { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext, EditorTheme } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { ViewLineData, ViewModelDecoration } from 'vs/editor/common/viewModel/viewModel';\r\nimport { minimapSelection, scrollbarShadow, minimapBackground, minimapSliderBackground, minimapSliderHoverBackground, minimapSliderActiveBackground } from 'vs/platform/theme/common/colorRegistry';\r\nimport { registerThemingParticipant } from 'vs/platform/theme/common/themeService';\r\nimport { ModelDecorationMinimapOptions } from 'vs/editor/common/model/textModel';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { GestureEvent, EventType, Gesture } from 'vs/base/browser/touch';\r\nimport { MinimapCharRendererFactory } from 'vs/editor/browser/viewParts/minimap/minimapCharRendererFactory';\r\nimport { MinimapPosition, TextModelResolvedOptions } from 'vs/editor/common/model';\r\nimport { once } from 'vs/base/common/functional';\r\n\r\n/**\r\n * The orthogonal distance to the slider at which dragging \"resets\". This implements \"snapping\"\r\n */\r\nconst MOUSE_DRAG_RESET_DISTANCE = 140;\r\n\r\nconst GUTTER_DECORATION_WIDTH = 2;\r\n\r\nclass MinimapOptions {\r\n\r\n\tpublic readonly renderMinimap: RenderMinimap;\r\n\r\n\tpublic readonly size: 'proportional' | 'fill' | 'fit';\r\n\r\n\tpublic readonly minimapHeightIsEditorHeight: boolean;\r\n\r\n\tpublic readonly scrollBeyondLastLine: boolean;\r\n\r\n\tpublic readonly showSlider: 'always' | 'mouseover';\r\n\r\n\tpublic readonly pixelRatio: number;\r\n\r\n\tpublic readonly typicalHalfwidthCharacterWidth: number;\r\n\r\n\tpublic readonly lineHeight: number;\r\n\r\n\t/**\r\n\t * container dom node left position (in CSS px)\r\n\t */\r\n\tpublic readonly minimapLeft: number;\r\n\t/**\r\n\t * container dom node width (in CSS px)\r\n\t */\r\n\tpublic readonly minimapWidth: number;\r\n\t/**\r\n\t * container dom node height (in CSS px)\r\n\t */\r\n\tpublic readonly minimapHeight: number;\r\n\r\n\t/**\r\n\t * canvas backing store width (in device px)\r\n\t */\r\n\tpublic readonly canvasInnerWidth: number;\r\n\t/**\r\n\t * canvas backing store height (in device px)\r\n\t */\r\n\tpublic readonly canvasInnerHeight: number;\r\n\r\n\t/**\r\n\t * canvas width (in CSS px)\r\n\t */\r\n\tpublic readonly canvasOuterWidth: number;\r\n\t/**\r\n\t * canvas height (in CSS px)\r\n\t */\r\n\tpublic readonly canvasOuterHeight: number;\r\n\r\n\tpublic readonly isSampling: boolean;\r\n\tpublic readonly editorHeight: number;\r\n\tpublic readonly fontScale: number;\r\n\tpublic readonly minimapLineHeight: number;\r\n\tpublic readonly minimapCharWidth: number;\r\n\r\n\tpublic readonly charRenderer: () => MinimapCharRenderer;\r\n\tpublic readonly backgroundColor: RGBA8;\r\n\r\n\tconstructor(configuration: IConfiguration, theme: EditorTheme, tokensColorTracker: MinimapTokensColorTracker) {\r\n\t\tconst options = configuration.options;\r\n\t\tconst pixelRatio = options.get(EditorOption.pixelRatio);\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\t\tconst minimapLayout = layoutInfo.minimap;\r\n\t\tconst fontInfo = options.get(EditorOption.fontInfo);\r\n\t\tconst minimapOpts = options.get(EditorOption.minimap);\r\n\r\n\t\tthis.renderMinimap = minimapLayout.renderMinimap;\r\n\t\tthis.size = minimapOpts.size;\r\n\t\tthis.minimapHeightIsEditorHeight = minimapLayout.minimapHeightIsEditorHeight;\r\n\t\tthis.scrollBeyondLastLine = options.get(EditorOption.scrollBeyondLastLine);\r\n\t\tthis.showSlider = minimapOpts.showSlider;\r\n\t\tthis.pixelRatio = pixelRatio;\r\n\t\tthis.typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth;\r\n\t\tthis.lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tthis.minimapLeft = minimapLayout.minimapLeft;\r\n\t\tthis.minimapWidth = minimapLayout.minimapWidth;\r\n\t\tthis.minimapHeight = layoutInfo.height;\r\n\r\n\t\tthis.canvasInnerWidth = minimapLayout.minimapCanvasInnerWidth;\r\n\t\tthis.canvasInnerHeight = minimapLayout.minimapCanvasInnerHeight;\r\n\t\tthis.canvasOuterWidth = minimapLayout.minimapCanvasOuterWidth;\r\n\t\tthis.canvasOuterHeight = minimapLayout.minimapCanvasOuterHeight;\r\n\r\n\t\tthis.isSampling = minimapLayout.minimapIsSampling;\r\n\t\tthis.editorHeight = layoutInfo.height;\r\n\t\tthis.fontScale = minimapLayout.minimapScale;\r\n\t\tthis.minimapLineHeight = minimapLayout.minimapLineHeight;\r\n\t\tthis.minimapCharWidth = Constants.BASE_CHAR_WIDTH * this.fontScale;\r\n\r\n\t\tthis.charRenderer = once(() => MinimapCharRendererFactory.create(this.fontScale, fontInfo.fontFamily));\r\n\t\tthis.backgroundColor = MinimapOptions._getMinimapBackground(theme, tokensColorTracker);\r\n\t}\r\n\r\n\tprivate static _getMinimapBackground(theme: EditorTheme, tokensColorTracker: MinimapTokensColorTracker): RGBA8 {\r\n\t\tconst themeColor = theme.getColor(minimapBackground);\r\n\t\tif (themeColor) {\r\n\t\t\treturn new RGBA8(themeColor.rgba.r, themeColor.rgba.g, themeColor.rgba.b, themeColor.rgba.a);\r\n\t\t}\r\n\t\treturn tokensColorTracker.getColor(ColorId.DefaultBackground);\r\n\t}\r\n\r\n\tpublic equals(other: MinimapOptions): boolean {\r\n\t\treturn (this.renderMinimap === other.renderMinimap\r\n\t\t\t&& this.size === other.size\r\n\t\t\t&& this.minimapHeightIsEditorHeight === other.minimapHeightIsEditorHeight\r\n\t\t\t&& this.scrollBeyondLastLine === other.scrollBeyondLastLine\r\n\t\t\t&& this.showSlider === other.showSlider\r\n\t\t\t&& this.pixelRatio === other.pixelRatio\r\n\t\t\t&& this.typicalHalfwidthCharacterWidth === other.typicalHalfwidthCharacterWidth\r\n\t\t\t&& this.lineHeight === other.lineHeight\r\n\t\t\t&& this.minimapLeft === other.minimapLeft\r\n\t\t\t&& this.minimapWidth === other.minimapWidth\r\n\t\t\t&& this.minimapHeight === other.minimapHeight\r\n\t\t\t&& this.canvasInnerWidth === other.canvasInnerWidth\r\n\t\t\t&& this.canvasInnerHeight === other.canvasInnerHeight\r\n\t\t\t&& this.canvasOuterWidth === other.canvasOuterWidth\r\n\t\t\t&& this.canvasOuterHeight === other.canvasOuterHeight\r\n\t\t\t&& this.isSampling === other.isSampling\r\n\t\t\t&& this.editorHeight === other.editorHeight\r\n\t\t\t&& this.fontScale === other.fontScale\r\n\t\t\t&& this.minimapLineHeight === other.minimapLineHeight\r\n\t\t\t&& this.minimapCharWidth === other.minimapCharWidth\r\n\t\t\t&& this.backgroundColor && this.backgroundColor.equals(other.backgroundColor)\r\n\t\t);\r\n\t}\r\n}\r\n\r\nclass MinimapLayout {\r\n\r\n\t/**\r\n\t * The given editor scrollTop (input).\r\n\t */\r\n\tpublic readonly scrollTop: number;\r\n\r\n\t/**\r\n\t* The given editor scrollHeight (input).\r\n\t*/\r\n\tpublic readonly scrollHeight: number;\r\n\r\n\tpublic readonly sliderNeeded: boolean;\r\n\tprivate readonly _computedSliderRatio: number;\r\n\r\n\t/**\r\n\t * slider dom node top (in CSS px)\r\n\t */\r\n\tpublic readonly sliderTop: number;\r\n\t/**\r\n\t * slider dom node height (in CSS px)\r\n\t */\r\n\tpublic readonly sliderHeight: number;\r\n\r\n\t/**\r\n\t * minimap render start line number.\r\n\t */\r\n\tpublic readonly startLineNumber: number;\r\n\t/**\r\n\t * minimap render end line number.\r\n\t */\r\n\tpublic readonly endLineNumber: number;\r\n\r\n\tconstructor(\r\n\t\tscrollTop: number,\r\n\t\tscrollHeight: number,\r\n\t\tsliderNeeded: boolean,\r\n\t\tcomputedSliderRatio: number,\r\n\t\tsliderTop: number,\r\n\t\tsliderHeight: number,\r\n\t\tstartLineNumber: number,\r\n\t\tendLineNumber: number\r\n\t) {\r\n\t\tthis.scrollTop = scrollTop;\r\n\t\tthis.scrollHeight = scrollHeight;\r\n\t\tthis.sliderNeeded = sliderNeeded;\r\n\t\tthis._computedSliderRatio = computedSliderRatio;\r\n\t\tthis.sliderTop = sliderTop;\r\n\t\tthis.sliderHeight = sliderHeight;\r\n\t\tthis.startLineNumber = startLineNumber;\r\n\t\tthis.endLineNumber = endLineNumber;\r\n\t}\r\n\r\n\t/**\r\n\t * Compute a desired `scrollPosition` such that the slider moves by `delta`.\r\n\t */\r\n\tpublic getDesiredScrollTopFromDelta(delta: number): number {\r\n\t\treturn Math.round(this.scrollTop + delta / this._computedSliderRatio);\r\n\t}\r\n\r\n\tpublic getDesiredScrollTopFromTouchLocation(pageY: number): number {\r\n\t\treturn Math.round((pageY - this.sliderHeight / 2) / this._computedSliderRatio);\r\n\t}\r\n\r\n\tpublic static create(\r\n\t\toptions: MinimapOptions,\r\n\t\tviewportStartLineNumber: number,\r\n\t\tviewportEndLineNumber: number,\r\n\t\tviewportStartLineNumberVerticalOffset: number,\r\n\t\tviewportHeight: number,\r\n\t\tviewportContainsWhitespaceGaps: boolean,\r\n\t\tlineCount: number,\r\n\t\trealLineCount: number,\r\n\t\tscrollTop: number,\r\n\t\tscrollHeight: number,\r\n\t\tpreviousLayout: MinimapLayout | null\r\n\t): MinimapLayout {\r\n\t\tconst pixelRatio = options.pixelRatio;\r\n\t\tconst minimapLineHeight = options.minimapLineHeight;\r\n\t\tconst minimapLinesFitting = Math.floor(options.canvasInnerHeight / minimapLineHeight);\r\n\t\tconst lineHeight = options.lineHeight;\r\n\r\n\t\tif (options.minimapHeightIsEditorHeight) {\r\n\t\t\tconst logicalScrollHeight = (\r\n\t\t\t\trealLineCount * options.lineHeight\r\n\t\t\t\t+ (options.scrollBeyondLastLine ? viewportHeight - options.lineHeight : 0)\r\n\t\t\t);\r\n\t\t\tconst sliderHeight = Math.max(1, Math.floor(viewportHeight * viewportHeight / logicalScrollHeight));\r\n\t\t\tconst maxMinimapSliderTop = Math.max(0, options.minimapHeight - sliderHeight);\r\n\t\t\t// The slider can move from 0 to `maxMinimapSliderTop`\r\n\t\t\t// in the same way `scrollTop` can move from 0 to `scrollHeight` - `viewportHeight`.\r\n\t\t\tconst computedSliderRatio = (maxMinimapSliderTop) / (scrollHeight - viewportHeight);\r\n\t\t\tconst sliderTop = (scrollTop * computedSliderRatio);\r\n\t\t\tconst sliderNeeded = (maxMinimapSliderTop > 0);\r\n\t\t\tconst maxLinesFitting = Math.floor(options.canvasInnerHeight / options.minimapLineHeight);\r\n\t\t\treturn new MinimapLayout(scrollTop, scrollHeight, sliderNeeded, computedSliderRatio, sliderTop, sliderHeight, 1, Math.min(lineCount, maxLinesFitting));\r\n\t\t}\r\n\r\n\t\t// The visible line count in a viewport can change due to a number of reasons:\r\n\t\t// a) with the same viewport width, different scroll positions can result in partial lines being visible:\r\n\t\t// e.g. for a line height of 20, and a viewport height of 600\r\n\t\t// * scrollTop = 0 => visible lines are [1, 30]\r\n\t\t// * scrollTop = 10 => visible lines are [1, 31] (with lines 1 and 31 partially visible)\r\n\t\t// * scrollTop = 20 => visible lines are [2, 31]\r\n\t\t// b) whitespace gaps might make their way in the viewport (which results in a decrease in the visible line count)\r\n\t\t// c) we could be in the scroll beyond last line case (which also results in a decrease in the visible line count, down to possibly only one line being visible)\r\n\r\n\t\t// We must first establish a desirable slider height.\r\n\t\tlet sliderHeight: number;\r\n\t\tif (viewportContainsWhitespaceGaps && viewportEndLineNumber !== lineCount) {\r\n\t\t\t// case b) from above: there are whitespace gaps in the viewport.\r\n\t\t\t// In this case, the height of the slider directly reflects the visible line count.\r\n\t\t\tconst viewportLineCount = viewportEndLineNumber - viewportStartLineNumber + 1;\r\n\t\t\tsliderHeight = Math.floor(viewportLineCount * minimapLineHeight / pixelRatio);\r\n\t\t} else {\r\n\t\t\t// The slider has a stable height\r\n\t\t\tconst expectedViewportLineCount = viewportHeight / lineHeight;\r\n\t\t\tsliderHeight = Math.floor(expectedViewportLineCount * minimapLineHeight / pixelRatio);\r\n\t\t}\r\n\r\n\t\tlet maxMinimapSliderTop: number;\r\n\t\tif (options.scrollBeyondLastLine) {\r\n\t\t\t// The minimap slider, when dragged all the way down, will contain the last line at its top\r\n\t\t\tmaxMinimapSliderTop = (lineCount - 1) * minimapLineHeight / pixelRatio;\r\n\t\t} else {\r\n\t\t\t// The minimap slider, when dragged all the way down, will contain the last line at its bottom\r\n\t\t\tmaxMinimapSliderTop = Math.max(0, lineCount * minimapLineHeight / pixelRatio - sliderHeight);\r\n\t\t}\r\n\t\tmaxMinimapSliderTop = Math.min(options.minimapHeight - sliderHeight, maxMinimapSliderTop);\r\n\r\n\t\t// The slider can move from 0 to `maxMinimapSliderTop`\r\n\t\t// in the same way `scrollTop` can move from 0 to `scrollHeight` - `viewportHeight`.\r\n\t\tconst computedSliderRatio = (maxMinimapSliderTop) / (scrollHeight - viewportHeight);\r\n\t\tconst sliderTop = (scrollTop * computedSliderRatio);\r\n\r\n\t\tlet extraLinesAtTheBottom = 0;\r\n\t\tif (options.scrollBeyondLastLine) {\r\n\t\t\tconst expectedViewportLineCount = viewportHeight / lineHeight;\r\n\t\t\textraLinesAtTheBottom = expectedViewportLineCount - 1;\r\n\t\t}\r\n\t\tif (minimapLinesFitting >= lineCount + extraLinesAtTheBottom) {\r\n\t\t\t// All lines fit in the minimap\r\n\t\t\tconst startLineNumber = 1;\r\n\t\t\tconst endLineNumber = lineCount;\r\n\t\t\tconst sliderNeeded = (maxMinimapSliderTop > 0);\r\n\t\t\treturn new MinimapLayout(scrollTop, scrollHeight, sliderNeeded, computedSliderRatio, sliderTop, sliderHeight, startLineNumber, endLineNumber);\r\n\t\t} else {\r\n\t\t\tlet startLineNumber = Math.max(1, Math.floor(viewportStartLineNumber - sliderTop * pixelRatio / minimapLineHeight));\r\n\r\n\t\t\t// Avoid flickering caused by a partial viewport start line\r\n\t\t\t// by being consistent w.r.t. the previous layout decision\r\n\t\t\tif (previousLayout && previousLayout.scrollHeight === scrollHeight) {\r\n\t\t\t\tif (previousLayout.scrollTop > scrollTop) {\r\n\t\t\t\t\t// Scrolling up => never increase `startLineNumber`\r\n\t\t\t\t\tstartLineNumber = Math.min(startLineNumber, previousLayout.startLineNumber);\r\n\t\t\t\t}\r\n\t\t\t\tif (previousLayout.scrollTop < scrollTop) {\r\n\t\t\t\t\t// Scrolling down => never decrease `startLineNumber`\r\n\t\t\t\t\tstartLineNumber = Math.max(startLineNumber, previousLayout.startLineNumber);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tconst endLineNumber = Math.min(lineCount, startLineNumber + minimapLinesFitting - 1);\r\n\t\t\tconst partialLine = (scrollTop - viewportStartLineNumberVerticalOffset) / lineHeight;\r\n\t\t\tconst sliderTopAligned = (viewportStartLineNumber - startLineNumber + partialLine) * minimapLineHeight / pixelRatio;\r\n\r\n\t\t\treturn new MinimapLayout(scrollTop, scrollHeight, true, computedSliderRatio, sliderTopAligned, sliderHeight, startLineNumber, endLineNumber);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass MinimapLine implements ILine {\r\n\r\n\tpublic static readonly INVALID = new MinimapLine(-1);\r\n\r\n\tdy: number;\r\n\r\n\tconstructor(dy: number) {\r\n\t\tthis.dy = dy;\r\n\t}\r\n\r\n\tpublic onContentChanged(): void {\r\n\t\tthis.dy = -1;\r\n\t}\r\n\r\n\tpublic onTokensChanged(): void {\r\n\t\tthis.dy = -1;\r\n\t}\r\n}\r\n\r\nclass RenderData {\r\n\t/**\r\n\t * last rendered layout.\r\n\t */\r\n\tpublic readonly renderedLayout: MinimapLayout;\r\n\tprivate readonly _imageData: ImageData;\r\n\tprivate readonly _renderedLines: RenderedLinesCollection;\r\n\r\n\tconstructor(\r\n\t\trenderedLayout: MinimapLayout,\r\n\t\timageData: ImageData,\r\n\t\tlines: MinimapLine[]\r\n\t) {\r\n\t\tthis.renderedLayout = renderedLayout;\r\n\t\tthis._imageData = imageData;\r\n\t\tthis._renderedLines = new RenderedLinesCollection(\r\n\t\t\t() => MinimapLine.INVALID\r\n\t\t);\r\n\t\tthis._renderedLines._set(renderedLayout.startLineNumber, lines);\r\n\t}\r\n\r\n\t/**\r\n\t * Check if the current RenderData matches accurately the new desired layout and no painting is needed.\r\n\t */\r\n\tpublic linesEquals(layout: MinimapLayout): boolean {\r\n\t\tif (!this.scrollEquals(layout)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tconst tmp = this._renderedLines._get();\r\n\t\tconst lines = tmp.lines;\r\n\t\tfor (let i = 0, len = lines.length; i < len; i++) {\r\n\t\t\tif (lines[i].dy === -1) {\r\n\t\t\t\t// This line is invalid\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t * Check if the current RenderData matches the new layout's scroll position\r\n\t */\r\n\tpublic scrollEquals(layout: MinimapLayout): boolean {\r\n\t\treturn this.renderedLayout.startLineNumber === layout.startLineNumber\r\n\t\t\t&& this.renderedLayout.endLineNumber === layout.endLineNumber;\r\n\t}\r\n\r\n\t_get(): { imageData: ImageData; rendLineNumberStart: number; lines: MinimapLine[]; } {\r\n\t\tconst tmp = this._renderedLines._get();\r\n\t\treturn {\r\n\t\t\timageData: this._imageData,\r\n\t\t\trendLineNumberStart: tmp.rendLineNumberStart,\r\n\t\t\tlines: tmp.lines\r\n\t\t};\r\n\t}\r\n\r\n\tpublic onLinesChanged(changeFromLineNumber: number, changeToLineNumber: number): boolean {\r\n\t\treturn this._renderedLines.onLinesChanged(changeFromLineNumber, changeToLineNumber);\r\n\t}\r\n\tpublic onLinesDeleted(deleteFromLineNumber: number, deleteToLineNumber: number): void {\r\n\t\tthis._renderedLines.onLinesDeleted(deleteFromLineNumber, deleteToLineNumber);\r\n\t}\r\n\tpublic onLinesInserted(insertFromLineNumber: number, insertToLineNumber: number): void {\r\n\t\tthis._renderedLines.onLinesInserted(insertFromLineNumber, insertToLineNumber);\r\n\t}\r\n\tpublic onTokensChanged(ranges: { fromLineNumber: number; toLineNumber: number; }[]): boolean {\r\n\t\treturn this._renderedLines.onTokensChanged(ranges);\r\n\t}\r\n}\r\n\r\n/**\r\n * Some sort of double buffering.\r\n *\r\n * Keeps two buffers around that will be rotated for painting.\r\n * Always gives a buffer that is filled with the background color.\r\n */\r\nclass MinimapBuffers {\r\n\r\n\tprivate readonly _backgroundFillData: Uint8ClampedArray;\r\n\tprivate readonly _buffers: [ImageData, ImageData];\r\n\tprivate _lastUsedBuffer: number;\r\n\r\n\tconstructor(ctx: CanvasRenderingContext2D, WIDTH: number, HEIGHT: number, background: RGBA8) {\r\n\t\tthis._backgroundFillData = MinimapBuffers._createBackgroundFillData(WIDTH, HEIGHT, background);\r\n\t\tthis._buffers = [\r\n\t\t\tctx.createImageData(WIDTH, HEIGHT),\r\n\t\t\tctx.createImageData(WIDTH, HEIGHT)\r\n\t\t];\r\n\t\tthis._lastUsedBuffer = 0;\r\n\t}\r\n\r\n\tpublic getBuffer(): ImageData {\r\n\t\t// rotate buffers\r\n\t\tthis._lastUsedBuffer = 1 - this._lastUsedBuffer;\r\n\t\tconst result = this._buffers[this._lastUsedBuffer];\r\n\r\n\t\t// fill with background color\r\n\t\tresult.data.set(this._backgroundFillData);\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _createBackgroundFillData(WIDTH: number, HEIGHT: number, background: RGBA8): Uint8ClampedArray {\r\n\t\tconst backgroundR = background.r;\r\n\t\tconst backgroundG = background.g;\r\n\t\tconst backgroundB = background.b;\r\n\r\n\t\tconst result = new Uint8ClampedArray(WIDTH * HEIGHT * 4);\r\n\t\tlet offset = 0;\r\n\t\tfor (let i = 0; i < HEIGHT; i++) {\r\n\t\t\tfor (let j = 0; j < WIDTH; j++) {\r\n\t\t\t\tresult[offset] = backgroundR;\r\n\t\t\t\tresult[offset + 1] = backgroundG;\r\n\t\t\t\tresult[offset + 2] = backgroundB;\r\n\t\t\t\tresult[offset + 3] = 255;\r\n\t\t\t\toffset += 4;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n}\r\n\r\nexport interface IMinimapModel {\r\n\treadonly tokensColorTracker: MinimapTokensColorTracker;\r\n\treadonly options: MinimapOptions;\r\n\r\n\tgetLineCount(): number;\r\n\tgetRealLineCount(): number;\r\n\tgetLineContent(lineNumber: number): string;\r\n\tgetMinimapLinesRenderingData(startLineNumber: number, endLineNumber: number, needed: boolean[]): (ViewLineData | null)[];\r\n\tgetSelections(): Selection[];\r\n\tgetMinimapDecorationsInViewport(startLineNumber: number, endLineNumber: number): ViewModelDecoration[];\r\n\tgetOptions(): TextModelResolvedOptions;\r\n\trevealLineNumber(lineNumber: number): void;\r\n\tsetScrollTop(scrollTop: number): void;\r\n}\r\n\r\ninterface IMinimapRenderingContext {\r\n\treadonly viewportContainsWhitespaceGaps: boolean;\r\n\r\n\treadonly scrollWidth: number;\r\n\treadonly scrollHeight: number;\r\n\r\n\treadonly viewportStartLineNumber: number;\r\n\treadonly viewportEndLineNumber: number;\r\n\treadonly viewportStartLineNumberVerticalOffset: number;\r\n\r\n\treadonly scrollTop: number;\r\n\treadonly scrollLeft: number;\r\n\r\n\treadonly viewportWidth: number;\r\n\treadonly viewportHeight: number;\r\n}\r\n\r\ninterface SamplingStateLinesDeletedEvent {\r\n\ttype: 'deleted';\r\n\t_oldIndex: number;\r\n\tdeleteFromLineNumber: number;\r\n\tdeleteToLineNumber: number;\r\n}\r\n\r\ninterface SamplingStateLinesInsertedEvent {\r\n\ttype: 'inserted';\r\n\t_i: number;\r\n\tinsertFromLineNumber: number;\r\n\tinsertToLineNumber: number;\r\n}\r\n\r\ninterface SamplingStateFlushEvent {\r\n\ttype: 'flush';\r\n}\r\n\r\ntype SamplingStateEvent = SamplingStateLinesInsertedEvent | SamplingStateLinesDeletedEvent | SamplingStateFlushEvent;\r\n\r\nclass MinimapSamplingState {\r\n\r\n\tpublic static compute(options: MinimapOptions, viewLineCount: number, oldSamplingState: MinimapSamplingState | null): [MinimapSamplingState | null, SamplingStateEvent[]] {\r\n\t\tif (options.renderMinimap === RenderMinimap.None || !options.isSampling) {\r\n\t\t\treturn [null, []];\r\n\t\t}\r\n\r\n\t\t// ratio is intentionally not part of the layout to avoid the layout changing all the time\r\n\t\t// so we need to recompute it again...\r\n\t\tconst pixelRatio = options.pixelRatio;\r\n\t\tconst lineHeight = options.lineHeight;\r\n\t\tconst scrollBeyondLastLine = options.scrollBeyondLastLine;\r\n\t\tconst { minimapLineCount } = EditorLayoutInfoComputer.computeContainedMinimapLineCount({\r\n\t\t\tviewLineCount: viewLineCount,\r\n\t\t\tscrollBeyondLastLine: scrollBeyondLastLine,\r\n\t\t\theight: options.editorHeight,\r\n\t\t\tlineHeight: lineHeight,\r\n\t\t\tpixelRatio: pixelRatio\r\n\t\t});\r\n\t\tconst ratio = viewLineCount / minimapLineCount;\r\n\t\tconst halfRatio = ratio / 2;\r\n\r\n\t\tif (!oldSamplingState || oldSamplingState.minimapLines.length === 0) {\r\n\t\t\tlet result: number[] = [];\r\n\t\t\tresult[0] = 1;\r\n\t\t\tif (minimapLineCount > 1) {\r\n\t\t\t\tfor (let i = 0, lastIndex = minimapLineCount - 1; i < lastIndex; i++) {\r\n\t\t\t\t\tresult[i] = Math.round(i * ratio + halfRatio);\r\n\t\t\t\t}\r\n\t\t\t\tresult[minimapLineCount - 1] = viewLineCount;\r\n\t\t\t}\r\n\t\t\treturn [new MinimapSamplingState(ratio, result), []];\r\n\t\t}\r\n\r\n\t\tconst oldMinimapLines = oldSamplingState.minimapLines;\r\n\t\tconst oldLength = oldMinimapLines.length;\r\n\t\tlet result: number[] = [];\r\n\t\tlet oldIndex = 0;\r\n\t\tlet oldDeltaLineCount = 0;\r\n\t\tlet minViewLineNumber = 1;\r\n\t\tconst MAX_EVENT_COUNT = 10; // generate at most 10 events, if there are more than 10 changes, just flush all previous data\r\n\t\tlet events: SamplingStateEvent[] = [];\r\n\t\tlet lastEvent: SamplingStateEvent | null = null;\r\n\t\tfor (let i = 0; i < minimapLineCount; i++) {\r\n\t\t\tconst fromViewLineNumber = Math.max(minViewLineNumber, Math.round(i * ratio));\r\n\t\t\tconst toViewLineNumber = Math.max(fromViewLineNumber, Math.round((i + 1) * ratio));\r\n\r\n\t\t\twhile (oldIndex < oldLength && oldMinimapLines[oldIndex] < fromViewLineNumber) {\r\n\t\t\t\tif (events.length < MAX_EVENT_COUNT) {\r\n\t\t\t\t\tconst oldMinimapLineNumber = oldIndex + 1 + oldDeltaLineCount;\r\n\t\t\t\t\tif (lastEvent && lastEvent.type === 'deleted' && lastEvent._oldIndex === oldIndex - 1) {\r\n\t\t\t\t\t\tlastEvent.deleteToLineNumber++;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tlastEvent = { type: 'deleted', _oldIndex: oldIndex, deleteFromLineNumber: oldMinimapLineNumber, deleteToLineNumber: oldMinimapLineNumber };\r\n\t\t\t\t\t\tevents.push(lastEvent);\r\n\t\t\t\t\t}\r\n\t\t\t\t\toldDeltaLineCount--;\r\n\t\t\t\t}\r\n\t\t\t\toldIndex++;\r\n\t\t\t}\r\n\r\n\t\t\tlet selectedViewLineNumber: number;\r\n\t\t\tif (oldIndex < oldLength && oldMinimapLines[oldIndex] <= toViewLineNumber) {\r\n\t\t\t\t// reuse the old sampled line\r\n\t\t\t\tselectedViewLineNumber = oldMinimapLines[oldIndex];\r\n\t\t\t\toldIndex++;\r\n\t\t\t} else {\r\n\t\t\t\tif (i === 0) {\r\n\t\t\t\t\tselectedViewLineNumber = 1;\r\n\t\t\t\t} else if (i + 1 === minimapLineCount) {\r\n\t\t\t\t\tselectedViewLineNumber = viewLineCount;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tselectedViewLineNumber = Math.round(i * ratio + halfRatio);\r\n\t\t\t\t}\r\n\t\t\t\tif (events.length < MAX_EVENT_COUNT) {\r\n\t\t\t\t\tconst oldMinimapLineNumber = oldIndex + 1 + oldDeltaLineCount;\r\n\t\t\t\t\tif (lastEvent && lastEvent.type === 'inserted' && lastEvent._i === i - 1) {\r\n\t\t\t\t\t\tlastEvent.insertToLineNumber++;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tlastEvent = { type: 'inserted', _i: i, insertFromLineNumber: oldMinimapLineNumber, insertToLineNumber: oldMinimapLineNumber };\r\n\t\t\t\t\t\tevents.push(lastEvent);\r\n\t\t\t\t\t}\r\n\t\t\t\t\toldDeltaLineCount++;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tresult[i] = selectedViewLineNumber;\r\n\t\t\tminViewLineNumber = selectedViewLineNumber;\r\n\t\t}\r\n\r\n\t\tif (events.length < MAX_EVENT_COUNT) {\r\n\t\t\twhile (oldIndex < oldLength) {\r\n\t\t\t\tconst oldMinimapLineNumber = oldIndex + 1 + oldDeltaLineCount;\r\n\t\t\t\tif (lastEvent && lastEvent.type === 'deleted' && lastEvent._oldIndex === oldIndex - 1) {\r\n\t\t\t\t\tlastEvent.deleteToLineNumber++;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tlastEvent = { type: 'deleted', _oldIndex: oldIndex, deleteFromLineNumber: oldMinimapLineNumber, deleteToLineNumber: oldMinimapLineNumber };\r\n\t\t\t\t\tevents.push(lastEvent);\r\n\t\t\t\t}\r\n\t\t\t\toldDeltaLineCount--;\r\n\t\t\t\toldIndex++;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\t// too many events, just give up\r\n\t\t\tevents = [{ type: 'flush' }];\r\n\t\t}\r\n\r\n\t\treturn [new MinimapSamplingState(ratio, result), events];\r\n\t}\r\n\r\n\tconstructor(\r\n\t\tpublic readonly samplingRatio: number,\r\n\t\tpublic readonly minimapLines: number[]\r\n\t) {\r\n\t}\r\n\r\n\tpublic modelLineToMinimapLine(lineNumber: number): number {\r\n\t\treturn Math.min(this.minimapLines.length, Math.max(1, Math.round(lineNumber / this.samplingRatio)));\r\n\t}\r\n\r\n\t/**\r\n\t * Will return null if the model line ranges are not intersecting with a sampled model line.\r\n\t */\r\n\tpublic modelLineRangeToMinimapLineRange(fromLineNumber: number, toLineNumber: number): [number, number] | null {\r\n\t\tlet fromLineIndex = this.modelLineToMinimapLine(fromLineNumber) - 1;\r\n\t\twhile (fromLineIndex > 0 && this.minimapLines[fromLineIndex - 1] >= fromLineNumber) {\r\n\t\t\tfromLineIndex--;\r\n\t\t}\r\n\t\tlet toLineIndex = this.modelLineToMinimapLine(toLineNumber) - 1;\r\n\t\twhile (toLineIndex + 1 < this.minimapLines.length && this.minimapLines[toLineIndex + 1] <= toLineNumber) {\r\n\t\t\ttoLineIndex++;\r\n\t\t}\r\n\t\tif (fromLineIndex === toLineIndex) {\r\n\t\t\tconst sampledLineNumber = this.minimapLines[fromLineIndex];\r\n\t\t\tif (sampledLineNumber < fromLineNumber || sampledLineNumber > toLineNumber) {\r\n\t\t\t\t// This line is not part of the sampled lines ==> nothing to do\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn [fromLineIndex + 1, toLineIndex + 1];\r\n\t}\r\n\r\n\t/**\r\n\t * Will always return a range, even if it is not intersecting with a sampled model line.\r\n\t */\r\n\tpublic decorationLineRangeToMinimapLineRange(startLineNumber: number, endLineNumber: number): [number, number] {\r\n\t\tlet minimapLineStart = this.modelLineToMinimapLine(startLineNumber);\r\n\t\tlet minimapLineEnd = this.modelLineToMinimapLine(endLineNumber);\r\n\t\tif (startLineNumber !== endLineNumber && minimapLineEnd === minimapLineStart) {\r\n\t\t\tif (minimapLineEnd === this.minimapLines.length) {\r\n\t\t\t\tif (minimapLineStart > 1) {\r\n\t\t\t\t\tminimapLineStart--;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tminimapLineEnd++;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn [minimapLineStart, minimapLineEnd];\r\n\t}\r\n\r\n\tpublic onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): [number, number] {\r\n\t\t// have the mapping be sticky\r\n\t\tconst deletedLineCount = e.toLineNumber - e.fromLineNumber + 1;\r\n\t\tlet changeStartIndex = this.minimapLines.length;\r\n\t\tlet changeEndIndex = 0;\r\n\t\tfor (let i = this.minimapLines.length - 1; i >= 0; i--) {\r\n\t\t\tif (this.minimapLines[i] < e.fromLineNumber) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tif (this.minimapLines[i] <= e.toLineNumber) {\r\n\t\t\t\t// this line got deleted => move to previous available\r\n\t\t\t\tthis.minimapLines[i] = Math.max(1, e.fromLineNumber - 1);\r\n\t\t\t\tchangeStartIndex = Math.min(changeStartIndex, i);\r\n\t\t\t\tchangeEndIndex = Math.max(changeEndIndex, i);\r\n\t\t\t} else {\r\n\t\t\t\tthis.minimapLines[i] -= deletedLineCount;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn [changeStartIndex, changeEndIndex];\r\n\t}\r\n\r\n\tpublic onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): void {\r\n\t\t// have the mapping be sticky\r\n\t\tconst insertedLineCount = e.toLineNumber - e.fromLineNumber + 1;\r\n\t\tfor (let i = this.minimapLines.length - 1; i >= 0; i--) {\r\n\t\t\tif (this.minimapLines[i] < e.fromLineNumber) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tthis.minimapLines[i] += insertedLineCount;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class Minimap extends ViewPart implements IMinimapModel {\r\n\r\n\tpublic readonly tokensColorTracker: MinimapTokensColorTracker;\r\n\r\n\tprivate _selections: Selection[];\r\n\tprivate _minimapSelections: Selection[] | null;\r\n\r\n\tpublic options: MinimapOptions;\r\n\r\n\tprivate _samplingState: MinimapSamplingState | null;\r\n\tprivate _shouldCheckSampling: boolean;\r\n\r\n\tprivate _actual: InnerMinimap;\r\n\r\n\tconstructor(context: ViewContext) {\r\n\t\tsuper(context);\r\n\r\n\t\tthis.tokensColorTracker = MinimapTokensColorTracker.getInstance();\r\n\r\n\t\tthis._selections = [];\r\n\t\tthis._minimapSelections = null;\r\n\r\n\t\tthis.options = new MinimapOptions(this._context.configuration, this._context.theme, this.tokensColorTracker);\r\n\t\tconst [samplingState,] = MinimapSamplingState.compute(this.options, this._context.model.getLineCount(), null);\r\n\t\tthis._samplingState = samplingState;\r\n\t\tthis._shouldCheckSampling = false;\r\n\r\n\t\tthis._actual = new InnerMinimap(context.theme, this);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._actual.dispose();\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tpublic getDomNode(): FastDomNode {\r\n\t\treturn this._actual.getDomNode();\r\n\t}\r\n\r\n\tprivate _onOptionsMaybeChanged(): boolean {\r\n\t\tconst opts = new MinimapOptions(this._context.configuration, this._context.theme, this.tokensColorTracker);\r\n\t\tif (this.options.equals(opts)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tthis.options = opts;\r\n\t\tthis._recreateLineSampling();\r\n\t\tthis._actual.onDidChangeOptions();\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// ---- begin view event handlers\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\treturn this._onOptionsMaybeChanged();\r\n\t}\r\n\tpublic onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {\r\n\t\tthis._selections = e.selections;\r\n\t\tthis._minimapSelections = null;\r\n\t\treturn this._actual.onSelectionChanged();\r\n\t}\r\n\tpublic onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {\r\n\t\tif (e.affectsMinimap) {\r\n\t\t\treturn this._actual.onDecorationsChanged();\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\tpublic onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\r\n\t\tif (this._samplingState) {\r\n\t\t\tthis._shouldCheckSampling = true;\r\n\t\t}\r\n\t\treturn this._actual.onFlushed();\r\n\t}\r\n\tpublic onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\r\n\t\tif (this._samplingState) {\r\n\t\t\tconst minimapLineRange = this._samplingState.modelLineRangeToMinimapLineRange(e.fromLineNumber, e.toLineNumber);\r\n\t\t\tif (minimapLineRange) {\r\n\t\t\t\treturn this._actual.onLinesChanged(minimapLineRange[0], minimapLineRange[1]);\r\n\t\t\t} else {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\treturn this._actual.onLinesChanged(e.fromLineNumber, e.toLineNumber);\r\n\t\t}\r\n\t}\r\n\tpublic onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\r\n\t\tif (this._samplingState) {\r\n\t\t\tconst [changeStartIndex, changeEndIndex] = this._samplingState.onLinesDeleted(e);\r\n\t\t\tif (changeStartIndex <= changeEndIndex) {\r\n\t\t\t\tthis._actual.onLinesChanged(changeStartIndex + 1, changeEndIndex + 1);\r\n\t\t\t}\r\n\t\t\tthis._shouldCheckSampling = true;\r\n\t\t\treturn true;\r\n\t\t} else {\r\n\t\t\treturn this._actual.onLinesDeleted(e.fromLineNumber, e.toLineNumber);\r\n\t\t}\r\n\t}\r\n\tpublic onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\r\n\t\tif (this._samplingState) {\r\n\t\t\tthis._samplingState.onLinesInserted(e);\r\n\t\t\tthis._shouldCheckSampling = true;\r\n\t\t\treturn true;\r\n\t\t} else {\r\n\t\t\treturn this._actual.onLinesInserted(e.fromLineNumber, e.toLineNumber);\r\n\t\t}\r\n\t}\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\treturn this._actual.onScrollChanged();\r\n\t}\r\n\tpublic onThemeChanged(e: viewEvents.ViewThemeChangedEvent): boolean {\r\n\t\tthis._context.model.invalidateMinimapColorCache();\r\n\t\tthis._actual.onThemeChanged();\r\n\t\tthis._onOptionsMaybeChanged();\r\n\t\treturn true;\r\n\t}\r\n\tpublic onTokensChanged(e: viewEvents.ViewTokensChangedEvent): boolean {\r\n\t\tif (this._samplingState) {\r\n\t\t\tlet ranges: { fromLineNumber: number; toLineNumber: number; }[] = [];\r\n\t\t\tfor (const range of e.ranges) {\r\n\t\t\t\tconst minimapLineRange = this._samplingState.modelLineRangeToMinimapLineRange(range.fromLineNumber, range.toLineNumber);\r\n\t\t\t\tif (minimapLineRange) {\r\n\t\t\t\t\tranges.push({ fromLineNumber: minimapLineRange[0], toLineNumber: minimapLineRange[1] });\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (ranges.length) {\r\n\t\t\t\treturn this._actual.onTokensChanged(ranges);\r\n\t\t\t} else {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\treturn this._actual.onTokensChanged(e.ranges);\r\n\t\t}\r\n\t}\r\n\tpublic onTokensColorsChanged(e: viewEvents.ViewTokensColorsChangedEvent): boolean {\r\n\t\tthis._onOptionsMaybeChanged();\r\n\t\treturn this._actual.onTokensColorsChanged();\r\n\t}\r\n\tpublic onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\r\n\t\treturn this._actual.onZonesChanged();\r\n\t}\r\n\r\n\t// --- end event handlers\r\n\r\n\tpublic prepareRender(ctx: RenderingContext): void {\r\n\t\tif (this._shouldCheckSampling) {\r\n\t\t\tthis._shouldCheckSampling = false;\r\n\t\t\tthis._recreateLineSampling();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic render(ctx: RestrictedRenderingContext): void {\r\n\t\tlet viewportStartLineNumber = ctx.visibleRange.startLineNumber;\r\n\t\tlet viewportEndLineNumber = ctx.visibleRange.endLineNumber;\r\n\r\n\t\tif (this._samplingState) {\r\n\t\t\tviewportStartLineNumber = this._samplingState.modelLineToMinimapLine(viewportStartLineNumber);\r\n\t\t\tviewportEndLineNumber = this._samplingState.modelLineToMinimapLine(viewportEndLineNumber);\r\n\t\t}\r\n\r\n\t\tconst minimapCtx: IMinimapRenderingContext = {\r\n\t\t\tviewportContainsWhitespaceGaps: (ctx.viewportData.whitespaceViewportData.length > 0),\r\n\r\n\t\t\tscrollWidth: ctx.scrollWidth,\r\n\t\t\tscrollHeight: ctx.scrollHeight,\r\n\r\n\t\t\tviewportStartLineNumber: viewportStartLineNumber,\r\n\t\t\tviewportEndLineNumber: viewportEndLineNumber,\r\n\t\t\tviewportStartLineNumberVerticalOffset: ctx.getVerticalOffsetForLineNumber(viewportStartLineNumber),\r\n\r\n\t\t\tscrollTop: ctx.scrollTop,\r\n\t\t\tscrollLeft: ctx.scrollLeft,\r\n\r\n\t\t\tviewportWidth: ctx.viewportWidth,\r\n\t\t\tviewportHeight: ctx.viewportHeight,\r\n\t\t};\r\n\t\tthis._actual.render(minimapCtx);\r\n\t}\r\n\r\n\t//#region IMinimapModel\r\n\r\n\tprivate _recreateLineSampling(): void {\r\n\t\tthis._minimapSelections = null;\r\n\r\n\t\tconst wasSampling = Boolean(this._samplingState);\r\n\t\tconst [samplingState, events] = MinimapSamplingState.compute(this.options, this._context.model.getLineCount(), this._samplingState);\r\n\t\tthis._samplingState = samplingState;\r\n\r\n\t\tif (wasSampling && this._samplingState) {\r\n\t\t\t// was sampling, is sampling\r\n\t\t\tfor (const event of events) {\r\n\t\t\t\tswitch (event.type) {\r\n\t\t\t\t\tcase 'deleted':\r\n\t\t\t\t\t\tthis._actual.onLinesDeleted(event.deleteFromLineNumber, event.deleteToLineNumber);\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tcase 'inserted':\r\n\t\t\t\t\t\tthis._actual.onLinesInserted(event.insertFromLineNumber, event.insertToLineNumber);\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tcase 'flush':\r\n\t\t\t\t\t\tthis._actual.onFlushed();\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getLineCount(): number {\r\n\t\tif (this._samplingState) {\r\n\t\t\treturn this._samplingState.minimapLines.length;\r\n\t\t}\r\n\t\treturn this._context.model.getLineCount();\r\n\t}\r\n\r\n\tpublic getRealLineCount(): number {\r\n\t\treturn this._context.model.getLineCount();\r\n\t}\r\n\r\n\tpublic getLineContent(lineNumber: number): string {\r\n\t\tif (this._samplingState) {\r\n\t\t\treturn this._context.model.getLineContent(this._samplingState.minimapLines[lineNumber - 1]);\r\n\t\t}\r\n\t\treturn this._context.model.getLineContent(lineNumber);\r\n\t}\r\n\r\n\tpublic getMinimapLinesRenderingData(startLineNumber: number, endLineNumber: number, needed: boolean[]): (ViewLineData | null)[] {\r\n\t\tif (this._samplingState) {\r\n\t\t\tlet result: (ViewLineData | null)[] = [];\r\n\t\t\tfor (let lineIndex = 0, lineCount = endLineNumber - startLineNumber + 1; lineIndex < lineCount; lineIndex++) {\r\n\t\t\t\tif (needed[lineIndex]) {\r\n\t\t\t\t\tresult[lineIndex] = this._context.model.getViewLineData(this._samplingState.minimapLines[startLineNumber + lineIndex - 1]);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tresult[lineIndex] = null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn result;\r\n\t\t}\r\n\t\treturn this._context.model.getMinimapLinesRenderingData(startLineNumber, endLineNumber, needed).data;\r\n\t}\r\n\r\n\tpublic getSelections(): Selection[] {\r\n\t\tif (this._minimapSelections === null) {\r\n\t\t\tif (this._samplingState) {\r\n\t\t\t\tthis._minimapSelections = [];\r\n\t\t\t\tfor (const selection of this._selections) {\r\n\t\t\t\t\tconst [minimapLineStart, minimapLineEnd] = this._samplingState.decorationLineRangeToMinimapLineRange(selection.startLineNumber, selection.endLineNumber);\r\n\t\t\t\t\tthis._minimapSelections.push(new Selection(minimapLineStart, selection.startColumn, minimapLineEnd, selection.endColumn));\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tthis._minimapSelections = this._selections;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this._minimapSelections;\r\n\t}\r\n\r\n\tpublic getMinimapDecorationsInViewport(startLineNumber: number, endLineNumber: number): ViewModelDecoration[] {\r\n\t\tlet visibleRange: Range;\r\n\t\tif (this._samplingState) {\r\n\t\t\tconst modelStartLineNumber = this._samplingState.minimapLines[startLineNumber - 1];\r\n\t\t\tconst modelEndLineNumber = this._samplingState.minimapLines[endLineNumber - 1];\r\n\t\t\tvisibleRange = new Range(modelStartLineNumber, 1, modelEndLineNumber, this._context.model.getLineMaxColumn(modelEndLineNumber));\r\n\t\t} else {\r\n\t\t\tvisibleRange = new Range(startLineNumber, 1, endLineNumber, this._context.model.getLineMaxColumn(endLineNumber));\r\n\t\t}\r\n\t\tconst decorations = this._context.model.getDecorationsInViewport(visibleRange);\r\n\r\n\t\tif (this._samplingState) {\r\n\t\t\tlet result: ViewModelDecoration[] = [];\r\n\t\t\tfor (const decoration of decorations) {\r\n\t\t\t\tif (!decoration.options.minimap) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\tconst range = decoration.range;\r\n\t\t\t\tconst minimapStartLineNumber = this._samplingState.modelLineToMinimapLine(range.startLineNumber);\r\n\t\t\t\tconst minimapEndLineNumber = this._samplingState.modelLineToMinimapLine(range.endLineNumber);\r\n\t\t\t\tresult.push(new ViewModelDecoration(new Range(minimapStartLineNumber, range.startColumn, minimapEndLineNumber, range.endColumn), decoration.options));\r\n\t\t\t}\r\n\t\t\treturn result;\r\n\t\t}\r\n\t\treturn decorations;\r\n\t}\r\n\r\n\tpublic getOptions(): TextModelResolvedOptions {\r\n\t\treturn this._context.model.getTextModelOptions();\r\n\t}\r\n\r\n\tpublic revealLineNumber(lineNumber: number): void {\r\n\t\tif (this._samplingState) {\r\n\t\t\tlineNumber = this._samplingState.minimapLines[lineNumber - 1];\r\n\t\t}\r\n\t\tthis._context.model.revealRange(\r\n\t\t\t'mouse',\r\n\t\t\tfalse,\r\n\t\t\tnew Range(lineNumber, 1, lineNumber, 1),\r\n\t\t\tviewEvents.VerticalRevealType.Center,\r\n\t\t\tScrollType.Smooth\r\n\t\t);\r\n\t}\r\n\r\n\tpublic setScrollTop(scrollTop: number): void {\r\n\t\tthis._context.model.setScrollPosition({\r\n\t\t\tscrollTop: scrollTop\r\n\t\t}, ScrollType.Immediate);\r\n\t}\r\n\r\n\t//#endregion\r\n}\r\n\r\nclass InnerMinimap extends Disposable {\r\n\r\n\tprivate readonly _theme: EditorTheme;\r\n\tprivate readonly _model: IMinimapModel;\r\n\r\n\tprivate readonly _domNode: FastDomNode;\r\n\tprivate readonly _shadow: FastDomNode;\r\n\tprivate readonly _canvas: FastDomNode;\r\n\tprivate readonly _decorationsCanvas: FastDomNode;\r\n\tprivate readonly _slider: FastDomNode;\r\n\tprivate readonly _sliderHorizontal: FastDomNode;\r\n\tprivate readonly _mouseDownListener: IDisposable;\r\n\tprivate readonly _sliderMouseMoveMonitor: GlobalMouseMoveMonitor;\r\n\tprivate readonly _sliderMouseDownListener: IDisposable;\r\n\tprivate readonly _gestureDisposable: IDisposable;\r\n\tprivate readonly _sliderTouchStartListener: IDisposable;\r\n\tprivate readonly _sliderTouchMoveListener: IDisposable;\r\n\tprivate readonly _sliderTouchEndListener: IDisposable;\r\n\r\n\tprivate _lastRenderData: RenderData | null;\r\n\tprivate _selectionColor: Color | undefined;\r\n\tprivate _renderDecorations: boolean = false;\r\n\tprivate _gestureInProgress: boolean = false;\r\n\tprivate _buffers: MinimapBuffers | null;\r\n\r\n\tconstructor(\r\n\t\ttheme: EditorTheme,\r\n\t\tmodel: IMinimapModel\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\tthis._theme = theme;\r\n\t\tthis._model = model;\r\n\r\n\t\tthis._lastRenderData = null;\r\n\t\tthis._buffers = null;\r\n\t\tthis._selectionColor = this._theme.getColor(minimapSelection);\r\n\r\n\t\tthis._domNode = createFastDomNode(document.createElement('div'));\r\n\t\tPartFingerprints.write(this._domNode, PartFingerprint.Minimap);\r\n\t\tthis._domNode.setClassName(this._getMinimapDomNodeClassName());\r\n\t\tthis._domNode.setPosition('absolute');\r\n\t\tthis._domNode.setAttribute('role', 'presentation');\r\n\t\tthis._domNode.setAttribute('aria-hidden', 'true');\r\n\r\n\t\tthis._shadow = createFastDomNode(document.createElement('div'));\r\n\t\tthis._shadow.setClassName('minimap-shadow-hidden');\r\n\t\tthis._domNode.appendChild(this._shadow);\r\n\r\n\t\tthis._canvas = createFastDomNode(document.createElement('canvas'));\r\n\t\tthis._canvas.setPosition('absolute');\r\n\t\tthis._canvas.setLeft(0);\r\n\t\tthis._domNode.appendChild(this._canvas);\r\n\r\n\t\tthis._decorationsCanvas = createFastDomNode(document.createElement('canvas'));\r\n\t\tthis._decorationsCanvas.setPosition('absolute');\r\n\t\tthis._decorationsCanvas.setClassName('minimap-decorations-layer');\r\n\t\tthis._decorationsCanvas.setLeft(0);\r\n\t\tthis._domNode.appendChild(this._decorationsCanvas);\r\n\r\n\t\tthis._slider = createFastDomNode(document.createElement('div'));\r\n\t\tthis._slider.setPosition('absolute');\r\n\t\tthis._slider.setClassName('minimap-slider');\r\n\t\tthis._slider.setLayerHinting(true);\r\n\t\tthis._slider.setContain('strict');\r\n\t\tthis._domNode.appendChild(this._slider);\r\n\r\n\t\tthis._sliderHorizontal = createFastDomNode(document.createElement('div'));\r\n\t\tthis._sliderHorizontal.setPosition('absolute');\r\n\t\tthis._sliderHorizontal.setClassName('minimap-slider-horizontal');\r\n\t\tthis._slider.appendChild(this._sliderHorizontal);\r\n\r\n\t\tthis._applyLayout();\r\n\r\n\t\tthis._mouseDownListener = dom.addStandardDisposableListener(this._domNode.domNode, 'mousedown', (e) => {\r\n\t\t\te.preventDefault();\r\n\r\n\t\t\tconst renderMinimap = this._model.options.renderMinimap;\r\n\t\t\tif (renderMinimap === RenderMinimap.None) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (!this._lastRenderData) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (this._model.options.size !== 'proportional') {\r\n\t\t\t\tif (e.leftButton && this._lastRenderData) {\r\n\t\t\t\t\t// pretend the click occured in the center of the slider\r\n\t\t\t\t\tconst position = dom.getDomNodePagePosition(this._slider.domNode);\r\n\t\t\t\t\tconst initialPosY = position.top + position.height / 2;\r\n\t\t\t\t\tthis._startSliderDragging(e.buttons, e.posx, initialPosY, e.posy, this._lastRenderData.renderedLayout);\r\n\t\t\t\t}\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tconst minimapLineHeight = this._model.options.minimapLineHeight;\r\n\t\t\tconst internalOffsetY = (this._model.options.canvasInnerHeight / this._model.options.canvasOuterHeight) * e.browserEvent.offsetY;\r\n\t\t\tconst lineIndex = Math.floor(internalOffsetY / minimapLineHeight);\r\n\r\n\t\t\tlet lineNumber = lineIndex + this._lastRenderData.renderedLayout.startLineNumber;\r\n\t\t\tlineNumber = Math.min(lineNumber, this._model.getLineCount());\r\n\r\n\t\t\tthis._model.revealLineNumber(lineNumber);\r\n\t\t});\r\n\r\n\t\tthis._sliderMouseMoveMonitor = new GlobalMouseMoveMonitor();\r\n\r\n\t\tthis._sliderMouseDownListener = dom.addStandardDisposableListener(this._slider.domNode, 'mousedown', (e) => {\r\n\t\t\te.preventDefault();\r\n\t\t\te.stopPropagation();\r\n\t\t\tif (e.leftButton && this._lastRenderData) {\r\n\t\t\t\tthis._startSliderDragging(e.buttons, e.posx, e.posy, e.posy, this._lastRenderData.renderedLayout);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tthis._gestureDisposable = Gesture.addTarget(this._domNode.domNode);\r\n\t\tthis._sliderTouchStartListener = dom.addDisposableListener(this._domNode.domNode, EventType.Start, (e: GestureEvent) => {\r\n\t\t\te.preventDefault();\r\n\t\t\te.stopPropagation();\r\n\t\t\tif (this._lastRenderData) {\r\n\t\t\t\tthis._slider.toggleClassName('active', true);\r\n\t\t\t\tthis._gestureInProgress = true;\r\n\t\t\t\tthis.scrollDueToTouchEvent(e);\r\n\t\t\t}\r\n\t\t}, { passive: false });\r\n\r\n\t\tthis._sliderTouchMoveListener = dom.addDisposableListener(this._domNode.domNode, EventType.Change, (e: GestureEvent) => {\r\n\t\t\te.preventDefault();\r\n\t\t\te.stopPropagation();\r\n\t\t\tif (this._lastRenderData && this._gestureInProgress) {\r\n\t\t\t\tthis.scrollDueToTouchEvent(e);\r\n\t\t\t}\r\n\t\t}, { passive: false });\r\n\r\n\t\tthis._sliderTouchEndListener = dom.addStandardDisposableListener(this._domNode.domNode, EventType.End, (e: GestureEvent) => {\r\n\t\t\te.preventDefault();\r\n\t\t\te.stopPropagation();\r\n\t\t\tthis._gestureInProgress = false;\r\n\t\t\tthis._slider.toggleClassName('active', false);\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _startSliderDragging(initialButtons: number, initialPosX: number, initialPosY: number, posy: number, initialSliderState: MinimapLayout): void {\r\n\t\tthis._slider.toggleClassName('active', true);\r\n\r\n\t\tconst handleMouseMove = (posy: number, posx: number) => {\r\n\t\t\tconst mouseOrthogonalDelta = Math.abs(posx - initialPosX);\r\n\r\n\t\t\tif (platform.isWindows && mouseOrthogonalDelta > MOUSE_DRAG_RESET_DISTANCE) {\r\n\t\t\t\t// The mouse has wondered away from the scrollbar => reset dragging\r\n\t\t\t\tthis._model.setScrollTop(initialSliderState.scrollTop);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst mouseDelta = posy - initialPosY;\r\n\t\t\tthis._model.setScrollTop(initialSliderState.getDesiredScrollTopFromDelta(mouseDelta));\r\n\t\t};\r\n\r\n\t\tif (posy !== initialPosY) {\r\n\t\t\thandleMouseMove(posy, initialPosX);\r\n\t\t}\r\n\r\n\t\tthis._sliderMouseMoveMonitor.startMonitoring(\r\n\t\t\tthis._slider.domNode,\r\n\t\t\tinitialButtons,\r\n\t\t\tstandardMouseMoveMerger,\r\n\t\t\t(mouseMoveData: IStandardMouseMoveEventData) => handleMouseMove(mouseMoveData.posy, mouseMoveData.posx),\r\n\t\t\t() => {\r\n\t\t\t\tthis._slider.toggleClassName('active', false);\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n\r\n\tprivate scrollDueToTouchEvent(touch: GestureEvent) {\r\n\t\tconst startY = this._domNode.domNode.getBoundingClientRect().top;\r\n\t\tconst scrollTop = this._lastRenderData!.renderedLayout.getDesiredScrollTopFromTouchLocation(touch.pageY - startY);\r\n\t\tthis._model.setScrollTop(scrollTop);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._mouseDownListener.dispose();\r\n\t\tthis._sliderMouseMoveMonitor.dispose();\r\n\t\tthis._sliderMouseDownListener.dispose();\r\n\t\tthis._gestureDisposable.dispose();\r\n\t\tthis._sliderTouchStartListener.dispose();\r\n\t\tthis._sliderTouchMoveListener.dispose();\r\n\t\tthis._sliderTouchEndListener.dispose();\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tprivate _getMinimapDomNodeClassName(): string {\r\n\t\tif (this._model.options.showSlider === 'always') {\r\n\t\t\treturn 'minimap slider-always';\r\n\t\t}\r\n\t\treturn 'minimap slider-mouseover';\r\n\t}\r\n\r\n\tpublic getDomNode(): FastDomNode {\r\n\t\treturn this._domNode;\r\n\t}\r\n\r\n\tprivate _applyLayout(): void {\r\n\t\tthis._domNode.setLeft(this._model.options.minimapLeft);\r\n\t\tthis._domNode.setWidth(this._model.options.minimapWidth);\r\n\t\tthis._domNode.setHeight(this._model.options.minimapHeight);\r\n\t\tthis._shadow.setHeight(this._model.options.minimapHeight);\r\n\r\n\t\tthis._canvas.setWidth(this._model.options.canvasOuterWidth);\r\n\t\tthis._canvas.setHeight(this._model.options.canvasOuterHeight);\r\n\t\tthis._canvas.domNode.width = this._model.options.canvasInnerWidth;\r\n\t\tthis._canvas.domNode.height = this._model.options.canvasInnerHeight;\r\n\r\n\t\tthis._decorationsCanvas.setWidth(this._model.options.canvasOuterWidth);\r\n\t\tthis._decorationsCanvas.setHeight(this._model.options.canvasOuterHeight);\r\n\t\tthis._decorationsCanvas.domNode.width = this._model.options.canvasInnerWidth;\r\n\t\tthis._decorationsCanvas.domNode.height = this._model.options.canvasInnerHeight;\r\n\r\n\t\tthis._slider.setWidth(this._model.options.minimapWidth);\r\n\t}\r\n\r\n\tprivate _getBuffer(): ImageData | null {\r\n\t\tif (!this._buffers) {\r\n\t\t\tif (this._model.options.canvasInnerWidth > 0 && this._model.options.canvasInnerHeight > 0) {\r\n\t\t\t\tthis._buffers = new MinimapBuffers(\r\n\t\t\t\t\tthis._canvas.domNode.getContext('2d')!,\r\n\t\t\t\t\tthis._model.options.canvasInnerWidth,\r\n\t\t\t\t\tthis._model.options.canvasInnerHeight,\r\n\t\t\t\t\tthis._model.options.backgroundColor\r\n\t\t\t\t);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this._buffers ? this._buffers.getBuffer() : null;\r\n\t}\r\n\r\n\t// ---- begin view event handlers\r\n\r\n\tpublic onDidChangeOptions(): void {\r\n\t\tthis._lastRenderData = null;\r\n\t\tthis._buffers = null;\r\n\t\tthis._applyLayout();\r\n\t\tthis._domNode.setClassName(this._getMinimapDomNodeClassName());\r\n\t}\r\n\tpublic onSelectionChanged(): boolean {\r\n\t\tthis._renderDecorations = true;\r\n\t\treturn true;\r\n\t}\r\n\tpublic onDecorationsChanged(): boolean {\r\n\t\tthis._renderDecorations = true;\r\n\t\treturn true;\r\n\t}\r\n\tpublic onFlushed(): boolean {\r\n\t\tthis._lastRenderData = null;\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesChanged(changeFromLineNumber: number, changeToLineNumber: number): boolean {\r\n\t\tif (this._lastRenderData) {\r\n\t\t\treturn this._lastRenderData.onLinesChanged(changeFromLineNumber, changeToLineNumber);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\tpublic onLinesDeleted(deleteFromLineNumber: number, deleteToLineNumber: number): boolean {\r\n\t\tif (this._lastRenderData) {\r\n\t\t\tthis._lastRenderData.onLinesDeleted(deleteFromLineNumber, deleteToLineNumber);\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesInserted(insertFromLineNumber: number, insertToLineNumber: number): boolean {\r\n\t\tif (this._lastRenderData) {\r\n\t\t\tthis._lastRenderData.onLinesInserted(insertFromLineNumber, insertToLineNumber);\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\tpublic onScrollChanged(): boolean {\r\n\t\tthis._renderDecorations = true;\r\n\t\treturn true;\r\n\t}\r\n\tpublic onThemeChanged(): boolean {\r\n\t\tthis._selectionColor = this._theme.getColor(minimapSelection);\r\n\t\tthis._renderDecorations = true;\r\n\t\treturn true;\r\n\t}\r\n\tpublic onTokensChanged(ranges: { fromLineNumber: number; toLineNumber: number; }[]): boolean {\r\n\t\tif (this._lastRenderData) {\r\n\t\t\treturn this._lastRenderData.onTokensChanged(ranges);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\tpublic onTokensColorsChanged(): boolean {\r\n\t\tthis._lastRenderData = null;\r\n\t\tthis._buffers = null;\r\n\t\treturn true;\r\n\t}\r\n\tpublic onZonesChanged(): boolean {\r\n\t\tthis._lastRenderData = null;\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// --- end event handlers\r\n\r\n\tpublic render(renderingCtx: IMinimapRenderingContext): void {\r\n\t\tconst renderMinimap = this._model.options.renderMinimap;\r\n\t\tif (renderMinimap === RenderMinimap.None) {\r\n\t\t\tthis._shadow.setClassName('minimap-shadow-hidden');\r\n\t\t\tthis._sliderHorizontal.setWidth(0);\r\n\t\t\tthis._sliderHorizontal.setHeight(0);\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (renderingCtx.scrollLeft + renderingCtx.viewportWidth >= renderingCtx.scrollWidth) {\r\n\t\t\tthis._shadow.setClassName('minimap-shadow-hidden');\r\n\t\t} else {\r\n\t\t\tthis._shadow.setClassName('minimap-shadow-visible');\r\n\t\t}\r\n\r\n\t\tconst layout = MinimapLayout.create(\r\n\t\t\tthis._model.options,\r\n\t\t\trenderingCtx.viewportStartLineNumber,\r\n\t\t\trenderingCtx.viewportEndLineNumber,\r\n\t\t\trenderingCtx.viewportStartLineNumberVerticalOffset,\r\n\t\t\trenderingCtx.viewportHeight,\r\n\t\t\trenderingCtx.viewportContainsWhitespaceGaps,\r\n\t\t\tthis._model.getLineCount(),\r\n\t\t\tthis._model.getRealLineCount(),\r\n\t\t\trenderingCtx.scrollTop,\r\n\t\t\trenderingCtx.scrollHeight,\r\n\t\t\tthis._lastRenderData ? this._lastRenderData.renderedLayout : null\r\n\t\t);\r\n\t\tthis._slider.setDisplay(layout.sliderNeeded ? 'block' : 'none');\r\n\t\tthis._slider.setTop(layout.sliderTop);\r\n\t\tthis._slider.setHeight(layout.sliderHeight);\r\n\r\n\t\t// Compute horizontal slider coordinates\r\n\t\tconst scrollLeftChars = renderingCtx.scrollLeft / this._model.options.typicalHalfwidthCharacterWidth;\r\n\t\tconst horizontalSliderLeft = Math.min(this._model.options.minimapWidth, Math.round(scrollLeftChars * this._model.options.minimapCharWidth / this._model.options.pixelRatio));\r\n\t\tthis._sliderHorizontal.setLeft(horizontalSliderLeft);\r\n\t\tthis._sliderHorizontal.setWidth(this._model.options.minimapWidth - horizontalSliderLeft);\r\n\t\tthis._sliderHorizontal.setTop(0);\r\n\t\tthis._sliderHorizontal.setHeight(layout.sliderHeight);\r\n\r\n\t\tthis.renderDecorations(layout);\r\n\t\tthis._lastRenderData = this.renderLines(layout);\r\n\t}\r\n\r\n\tprivate renderDecorations(layout: MinimapLayout) {\r\n\t\tif (this._renderDecorations) {\r\n\t\t\tthis._renderDecorations = false;\r\n\t\t\tconst selections = this._model.getSelections();\r\n\t\t\tconst decorations = this._model.getMinimapDecorationsInViewport(layout.startLineNumber, layout.endLineNumber);\r\n\r\n\t\t\tconst { canvasInnerWidth, canvasInnerHeight } = this._model.options;\r\n\t\t\tconst lineHeight = this._model.options.minimapLineHeight;\r\n\t\t\tconst characterWidth = this._model.options.minimapCharWidth;\r\n\t\t\tconst tabSize = this._model.getOptions().tabSize;\r\n\t\t\tconst canvasContext = this._decorationsCanvas.domNode.getContext('2d')!;\r\n\r\n\t\t\tcanvasContext.clearRect(0, 0, canvasInnerWidth, canvasInnerHeight);\r\n\r\n\t\t\tconst lineOffsetMap = new Map();\r\n\t\t\tfor (let i = 0; i < selections.length; i++) {\r\n\t\t\t\tconst selection = selections[i];\r\n\r\n\t\t\t\tfor (let line = selection.startLineNumber; line <= selection.endLineNumber; line++) {\r\n\t\t\t\t\tthis.renderDecorationOnLine(canvasContext, lineOffsetMap, selection, this._selectionColor, layout, line, lineHeight, lineHeight, tabSize, characterWidth);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// Loop over decorations, ignoring those that don't have the minimap property set and rendering rectangles for each line the decoration spans\r\n\t\t\tfor (let i = 0; i < decorations.length; i++) {\r\n\t\t\t\tconst decoration = decorations[i];\r\n\r\n\t\t\t\tif (!decoration.options.minimap) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst decorationColor = (decoration.options.minimap).getColor(this._theme);\r\n\t\t\t\tfor (let line = decoration.range.startLineNumber; line <= decoration.range.endLineNumber; line++) {\r\n\t\t\t\t\tswitch (decoration.options.minimap.position) {\r\n\r\n\t\t\t\t\t\tcase MinimapPosition.Inline:\r\n\t\t\t\t\t\t\tthis.renderDecorationOnLine(canvasContext, lineOffsetMap, decoration.range, decorationColor, layout, line, lineHeight, lineHeight, tabSize, characterWidth);\r\n\t\t\t\t\t\t\tcontinue;\r\n\r\n\t\t\t\t\t\tcase MinimapPosition.Gutter:\r\n\t\t\t\t\t\t\tconst y = (line - layout.startLineNumber) * lineHeight;\r\n\t\t\t\t\t\t\tconst x = 2;\r\n\t\t\t\t\t\t\tthis.renderDecoration(canvasContext, decorationColor, x, y, GUTTER_DECORATION_WIDTH, lineHeight);\r\n\t\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate renderDecorationOnLine(canvasContext: CanvasRenderingContext2D,\r\n\t\tlineOffsetMap: Map,\r\n\t\tdecorationRange: Range,\r\n\t\tdecorationColor: Color | undefined,\r\n\t\tlayout: MinimapLayout,\r\n\t\tlineNumber: number,\r\n\t\theight: number,\r\n\t\tlineHeight: number,\r\n\t\ttabSize: number,\r\n\t\tcharWidth: number): void {\r\n\t\tconst y = (lineNumber - layout.startLineNumber) * lineHeight;\r\n\r\n\t\t// Skip rendering the line if it's vertically outside our viewport\r\n\t\tif (y + height < 0 || y > this._model.options.canvasInnerHeight) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// Cache line offset data so that it is only read once per line\r\n\t\tlet lineIndexToXOffset = lineOffsetMap.get(lineNumber);\r\n\t\tconst isFirstDecorationForLine = !lineIndexToXOffset;\r\n\t\tif (!lineIndexToXOffset) {\r\n\t\t\tconst lineData = this._model.getLineContent(lineNumber);\r\n\t\t\tlineIndexToXOffset = [MINIMAP_GUTTER_WIDTH];\r\n\t\t\tfor (let i = 1; i < lineData.length + 1; i++) {\r\n\t\t\t\tconst charCode = lineData.charCodeAt(i - 1);\r\n\t\t\t\tconst dx = charCode === CharCode.Tab\r\n\t\t\t\t\t? tabSize * charWidth\r\n\t\t\t\t\t: strings.isFullWidthCharacter(charCode)\r\n\t\t\t\t\t\t? 2 * charWidth\r\n\t\t\t\t\t\t: charWidth;\r\n\r\n\t\t\t\tlineIndexToXOffset[i] = lineIndexToXOffset[i - 1] + dx;\r\n\t\t\t}\r\n\r\n\t\t\tlineOffsetMap.set(lineNumber, lineIndexToXOffset);\r\n\t\t}\r\n\r\n\t\tconst { startColumn, endColumn, startLineNumber, endLineNumber } = decorationRange;\r\n\t\tconst x = startLineNumber === lineNumber ? lineIndexToXOffset[startColumn - 1] : MINIMAP_GUTTER_WIDTH;\r\n\r\n\t\tconst endColumnForLine = endLineNumber > lineNumber ? lineIndexToXOffset.length - 1 : endColumn - 1;\r\n\r\n\t\tif (endColumnForLine > 0) {\r\n\t\t\t// If the decoration starts at the last character of the column and spans over it, ensure it has a width\r\n\t\t\tconst width = lineIndexToXOffset[endColumnForLine] - x || 2;\r\n\r\n\t\t\tthis.renderDecoration(canvasContext, decorationColor, x, y, width, height);\r\n\t\t}\r\n\r\n\t\tif (isFirstDecorationForLine) {\r\n\t\t\tthis.renderLineHighlight(canvasContext, decorationColor, y, height);\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tprivate renderLineHighlight(canvasContext: CanvasRenderingContext2D, decorationColor: Color | undefined, y: number, height: number): void {\r\n\t\tcanvasContext.fillStyle = decorationColor && decorationColor.transparent(0.5).toString() || '';\r\n\t\tcanvasContext.fillRect(MINIMAP_GUTTER_WIDTH, y, canvasContext.canvas.width, height);\r\n\t}\r\n\r\n\tprivate renderDecoration(canvasContext: CanvasRenderingContext2D, decorationColor: Color | undefined, x: number, y: number, width: number, height: number) {\r\n\t\tcanvasContext.fillStyle = decorationColor && decorationColor.toString() || '';\r\n\t\tcanvasContext.fillRect(x, y, width, height);\r\n\t}\r\n\r\n\tprivate renderLines(layout: MinimapLayout): RenderData | null {\r\n\t\tconst startLineNumber = layout.startLineNumber;\r\n\t\tconst endLineNumber = layout.endLineNumber;\r\n\t\tconst minimapLineHeight = this._model.options.minimapLineHeight;\r\n\r\n\t\t// Check if nothing changed w.r.t. lines from last frame\r\n\t\tif (this._lastRenderData && this._lastRenderData.linesEquals(layout)) {\r\n\t\t\tconst _lastData = this._lastRenderData._get();\r\n\t\t\t// Nice!! Nothing changed from last frame\r\n\t\t\treturn new RenderData(layout, _lastData.imageData, _lastData.lines);\r\n\t\t}\r\n\r\n\t\t// Oh well!! We need to repaint some lines...\r\n\r\n\t\tconst imageData = this._getBuffer();\r\n\t\tif (!imageData) {\r\n\t\t\t// 0 width or 0 height canvas, nothing to do\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\t// Render untouched lines by using last rendered data.\r\n\t\tlet [_dirtyY1, _dirtyY2, needed] = InnerMinimap._renderUntouchedLines(\r\n\t\t\timageData,\r\n\t\t\tstartLineNumber,\r\n\t\t\tendLineNumber,\r\n\t\t\tminimapLineHeight,\r\n\t\t\tthis._lastRenderData\r\n\t\t);\r\n\r\n\t\t// Fetch rendering info from view model for rest of lines that need rendering.\r\n\t\tconst lineInfo = this._model.getMinimapLinesRenderingData(startLineNumber, endLineNumber, needed);\r\n\t\tconst tabSize = this._model.getOptions().tabSize;\r\n\t\tconst background = this._model.options.backgroundColor;\r\n\t\tconst tokensColorTracker = this._model.tokensColorTracker;\r\n\t\tconst useLighterFont = tokensColorTracker.backgroundIsLight();\r\n\t\tconst renderMinimap = this._model.options.renderMinimap;\r\n\t\tconst charRenderer = this._model.options.charRenderer();\r\n\t\tconst fontScale = this._model.options.fontScale;\r\n\t\tconst minimapCharWidth = this._model.options.minimapCharWidth;\r\n\r\n\t\tconst baseCharHeight = (renderMinimap === RenderMinimap.Text ? Constants.BASE_CHAR_HEIGHT : Constants.BASE_CHAR_HEIGHT + 1);\r\n\t\tconst renderMinimapLineHeight = baseCharHeight * fontScale;\r\n\t\tconst innerLinePadding = (minimapLineHeight > renderMinimapLineHeight ? Math.floor((minimapLineHeight - renderMinimapLineHeight) / 2) : 0);\r\n\r\n\t\t// Render the rest of lines\r\n\t\tlet dy = 0;\r\n\t\tconst renderedLines: MinimapLine[] = [];\r\n\t\tfor (let lineIndex = 0, lineCount = endLineNumber - startLineNumber + 1; lineIndex < lineCount; lineIndex++) {\r\n\t\t\tif (needed[lineIndex]) {\r\n\t\t\t\tInnerMinimap._renderLine(\r\n\t\t\t\t\timageData,\r\n\t\t\t\t\tbackground,\r\n\t\t\t\t\tuseLighterFont,\r\n\t\t\t\t\trenderMinimap,\r\n\t\t\t\t\tminimapCharWidth,\r\n\t\t\t\t\ttokensColorTracker,\r\n\t\t\t\t\tcharRenderer,\r\n\t\t\t\t\tdy,\r\n\t\t\t\t\tinnerLinePadding,\r\n\t\t\t\t\ttabSize,\r\n\t\t\t\t\tlineInfo[lineIndex]!,\r\n\t\t\t\t\tfontScale,\r\n\t\t\t\t\tminimapLineHeight\r\n\t\t\t\t);\r\n\t\t\t}\r\n\t\t\trenderedLines[lineIndex] = new MinimapLine(dy);\r\n\t\t\tdy += minimapLineHeight;\r\n\t\t}\r\n\r\n\t\tconst dirtyY1 = (_dirtyY1 === -1 ? 0 : _dirtyY1);\r\n\t\tconst dirtyY2 = (_dirtyY2 === -1 ? imageData.height : _dirtyY2);\r\n\t\tconst dirtyHeight = dirtyY2 - dirtyY1;\r\n\r\n\t\t// Finally, paint to the canvas\r\n\t\tconst ctx = this._canvas.domNode.getContext('2d')!;\r\n\t\tctx.putImageData(imageData, 0, 0, 0, dirtyY1, imageData.width, dirtyHeight);\r\n\r\n\t\t// Save rendered data for reuse on next frame if possible\r\n\t\treturn new RenderData(\r\n\t\t\tlayout,\r\n\t\t\timageData,\r\n\t\t\trenderedLines\r\n\t\t);\r\n\t}\r\n\r\n\tprivate static _renderUntouchedLines(\r\n\t\ttarget: ImageData,\r\n\t\tstartLineNumber: number,\r\n\t\tendLineNumber: number,\r\n\t\tminimapLineHeight: number,\r\n\t\tlastRenderData: RenderData | null,\r\n\t): [number, number, boolean[]] {\r\n\r\n\t\tconst needed: boolean[] = [];\r\n\t\tif (!lastRenderData) {\r\n\t\t\tfor (let i = 0, len = endLineNumber - startLineNumber + 1; i < len; i++) {\r\n\t\t\t\tneeded[i] = true;\r\n\t\t\t}\r\n\t\t\treturn [-1, -1, needed];\r\n\t\t}\r\n\r\n\t\tconst _lastData = lastRenderData._get();\r\n\t\tconst lastTargetData = _lastData.imageData.data;\r\n\t\tconst lastStartLineNumber = _lastData.rendLineNumberStart;\r\n\t\tconst lastLines = _lastData.lines;\r\n\t\tconst lastLinesLength = lastLines.length;\r\n\t\tconst WIDTH = target.width;\r\n\t\tconst targetData = target.data;\r\n\r\n\t\tconst maxDestPixel = (endLineNumber - startLineNumber + 1) * minimapLineHeight * WIDTH * 4;\r\n\t\tlet dirtyPixel1 = -1; // the pixel offset up to which all the data is equal to the prev frame\r\n\t\tlet dirtyPixel2 = -1; // the pixel offset after which all the data is equal to the prev frame\r\n\r\n\t\tlet copySourceStart = -1;\r\n\t\tlet copySourceEnd = -1;\r\n\t\tlet copyDestStart = -1;\r\n\t\tlet copyDestEnd = -1;\r\n\r\n\t\tlet dest_dy = 0;\r\n\t\tfor (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {\r\n\t\t\tconst lineIndex = lineNumber - startLineNumber;\r\n\t\t\tconst lastLineIndex = lineNumber - lastStartLineNumber;\r\n\t\t\tconst source_dy = (lastLineIndex >= 0 && lastLineIndex < lastLinesLength ? lastLines[lastLineIndex].dy : -1);\r\n\r\n\t\t\tif (source_dy === -1) {\r\n\t\t\t\tneeded[lineIndex] = true;\r\n\t\t\t\tdest_dy += minimapLineHeight;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tconst sourceStart = source_dy * WIDTH * 4;\r\n\t\t\tconst sourceEnd = (source_dy + minimapLineHeight) * WIDTH * 4;\r\n\t\t\tconst destStart = dest_dy * WIDTH * 4;\r\n\t\t\tconst destEnd = (dest_dy + minimapLineHeight) * WIDTH * 4;\r\n\r\n\t\t\tif (copySourceEnd === sourceStart && copyDestEnd === destStart) {\r\n\t\t\t\t// contiguous zone => extend copy request\r\n\t\t\t\tcopySourceEnd = sourceEnd;\r\n\t\t\t\tcopyDestEnd = destEnd;\r\n\t\t\t} else {\r\n\t\t\t\tif (copySourceStart !== -1) {\r\n\t\t\t\t\t// flush existing copy request\r\n\t\t\t\t\ttargetData.set(lastTargetData.subarray(copySourceStart, copySourceEnd), copyDestStart);\r\n\t\t\t\t\tif (dirtyPixel1 === -1 && copySourceStart === 0 && copySourceStart === copyDestStart) {\r\n\t\t\t\t\t\tdirtyPixel1 = copySourceEnd;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (dirtyPixel2 === -1 && copySourceEnd === maxDestPixel && copySourceStart === copyDestStart) {\r\n\t\t\t\t\t\tdirtyPixel2 = copySourceStart;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tcopySourceStart = sourceStart;\r\n\t\t\t\tcopySourceEnd = sourceEnd;\r\n\t\t\t\tcopyDestStart = destStart;\r\n\t\t\t\tcopyDestEnd = destEnd;\r\n\t\t\t}\r\n\r\n\t\t\tneeded[lineIndex] = false;\r\n\t\t\tdest_dy += minimapLineHeight;\r\n\t\t}\r\n\r\n\t\tif (copySourceStart !== -1) {\r\n\t\t\t// flush existing copy request\r\n\t\t\ttargetData.set(lastTargetData.subarray(copySourceStart, copySourceEnd), copyDestStart);\r\n\t\t\tif (dirtyPixel1 === -1 && copySourceStart === 0 && copySourceStart === copyDestStart) {\r\n\t\t\t\tdirtyPixel1 = copySourceEnd;\r\n\t\t\t}\r\n\t\t\tif (dirtyPixel2 === -1 && copySourceEnd === maxDestPixel && copySourceStart === copyDestStart) {\r\n\t\t\t\tdirtyPixel2 = copySourceStart;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst dirtyY1 = (dirtyPixel1 === -1 ? -1 : dirtyPixel1 / (WIDTH * 4));\r\n\t\tconst dirtyY2 = (dirtyPixel2 === -1 ? -1 : dirtyPixel2 / (WIDTH * 4));\r\n\r\n\t\treturn [dirtyY1, dirtyY2, needed];\r\n\t}\r\n\r\n\tprivate static _renderLine(\r\n\t\ttarget: ImageData,\r\n\t\tbackgroundColor: RGBA8,\r\n\t\tuseLighterFont: boolean,\r\n\t\trenderMinimap: RenderMinimap,\r\n\t\tcharWidth: number,\r\n\t\tcolorTracker: MinimapTokensColorTracker,\r\n\t\tminimapCharRenderer: MinimapCharRenderer,\r\n\t\tdy: number,\r\n\t\tinnerLinePadding: number,\r\n\t\ttabSize: number,\r\n\t\tlineData: ViewLineData,\r\n\t\tfontScale: number,\r\n\t\tminimapLineHeight: number\r\n\t): void {\r\n\t\tconst content = lineData.content;\r\n\t\tconst tokens = lineData.tokens;\r\n\t\tconst maxDx = target.width - charWidth;\r\n\t\tconst force1pxHeight = (minimapLineHeight === 1);\r\n\r\n\t\tlet dx = MINIMAP_GUTTER_WIDTH;\r\n\t\tlet charIndex = 0;\r\n\t\tlet tabsCharDelta = 0;\r\n\r\n\t\tfor (let tokenIndex = 0, tokensLen = tokens.getCount(); tokenIndex < tokensLen; tokenIndex++) {\r\n\t\t\tconst tokenEndIndex = tokens.getEndOffset(tokenIndex);\r\n\t\t\tconst tokenColorId = tokens.getForeground(tokenIndex);\r\n\t\t\tconst tokenColor = colorTracker.getColor(tokenColorId);\r\n\r\n\t\t\tfor (; charIndex < tokenEndIndex; charIndex++) {\r\n\t\t\t\tif (dx > maxDx) {\r\n\t\t\t\t\t// hit edge of minimap\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\tconst charCode = content.charCodeAt(charIndex);\r\n\r\n\t\t\t\tif (charCode === CharCode.Tab) {\r\n\t\t\t\t\tconst insertSpacesCount = tabSize - (charIndex + tabsCharDelta) % tabSize;\r\n\t\t\t\t\ttabsCharDelta += insertSpacesCount - 1;\r\n\t\t\t\t\t// No need to render anything since tab is invisible\r\n\t\t\t\t\tdx += insertSpacesCount * charWidth;\r\n\t\t\t\t} else if (charCode === CharCode.Space) {\r\n\t\t\t\t\t// No need to render anything since space is invisible\r\n\t\t\t\t\tdx += charWidth;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// Render twice for a full width character\r\n\t\t\t\t\tconst count = strings.isFullWidthCharacter(charCode) ? 2 : 1;\r\n\r\n\t\t\t\t\tfor (let i = 0; i < count; i++) {\r\n\t\t\t\t\t\tif (renderMinimap === RenderMinimap.Blocks) {\r\n\t\t\t\t\t\t\tminimapCharRenderer.blockRenderChar(target, dx, dy + innerLinePadding, tokenColor, backgroundColor, useLighterFont, force1pxHeight);\r\n\t\t\t\t\t\t} else { // RenderMinimap.Text\r\n\t\t\t\t\t\t\tminimapCharRenderer.renderChar(target, dx, dy + innerLinePadding, charCode, tokenColor, backgroundColor, fontScale, useLighterFont, force1pxHeight);\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tdx += charWidth;\r\n\r\n\t\t\t\t\t\tif (dx > maxDx) {\r\n\t\t\t\t\t\t\t// hit edge of minimap\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst minimapBackgroundValue = theme.getColor(minimapBackground);\r\n\tif (minimapBackgroundValue) {\r\n\t\tcollector.addRule(`.monaco-editor .minimap > canvas { opacity: ${minimapBackgroundValue.rgba.a}; will-change: opacity; }`);\r\n\t}\r\n\tconst sliderBackground = theme.getColor(minimapSliderBackground);\r\n\tif (sliderBackground) {\r\n\t\tcollector.addRule(`.monaco-editor .minimap-slider .minimap-slider-horizontal { background: ${sliderBackground}; }`);\r\n\t}\r\n\tconst sliderHoverBackground = theme.getColor(minimapSliderHoverBackground);\r\n\tif (sliderHoverBackground) {\r\n\t\tcollector.addRule(`.monaco-editor .minimap-slider:hover .minimap-slider-horizontal { background: ${sliderHoverBackground}; }`);\r\n\t}\r\n\tconst sliderActiveBackground = theme.getColor(minimapSliderActiveBackground);\r\n\tif (sliderActiveBackground) {\r\n\t\tcollector.addRule(`.monaco-editor .minimap-slider.active .minimap-slider-horizontal { background: ${sliderActiveBackground}; }`);\r\n\t}\r\n\tconst shadow = theme.getColor(scrollbarShadow);\r\n\tif (shadow) {\r\n\t\tcollector.addRule(`.monaco-editor .minimap-shadow-visible { box-shadow: ${shadow} -6px 0 6px -6px inset; }`);\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./scrollDecoration';\r\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { ViewPart } from 'vs/editor/browser/view/viewPart';\r\nimport { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { scrollbarShadow } from 'vs/platform/theme/common/colorRegistry';\r\nimport { registerThemingParticipant } from 'vs/platform/theme/common/themeService';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\n\r\nexport class ScrollDecorationViewPart extends ViewPart {\r\n\r\n\tprivate readonly _domNode: FastDomNode;\r\n\tprivate _scrollTop: number;\r\n\tprivate _width: number;\r\n\tprivate _shouldShow: boolean;\r\n\tprivate _useShadows: boolean;\r\n\r\n\tconstructor(context: ViewContext) {\r\n\t\tsuper(context);\r\n\r\n\t\tthis._scrollTop = 0;\r\n\t\tthis._width = 0;\r\n\t\tthis._updateWidth();\r\n\t\tthis._shouldShow = false;\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst scrollbar = options.get(EditorOption.scrollbar);\r\n\t\tthis._useShadows = scrollbar.useShadows;\r\n\t\tthis._domNode = createFastDomNode(document.createElement('div'));\r\n\t\tthis._domNode.setAttribute('role', 'presentation');\r\n\t\tthis._domNode.setAttribute('aria-hidden', 'true');\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tprivate _updateShouldShow(): boolean {\r\n\t\tconst newShouldShow = (this._useShadows && this._scrollTop > 0);\r\n\t\tif (this._shouldShow !== newShouldShow) {\r\n\t\t\tthis._shouldShow = newShouldShow;\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic getDomNode(): FastDomNode {\r\n\t\treturn this._domNode;\r\n\t}\r\n\r\n\tprivate _updateWidth(): void {\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\r\n\t\tif (layoutInfo.minimap.renderMinimap === 0 || (layoutInfo.minimap.minimapWidth > 0 && layoutInfo.minimap.minimapLeft === 0)) {\r\n\t\t\tthis._width = layoutInfo.width;\r\n\t\t} else {\r\n\t\t\tthis._width = layoutInfo.width - layoutInfo.minimap.minimapWidth - layoutInfo.verticalScrollbarWidth;\r\n\t\t}\r\n\t}\r\n\r\n\t// --- begin event handlers\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst scrollbar = options.get(EditorOption.scrollbar);\r\n\t\tthis._useShadows = scrollbar.useShadows;\r\n\t\tthis._updateWidth();\r\n\t\tthis._updateShouldShow();\r\n\t\treturn true;\r\n\t}\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\tthis._scrollTop = e.scrollTop;\r\n\t\treturn this._updateShouldShow();\r\n\t}\r\n\r\n\t// --- end event handlers\r\n\r\n\tpublic prepareRender(ctx: RenderingContext): void {\r\n\t\t// Nothing to read\r\n\t}\r\n\r\n\tpublic render(ctx: RestrictedRenderingContext): void {\r\n\t\tthis._domNode.setWidth(this._width);\r\n\t\tthis._domNode.setClassName(this._shouldShow ? 'scroll-decoration' : '');\r\n\t}\r\n}\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst shadow = theme.getColor(scrollbarShadow);\r\n\tif (shadow) {\r\n\t\tcollector.addRule(`.monaco-editor .scroll-decoration { box-shadow: ${shadow} 0 6px 6px -6px inset; }`);\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./selections';\r\nimport * as browser from 'vs/base/browser/browser';\r\nimport { DynamicViewOverlay } from 'vs/editor/browser/view/dynamicViewOverlay';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { HorizontalRange, LineVisibleRanges, RenderingContext } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { editorInactiveSelection, editorSelectionBackground, editorSelectionForeground } from 'vs/platform/theme/common/colorRegistry';\r\nimport { registerThemingParticipant } from 'vs/platform/theme/common/themeService';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\nconst enum CornerStyle {\r\n\tEXTERN,\r\n\tINTERN,\r\n\tFLAT\r\n}\r\n\r\ninterface IVisibleRangeEndPointStyle {\r\n\ttop: CornerStyle;\r\n\tbottom: CornerStyle;\r\n}\r\n\r\nclass HorizontalRangeWithStyle {\r\n\tpublic left: number;\r\n\tpublic width: number;\r\n\tpublic startStyle: IVisibleRangeEndPointStyle | null;\r\n\tpublic endStyle: IVisibleRangeEndPointStyle | null;\r\n\r\n\tconstructor(other: HorizontalRange) {\r\n\t\tthis.left = other.left;\r\n\t\tthis.width = other.width;\r\n\t\tthis.startStyle = null;\r\n\t\tthis.endStyle = null;\r\n\t}\r\n}\r\n\r\nclass LineVisibleRangesWithStyle {\r\n\tpublic lineNumber: number;\r\n\tpublic ranges: HorizontalRangeWithStyle[];\r\n\r\n\tconstructor(lineNumber: number, ranges: HorizontalRangeWithStyle[]) {\r\n\t\tthis.lineNumber = lineNumber;\r\n\t\tthis.ranges = ranges;\r\n\t}\r\n}\r\n\r\nfunction toStyledRange(item: HorizontalRange): HorizontalRangeWithStyle {\r\n\treturn new HorizontalRangeWithStyle(item);\r\n}\r\n\r\nfunction toStyled(item: LineVisibleRanges): LineVisibleRangesWithStyle {\r\n\treturn new LineVisibleRangesWithStyle(item.lineNumber, item.ranges.map(toStyledRange));\r\n}\r\n\r\n// TODO@Alex: Remove this once IE11 fixes Bug #524217\r\n// The problem in IE11 is that it does some sort of auto-zooming to accomodate for displays with different pixel density.\r\n// Unfortunately, this auto-zooming is buggy around dealing with rounded borders\r\nconst isIEWithZoomingIssuesNearRoundedBorders = browser.isEdgeLegacy;\r\n\r\n\r\nexport class SelectionsOverlay extends DynamicViewOverlay {\r\n\r\n\tprivate static readonly SELECTION_CLASS_NAME = 'selected-text';\r\n\tprivate static readonly SELECTION_TOP_LEFT = 'top-left-radius';\r\n\tprivate static readonly SELECTION_BOTTOM_LEFT = 'bottom-left-radius';\r\n\tprivate static readonly SELECTION_TOP_RIGHT = 'top-right-radius';\r\n\tprivate static readonly SELECTION_BOTTOM_RIGHT = 'bottom-right-radius';\r\n\tprivate static readonly EDITOR_BACKGROUND_CLASS_NAME = 'monaco-editor-background';\r\n\r\n\tprivate static readonly ROUNDED_PIECE_WIDTH = 10;\r\n\r\n\tprivate readonly _context: ViewContext;\r\n\tprivate _lineHeight: number;\r\n\tprivate _roundedSelection: boolean;\r\n\tprivate _typicalHalfwidthCharacterWidth: number;\r\n\tprivate _selections: Range[];\r\n\tprivate _renderResult: string[] | null;\r\n\r\n\tconstructor(context: ViewContext) {\r\n\t\tsuper();\r\n\t\tthis._context = context;\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tthis._roundedSelection = options.get(EditorOption.roundedSelection);\r\n\t\tthis._typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth;\r\n\t\tthis._selections = [];\r\n\t\tthis._renderResult = null;\r\n\t\tthis._context.addEventHandler(this);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._context.removeEventHandler(this);\r\n\t\tthis._renderResult = null;\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\t// --- begin event handlers\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tthis._roundedSelection = options.get(EditorOption.roundedSelection);\r\n\t\tthis._typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth;\r\n\t\treturn true;\r\n\t}\r\n\tpublic onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {\r\n\t\tthis._selections = e.selections.slice(0);\r\n\t\treturn true;\r\n\t}\r\n\tpublic onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {\r\n\t\t// true for inline decorations that can end up relayouting text\r\n\t\treturn true;//e.inlineDecorationsChanged;\r\n\t}\r\n\tpublic onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\treturn e.scrollTopChanged;\r\n\t}\r\n\tpublic onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// --- end event handlers\r\n\r\n\tprivate _visibleRangesHaveGaps(linesVisibleRanges: LineVisibleRangesWithStyle[]): boolean {\r\n\r\n\t\tfor (let i = 0, len = linesVisibleRanges.length; i < len; i++) {\r\n\t\t\tconst lineVisibleRanges = linesVisibleRanges[i];\r\n\r\n\t\t\tif (lineVisibleRanges.ranges.length > 1) {\r\n\t\t\t\t// There are two ranges on the same line\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\t}\r\n\r\n\tprivate _enrichVisibleRangesWithStyle(viewport: Range, linesVisibleRanges: LineVisibleRangesWithStyle[], previousFrame: LineVisibleRangesWithStyle[] | null): void {\r\n\t\tconst epsilon = this._typicalHalfwidthCharacterWidth / 4;\r\n\t\tlet previousFrameTop: HorizontalRangeWithStyle | null = null;\r\n\t\tlet previousFrameBottom: HorizontalRangeWithStyle | null = null;\r\n\r\n\t\tif (previousFrame && previousFrame.length > 0 && linesVisibleRanges.length > 0) {\r\n\r\n\t\t\tconst topLineNumber = linesVisibleRanges[0].lineNumber;\r\n\t\t\tif (topLineNumber === viewport.startLineNumber) {\r\n\t\t\t\tfor (let i = 0; !previousFrameTop && i < previousFrame.length; i++) {\r\n\t\t\t\t\tif (previousFrame[i].lineNumber === topLineNumber) {\r\n\t\t\t\t\t\tpreviousFrameTop = previousFrame[i].ranges[0];\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tconst bottomLineNumber = linesVisibleRanges[linesVisibleRanges.length - 1].lineNumber;\r\n\t\t\tif (bottomLineNumber === viewport.endLineNumber) {\r\n\t\t\t\tfor (let i = previousFrame.length - 1; !previousFrameBottom && i >= 0; i--) {\r\n\t\t\t\t\tif (previousFrame[i].lineNumber === bottomLineNumber) {\r\n\t\t\t\t\t\tpreviousFrameBottom = previousFrame[i].ranges[0];\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (previousFrameTop && !previousFrameTop.startStyle) {\r\n\t\t\t\tpreviousFrameTop = null;\r\n\t\t\t}\r\n\t\t\tif (previousFrameBottom && !previousFrameBottom.startStyle) {\r\n\t\t\t\tpreviousFrameBottom = null;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tfor (let i = 0, len = linesVisibleRanges.length; i < len; i++) {\r\n\t\t\t// We know for a fact that there is precisely one range on each line\r\n\t\t\tconst curLineRange = linesVisibleRanges[i].ranges[0];\r\n\t\t\tconst curLeft = curLineRange.left;\r\n\t\t\tconst curRight = curLineRange.left + curLineRange.width;\r\n\r\n\t\t\tconst startStyle = {\r\n\t\t\t\ttop: CornerStyle.EXTERN,\r\n\t\t\t\tbottom: CornerStyle.EXTERN\r\n\t\t\t};\r\n\r\n\t\t\tconst endStyle = {\r\n\t\t\t\ttop: CornerStyle.EXTERN,\r\n\t\t\t\tbottom: CornerStyle.EXTERN\r\n\t\t\t};\r\n\r\n\t\t\tif (i > 0) {\r\n\t\t\t\t// Look above\r\n\t\t\t\tconst prevLeft = linesVisibleRanges[i - 1].ranges[0].left;\r\n\t\t\t\tconst prevRight = linesVisibleRanges[i - 1].ranges[0].left + linesVisibleRanges[i - 1].ranges[0].width;\r\n\r\n\t\t\t\tif (abs(curLeft - prevLeft) < epsilon) {\r\n\t\t\t\t\tstartStyle.top = CornerStyle.FLAT;\r\n\t\t\t\t} else if (curLeft > prevLeft) {\r\n\t\t\t\t\tstartStyle.top = CornerStyle.INTERN;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (abs(curRight - prevRight) < epsilon) {\r\n\t\t\t\t\tendStyle.top = CornerStyle.FLAT;\r\n\t\t\t\t} else if (prevLeft < curRight && curRight < prevRight) {\r\n\t\t\t\t\tendStyle.top = CornerStyle.INTERN;\r\n\t\t\t\t}\r\n\t\t\t} else if (previousFrameTop) {\r\n\t\t\t\t// Accept some hiccups near the viewport edges to save on repaints\r\n\t\t\t\tstartStyle.top = previousFrameTop.startStyle!.top;\r\n\t\t\t\tendStyle.top = previousFrameTop.endStyle!.top;\r\n\t\t\t}\r\n\r\n\t\t\tif (i + 1 < len) {\r\n\t\t\t\t// Look below\r\n\t\t\t\tconst nextLeft = linesVisibleRanges[i + 1].ranges[0].left;\r\n\t\t\t\tconst nextRight = linesVisibleRanges[i + 1].ranges[0].left + linesVisibleRanges[i + 1].ranges[0].width;\r\n\r\n\t\t\t\tif (abs(curLeft - nextLeft) < epsilon) {\r\n\t\t\t\t\tstartStyle.bottom = CornerStyle.FLAT;\r\n\t\t\t\t} else if (nextLeft < curLeft && curLeft < nextRight) {\r\n\t\t\t\t\tstartStyle.bottom = CornerStyle.INTERN;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (abs(curRight - nextRight) < epsilon) {\r\n\t\t\t\t\tendStyle.bottom = CornerStyle.FLAT;\r\n\t\t\t\t} else if (curRight < nextRight) {\r\n\t\t\t\t\tendStyle.bottom = CornerStyle.INTERN;\r\n\t\t\t\t}\r\n\t\t\t} else if (previousFrameBottom) {\r\n\t\t\t\t// Accept some hiccups near the viewport edges to save on repaints\r\n\t\t\t\tstartStyle.bottom = previousFrameBottom.startStyle!.bottom;\r\n\t\t\t\tendStyle.bottom = previousFrameBottom.endStyle!.bottom;\r\n\t\t\t}\r\n\r\n\t\t\tcurLineRange.startStyle = startStyle;\r\n\t\t\tcurLineRange.endStyle = endStyle;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _getVisibleRangesWithStyle(selection: Range, ctx: RenderingContext, previousFrame: LineVisibleRangesWithStyle[] | null): LineVisibleRangesWithStyle[] {\r\n\t\tconst _linesVisibleRanges = ctx.linesVisibleRangesForRange(selection, true) || [];\r\n\t\tconst linesVisibleRanges = _linesVisibleRanges.map(toStyled);\r\n\t\tconst visibleRangesHaveGaps = this._visibleRangesHaveGaps(linesVisibleRanges);\r\n\r\n\t\tif (!isIEWithZoomingIssuesNearRoundedBorders && !visibleRangesHaveGaps && this._roundedSelection) {\r\n\t\t\tthis._enrichVisibleRangesWithStyle(ctx.visibleRange, linesVisibleRanges, previousFrame);\r\n\t\t}\r\n\r\n\t\t// The visible ranges are sorted TOP-BOTTOM and LEFT-RIGHT\r\n\t\treturn linesVisibleRanges;\r\n\t}\r\n\r\n\tprivate _createSelectionPiece(top: number, height: string, className: string, left: number, width: number): string {\r\n\t\treturn (\r\n\t\t\t'
    '\r\n\t\t);\r\n\t}\r\n\r\n\tprivate _actualRenderOneSelection(output2: [string, string][], visibleStartLineNumber: number, hasMultipleSelections: boolean, visibleRanges: LineVisibleRangesWithStyle[]): void {\r\n\t\tif (visibleRanges.length === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst visibleRangesHaveStyle = !!visibleRanges[0].ranges[0].startStyle;\r\n\t\tconst fullLineHeight = (this._lineHeight).toString();\r\n\t\tconst reducedLineHeight = (this._lineHeight - 1).toString();\r\n\r\n\t\tconst firstLineNumber = visibleRanges[0].lineNumber;\r\n\t\tconst lastLineNumber = visibleRanges[visibleRanges.length - 1].lineNumber;\r\n\r\n\t\tfor (let i = 0, len = visibleRanges.length; i < len; i++) {\r\n\t\t\tconst lineVisibleRanges = visibleRanges[i];\r\n\t\t\tconst lineNumber = lineVisibleRanges.lineNumber;\r\n\t\t\tconst lineIndex = lineNumber - visibleStartLineNumber;\r\n\r\n\t\t\tconst lineHeight = hasMultipleSelections ? (lineNumber === lastLineNumber || lineNumber === firstLineNumber ? reducedLineHeight : fullLineHeight) : fullLineHeight;\r\n\t\t\tconst top = hasMultipleSelections ? (lineNumber === firstLineNumber ? 1 : 0) : 0;\r\n\r\n\t\t\tlet innerCornerOutput = '';\r\n\t\t\tlet restOfSelectionOutput = '';\r\n\r\n\t\t\tfor (let j = 0, lenJ = lineVisibleRanges.ranges.length; j < lenJ; j++) {\r\n\t\t\t\tconst visibleRange = lineVisibleRanges.ranges[j];\r\n\r\n\t\t\t\tif (visibleRangesHaveStyle) {\r\n\t\t\t\t\tconst startStyle = visibleRange.startStyle!;\r\n\t\t\t\t\tconst endStyle = visibleRange.endStyle!;\r\n\t\t\t\t\tif (startStyle.top === CornerStyle.INTERN || startStyle.bottom === CornerStyle.INTERN) {\r\n\t\t\t\t\t\t// Reverse rounded corner to the left\r\n\r\n\t\t\t\t\t\t// First comes the selection (blue layer)\r\n\t\t\t\t\t\tinnerCornerOutput += this._createSelectionPiece(top, lineHeight, SelectionsOverlay.SELECTION_CLASS_NAME, visibleRange.left - SelectionsOverlay.ROUNDED_PIECE_WIDTH, SelectionsOverlay.ROUNDED_PIECE_WIDTH);\r\n\r\n\t\t\t\t\t\t// Second comes the background (white layer) with inverse border radius\r\n\t\t\t\t\t\tlet className = SelectionsOverlay.EDITOR_BACKGROUND_CLASS_NAME;\r\n\t\t\t\t\t\tif (startStyle.top === CornerStyle.INTERN) {\r\n\t\t\t\t\t\t\tclassName += ' ' + SelectionsOverlay.SELECTION_TOP_RIGHT;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (startStyle.bottom === CornerStyle.INTERN) {\r\n\t\t\t\t\t\t\tclassName += ' ' + SelectionsOverlay.SELECTION_BOTTOM_RIGHT;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tinnerCornerOutput += this._createSelectionPiece(top, lineHeight, className, visibleRange.left - SelectionsOverlay.ROUNDED_PIECE_WIDTH, SelectionsOverlay.ROUNDED_PIECE_WIDTH);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (endStyle.top === CornerStyle.INTERN || endStyle.bottom === CornerStyle.INTERN) {\r\n\t\t\t\t\t\t// Reverse rounded corner to the right\r\n\r\n\t\t\t\t\t\t// First comes the selection (blue layer)\r\n\t\t\t\t\t\tinnerCornerOutput += this._createSelectionPiece(top, lineHeight, SelectionsOverlay.SELECTION_CLASS_NAME, visibleRange.left + visibleRange.width, SelectionsOverlay.ROUNDED_PIECE_WIDTH);\r\n\r\n\t\t\t\t\t\t// Second comes the background (white layer) with inverse border radius\r\n\t\t\t\t\t\tlet className = SelectionsOverlay.EDITOR_BACKGROUND_CLASS_NAME;\r\n\t\t\t\t\t\tif (endStyle.top === CornerStyle.INTERN) {\r\n\t\t\t\t\t\t\tclassName += ' ' + SelectionsOverlay.SELECTION_TOP_LEFT;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (endStyle.bottom === CornerStyle.INTERN) {\r\n\t\t\t\t\t\t\tclassName += ' ' + SelectionsOverlay.SELECTION_BOTTOM_LEFT;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tinnerCornerOutput += this._createSelectionPiece(top, lineHeight, className, visibleRange.left + visibleRange.width, SelectionsOverlay.ROUNDED_PIECE_WIDTH);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tlet className = SelectionsOverlay.SELECTION_CLASS_NAME;\r\n\t\t\t\tif (visibleRangesHaveStyle) {\r\n\t\t\t\t\tconst startStyle = visibleRange.startStyle!;\r\n\t\t\t\t\tconst endStyle = visibleRange.endStyle!;\r\n\t\t\t\t\tif (startStyle.top === CornerStyle.EXTERN) {\r\n\t\t\t\t\t\tclassName += ' ' + SelectionsOverlay.SELECTION_TOP_LEFT;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (startStyle.bottom === CornerStyle.EXTERN) {\r\n\t\t\t\t\t\tclassName += ' ' + SelectionsOverlay.SELECTION_BOTTOM_LEFT;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (endStyle.top === CornerStyle.EXTERN) {\r\n\t\t\t\t\t\tclassName += ' ' + SelectionsOverlay.SELECTION_TOP_RIGHT;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (endStyle.bottom === CornerStyle.EXTERN) {\r\n\t\t\t\t\t\tclassName += ' ' + SelectionsOverlay.SELECTION_BOTTOM_RIGHT;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\trestOfSelectionOutput += this._createSelectionPiece(top, lineHeight, className, visibleRange.left, visibleRange.width);\r\n\t\t\t}\r\n\r\n\t\t\toutput2[lineIndex][0] += innerCornerOutput;\r\n\t\t\toutput2[lineIndex][1] += restOfSelectionOutput;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _previousFrameVisibleRangesWithStyle: (LineVisibleRangesWithStyle[] | null)[] = [];\r\n\tpublic prepareRender(ctx: RenderingContext): void {\r\n\r\n\t\t// Build HTML for inner corners separate from HTML for the rest of selections,\r\n\t\t// as the inner corner HTML can interfere with that of other selections.\r\n\t\t// In final render, make sure to place the inner corner HTML before the rest of selection HTML. See issue #77777.\r\n\t\tconst output: [string, string][] = [];\r\n\t\tconst visibleStartLineNumber = ctx.visibleRange.startLineNumber;\r\n\t\tconst visibleEndLineNumber = ctx.visibleRange.endLineNumber;\r\n\t\tfor (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) {\r\n\t\t\tconst lineIndex = lineNumber - visibleStartLineNumber;\r\n\t\t\toutput[lineIndex] = ['', ''];\r\n\t\t}\r\n\r\n\t\tconst thisFrameVisibleRangesWithStyle: (LineVisibleRangesWithStyle[] | null)[] = [];\r\n\t\tfor (let i = 0, len = this._selections.length; i < len; i++) {\r\n\t\t\tconst selection = this._selections[i];\r\n\t\t\tif (selection.isEmpty()) {\r\n\t\t\t\tthisFrameVisibleRangesWithStyle[i] = null;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tconst visibleRangesWithStyle = this._getVisibleRangesWithStyle(selection, ctx, this._previousFrameVisibleRangesWithStyle[i]);\r\n\t\t\tthisFrameVisibleRangesWithStyle[i] = visibleRangesWithStyle;\r\n\t\t\tthis._actualRenderOneSelection(output, visibleStartLineNumber, this._selections.length > 1, visibleRangesWithStyle);\r\n\t\t}\r\n\r\n\t\tthis._previousFrameVisibleRangesWithStyle = thisFrameVisibleRangesWithStyle;\r\n\t\tthis._renderResult = output.map(([internalCorners, restOfSelection]) => internalCorners + restOfSelection);\r\n\t}\r\n\r\n\tpublic render(startLineNumber: number, lineNumber: number): string {\r\n\t\tif (!this._renderResult) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\tconst lineIndex = lineNumber - startLineNumber;\r\n\t\tif (lineIndex < 0 || lineIndex >= this._renderResult.length) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\treturn this._renderResult[lineIndex];\r\n\t}\r\n}\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst editorSelectionColor = theme.getColor(editorSelectionBackground);\r\n\tif (editorSelectionColor) {\r\n\t\tcollector.addRule(`.monaco-editor .focused .selected-text { background-color: ${editorSelectionColor}; }`);\r\n\t}\r\n\tconst editorInactiveSelectionColor = theme.getColor(editorInactiveSelection);\r\n\tif (editorInactiveSelectionColor) {\r\n\t\tcollector.addRule(`.monaco-editor .selected-text { background-color: ${editorInactiveSelectionColor}; }`);\r\n\t}\r\n\tconst editorSelectionForegroundColor = theme.getColor(editorSelectionForeground);\r\n\tif (editorSelectionForegroundColor && !editorSelectionForegroundColor.isTransparent()) {\r\n\t\tcollector.addRule(`.monaco-editor .view-line span.inline-selected-text { color: ${editorSelectionForegroundColor}; }`);\r\n\t}\r\n});\r\n\r\nfunction abs(n: number): number {\r\n\treturn n < 0 ? -n : n;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { Color, RGBA } from 'vs/base/common/color';\r\nimport { activeContrastBorder, editorBackground, editorForeground, registerColor, editorWarningForeground, editorInfoForeground, editorWarningBorder, editorInfoBorder, contrastBorder, editorFindMatchHighlight } from 'vs/platform/theme/common/colorRegistry';\r\nimport { registerThemingParticipant } from 'vs/platform/theme/common/themeService';\r\n\r\n/**\r\n * Definition of the editor colors\r\n */\r\nexport const editorLineHighlight = registerColor('editor.lineHighlightBackground', { dark: null, light: null, hc: null }, nls.localize('lineHighlight', 'Background color for the highlight of line at the cursor position.'));\r\nexport const editorLineHighlightBorder = registerColor('editor.lineHighlightBorder', { dark: '#282828', light: '#eeeeee', hc: '#f38518' }, nls.localize('lineHighlightBorderBox', 'Background color for the border around the line at the cursor position.'));\r\nexport const editorRangeHighlight = registerColor('editor.rangeHighlightBackground', { dark: '#ffffff0b', light: '#fdff0033', hc: null }, nls.localize('rangeHighlight', 'Background color of highlighted ranges, like by quick open and find features. The color must not be opaque so as not to hide underlying decorations.'), true);\r\nexport const editorRangeHighlightBorder = registerColor('editor.rangeHighlightBorder', { dark: null, light: null, hc: activeContrastBorder }, nls.localize('rangeHighlightBorder', 'Background color of the border around highlighted ranges.'), true);\r\nexport const editorSymbolHighlight = registerColor('editor.symbolHighlightBackground', { dark: editorFindMatchHighlight, light: editorFindMatchHighlight, hc: null }, nls.localize('symbolHighlight', 'Background color of highlighted symbol, like for go to definition or go next/previous symbol. The color must not be opaque so as not to hide underlying decorations.'), true);\r\nexport const editorSymbolHighlightBorder = registerColor('editor.symbolHighlightBorder', { dark: null, light: null, hc: activeContrastBorder }, nls.localize('symbolHighlightBorder', 'Background color of the border around highlighted symbols.'), true);\r\n\r\nexport const editorCursorForeground = registerColor('editorCursor.foreground', { dark: '#AEAFAD', light: Color.black, hc: Color.white }, nls.localize('caret', 'Color of the editor cursor.'));\r\nexport const editorCursorBackground = registerColor('editorCursor.background', null, nls.localize('editorCursorBackground', 'The background color of the editor cursor. Allows customizing the color of a character overlapped by a block cursor.'));\r\nexport const editorWhitespaces = registerColor('editorWhitespace.foreground', { dark: '#e3e4e229', light: '#33333333', hc: '#e3e4e229' }, nls.localize('editorWhitespaces', 'Color of whitespace characters in the editor.'));\r\nexport const editorIndentGuides = registerColor('editorIndentGuide.background', { dark: editorWhitespaces, light: editorWhitespaces, hc: editorWhitespaces }, nls.localize('editorIndentGuides', 'Color of the editor indentation guides.'));\r\nexport const editorActiveIndentGuides = registerColor('editorIndentGuide.activeBackground', { dark: editorWhitespaces, light: editorWhitespaces, hc: editorWhitespaces }, nls.localize('editorActiveIndentGuide', 'Color of the active editor indentation guides.'));\r\nexport const editorLineNumbers = registerColor('editorLineNumber.foreground', { dark: '#858585', light: '#237893', hc: Color.white }, nls.localize('editorLineNumbers', 'Color of editor line numbers.'));\r\n\r\nconst deprecatedEditorActiveLineNumber = registerColor('editorActiveLineNumber.foreground', { dark: '#c6c6c6', light: '#0B216F', hc: activeContrastBorder }, nls.localize('editorActiveLineNumber', 'Color of editor active line number'), false, nls.localize('deprecatedEditorActiveLineNumber', 'Id is deprecated. Use \\'editorLineNumber.activeForeground\\' instead.'));\r\nexport const editorActiveLineNumber = registerColor('editorLineNumber.activeForeground', { dark: deprecatedEditorActiveLineNumber, light: deprecatedEditorActiveLineNumber, hc: deprecatedEditorActiveLineNumber }, nls.localize('editorActiveLineNumber', 'Color of editor active line number'));\r\n\r\nexport const editorRuler = registerColor('editorRuler.foreground', { dark: '#5A5A5A', light: Color.lightgrey, hc: Color.white }, nls.localize('editorRuler', 'Color of the editor rulers.'));\r\n\r\nexport const editorCodeLensForeground = registerColor('editorCodeLens.foreground', { dark: '#999999', light: '#999999', hc: '#999999' }, nls.localize('editorCodeLensForeground', 'Foreground color of editor CodeLens'));\r\n\r\nexport const editorBracketMatchBackground = registerColor('editorBracketMatch.background', { dark: '#0064001a', light: '#0064001a', hc: '#0064001a' }, nls.localize('editorBracketMatchBackground', 'Background color behind matching brackets'));\r\nexport const editorBracketMatchBorder = registerColor('editorBracketMatch.border', { dark: '#888', light: '#B9B9B9', hc: contrastBorder }, nls.localize('editorBracketMatchBorder', 'Color for matching brackets boxes'));\r\n\r\nexport const editorOverviewRulerBorder = registerColor('editorOverviewRuler.border', { dark: '#7f7f7f4d', light: '#7f7f7f4d', hc: '#7f7f7f4d' }, nls.localize('editorOverviewRulerBorder', 'Color of the overview ruler border.'));\r\nexport const editorOverviewRulerBackground = registerColor('editorOverviewRuler.background', null, nls.localize('editorOverviewRulerBackground', 'Background color of the editor overview ruler. Only used when the minimap is enabled and placed on the right side of the editor.'));\r\n\r\nexport const editorGutter = registerColor('editorGutter.background', { dark: editorBackground, light: editorBackground, hc: editorBackground }, nls.localize('editorGutter', 'Background color of the editor gutter. The gutter contains the glyph margins and the line numbers.'));\r\n\r\nexport const editorUnnecessaryCodeBorder = registerColor('editorUnnecessaryCode.border', { dark: null, light: null, hc: Color.fromHex('#fff').transparent(0.8) }, nls.localize('unnecessaryCodeBorder', 'Border color of unnecessary (unused) source code in the editor.'));\r\nexport const editorUnnecessaryCodeOpacity = registerColor('editorUnnecessaryCode.opacity', { dark: Color.fromHex('#000a'), light: Color.fromHex('#0007'), hc: null }, nls.localize('unnecessaryCodeOpacity', 'Opacity of unnecessary (unused) source code in the editor. For example, \"#000000c0\" will render the code with 75% opacity. For high contrast themes, use the \\'editorUnnecessaryCode.border\\' theme color to underline unnecessary code instead of fading it out.'));\r\n\r\nconst rulerRangeDefault = new Color(new RGBA(0, 122, 204, 0.6));\r\nexport const overviewRulerRangeHighlight = registerColor('editorOverviewRuler.rangeHighlightForeground', { dark: rulerRangeDefault, light: rulerRangeDefault, hc: rulerRangeDefault }, nls.localize('overviewRulerRangeHighlight', 'Overview ruler marker color for range highlights. The color must not be opaque so as not to hide underlying decorations.'), true);\r\nexport const overviewRulerError = registerColor('editorOverviewRuler.errorForeground', { dark: new Color(new RGBA(255, 18, 18, 0.7)), light: new Color(new RGBA(255, 18, 18, 0.7)), hc: new Color(new RGBA(255, 50, 50, 1)) }, nls.localize('overviewRuleError', 'Overview ruler marker color for errors.'));\r\nexport const overviewRulerWarning = registerColor('editorOverviewRuler.warningForeground', { dark: editorWarningForeground, light: editorWarningForeground, hc: editorWarningBorder }, nls.localize('overviewRuleWarning', 'Overview ruler marker color for warnings.'));\r\nexport const overviewRulerInfo = registerColor('editorOverviewRuler.infoForeground', { dark: editorInfoForeground, light: editorInfoForeground, hc: editorInfoBorder }, nls.localize('overviewRuleInfo', 'Overview ruler marker color for infos.'));\r\n\r\n// contains all color rules that used to defined in editor/browser/widget/editor.css\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst background = theme.getColor(editorBackground);\r\n\tif (background) {\r\n\t\tcollector.addRule(`.monaco-editor, .monaco-editor-background, .monaco-editor .inputarea.ime-input { background-color: ${background}; }`);\r\n\t}\r\n\r\n\tconst foreground = theme.getColor(editorForeground);\r\n\tif (foreground) {\r\n\t\tcollector.addRule(`.monaco-editor, .monaco-editor .inputarea.ime-input { color: ${foreground}; }`);\r\n\t}\r\n\r\n\tconst gutter = theme.getColor(editorGutter);\r\n\tif (gutter) {\r\n\t\tcollector.addRule(`.monaco-editor .margin { background-color: ${gutter}; }`);\r\n\t}\r\n\r\n\tconst rangeHighlight = theme.getColor(editorRangeHighlight);\r\n\tif (rangeHighlight) {\r\n\t\tcollector.addRule(`.monaco-editor .rangeHighlight { background-color: ${rangeHighlight}; }`);\r\n\t}\r\n\r\n\tconst rangeHighlightBorder = theme.getColor(editorRangeHighlightBorder);\r\n\tif (rangeHighlightBorder) {\r\n\t\tcollector.addRule(`.monaco-editor .rangeHighlight { border: 1px ${theme.type === 'hc' ? 'dotted' : 'solid'} ${rangeHighlightBorder}; }`);\r\n\t}\r\n\r\n\tconst symbolHighlight = theme.getColor(editorSymbolHighlight);\r\n\tif (symbolHighlight) {\r\n\t\tcollector.addRule(`.monaco-editor .symbolHighlight { background-color: ${symbolHighlight}; }`);\r\n\t}\r\n\r\n\tconst symbolHighlightBorder = theme.getColor(editorSymbolHighlightBorder);\r\n\tif (symbolHighlightBorder) {\r\n\t\tcollector.addRule(`.monaco-editor .symbolHighlight { border: 1px ${theme.type === 'hc' ? 'dotted' : 'solid'} ${symbolHighlightBorder}; }`);\r\n\t}\r\n\r\n\tconst invisibles = theme.getColor(editorWhitespaces);\r\n\tif (invisibles) {\r\n\t\tcollector.addRule(`.monaco-editor .mtkw { color: ${invisibles} !important; }`);\r\n\t\tcollector.addRule(`.monaco-editor .mtkz { color: ${invisibles} !important; }`);\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./currentLineHighlight';\r\nimport { DynamicViewOverlay } from 'vs/editor/browser/view/dynamicViewOverlay';\r\nimport { editorLineHighlight, editorLineHighlightBorder } from 'vs/editor/common/view/editorColorRegistry';\r\nimport { RenderingContext } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport * as arrays from 'vs/base/common/arrays';\r\nimport { registerThemingParticipant } from 'vs/platform/theme/common/themeService';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\nlet isRenderedUsingBorder = true;\r\n\r\nexport abstract class AbstractLineHighlightOverlay extends DynamicViewOverlay {\r\n\tprivate readonly _context: ViewContext;\r\n\tprotected _lineHeight: number;\r\n\tprotected _renderLineHighlight: 'none' | 'gutter' | 'line' | 'all';\r\n\tprotected _contentLeft: number;\r\n\tprotected _contentWidth: number;\r\n\tprotected _selectionIsEmpty: boolean;\r\n\tprotected _renderLineHighlightOnlyWhenFocus: boolean;\r\n\tprotected _focused: boolean;\r\n\tprivate _cursorLineNumbers: number[];\r\n\tprivate _selections: Selection[];\r\n\tprivate _renderData: string[] | null;\r\n\r\n\tconstructor(context: ViewContext) {\r\n\t\tsuper();\r\n\t\tthis._context = context;\r\n\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tthis._renderLineHighlight = options.get(EditorOption.renderLineHighlight);\r\n\t\tthis._renderLineHighlightOnlyWhenFocus = options.get(EditorOption.renderLineHighlightOnlyWhenFocus);\r\n\t\tthis._contentLeft = layoutInfo.contentLeft;\r\n\t\tthis._contentWidth = layoutInfo.contentWidth;\r\n\t\tthis._selectionIsEmpty = true;\r\n\t\tthis._focused = false;\r\n\t\tthis._cursorLineNumbers = [1];\r\n\t\tthis._selections = [new Selection(1, 1, 1, 1)];\r\n\t\tthis._renderData = null;\r\n\r\n\t\tthis._context.addEventHandler(this);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._context.removeEventHandler(this);\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tprivate _readFromSelections(): boolean {\r\n\t\tlet hasChanged = false;\r\n\r\n\t\t// Only render the first selection when using border\r\n\t\tconst renderSelections = isRenderedUsingBorder ? this._selections.slice(0, 1) : this._selections;\r\n\r\n\t\tconst cursorsLineNumbers = renderSelections.map(s => s.positionLineNumber);\r\n\t\tcursorsLineNumbers.sort((a, b) => a - b);\r\n\t\tif (!arrays.equals(this._cursorLineNumbers, cursorsLineNumbers)) {\r\n\t\t\tthis._cursorLineNumbers = cursorsLineNumbers;\r\n\t\t\thasChanged = true;\r\n\t\t}\r\n\r\n\t\tconst selectionIsEmpty = renderSelections.every(s => s.isEmpty());\r\n\t\tif (this._selectionIsEmpty !== selectionIsEmpty) {\r\n\t\t\tthis._selectionIsEmpty = selectionIsEmpty;\r\n\t\t\thasChanged = true;\r\n\t\t}\r\n\r\n\t\treturn hasChanged;\r\n\t}\r\n\r\n\t// --- begin event handlers\r\n\tpublic onThemeChanged(e: viewEvents.ViewThemeChangedEvent): boolean {\r\n\t\treturn this._readFromSelections();\r\n\t}\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tthis._renderLineHighlight = options.get(EditorOption.renderLineHighlight);\r\n\t\tthis._renderLineHighlightOnlyWhenFocus = options.get(EditorOption.renderLineHighlightOnlyWhenFocus);\r\n\t\tthis._contentLeft = layoutInfo.contentLeft;\r\n\t\tthis._contentWidth = layoutInfo.contentWidth;\r\n\t\treturn true;\r\n\t}\r\n\tpublic onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {\r\n\t\tthis._selections = e.selections;\r\n\t\treturn this._readFromSelections();\r\n\t}\r\n\tpublic onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\treturn e.scrollWidthChanged || e.scrollTopChanged;\r\n\t}\r\n\tpublic onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onFocusChanged(e: viewEvents.ViewFocusChangedEvent): boolean {\r\n\t\tif (!this._renderLineHighlightOnlyWhenFocus) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tthis._focused = e.isFocused;\r\n\t\treturn true;\r\n\t}\r\n\t// --- end event handlers\r\n\r\n\tpublic prepareRender(ctx: RenderingContext): void {\r\n\t\tif (!this._shouldRenderThis()) {\r\n\t\t\tthis._renderData = null;\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst renderedLine = this._renderOne(ctx);\r\n\t\tconst visibleStartLineNumber = ctx.visibleRange.startLineNumber;\r\n\t\tconst visibleEndLineNumber = ctx.visibleRange.endLineNumber;\r\n\t\tconst len = this._cursorLineNumbers.length;\r\n\t\tlet index = 0;\r\n\t\tconst renderData: string[] = [];\r\n\t\tfor (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) {\r\n\t\t\tconst lineIndex = lineNumber - visibleStartLineNumber;\r\n\t\t\twhile (index < len && this._cursorLineNumbers[index] < lineNumber) {\r\n\t\t\t\tindex++;\r\n\t\t\t}\r\n\t\t\tif (index < len && this._cursorLineNumbers[index] === lineNumber) {\r\n\t\t\t\trenderData[lineIndex] = renderedLine;\r\n\t\t\t} else {\r\n\t\t\t\trenderData[lineIndex] = '';\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis._renderData = renderData;\r\n\t}\r\n\r\n\tpublic render(startLineNumber: number, lineNumber: number): string {\r\n\t\tif (!this._renderData) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\tconst lineIndex = lineNumber - startLineNumber;\r\n\t\tif (lineIndex >= this._renderData.length) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\treturn this._renderData[lineIndex];\r\n\t}\r\n\r\n\tprotected abstract _shouldRenderThis(): boolean;\r\n\tprotected abstract _shouldRenderOther(): boolean;\r\n\tprotected abstract _renderOne(ctx: RenderingContext): string;\r\n}\r\n\r\nexport class CurrentLineHighlightOverlay extends AbstractLineHighlightOverlay {\r\n\r\n\tprotected _renderOne(ctx: RenderingContext): string {\r\n\t\tconst className = 'current-line' + (this._shouldRenderOther() ? ' current-line-both' : '');\r\n\t\treturn `
    `;\r\n\t}\r\n\tprotected _shouldRenderThis(): boolean {\r\n\t\treturn (\r\n\t\t\t(this._renderLineHighlight === 'line' || this._renderLineHighlight === 'all')\r\n\t\t\t&& this._selectionIsEmpty\r\n\t\t\t&& (!this._renderLineHighlightOnlyWhenFocus || this._focused)\r\n\t\t);\r\n\t}\r\n\tprotected _shouldRenderOther(): boolean {\r\n\t\treturn (\r\n\t\t\t(this._renderLineHighlight === 'gutter' || this._renderLineHighlight === 'all')\r\n\t\t\t&& (!this._renderLineHighlightOnlyWhenFocus || this._focused)\r\n\t\t);\r\n\t}\r\n}\r\n\r\nexport class CurrentLineMarginHighlightOverlay extends AbstractLineHighlightOverlay {\r\n\tprotected _renderOne(ctx: RenderingContext): string {\r\n\t\tconst className = 'current-line' + (this._shouldRenderMargin() ? ' current-line-margin' : '') + (this._shouldRenderOther() ? ' current-line-margin-both' : '');\r\n\t\treturn `
    `;\r\n\t}\r\n\tprotected _shouldRenderMargin(): boolean {\r\n\t\treturn (\r\n\t\t\t(this._renderLineHighlight === 'gutter' || this._renderLineHighlight === 'all')\r\n\t\t\t&& (!this._renderLineHighlightOnlyWhenFocus || this._focused)\r\n\t\t);\r\n\t}\r\n\tprotected _shouldRenderThis(): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tprotected _shouldRenderOther(): boolean {\r\n\t\treturn (\r\n\t\t\t(this._renderLineHighlight === 'line' || this._renderLineHighlight === 'all')\r\n\t\t\t&& this._selectionIsEmpty\r\n\t\t\t&& (!this._renderLineHighlightOnlyWhenFocus || this._focused)\r\n\t\t);\r\n\t}\r\n}\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tisRenderedUsingBorder = false;\r\n\tconst lineHighlight = theme.getColor(editorLineHighlight);\r\n\tif (lineHighlight) {\r\n\t\tcollector.addRule(`.monaco-editor .view-overlays .current-line { background-color: ${lineHighlight}; }`);\r\n\t\tcollector.addRule(`.monaco-editor .margin-view-overlays .current-line-margin { background-color: ${lineHighlight}; border: none; }`);\r\n\t}\r\n\tif (!lineHighlight || lineHighlight.isTransparent() || theme.defines(editorLineHighlightBorder)) {\r\n\t\tconst lineHighlightBorder = theme.getColor(editorLineHighlightBorder);\r\n\t\tif (lineHighlightBorder) {\r\n\t\t\tisRenderedUsingBorder = true;\r\n\t\t\tcollector.addRule(`.monaco-editor .view-overlays .current-line { border: 2px solid ${lineHighlightBorder}; }`);\r\n\t\t\tcollector.addRule(`.monaco-editor .margin-view-overlays .current-line-margin { border: 2px solid ${lineHighlightBorder}; }`);\r\n\t\t\tif (theme.type === 'hc') {\r\n\t\t\t\tcollector.addRule(`.monaco-editor .view-overlays .current-line { border-width: 1px; }`);\r\n\t\t\t\tcollector.addRule(`.monaco-editor .margin-view-overlays .current-line-margin { border-width: 1px; }`);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./indentGuides';\r\nimport { DynamicViewOverlay } from 'vs/editor/browser/view/dynamicViewOverlay';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { editorActiveIndentGuides, editorIndentGuides } from 'vs/editor/common/view/editorColorRegistry';\r\nimport { RenderingContext } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { registerThemingParticipant } from 'vs/platform/theme/common/themeService';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\n\r\nexport class IndentGuidesOverlay extends DynamicViewOverlay {\r\n\r\n\tprivate readonly _context: ViewContext;\r\n\tprivate _primaryLineNumber: number;\r\n\tprivate _lineHeight: number;\r\n\tprivate _spaceWidth: number;\r\n\tprivate _renderResult: string[] | null;\r\n\tprivate _enabled: boolean;\r\n\tprivate _activeIndentEnabled: boolean;\r\n\tprivate _maxIndentLeft: number;\r\n\r\n\tconstructor(context: ViewContext) {\r\n\t\tsuper();\r\n\t\tthis._context = context;\r\n\t\tthis._primaryLineNumber = 0;\r\n\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst wrappingInfo = options.get(EditorOption.wrappingInfo);\r\n\t\tconst fontInfo = options.get(EditorOption.fontInfo);\r\n\r\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tthis._spaceWidth = fontInfo.spaceWidth;\r\n\t\tthis._enabled = options.get(EditorOption.renderIndentGuides);\r\n\t\tthis._activeIndentEnabled = options.get(EditorOption.highlightActiveIndentGuide);\r\n\t\tthis._maxIndentLeft = wrappingInfo.wrappingColumn === -1 ? -1 : (wrappingInfo.wrappingColumn * fontInfo.typicalHalfwidthCharacterWidth);\r\n\r\n\t\tthis._renderResult = null;\r\n\r\n\t\tthis._context.addEventHandler(this);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._context.removeEventHandler(this);\r\n\t\tthis._renderResult = null;\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\t// --- begin event handlers\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst wrappingInfo = options.get(EditorOption.wrappingInfo);\r\n\t\tconst fontInfo = options.get(EditorOption.fontInfo);\r\n\r\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tthis._spaceWidth = fontInfo.spaceWidth;\r\n\t\tthis._enabled = options.get(EditorOption.renderIndentGuides);\r\n\t\tthis._activeIndentEnabled = options.get(EditorOption.highlightActiveIndentGuide);\r\n\t\tthis._maxIndentLeft = wrappingInfo.wrappingColumn === -1 ? -1 : (wrappingInfo.wrappingColumn * fontInfo.typicalHalfwidthCharacterWidth);\r\n\t\treturn true;\r\n\t}\r\n\tpublic onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {\r\n\t\tconst selection = e.selections[0];\r\n\t\tconst newPrimaryLineNumber = selection.isEmpty() ? selection.positionLineNumber : 0;\r\n\r\n\t\tif (this._primaryLineNumber !== newPrimaryLineNumber) {\r\n\t\t\tthis._primaryLineNumber = newPrimaryLineNumber;\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\t}\r\n\tpublic onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {\r\n\t\t// true for inline decorations\r\n\t\treturn true;\r\n\t}\r\n\tpublic onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\treturn e.scrollTopChanged;// || e.scrollWidthChanged;\r\n\t}\r\n\tpublic onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLanguageConfigurationChanged(e: viewEvents.ViewLanguageConfigurationEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// --- end event handlers\r\n\r\n\tpublic prepareRender(ctx: RenderingContext): void {\r\n\t\tif (!this._enabled) {\r\n\t\t\tthis._renderResult = null;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst visibleStartLineNumber = ctx.visibleRange.startLineNumber;\r\n\t\tconst visibleEndLineNumber = ctx.visibleRange.endLineNumber;\r\n\t\tconst { indentSize } = this._context.model.getTextModelOptions();\r\n\t\tconst indentWidth = indentSize * this._spaceWidth;\r\n\t\tconst scrollWidth = ctx.scrollWidth;\r\n\t\tconst lineHeight = this._lineHeight;\r\n\r\n\t\tconst indents = this._context.model.getLinesIndentGuides(visibleStartLineNumber, visibleEndLineNumber);\r\n\r\n\t\tlet activeIndentStartLineNumber = 0;\r\n\t\tlet activeIndentEndLineNumber = 0;\r\n\t\tlet activeIndentLevel = 0;\r\n\t\tif (this._activeIndentEnabled && this._primaryLineNumber) {\r\n\t\t\tconst activeIndentInfo = this._context.model.getActiveIndentGuide(this._primaryLineNumber, visibleStartLineNumber, visibleEndLineNumber);\r\n\t\t\tactiveIndentStartLineNumber = activeIndentInfo.startLineNumber;\r\n\t\t\tactiveIndentEndLineNumber = activeIndentInfo.endLineNumber;\r\n\t\t\tactiveIndentLevel = activeIndentInfo.indent;\r\n\t\t}\r\n\r\n\t\tconst output: string[] = [];\r\n\t\tfor (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) {\r\n\t\t\tconst containsActiveIndentGuide = (activeIndentStartLineNumber <= lineNumber && lineNumber <= activeIndentEndLineNumber);\r\n\t\t\tconst lineIndex = lineNumber - visibleStartLineNumber;\r\n\t\t\tconst indent = indents[lineIndex];\r\n\r\n\t\t\tlet result = '';\r\n\t\t\tif (indent >= 1) {\r\n\t\t\t\tconst leftMostVisiblePosition = ctx.visibleRangeForPosition(new Position(lineNumber, 1));\r\n\t\t\t\tlet left = leftMostVisiblePosition ? leftMostVisiblePosition.left : 0;\r\n\t\t\t\tfor (let i = 1; i <= indent; i++) {\r\n\t\t\t\t\tconst className = (containsActiveIndentGuide && i === activeIndentLevel ? 'cigra' : 'cigr');\r\n\t\t\t\t\tresult += `
    `;\r\n\t\t\t\t\tleft += indentWidth;\r\n\t\t\t\t\tif (left > scrollWidth || (this._maxIndentLeft > 0 && left > this._maxIndentLeft)) {\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\toutput[lineIndex] = result;\r\n\t\t}\r\n\t\tthis._renderResult = output;\r\n\t}\r\n\r\n\tpublic render(startLineNumber: number, lineNumber: number): string {\r\n\t\tif (!this._renderResult) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\tconst lineIndex = lineNumber - startLineNumber;\r\n\t\tif (lineIndex < 0 || lineIndex >= this._renderResult.length) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\treturn this._renderResult[lineIndex];\r\n\t}\r\n}\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst editorIndentGuidesColor = theme.getColor(editorIndentGuides);\r\n\tif (editorIndentGuidesColor) {\r\n\t\tcollector.addRule(`.monaco-editor .lines-content .cigr { box-shadow: 1px 0 0 0 ${editorIndentGuidesColor} inset; }`);\r\n\t}\r\n\tconst editorActiveIndentGuidesColor = theme.getColor(editorActiveIndentGuides) || editorIndentGuidesColor;\r\n\tif (editorActiveIndentGuidesColor) {\r\n\t\tcollector.addRule(`.monaco-editor .lines-content .cigra { box-shadow: 1px 0 0 0 ${editorActiveIndentGuidesColor} inset; }`);\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./lineNumbers';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport { DynamicViewOverlay } from 'vs/editor/browser/view/dynamicViewOverlay';\r\nimport { RenderLineNumbersType, EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { editorActiveLineNumber, editorLineNumbers } from 'vs/editor/common/view/editorColorRegistry';\r\nimport { RenderingContext } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { registerThemingParticipant } from 'vs/platform/theme/common/themeService';\r\n\r\nexport class LineNumbersOverlay extends DynamicViewOverlay {\r\n\r\n\tpublic static readonly CLASS_NAME = 'line-numbers';\r\n\r\n\tprivate readonly _context: ViewContext;\r\n\r\n\tprivate _lineHeight!: number;\r\n\tprivate _renderLineNumbers!: RenderLineNumbersType;\r\n\tprivate _renderCustomLineNumbers!: ((lineNumber: number) => string) | null;\r\n\tprivate _renderFinalNewline!: boolean;\r\n\tprivate _lineNumbersLeft!: number;\r\n\tprivate _lineNumbersWidth!: number;\r\n\tprivate _lastCursorModelPosition: Position;\r\n\tprivate _renderResult: string[] | null;\r\n\r\n\tconstructor(context: ViewContext) {\r\n\t\tsuper();\r\n\t\tthis._context = context;\r\n\r\n\t\tthis._readConfig();\r\n\r\n\t\tthis._lastCursorModelPosition = new Position(1, 1);\r\n\t\tthis._renderResult = null;\r\n\t\tthis._context.addEventHandler(this);\r\n\t}\r\n\r\n\tprivate _readConfig(): void {\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tconst lineNumbers = options.get(EditorOption.lineNumbers);\r\n\t\tthis._renderLineNumbers = lineNumbers.renderType;\r\n\t\tthis._renderCustomLineNumbers = lineNumbers.renderFn;\r\n\t\tthis._renderFinalNewline = options.get(EditorOption.renderFinalNewline);\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\t\tthis._lineNumbersLeft = layoutInfo.lineNumbersLeft;\r\n\t\tthis._lineNumbersWidth = layoutInfo.lineNumbersWidth;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._context.removeEventHandler(this);\r\n\t\tthis._renderResult = null;\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\t// --- begin event handlers\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tthis._readConfig();\r\n\t\treturn true;\r\n\t}\r\n\tpublic onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {\r\n\t\tconst primaryViewPosition = e.selections[0].getPosition();\r\n\t\tthis._lastCursorModelPosition = this._context.model.coordinatesConverter.convertViewPositionToModelPosition(primaryViewPosition);\r\n\r\n\t\tif (this._renderLineNumbers === RenderLineNumbersType.Relative || this._renderLineNumbers === RenderLineNumbersType.Interval) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\tpublic onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\treturn e.scrollTopChanged;\r\n\t}\r\n\tpublic onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// --- end event handlers\r\n\r\n\tprivate _getLineRenderLineNumber(viewLineNumber: number): string {\r\n\t\tconst modelPosition = this._context.model.coordinatesConverter.convertViewPositionToModelPosition(new Position(viewLineNumber, 1));\r\n\t\tif (modelPosition.column !== 1) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\tconst modelLineNumber = modelPosition.lineNumber;\r\n\r\n\t\tif (this._renderCustomLineNumbers) {\r\n\t\t\treturn this._renderCustomLineNumbers(modelLineNumber);\r\n\t\t}\r\n\r\n\t\tif (this._renderLineNumbers === RenderLineNumbersType.Relative) {\r\n\t\t\tconst diff = Math.abs(this._lastCursorModelPosition.lineNumber - modelLineNumber);\r\n\t\t\tif (diff === 0) {\r\n\t\t\t\treturn '' + modelLineNumber + '';\r\n\t\t\t}\r\n\t\t\treturn String(diff);\r\n\t\t}\r\n\r\n\t\tif (this._renderLineNumbers === RenderLineNumbersType.Interval) {\r\n\t\t\tif (this._lastCursorModelPosition.lineNumber === modelLineNumber) {\r\n\t\t\t\treturn String(modelLineNumber);\r\n\t\t\t}\r\n\t\t\tif (modelLineNumber % 10 === 0) {\r\n\t\t\t\treturn String(modelLineNumber);\r\n\t\t\t}\r\n\t\t\treturn '';\r\n\t\t}\r\n\r\n\t\treturn String(modelLineNumber);\r\n\t}\r\n\r\n\tpublic prepareRender(ctx: RenderingContext): void {\r\n\t\tif (this._renderLineNumbers === RenderLineNumbersType.Off) {\r\n\t\t\tthis._renderResult = null;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst lineHeightClassName = (platform.isLinux ? (this._lineHeight % 2 === 0 ? ' lh-even' : ' lh-odd') : '');\r\n\t\tconst visibleStartLineNumber = ctx.visibleRange.startLineNumber;\r\n\t\tconst visibleEndLineNumber = ctx.visibleRange.endLineNumber;\r\n\t\tconst common = '
    ';\r\n\r\n\t\tconst lineCount = this._context.model.getLineCount();\r\n\t\tconst output: string[] = [];\r\n\t\tfor (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) {\r\n\t\t\tconst lineIndex = lineNumber - visibleStartLineNumber;\r\n\r\n\t\t\tif (!this._renderFinalNewline) {\r\n\t\t\t\tif (lineNumber === lineCount && this._context.model.getLineLength(lineNumber) === 0) {\r\n\t\t\t\t\t// Do not render last (empty) line\r\n\t\t\t\t\toutput[lineIndex] = '';\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tconst renderLineNumber = this._getLineRenderLineNumber(lineNumber);\r\n\r\n\t\t\tif (renderLineNumber) {\r\n\t\t\t\toutput[lineIndex] = (\r\n\t\t\t\t\tcommon\r\n\t\t\t\t\t+ renderLineNumber\r\n\t\t\t\t\t+ '
    '\r\n\t\t\t\t);\r\n\t\t\t} else {\r\n\t\t\t\toutput[lineIndex] = '';\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._renderResult = output;\r\n\t}\r\n\r\n\tpublic render(startLineNumber: number, lineNumber: number): string {\r\n\t\tif (!this._renderResult) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\tconst lineIndex = lineNumber - startLineNumber;\r\n\t\tif (lineIndex < 0 || lineIndex >= this._renderResult.length) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\treturn this._renderResult[lineIndex];\r\n\t}\r\n}\r\n\r\n// theming\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst lineNumbers = theme.getColor(editorLineNumbers);\r\n\tif (lineNumbers) {\r\n\t\tcollector.addRule(`.monaco-editor .line-numbers { color: ${lineNumbers}; }`);\r\n\t}\r\n\tconst activeLineNumber = theme.getColor(editorActiveLineNumber);\r\n\tif (activeLineNumber) {\r\n\t\tcollector.addRule(`.monaco-editor .current-line ~ .line-numbers { color: ${activeLineNumber}; }`);\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./textAreaHandler';\r\nimport * as nls from 'vs/nls';\r\nimport * as browser from 'vs/base/browser/browser';\r\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { Configuration } from 'vs/editor/browser/config/configuration';\r\nimport { CopyOptions, ICompositionData, IPasteData, ITextAreaInputHost, TextAreaInput, ClipboardDataToCopy } from 'vs/editor/browser/controller/textAreaInput';\r\nimport { ISimpleModel, ITypeData, PagedScreenReaderStrategy, TextAreaState } from 'vs/editor/browser/controller/textAreaState';\r\nimport { ViewController } from 'vs/editor/browser/view/viewController';\r\nimport { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/view/viewPart';\r\nimport { LineNumbersOverlay } from 'vs/editor/browser/viewParts/lineNumbers/lineNumbers';\r\nimport { Margin } from 'vs/editor/browser/viewParts/margin/margin';\r\nimport { RenderLineNumbersType, EditorOption, IComputedEditorOptions, EditorOptions } from 'vs/editor/common/config/editorOptions';\r\nimport { BareFontInfo } from 'vs/editor/common/config/fontInfo';\r\nimport { WordCharacterClass, getMapForWordSeparators } from 'vs/editor/common/controller/wordCharacterClassifier';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { ScrollType } from 'vs/editor/common/editorCommon';\r\nimport { EndOfLinePreference } from 'vs/editor/common/model';\r\nimport { RenderingContext, RestrictedRenderingContext, HorizontalPosition } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';\r\nimport { IEditorAriaOptions } from 'vs/editor/browser/editorBrowser';\r\nimport { MOUSE_CURSOR_TEXT_CSS_CLASS_NAME } from 'vs/base/browser/ui/mouseCursor/mouseCursor';\r\n\r\nexport interface ITextAreaHandlerHelper {\r\n\tvisibleRangeForPositionRelativeToEditor(lineNumber: number, column: number): HorizontalPosition | null;\r\n}\r\n\r\nclass VisibleTextAreaData {\r\n\t_visibleTextAreaBrand: void;\r\n\r\n\tpublic readonly top: number;\r\n\tpublic readonly left: number;\r\n\tpublic readonly width: number;\r\n\r\n\tconstructor(top: number, left: number, width: number) {\r\n\t\tthis.top = top;\r\n\t\tthis.left = left;\r\n\t\tthis.width = width;\r\n\t}\r\n\r\n\tpublic setWidth(width: number): VisibleTextAreaData {\r\n\t\treturn new VisibleTextAreaData(this.top, this.left, width);\r\n\t}\r\n}\r\n\r\nconst canUseZeroSizeTextarea = (browser.isFirefox);\r\n\r\nexport class TextAreaHandler extends ViewPart {\r\n\r\n\tprivate readonly _viewController: ViewController;\r\n\tprivate readonly _viewHelper: ITextAreaHandlerHelper;\r\n\tprivate _scrollLeft: number;\r\n\tprivate _scrollTop: number;\r\n\r\n\tprivate _accessibilitySupport!: AccessibilitySupport;\r\n\tprivate _accessibilityPageSize!: number;\r\n\tprivate _contentLeft: number;\r\n\tprivate _contentWidth: number;\r\n\tprivate _contentHeight: number;\r\n\tprivate _fontInfo: BareFontInfo;\r\n\tprivate _lineHeight: number;\r\n\tprivate _emptySelectionClipboard: boolean;\r\n\tprivate _copyWithSyntaxHighlighting: boolean;\r\n\r\n\t/**\r\n\t * Defined only when the text area is visible (composition case).\r\n\t */\r\n\tprivate _visibleTextArea: VisibleTextAreaData | null;\r\n\tprivate _selections: Selection[];\r\n\tprivate _modelSelections: Selection[];\r\n\r\n\t/**\r\n\t * The position at which the textarea was rendered.\r\n\t * This is useful for hit-testing and determining the mouse position.\r\n\t */\r\n\tprivate _lastRenderPosition: Position | null;\r\n\r\n\tpublic readonly textArea: FastDomNode;\r\n\tpublic readonly textAreaCover: FastDomNode;\r\n\tprivate readonly _textAreaInput: TextAreaInput;\r\n\r\n\tconstructor(context: ViewContext, viewController: ViewController, viewHelper: ITextAreaHandlerHelper) {\r\n\t\tsuper(context);\r\n\r\n\t\tthis._viewController = viewController;\r\n\t\tthis._viewHelper = viewHelper;\r\n\t\tthis._scrollLeft = 0;\r\n\t\tthis._scrollTop = 0;\r\n\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\r\n\t\tthis._setAccessibilityOptions(options);\r\n\t\tthis._contentLeft = layoutInfo.contentLeft;\r\n\t\tthis._contentWidth = layoutInfo.contentWidth;\r\n\t\tthis._contentHeight = layoutInfo.height;\r\n\t\tthis._fontInfo = options.get(EditorOption.fontInfo);\r\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tthis._emptySelectionClipboard = options.get(EditorOption.emptySelectionClipboard);\r\n\t\tthis._copyWithSyntaxHighlighting = options.get(EditorOption.copyWithSyntaxHighlighting);\r\n\r\n\t\tthis._visibleTextArea = null;\r\n\t\tthis._selections = [new Selection(1, 1, 1, 1)];\r\n\t\tthis._modelSelections = [new Selection(1, 1, 1, 1)];\r\n\t\tthis._lastRenderPosition = null;\r\n\r\n\t\t// Text Area (The focus will always be in the textarea when the cursor is blinking)\r\n\t\tthis.textArea = createFastDomNode(document.createElement('textarea'));\r\n\t\tPartFingerprints.write(this.textArea, PartFingerprint.TextArea);\r\n\t\tthis.textArea.setClassName(`inputarea ${MOUSE_CURSOR_TEXT_CSS_CLASS_NAME}`);\r\n\t\tthis.textArea.setAttribute('wrap', 'off');\r\n\t\tthis.textArea.setAttribute('autocorrect', 'off');\r\n\t\tthis.textArea.setAttribute('autocapitalize', 'off');\r\n\t\tthis.textArea.setAttribute('autocomplete', 'off');\r\n\t\tthis.textArea.setAttribute('spellcheck', 'false');\r\n\t\tthis.textArea.setAttribute('aria-label', this._getAriaLabel(options));\r\n\t\tthis.textArea.setAttribute('tabindex', String(options.get(EditorOption.tabIndex)));\r\n\t\tthis.textArea.setAttribute('role', 'textbox');\r\n\t\tthis.textArea.setAttribute('aria-roledescription', nls.localize('editor', \"editor\"));\r\n\t\tthis.textArea.setAttribute('aria-multiline', 'true');\r\n\t\tthis.textArea.setAttribute('aria-haspopup', 'false');\r\n\t\tthis.textArea.setAttribute('aria-autocomplete', 'both');\r\n\r\n\t\tif (platform.isWeb && options.get(EditorOption.readOnly)) {\r\n\t\t\tthis.textArea.setAttribute('readonly', 'true');\r\n\t\t}\r\n\r\n\t\tthis.textAreaCover = createFastDomNode(document.createElement('div'));\r\n\t\tthis.textAreaCover.setPosition('absolute');\r\n\r\n\t\tconst simpleModel: ISimpleModel = {\r\n\t\t\tgetLineCount: (): number => {\r\n\t\t\t\treturn this._context.model.getLineCount();\r\n\t\t\t},\r\n\t\t\tgetLineMaxColumn: (lineNumber: number): number => {\r\n\t\t\t\treturn this._context.model.getLineMaxColumn(lineNumber);\r\n\t\t\t},\r\n\t\t\tgetValueInRange: (range: Range, eol: EndOfLinePreference): string => {\r\n\t\t\t\treturn this._context.model.getValueInRange(range, eol);\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tconst textAreaInputHost: ITextAreaInputHost = {\r\n\t\t\tgetDataToCopy: (generateHTML: boolean): ClipboardDataToCopy => {\r\n\t\t\t\tconst rawTextToCopy = this._context.model.getPlainTextToCopy(this._modelSelections, this._emptySelectionClipboard, platform.isWindows);\r\n\t\t\t\tconst newLineCharacter = this._context.model.getEOL();\r\n\r\n\t\t\t\tconst isFromEmptySelection = (this._emptySelectionClipboard && this._modelSelections.length === 1 && this._modelSelections[0].isEmpty());\r\n\t\t\t\tconst multicursorText = (Array.isArray(rawTextToCopy) ? rawTextToCopy : null);\r\n\t\t\t\tconst text = (Array.isArray(rawTextToCopy) ? rawTextToCopy.join(newLineCharacter) : rawTextToCopy);\r\n\r\n\t\t\t\tlet html: string | null | undefined = undefined;\r\n\t\t\t\tlet mode: string | null = null;\r\n\t\t\t\tif (generateHTML) {\r\n\t\t\t\t\tif (CopyOptions.forceCopyWithSyntaxHighlighting || (this._copyWithSyntaxHighlighting && text.length < 65536)) {\r\n\t\t\t\t\t\tconst richText = this._context.model.getRichTextToCopy(this._modelSelections, this._emptySelectionClipboard);\r\n\t\t\t\t\t\tif (richText) {\r\n\t\t\t\t\t\t\thtml = richText.html;\r\n\t\t\t\t\t\t\tmode = richText.mode;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\treturn {\r\n\t\t\t\t\tisFromEmptySelection,\r\n\t\t\t\t\tmulticursorText,\r\n\t\t\t\t\ttext,\r\n\t\t\t\t\thtml,\r\n\t\t\t\t\tmode\r\n\t\t\t\t};\r\n\t\t\t},\r\n\t\t\tgetScreenReaderContent: (currentState: TextAreaState): TextAreaState => {\r\n\t\t\t\tif (this._accessibilitySupport === AccessibilitySupport.Disabled) {\r\n\t\t\t\t\t// We know for a fact that a screen reader is not attached\r\n\t\t\t\t\t// On OSX, we write the character before the cursor to allow for \"long-press\" composition\r\n\t\t\t\t\t// Also on OSX, we write the word before the cursor to allow for the Accessibility Keyboard to give good hints\r\n\t\t\t\t\tif (platform.isMacintosh) {\r\n\t\t\t\t\t\tconst selection = this._selections[0];\r\n\t\t\t\t\t\tif (selection.isEmpty()) {\r\n\t\t\t\t\t\t\tconst position = selection.getStartPosition();\r\n\r\n\t\t\t\t\t\t\tlet textBefore = this._getWordBeforePosition(position);\r\n\t\t\t\t\t\t\tif (textBefore.length === 0) {\r\n\t\t\t\t\t\t\t\ttextBefore = this._getCharacterBeforePosition(position);\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tif (textBefore.length > 0) {\r\n\t\t\t\t\t\t\t\treturn new TextAreaState(textBefore, textBefore.length, textBefore.length, position, position);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn TextAreaState.EMPTY;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn PagedScreenReaderStrategy.fromEditorSelection(currentState, simpleModel, this._selections[0], this._accessibilityPageSize, this._accessibilitySupport === AccessibilitySupport.Unknown);\r\n\t\t\t},\r\n\r\n\t\t\tdeduceModelPosition: (viewAnchorPosition: Position, deltaOffset: number, lineFeedCnt: number): Position => {\r\n\t\t\t\treturn this._context.model.deduceModelPositionRelativeToViewPosition(viewAnchorPosition, deltaOffset, lineFeedCnt);\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tthis._textAreaInput = this._register(new TextAreaInput(textAreaInputHost, this.textArea));\r\n\r\n\t\tthis._register(this._textAreaInput.onKeyDown((e: IKeyboardEvent) => {\r\n\t\t\tthis._viewController.emitKeyDown(e);\r\n\t\t}));\r\n\r\n\t\tthis._register(this._textAreaInput.onKeyUp((e: IKeyboardEvent) => {\r\n\t\t\tthis._viewController.emitKeyUp(e);\r\n\t\t}));\r\n\r\n\t\tthis._register(this._textAreaInput.onPaste((e: IPasteData) => {\r\n\t\t\tlet pasteOnNewLine = false;\r\n\t\t\tlet multicursorText: string[] | null = null;\r\n\t\t\tlet mode: string | null = null;\r\n\t\t\tif (e.metadata) {\r\n\t\t\t\tpasteOnNewLine = (this._emptySelectionClipboard && !!e.metadata.isFromEmptySelection);\r\n\t\t\t\tmulticursorText = (typeof e.metadata.multicursorText !== 'undefined' ? e.metadata.multicursorText : null);\r\n\t\t\t\tmode = e.metadata.mode;\r\n\t\t\t}\r\n\t\t\tthis._viewController.paste(e.text, pasteOnNewLine, multicursorText, mode);\r\n\t\t}));\r\n\r\n\t\tthis._register(this._textAreaInput.onCut(() => {\r\n\t\t\tthis._viewController.cut();\r\n\t\t}));\r\n\r\n\t\tthis._register(this._textAreaInput.onType((e: ITypeData) => {\r\n\t\t\tif (e.replaceCharCnt) {\r\n\t\t\t\tthis._viewController.replacePreviousChar(e.text, e.replaceCharCnt);\r\n\t\t\t} else {\r\n\t\t\t\tthis._viewController.type(e.text);\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._register(this._textAreaInput.onSelectionChangeRequest((modelSelection: Selection) => {\r\n\t\t\tthis._viewController.setSelection(modelSelection);\r\n\t\t}));\r\n\r\n\t\tthis._register(this._textAreaInput.onCompositionStart((e) => {\r\n\t\t\tconst lineNumber = this._selections[0].startLineNumber;\r\n\t\t\tconst column = this._selections[0].startColumn - (e.moveOneCharacterLeft ? 1 : 0);\r\n\r\n\t\t\tthis._context.model.revealRange(\r\n\t\t\t\t'keyboard',\r\n\t\t\t\ttrue,\r\n\t\t\t\tnew Range(lineNumber, column, lineNumber, column),\r\n\t\t\t\tviewEvents.VerticalRevealType.Simple,\r\n\t\t\t\tScrollType.Immediate\r\n\t\t\t);\r\n\r\n\t\t\t// Find range pixel position\r\n\t\t\tconst visibleRange = this._viewHelper.visibleRangeForPositionRelativeToEditor(lineNumber, column);\r\n\r\n\t\t\tif (visibleRange) {\r\n\t\t\t\tthis._visibleTextArea = new VisibleTextAreaData(\r\n\t\t\t\t\tthis._context.viewLayout.getVerticalOffsetForLineNumber(lineNumber),\r\n\t\t\t\t\tvisibleRange.left,\r\n\t\t\t\t\tcanUseZeroSizeTextarea ? 0 : 1\r\n\t\t\t\t);\r\n\t\t\t\tthis._render();\r\n\t\t\t}\r\n\r\n\t\t\t// Show the textarea\r\n\t\t\tthis.textArea.setClassName(`inputarea ${MOUSE_CURSOR_TEXT_CSS_CLASS_NAME} ime-input`);\r\n\r\n\t\t\tthis._viewController.compositionStart();\r\n\t\t\tthis._context.model.onCompositionStart();\r\n\t\t}));\r\n\r\n\t\tthis._register(this._textAreaInput.onCompositionUpdate((e: ICompositionData) => {\r\n\t\t\t// adjust width by its size\r\n\t\t\tthis._visibleTextArea = this._visibleTextArea!.setWidth(measureText(e.data, this._fontInfo));\r\n\t\t\tthis._render();\r\n\t\t}));\r\n\r\n\t\tthis._register(this._textAreaInput.onCompositionEnd(() => {\r\n\r\n\t\t\tthis._visibleTextArea = null;\r\n\t\t\tthis._render();\r\n\r\n\t\t\tthis.textArea.setClassName(`inputarea ${MOUSE_CURSOR_TEXT_CSS_CLASS_NAME}`);\r\n\t\t\tthis._viewController.compositionEnd();\r\n\t\t\tthis._context.model.onCompositionEnd();\r\n\t\t}));\r\n\r\n\t\tthis._register(this._textAreaInput.onFocus(() => {\r\n\t\t\tthis._context.model.setHasFocus(true);\r\n\t\t}));\r\n\r\n\t\tthis._register(this._textAreaInput.onBlur(() => {\r\n\t\t\tthis._context.model.setHasFocus(false);\r\n\t\t}));\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tprivate _getWordBeforePosition(position: Position): string {\r\n\t\tconst lineContent = this._context.model.getLineContent(position.lineNumber);\r\n\t\tconst wordSeparators = getMapForWordSeparators(this._context.configuration.options.get(EditorOption.wordSeparators));\r\n\r\n\t\tlet column = position.column;\r\n\t\tlet distance = 0;\r\n\t\twhile (column > 1) {\r\n\t\t\tconst charCode = lineContent.charCodeAt(column - 2);\r\n\t\t\tconst charClass = wordSeparators.get(charCode);\r\n\t\t\tif (charClass !== WordCharacterClass.Regular || distance > 50) {\r\n\t\t\t\treturn lineContent.substring(column - 1, position.column - 1);\r\n\t\t\t}\r\n\t\t\tdistance++;\r\n\t\t\tcolumn--;\r\n\t\t}\r\n\t\treturn lineContent.substring(0, position.column - 1);\r\n\t}\r\n\r\n\tprivate _getCharacterBeforePosition(position: Position): string {\r\n\t\tif (position.column > 1) {\r\n\t\t\tconst lineContent = this._context.model.getLineContent(position.lineNumber);\r\n\t\t\tconst charBefore = lineContent.charAt(position.column - 2);\r\n\t\t\tif (!strings.isHighSurrogate(charBefore.charCodeAt(0))) {\r\n\t\t\t\treturn charBefore;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn '';\r\n\t}\r\n\r\n\tprivate _getAriaLabel(options: IComputedEditorOptions): string {\r\n\t\tconst accessibilitySupport = options.get(EditorOption.accessibilitySupport);\r\n\t\tif (accessibilitySupport === AccessibilitySupport.Disabled) {\r\n\t\t\treturn nls.localize('accessibilityOffAriaLabel', \"The editor is not accessible at this time. Press {0} for options.\", platform.isLinux ? 'Shift+Alt+F1' : 'Alt+F1');\r\n\t\t}\r\n\t\treturn options.get(EditorOption.ariaLabel);\r\n\t}\r\n\r\n\tprivate _setAccessibilityOptions(options: IComputedEditorOptions): void {\r\n\t\tthis._accessibilitySupport = options.get(EditorOption.accessibilitySupport);\r\n\t\tconst accessibilityPageSize = options.get(EditorOption.accessibilityPageSize);\r\n\t\tif (this._accessibilitySupport === AccessibilitySupport.Enabled && accessibilityPageSize === EditorOptions.accessibilityPageSize.defaultValue) {\r\n\t\t\t// If a screen reader is attached and the default value is not set we shuold automatically increase the page size to 100 for a better experience\r\n\t\t\t// If we put more than 100 lines the nvda can not handle this https://github.com/microsoft/vscode/issues/89717\r\n\t\t\tthis._accessibilityPageSize = 100;\r\n\t\t} else {\r\n\t\t\tthis._accessibilityPageSize = accessibilityPageSize;\r\n\t\t}\r\n\t}\r\n\r\n\t// --- begin event handlers\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\r\n\t\tthis._setAccessibilityOptions(options);\r\n\t\tthis._contentLeft = layoutInfo.contentLeft;\r\n\t\tthis._contentWidth = layoutInfo.contentWidth;\r\n\t\tthis._contentHeight = layoutInfo.height;\r\n\t\tthis._fontInfo = options.get(EditorOption.fontInfo);\r\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tthis._emptySelectionClipboard = options.get(EditorOption.emptySelectionClipboard);\r\n\t\tthis._copyWithSyntaxHighlighting = options.get(EditorOption.copyWithSyntaxHighlighting);\r\n\t\tthis.textArea.setAttribute('aria-label', this._getAriaLabel(options));\r\n\t\tthis.textArea.setAttribute('tabindex', String(options.get(EditorOption.tabIndex)));\r\n\r\n\t\tif (platform.isWeb && e.hasChanged(EditorOption.readOnly)) {\r\n\t\t\tif (options.get(EditorOption.readOnly)) {\r\n\t\t\t\tthis.textArea.setAttribute('readonly', 'true');\r\n\t\t\t} else {\r\n\t\t\t\tthis.textArea.removeAttribute('readonly');\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (e.hasChanged(EditorOption.accessibilitySupport)) {\r\n\t\t\tthis._textAreaInput.writeScreenReaderContent('strategy changed');\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\tpublic onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {\r\n\t\tthis._selections = e.selections.slice(0);\r\n\t\tthis._modelSelections = e.modelSelections.slice(0);\r\n\t\tthis._textAreaInput.writeScreenReaderContent('selection changed');\r\n\t\treturn true;\r\n\t}\r\n\tpublic onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {\r\n\t\t// true for inline decorations that can end up relayouting text\r\n\t\treturn true;\r\n\t}\r\n\tpublic onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\tthis._scrollLeft = e.scrollLeft;\r\n\t\tthis._scrollTop = e.scrollTop;\r\n\t\treturn true;\r\n\t}\r\n\tpublic onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// --- end event handlers\r\n\r\n\t// --- begin view API\r\n\r\n\tpublic isFocused(): boolean {\r\n\t\treturn this._textAreaInput.isFocused();\r\n\t}\r\n\r\n\tpublic focusTextArea(): void {\r\n\t\tthis._textAreaInput.focusTextArea();\r\n\t}\r\n\r\n\tpublic getLastRenderData(): Position | null {\r\n\t\treturn this._lastRenderPosition;\r\n\t}\r\n\r\n\tpublic setAriaOptions(options: IEditorAriaOptions): void {\r\n\t\tif (options.activeDescendant) {\r\n\t\t\tthis.textArea.setAttribute('aria-haspopup', 'true');\r\n\t\t\tthis.textArea.setAttribute('aria-autocomplete', 'list');\r\n\t\t\tthis.textArea.setAttribute('aria-activedescendant', options.activeDescendant);\r\n\t\t} else {\r\n\t\t\tthis.textArea.setAttribute('aria-haspopup', 'false');\r\n\t\t\tthis.textArea.setAttribute('aria-autocomplete', 'both');\r\n\t\t\tthis.textArea.removeAttribute('aria-activedescendant');\r\n\t\t}\r\n\t\tif (options.role) {\r\n\t\t\tthis.textArea.setAttribute('role', options.role);\r\n\t\t}\r\n\t}\r\n\r\n\t// --- end view API\r\n\r\n\tprivate _primaryCursorPosition: Position = new Position(1, 1);\r\n\tprivate _primaryCursorVisibleRange: HorizontalPosition | null = null;\r\n\r\n\tpublic prepareRender(ctx: RenderingContext): void {\r\n\t\tthis._primaryCursorPosition = new Position(this._selections[0].positionLineNumber, this._selections[0].positionColumn);\r\n\t\tthis._primaryCursorVisibleRange = ctx.visibleRangeForPosition(this._primaryCursorPosition);\r\n\t}\r\n\r\n\tpublic render(ctx: RestrictedRenderingContext): void {\r\n\t\tthis._textAreaInput.writeScreenReaderContent('render');\r\n\t\tthis._render();\r\n\t}\r\n\r\n\tprivate _render(): void {\r\n\t\tif (this._visibleTextArea) {\r\n\t\t\t// The text area is visible for composition reasons\r\n\t\t\tthis._renderInsideEditor(\r\n\t\t\t\tnull,\r\n\t\t\t\tthis._visibleTextArea.top - this._scrollTop,\r\n\t\t\t\tthis._contentLeft + this._visibleTextArea.left - this._scrollLeft,\r\n\t\t\t\tthis._visibleTextArea.width,\r\n\t\t\t\tthis._lineHeight\r\n\t\t\t);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!this._primaryCursorVisibleRange) {\r\n\t\t\t// The primary cursor is outside the viewport => place textarea to the top left\r\n\t\t\tthis._renderAtTopLeft();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst left = this._contentLeft + this._primaryCursorVisibleRange.left - this._scrollLeft;\r\n\t\tif (left < this._contentLeft || left > this._contentLeft + this._contentWidth) {\r\n\t\t\t// cursor is outside the viewport\r\n\t\t\tthis._renderAtTopLeft();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst top = this._context.viewLayout.getVerticalOffsetForLineNumber(this._selections[0].positionLineNumber) - this._scrollTop;\r\n\t\tif (top < 0 || top > this._contentHeight) {\r\n\t\t\t// cursor is outside the viewport\r\n\t\t\tthis._renderAtTopLeft();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// The primary cursor is in the viewport (at least vertically) => place textarea on the cursor\r\n\r\n\t\tif (platform.isMacintosh) {\r\n\t\t\t// For the popup emoji input, we will make the text area as high as the line height\r\n\t\t\t// We will also make the fontSize and lineHeight the correct dimensions to help with the placement of these pickers\r\n\t\t\tthis._renderInsideEditor(\r\n\t\t\t\tthis._primaryCursorPosition,\r\n\t\t\t\ttop, left,\r\n\t\t\t\tcanUseZeroSizeTextarea ? 0 : 1, this._lineHeight\r\n\t\t\t);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._renderInsideEditor(\r\n\t\t\tthis._primaryCursorPosition,\r\n\t\t\ttop, left,\r\n\t\t\tcanUseZeroSizeTextarea ? 0 : 1, canUseZeroSizeTextarea ? 0 : 1\r\n\t\t);\r\n\t}\r\n\r\n\tprivate _renderInsideEditor(renderedPosition: Position | null, top: number, left: number, width: number, height: number): void {\r\n\t\tthis._lastRenderPosition = renderedPosition;\r\n\t\tconst ta = this.textArea;\r\n\t\tconst tac = this.textAreaCover;\r\n\r\n\t\tConfiguration.applyFontInfo(ta, this._fontInfo);\r\n\r\n\t\tta.setTop(top);\r\n\t\tta.setLeft(left);\r\n\t\tta.setWidth(width);\r\n\t\tta.setHeight(height);\r\n\r\n\t\ttac.setTop(0);\r\n\t\ttac.setLeft(0);\r\n\t\ttac.setWidth(0);\r\n\t\ttac.setHeight(0);\r\n\t}\r\n\r\n\tprivate _renderAtTopLeft(): void {\r\n\t\tthis._lastRenderPosition = null;\r\n\t\tconst ta = this.textArea;\r\n\t\tconst tac = this.textAreaCover;\r\n\r\n\t\tConfiguration.applyFontInfo(ta, this._fontInfo);\r\n\t\tta.setTop(0);\r\n\t\tta.setLeft(0);\r\n\t\ttac.setTop(0);\r\n\t\ttac.setLeft(0);\r\n\r\n\t\tif (canUseZeroSizeTextarea) {\r\n\t\t\tta.setWidth(0);\r\n\t\t\tta.setHeight(0);\r\n\t\t\ttac.setWidth(0);\r\n\t\t\ttac.setHeight(0);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// (in WebKit the textarea is 1px by 1px because it cannot handle input to a 0x0 textarea)\r\n\t\t// specifically, when doing Korean IME, setting the textarea to 0x0 breaks IME badly.\r\n\r\n\t\tta.setWidth(1);\r\n\t\tta.setHeight(1);\r\n\t\ttac.setWidth(1);\r\n\t\ttac.setHeight(1);\r\n\r\n\t\tconst options = this._context.configuration.options;\r\n\r\n\t\tif (options.get(EditorOption.glyphMargin)) {\r\n\t\t\ttac.setClassName('monaco-editor-background textAreaCover ' + Margin.OUTER_CLASS_NAME);\r\n\t\t} else {\r\n\t\t\tif (options.get(EditorOption.lineNumbers).renderType !== RenderLineNumbersType.Off) {\r\n\t\t\t\ttac.setClassName('monaco-editor-background textAreaCover ' + LineNumbersOverlay.CLASS_NAME);\r\n\t\t\t} else {\r\n\t\t\t\ttac.setClassName('monaco-editor-background textAreaCover');\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction measureText(text: string, fontInfo: BareFontInfo): number {\r\n\t// adjust width by its size\r\n\tconst canvasElem = document.createElement('canvas');\r\n\tconst context = canvasElem.getContext('2d')!;\r\n\tcontext.font = createFontString(fontInfo);\r\n\tconst metrics = context.measureText(text);\r\n\r\n\tif (browser.isFirefox) {\r\n\t\treturn metrics.width + 2; // +2 for Japanese...\r\n\t} else {\r\n\t\treturn metrics.width;\r\n\t}\r\n}\r\n\r\nfunction createFontString(bareFontInfo: BareFontInfo): string {\r\n\treturn doCreateFontString('normal', bareFontInfo.fontWeight, bareFontInfo.fontSize, bareFontInfo.lineHeight, bareFontInfo.fontFamily);\r\n}\r\n\r\nfunction doCreateFontString(fontStyle: string, fontWeight: string, fontSize: number, lineHeight: number, fontFamily: string): string {\r\n\t// The full font syntax is:\r\n\t// style | variant | weight | stretch | size/line-height | fontFamily\r\n\t// (https://developer.mozilla.org/en-US/docs/Web/CSS/font)\r\n\t// But it appears Edge and IE11 cannot properly parse `stretch`.\r\n\treturn `${fontStyle} normal ${fontWeight} ${fontSize}px / ${lineHeight}px ${fontFamily}`;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { ViewPart } from 'vs/editor/browser/view/viewPart';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { IConfiguration } from 'vs/editor/common/editorCommon';\r\nimport { TokenizationRegistry } from 'vs/editor/common/modes';\r\nimport { editorCursorForeground, editorOverviewRulerBorder, editorOverviewRulerBackground } from 'vs/editor/common/view/editorColorRegistry';\r\nimport { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext, EditorTheme } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\nclass Settings {\r\n\r\n\tpublic readonly lineHeight: number;\r\n\tpublic readonly pixelRatio: number;\r\n\tpublic readonly overviewRulerLanes: number;\r\n\r\n\tpublic readonly renderBorder: boolean;\r\n\tpublic readonly borderColor: string | null;\r\n\r\n\tpublic readonly hideCursor: boolean;\r\n\tpublic readonly cursorColor: string | null;\r\n\r\n\tpublic readonly themeType: 'light' | 'dark' | 'hc';\r\n\tpublic readonly backgroundColor: string | null;\r\n\r\n\tpublic readonly top: number;\r\n\tpublic readonly right: number;\r\n\tpublic readonly domWidth: number;\r\n\tpublic readonly domHeight: number;\r\n\tpublic readonly canvasWidth: number;\r\n\tpublic readonly canvasHeight: number;\r\n\r\n\tpublic readonly x: number[];\r\n\tpublic readonly w: number[];\r\n\r\n\tconstructor(config: IConfiguration, theme: EditorTheme) {\r\n\t\tconst options = config.options;\r\n\t\tthis.lineHeight = options.get(EditorOption.lineHeight);\r\n\t\tthis.pixelRatio = options.get(EditorOption.pixelRatio);\r\n\t\tthis.overviewRulerLanes = options.get(EditorOption.overviewRulerLanes);\r\n\r\n\t\tthis.renderBorder = options.get(EditorOption.overviewRulerBorder);\r\n\t\tconst borderColor = theme.getColor(editorOverviewRulerBorder);\r\n\t\tthis.borderColor = borderColor ? borderColor.toString() : null;\r\n\r\n\t\tthis.hideCursor = options.get(EditorOption.hideCursorInOverviewRuler);\r\n\t\tconst cursorColor = theme.getColor(editorCursorForeground);\r\n\t\tthis.cursorColor = cursorColor ? cursorColor.transparent(0.7).toString() : null;\r\n\r\n\t\tthis.themeType = theme.type;\r\n\r\n\t\tconst minimapOpts = options.get(EditorOption.minimap);\r\n\t\tconst minimapEnabled = minimapOpts.enabled;\r\n\t\tconst minimapSide = minimapOpts.side;\r\n\t\tconst backgroundColor = minimapEnabled\r\n\t\t\t? theme.getColor(editorOverviewRulerBackground) || TokenizationRegistry.getDefaultBackground()\r\n\t\t\t: null;\r\n\r\n\t\tif (backgroundColor === null || minimapSide === 'left') {\r\n\t\t\tthis.backgroundColor = null;\r\n\t\t} else {\r\n\t\t\tthis.backgroundColor = Color.Format.CSS.formatHex(backgroundColor);\r\n\t\t}\r\n\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\t\tconst position = layoutInfo.overviewRuler;\r\n\t\tthis.top = position.top;\r\n\t\tthis.right = position.right;\r\n\t\tthis.domWidth = position.width;\r\n\t\tthis.domHeight = position.height;\r\n\t\tif (this.overviewRulerLanes === 0) {\r\n\t\t\t// overview ruler is off\r\n\t\t\tthis.canvasWidth = 0;\r\n\t\t\tthis.canvasHeight = 0;\r\n\t\t} else {\r\n\t\t\tthis.canvasWidth = (this.domWidth * this.pixelRatio) | 0;\r\n\t\t\tthis.canvasHeight = (this.domHeight * this.pixelRatio) | 0;\r\n\t\t}\r\n\r\n\t\tconst [x, w] = this._initLanes(1, this.canvasWidth, this.overviewRulerLanes);\r\n\t\tthis.x = x;\r\n\t\tthis.w = w;\r\n\t}\r\n\r\n\tprivate _initLanes(canvasLeftOffset: number, canvasWidth: number, laneCount: number): [number[], number[]] {\r\n\t\tconst remainingWidth = canvasWidth - canvasLeftOffset;\r\n\r\n\t\tif (laneCount >= 3) {\r\n\t\t\tconst leftWidth = Math.floor(remainingWidth / 3);\r\n\t\t\tconst rightWidth = Math.floor(remainingWidth / 3);\r\n\t\t\tconst centerWidth = remainingWidth - leftWidth - rightWidth;\r\n\t\t\tconst leftOffset = canvasLeftOffset;\r\n\t\t\tconst centerOffset = leftOffset + leftWidth;\r\n\t\t\tconst rightOffset = leftOffset + leftWidth + centerWidth;\r\n\r\n\t\t\treturn [\r\n\t\t\t\t[\r\n\t\t\t\t\t0,\r\n\t\t\t\t\tleftOffset, // Left\r\n\t\t\t\t\tcenterOffset, // Center\r\n\t\t\t\t\tleftOffset, // Left | Center\r\n\t\t\t\t\trightOffset, // Right\r\n\t\t\t\t\tleftOffset, // Left | Right\r\n\t\t\t\t\tcenterOffset, // Center | Right\r\n\t\t\t\t\tleftOffset, // Left | Center | Right\r\n\t\t\t\t], [\r\n\t\t\t\t\t0,\r\n\t\t\t\t\tleftWidth, // Left\r\n\t\t\t\t\tcenterWidth, // Center\r\n\t\t\t\t\tleftWidth + centerWidth, // Left | Center\r\n\t\t\t\t\trightWidth, // Right\r\n\t\t\t\t\tleftWidth + centerWidth + rightWidth, // Left | Right\r\n\t\t\t\t\tcenterWidth + rightWidth, // Center | Right\r\n\t\t\t\t\tleftWidth + centerWidth + rightWidth, // Left | Center | Right\r\n\t\t\t\t]\r\n\t\t\t];\r\n\t\t} else if (laneCount === 2) {\r\n\t\t\tconst leftWidth = Math.floor(remainingWidth / 2);\r\n\t\t\tconst rightWidth = remainingWidth - leftWidth;\r\n\t\t\tconst leftOffset = canvasLeftOffset;\r\n\t\t\tconst rightOffset = leftOffset + leftWidth;\r\n\r\n\t\t\treturn [\r\n\t\t\t\t[\r\n\t\t\t\t\t0,\r\n\t\t\t\t\tleftOffset, // Left\r\n\t\t\t\t\tleftOffset, // Center\r\n\t\t\t\t\tleftOffset, // Left | Center\r\n\t\t\t\t\trightOffset, // Right\r\n\t\t\t\t\tleftOffset, // Left | Right\r\n\t\t\t\t\tleftOffset, // Center | Right\r\n\t\t\t\t\tleftOffset, // Left | Center | Right\r\n\t\t\t\t], [\r\n\t\t\t\t\t0,\r\n\t\t\t\t\tleftWidth, // Left\r\n\t\t\t\t\tleftWidth, // Center\r\n\t\t\t\t\tleftWidth, // Left | Center\r\n\t\t\t\t\trightWidth, // Right\r\n\t\t\t\t\tleftWidth + rightWidth, // Left | Right\r\n\t\t\t\t\tleftWidth + rightWidth, // Center | Right\r\n\t\t\t\t\tleftWidth + rightWidth, // Left | Center | Right\r\n\t\t\t\t]\r\n\t\t\t];\r\n\t\t} else {\r\n\t\t\tconst offset = canvasLeftOffset;\r\n\t\t\tconst width = remainingWidth;\r\n\r\n\t\t\treturn [\r\n\t\t\t\t[\r\n\t\t\t\t\t0,\r\n\t\t\t\t\toffset, // Left\r\n\t\t\t\t\toffset, // Center\r\n\t\t\t\t\toffset, // Left | Center\r\n\t\t\t\t\toffset, // Right\r\n\t\t\t\t\toffset, // Left | Right\r\n\t\t\t\t\toffset, // Center | Right\r\n\t\t\t\t\toffset, // Left | Center | Right\r\n\t\t\t\t], [\r\n\t\t\t\t\t0,\r\n\t\t\t\t\twidth, // Left\r\n\t\t\t\t\twidth, // Center\r\n\t\t\t\t\twidth, // Left | Center\r\n\t\t\t\t\twidth, // Right\r\n\t\t\t\t\twidth, // Left | Right\r\n\t\t\t\t\twidth, // Center | Right\r\n\t\t\t\t\twidth, // Left | Center | Right\r\n\t\t\t\t]\r\n\t\t\t];\r\n\t\t}\r\n\t}\r\n\r\n\tpublic equals(other: Settings): boolean {\r\n\t\treturn (\r\n\t\t\tthis.lineHeight === other.lineHeight\r\n\t\t\t&& this.pixelRatio === other.pixelRatio\r\n\t\t\t&& this.overviewRulerLanes === other.overviewRulerLanes\r\n\t\t\t&& this.renderBorder === other.renderBorder\r\n\t\t\t&& this.borderColor === other.borderColor\r\n\t\t\t&& this.hideCursor === other.hideCursor\r\n\t\t\t&& this.cursorColor === other.cursorColor\r\n\t\t\t&& this.themeType === other.themeType\r\n\t\t\t&& this.backgroundColor === other.backgroundColor\r\n\t\t\t&& this.top === other.top\r\n\t\t\t&& this.right === other.right\r\n\t\t\t&& this.domWidth === other.domWidth\r\n\t\t\t&& this.domHeight === other.domHeight\r\n\t\t\t&& this.canvasWidth === other.canvasWidth\r\n\t\t\t&& this.canvasHeight === other.canvasHeight\r\n\t\t);\r\n\t}\r\n}\r\n\r\nconst enum Constants {\r\n\tMIN_DECORATION_HEIGHT = 6\r\n}\r\n\r\nconst enum OverviewRulerLane {\r\n\tLeft = 1,\r\n\tCenter = 2,\r\n\tRight = 4,\r\n\tFull = 7\r\n}\r\n\r\nexport class DecorationsOverviewRuler extends ViewPart {\r\n\r\n\tprivate readonly _tokensColorTrackerListener: IDisposable;\r\n\tprivate readonly _domNode: FastDomNode;\r\n\tprivate _settings!: Settings;\r\n\tprivate _cursorPositions: Position[];\r\n\r\n\tconstructor(context: ViewContext) {\r\n\t\tsuper(context);\r\n\r\n\t\tthis._domNode = createFastDomNode(document.createElement('canvas'));\r\n\t\tthis._domNode.setClassName('decorationsOverviewRuler');\r\n\t\tthis._domNode.setPosition('absolute');\r\n\t\tthis._domNode.setLayerHinting(true);\r\n\t\tthis._domNode.setContain('strict');\r\n\t\tthis._domNode.setAttribute('aria-hidden', 'true');\r\n\r\n\t\tthis._updateSettings(false);\r\n\r\n\t\tthis._tokensColorTrackerListener = TokenizationRegistry.onDidChange((e) => {\r\n\t\t\tif (e.changedColorMap) {\r\n\t\t\t\tthis._updateSettings(true);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tthis._cursorPositions = [];\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tsuper.dispose();\r\n\t\tthis._tokensColorTrackerListener.dispose();\r\n\t}\r\n\r\n\tprivate _updateSettings(renderNow: boolean): boolean {\r\n\t\tconst newSettings = new Settings(this._context.configuration, this._context.theme);\r\n\t\tif (this._settings && this._settings.equals(newSettings)) {\r\n\t\t\t// nothing to do\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tthis._settings = newSettings;\r\n\r\n\t\tthis._domNode.setTop(this._settings.top);\r\n\t\tthis._domNode.setRight(this._settings.right);\r\n\t\tthis._domNode.setWidth(this._settings.domWidth);\r\n\t\tthis._domNode.setHeight(this._settings.domHeight);\r\n\t\tthis._domNode.domNode.width = this._settings.canvasWidth;\r\n\t\tthis._domNode.domNode.height = this._settings.canvasHeight;\r\n\r\n\t\tif (renderNow) {\r\n\t\t\tthis._render();\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// ---- begin view event handlers\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\treturn this._updateSettings(false);\r\n\t}\r\n\tpublic onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {\r\n\t\tthis._cursorPositions = [];\r\n\t\tfor (let i = 0, len = e.selections.length; i < len; i++) {\r\n\t\t\tthis._cursorPositions[i] = e.selections[i].getPosition();\r\n\t\t}\r\n\t\tthis._cursorPositions.sort(Position.compare);\r\n\t\treturn true;\r\n\t}\r\n\tpublic onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {\r\n\t\tif (e.affectsOverviewRuler) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\tpublic onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\treturn e.scrollHeightChanged;\r\n\t}\r\n\tpublic onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onThemeChanged(e: viewEvents.ViewThemeChangedEvent): boolean {\r\n\t\t// invalidate color cache\r\n\t\tthis._context.model.invalidateOverviewRulerColorCache();\r\n\t\treturn this._updateSettings(false);\r\n\t}\r\n\r\n\t// ---- end view event handlers\r\n\r\n\tpublic getDomNode(): HTMLElement {\r\n\t\treturn this._domNode.domNode;\r\n\t}\r\n\r\n\tpublic prepareRender(ctx: RenderingContext): void {\r\n\t\t// Nothing to read\r\n\t}\r\n\r\n\tpublic render(editorCtx: RestrictedRenderingContext): void {\r\n\t\tthis._render();\r\n\t}\r\n\r\n\tprivate _render(): void {\r\n\t\tif (this._settings.overviewRulerLanes === 0) {\r\n\t\t\t// overview ruler is off\r\n\t\t\tthis._domNode.setBackgroundColor(this._settings.backgroundColor ? this._settings.backgroundColor : '');\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst canvasWidth = this._settings.canvasWidth;\r\n\t\tconst canvasHeight = this._settings.canvasHeight;\r\n\t\tconst lineHeight = this._settings.lineHeight;\r\n\t\tconst viewLayout = this._context.viewLayout;\r\n\t\tconst outerHeight = this._context.viewLayout.getScrollHeight();\r\n\t\tconst heightRatio = canvasHeight / outerHeight;\r\n\t\tconst decorations = this._context.model.getAllOverviewRulerDecorations(this._context.theme);\r\n\r\n\t\tconst minDecorationHeight = (Constants.MIN_DECORATION_HEIGHT * this._settings.pixelRatio) | 0;\r\n\t\tconst halfMinDecorationHeight = (minDecorationHeight / 2) | 0;\r\n\r\n\t\tconst canvasCtx = this._domNode.domNode.getContext('2d')!;\r\n\t\tif (this._settings.backgroundColor === null) {\r\n\t\t\tcanvasCtx.clearRect(0, 0, canvasWidth, canvasHeight);\r\n\t\t} else {\r\n\t\t\tcanvasCtx.fillStyle = this._settings.backgroundColor;\r\n\t\t\tcanvasCtx.fillRect(0, 0, canvasWidth, canvasHeight);\r\n\t\t}\r\n\r\n\t\tconst x = this._settings.x;\r\n\t\tconst w = this._settings.w;\r\n\t\t// Avoid flickering by always rendering the colors in the same order\r\n\t\t// colors that don't use transparency will be sorted last (they start with #)\r\n\t\tconst colors = Object.keys(decorations);\r\n\t\tcolors.sort();\r\n\t\tfor (let cIndex = 0, cLen = colors.length; cIndex < cLen; cIndex++) {\r\n\t\t\tconst color = colors[cIndex];\r\n\r\n\t\t\tconst colorDecorations = decorations[color];\r\n\r\n\t\t\tcanvasCtx.fillStyle = color;\r\n\r\n\t\t\tlet prevLane = 0;\r\n\t\t\tlet prevY1 = 0;\r\n\t\t\tlet prevY2 = 0;\r\n\t\t\tfor (let i = 0, len = colorDecorations.length; i < len; i++) {\r\n\t\t\t\tconst lane = colorDecorations[3 * i];\r\n\t\t\t\tconst startLineNumber = colorDecorations[3 * i + 1];\r\n\t\t\t\tconst endLineNumber = colorDecorations[3 * i + 2];\r\n\r\n\t\t\t\tlet y1 = (viewLayout.getVerticalOffsetForLineNumber(startLineNumber) * heightRatio) | 0;\r\n\t\t\t\tlet y2 = ((viewLayout.getVerticalOffsetForLineNumber(endLineNumber) + lineHeight) * heightRatio) | 0;\r\n\t\t\t\tconst height = y2 - y1;\r\n\t\t\t\tif (height < minDecorationHeight) {\r\n\t\t\t\t\tlet yCenter = ((y1 + y2) / 2) | 0;\r\n\t\t\t\t\tif (yCenter < halfMinDecorationHeight) {\r\n\t\t\t\t\t\tyCenter = halfMinDecorationHeight;\r\n\t\t\t\t\t} else if (yCenter + halfMinDecorationHeight > canvasHeight) {\r\n\t\t\t\t\t\tyCenter = canvasHeight - halfMinDecorationHeight;\r\n\t\t\t\t\t}\r\n\t\t\t\t\ty1 = yCenter - halfMinDecorationHeight;\r\n\t\t\t\t\ty2 = yCenter + halfMinDecorationHeight;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (y1 > prevY2 + 1 || lane !== prevLane) {\r\n\t\t\t\t\t// flush prev\r\n\t\t\t\t\tif (i !== 0) {\r\n\t\t\t\t\t\tcanvasCtx.fillRect(x[prevLane], prevY1, w[prevLane], prevY2 - prevY1);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tprevLane = lane;\r\n\t\t\t\t\tprevY1 = y1;\r\n\t\t\t\t\tprevY2 = y2;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// merge into prev\r\n\t\t\t\t\tif (y2 > prevY2) {\r\n\t\t\t\t\t\tprevY2 = y2;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tcanvasCtx.fillRect(x[prevLane], prevY1, w[prevLane], prevY2 - prevY1);\r\n\t\t}\r\n\r\n\t\t// Draw cursors\r\n\t\tif (!this._settings.hideCursor && this._settings.cursorColor) {\r\n\t\t\tconst cursorHeight = (2 * this._settings.pixelRatio) | 0;\r\n\t\t\tconst halfCursorHeight = (cursorHeight / 2) | 0;\r\n\t\t\tconst cursorX = this._settings.x[OverviewRulerLane.Full];\r\n\t\t\tconst cursorW = this._settings.w[OverviewRulerLane.Full];\r\n\t\t\tcanvasCtx.fillStyle = this._settings.cursorColor;\r\n\r\n\t\t\tlet prevY1 = -100;\r\n\t\t\tlet prevY2 = -100;\r\n\t\t\tfor (let i = 0, len = this._cursorPositions.length; i < len; i++) {\r\n\t\t\t\tconst cursor = this._cursorPositions[i];\r\n\r\n\t\t\t\tlet yCenter = (viewLayout.getVerticalOffsetForLineNumber(cursor.lineNumber) * heightRatio) | 0;\r\n\t\t\t\tif (yCenter < halfCursorHeight) {\r\n\t\t\t\t\tyCenter = halfCursorHeight;\r\n\t\t\t\t} else if (yCenter + halfCursorHeight > canvasHeight) {\r\n\t\t\t\t\tyCenter = canvasHeight - halfCursorHeight;\r\n\t\t\t\t}\r\n\t\t\t\tconst y1 = yCenter - halfCursorHeight;\r\n\t\t\t\tconst y2 = y1 + cursorHeight;\r\n\r\n\t\t\t\tif (y1 > prevY2 + 1) {\r\n\t\t\t\t\t// flush prev\r\n\t\t\t\t\tif (i !== 0) {\r\n\t\t\t\t\t\tcanvasCtx.fillRect(cursorX, prevY1, cursorW, prevY2 - prevY1);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tprevY1 = y1;\r\n\t\t\t\t\tprevY2 = y2;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// merge into prev\r\n\t\t\t\t\tif (y2 > prevY2) {\r\n\t\t\t\t\t\tprevY2 = y2;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tcanvasCtx.fillRect(cursorX, prevY1, cursorW, prevY2 - prevY1);\r\n\t\t}\r\n\r\n\t\tif (this._settings.renderBorder && this._settings.borderColor && this._settings.overviewRulerLanes > 0) {\r\n\t\t\tcanvasCtx.beginPath();\r\n\t\t\tcanvasCtx.lineWidth = 1;\r\n\t\t\tcanvasCtx.strokeStyle = this._settings.borderColor;\r\n\t\t\tcanvasCtx.moveTo(0, 0);\r\n\t\t\tcanvasCtx.lineTo(0, canvasHeight);\r\n\t\t\tcanvasCtx.stroke();\r\n\r\n\t\t\tcanvasCtx.moveTo(0, 0);\r\n\t\t\tcanvasCtx.lineTo(canvasWidth, 0);\r\n\t\t\tcanvasCtx.stroke();\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./rulers';\r\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { ViewPart } from 'vs/editor/browser/view/viewPart';\r\nimport { editorRuler } from 'vs/editor/common/view/editorColorRegistry';\r\nimport { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { registerThemingParticipant } from 'vs/platform/theme/common/themeService';\r\nimport { EditorOption, IRulerOption } from 'vs/editor/common/config/editorOptions';\r\n\r\nexport class Rulers extends ViewPart {\r\n\r\n\tpublic domNode: FastDomNode;\r\n\tprivate readonly _renderedRulers: FastDomNode[];\r\n\tprivate _rulers: IRulerOption[];\r\n\tprivate _typicalHalfwidthCharacterWidth: number;\r\n\r\n\tconstructor(context: ViewContext) {\r\n\t\tsuper(context);\r\n\t\tthis.domNode = createFastDomNode(document.createElement('div'));\r\n\t\tthis.domNode.setAttribute('role', 'presentation');\r\n\t\tthis.domNode.setAttribute('aria-hidden', 'true');\r\n\t\tthis.domNode.setClassName('view-rulers');\r\n\t\tthis._renderedRulers = [];\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tthis._rulers = options.get(EditorOption.rulers);\r\n\t\tthis._typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\t// --- begin event handlers\r\n\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tthis._rulers = options.get(EditorOption.rulers);\r\n\t\tthis._typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth;\r\n\t\treturn true;\r\n\t}\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\treturn e.scrollHeightChanged;\r\n\t}\r\n\r\n\t// --- end event handlers\r\n\r\n\tpublic prepareRender(ctx: RenderingContext): void {\r\n\t\t// Nothing to read\r\n\t}\r\n\r\n\tprivate _ensureRulersCount(): void {\r\n\t\tconst currentCount = this._renderedRulers.length;\r\n\t\tconst desiredCount = this._rulers.length;\r\n\r\n\t\tif (currentCount === desiredCount) {\r\n\t\t\t// Nothing to do\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (currentCount < desiredCount) {\r\n\t\t\tconst { tabSize } = this._context.model.getTextModelOptions();\r\n\t\t\tconst rulerWidth = tabSize;\r\n\t\t\tlet addCount = desiredCount - currentCount;\r\n\t\t\twhile (addCount > 0) {\r\n\t\t\t\tconst node = createFastDomNode(document.createElement('div'));\r\n\t\t\t\tnode.setClassName('view-ruler');\r\n\t\t\t\tnode.setWidth(rulerWidth);\r\n\t\t\t\tthis.domNode.appendChild(node);\r\n\t\t\t\tthis._renderedRulers.push(node);\r\n\t\t\t\taddCount--;\r\n\t\t\t}\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet removeCount = currentCount - desiredCount;\r\n\t\twhile (removeCount > 0) {\r\n\t\t\tconst node = this._renderedRulers.pop()!;\r\n\t\t\tthis.domNode.removeChild(node);\r\n\t\t\tremoveCount--;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic render(ctx: RestrictedRenderingContext): void {\r\n\r\n\t\tthis._ensureRulersCount();\r\n\r\n\t\tfor (let i = 0, len = this._rulers.length; i < len; i++) {\r\n\t\t\tconst node = this._renderedRulers[i];\r\n\t\t\tconst ruler = this._rulers[i];\r\n\r\n\t\t\tnode.setBoxShadow(ruler.color ? `1px 0 0 0 ${ruler.color} inset` : ``);\r\n\t\t\tnode.setHeight(Math.min(ctx.scrollHeight, 1000000));\r\n\t\t\tnode.setLeft(ruler.column * this._typicalHalfwidthCharacterWidth);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst rulerColor = theme.getColor(editorRuler);\r\n\tif (rulerColor) {\r\n\t\tcollector.addRule(`.monaco-editor .view-ruler { box-shadow: 1px 0 0 0 ${rulerColor} inset; }`);\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./viewCursors';\r\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { IntervalTimer, TimeoutTimer } from 'vs/base/common/async';\r\nimport { ViewPart } from 'vs/editor/browser/view/viewPart';\r\nimport { IViewCursorRenderData, ViewCursor } from 'vs/editor/browser/viewParts/viewCursors/viewCursor';\r\nimport { TextEditorCursorBlinkingStyle, TextEditorCursorStyle, EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { editorCursorBackground, editorCursorForeground } from 'vs/editor/common/view/editorColorRegistry';\r\nimport { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { registerThemingParticipant } from 'vs/platform/theme/common/themeService';\r\n\r\nexport class ViewCursors extends ViewPart {\r\n\r\n\tstatic readonly BLINK_INTERVAL = 500;\r\n\r\n\tprivate _readOnly: boolean;\r\n\tprivate _cursorBlinking: TextEditorCursorBlinkingStyle;\r\n\tprivate _cursorStyle: TextEditorCursorStyle;\r\n\tprivate _cursorSmoothCaretAnimation: boolean;\r\n\tprivate _selectionIsEmpty: boolean;\r\n\tprivate _isComposingInput: boolean;\r\n\r\n\tprivate _isVisible: boolean;\r\n\r\n\tprivate readonly _domNode: FastDomNode;\r\n\r\n\tprivate readonly _startCursorBlinkAnimation: TimeoutTimer;\r\n\tprivate readonly _cursorFlatBlinkInterval: IntervalTimer;\r\n\tprivate _blinkingEnabled: boolean;\r\n\r\n\tprivate _editorHasFocus: boolean;\r\n\r\n\tprivate readonly _primaryCursor: ViewCursor;\r\n\tprivate readonly _secondaryCursors: ViewCursor[];\r\n\tprivate _renderData: IViewCursorRenderData[];\r\n\r\n\tconstructor(context: ViewContext) {\r\n\t\tsuper(context);\r\n\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tthis._readOnly = options.get(EditorOption.readOnly);\r\n\t\tthis._cursorBlinking = options.get(EditorOption.cursorBlinking);\r\n\t\tthis._cursorStyle = options.get(EditorOption.cursorStyle);\r\n\t\tthis._cursorSmoothCaretAnimation = options.get(EditorOption.cursorSmoothCaretAnimation);\r\n\t\tthis._selectionIsEmpty = true;\r\n\t\tthis._isComposingInput = false;\r\n\r\n\t\tthis._isVisible = false;\r\n\r\n\t\tthis._primaryCursor = new ViewCursor(this._context);\r\n\t\tthis._secondaryCursors = [];\r\n\t\tthis._renderData = [];\r\n\r\n\t\tthis._domNode = createFastDomNode(document.createElement('div'));\r\n\t\tthis._domNode.setAttribute('role', 'presentation');\r\n\t\tthis._domNode.setAttribute('aria-hidden', 'true');\r\n\t\tthis._updateDomClassName();\r\n\r\n\t\tthis._domNode.appendChild(this._primaryCursor.getDomNode());\r\n\r\n\t\tthis._startCursorBlinkAnimation = new TimeoutTimer();\r\n\t\tthis._cursorFlatBlinkInterval = new IntervalTimer();\r\n\r\n\t\tthis._blinkingEnabled = false;\r\n\r\n\t\tthis._editorHasFocus = false;\r\n\t\tthis._updateBlinking();\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tsuper.dispose();\r\n\t\tthis._startCursorBlinkAnimation.dispose();\r\n\t\tthis._cursorFlatBlinkInterval.dispose();\r\n\t}\r\n\r\n\tpublic getDomNode(): FastDomNode {\r\n\t\treturn this._domNode;\r\n\t}\r\n\r\n\t// --- begin event handlers\r\n\tpublic onCompositionStart(e: viewEvents.ViewCompositionStartEvent): boolean {\r\n\t\tthis._isComposingInput = true;\r\n\t\tthis._updateBlinking();\r\n\t\treturn true;\r\n\t}\r\n\tpublic onCompositionEnd(e: viewEvents.ViewCompositionEndEvent): boolean {\r\n\t\tthis._isComposingInput = false;\r\n\t\tthis._updateBlinking();\r\n\t\treturn true;\r\n\t}\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tconst options = this._context.configuration.options;\r\n\r\n\t\tthis._readOnly = options.get(EditorOption.readOnly);\r\n\t\tthis._cursorBlinking = options.get(EditorOption.cursorBlinking);\r\n\t\tthis._cursorStyle = options.get(EditorOption.cursorStyle);\r\n\t\tthis._cursorSmoothCaretAnimation = options.get(EditorOption.cursorSmoothCaretAnimation);\r\n\r\n\t\tthis._updateBlinking();\r\n\t\tthis._updateDomClassName();\r\n\r\n\t\tthis._primaryCursor.onConfigurationChanged(e);\r\n\t\tfor (let i = 0, len = this._secondaryCursors.length; i < len; i++) {\r\n\t\t\tthis._secondaryCursors[i].onConfigurationChanged(e);\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\tprivate _onCursorPositionChanged(position: Position, secondaryPositions: Position[]): void {\r\n\t\tthis._primaryCursor.onCursorPositionChanged(position);\r\n\t\tthis._updateBlinking();\r\n\r\n\t\tif (this._secondaryCursors.length < secondaryPositions.length) {\r\n\t\t\t// Create new cursors\r\n\t\t\tconst addCnt = secondaryPositions.length - this._secondaryCursors.length;\r\n\t\t\tfor (let i = 0; i < addCnt; i++) {\r\n\t\t\t\tconst newCursor = new ViewCursor(this._context);\r\n\t\t\t\tthis._domNode.domNode.insertBefore(newCursor.getDomNode().domNode, this._primaryCursor.getDomNode().domNode.nextSibling);\r\n\t\t\t\tthis._secondaryCursors.push(newCursor);\r\n\t\t\t}\r\n\t\t} else if (this._secondaryCursors.length > secondaryPositions.length) {\r\n\t\t\t// Remove some cursors\r\n\t\t\tconst removeCnt = this._secondaryCursors.length - secondaryPositions.length;\r\n\t\t\tfor (let i = 0; i < removeCnt; i++) {\r\n\t\t\t\tthis._domNode.removeChild(this._secondaryCursors[0].getDomNode());\r\n\t\t\t\tthis._secondaryCursors.splice(0, 1);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tfor (let i = 0; i < secondaryPositions.length; i++) {\r\n\t\t\tthis._secondaryCursors[i].onCursorPositionChanged(secondaryPositions[i]);\r\n\t\t}\r\n\r\n\t}\r\n\tpublic onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {\r\n\t\tconst positions: Position[] = [];\r\n\t\tfor (let i = 0, len = e.selections.length; i < len; i++) {\r\n\t\t\tpositions[i] = e.selections[i].getPosition();\r\n\t\t}\r\n\t\tthis._onCursorPositionChanged(positions[0], positions.slice(1));\r\n\r\n\t\tconst selectionIsEmpty = e.selections[0].isEmpty();\r\n\t\tif (this._selectionIsEmpty !== selectionIsEmpty) {\r\n\t\t\tthis._selectionIsEmpty = selectionIsEmpty;\r\n\t\t\tthis._updateDomClassName();\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {\r\n\t\t// true for inline decorations that can end up relayouting text\r\n\t\treturn true;\r\n\t}\r\n\tpublic onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onFocusChanged(e: viewEvents.ViewFocusChangedEvent): boolean {\r\n\t\tthis._editorHasFocus = e.isFocused;\r\n\t\tthis._updateBlinking();\r\n\t\treturn false;\r\n\t}\r\n\tpublic onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\tpublic onTokensChanged(e: viewEvents.ViewTokensChangedEvent): boolean {\r\n\t\tconst shouldRender = (position: Position) => {\r\n\t\t\tfor (let i = 0, len = e.ranges.length; i < len; i++) {\r\n\t\t\t\tif (e.ranges[i].fromLineNumber <= position.lineNumber && position.lineNumber <= e.ranges[i].toLineNumber) {\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn false;\r\n\t\t};\r\n\t\tif (shouldRender(this._primaryCursor.getPosition())) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tfor (const secondaryCursor of this._secondaryCursors) {\r\n\t\t\tif (shouldRender(secondaryCursor.getPosition())) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\tpublic onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// --- end event handlers\r\n\r\n\t// ---- blinking logic\r\n\r\n\tprivate _getCursorBlinking(): TextEditorCursorBlinkingStyle {\r\n\t\tif (this._isComposingInput) {\r\n\t\t\t// avoid double cursors\r\n\t\t\treturn TextEditorCursorBlinkingStyle.Hidden;\r\n\t\t}\r\n\t\tif (!this._editorHasFocus) {\r\n\t\t\treturn TextEditorCursorBlinkingStyle.Hidden;\r\n\t\t}\r\n\t\tif (this._readOnly) {\r\n\t\t\treturn TextEditorCursorBlinkingStyle.Solid;\r\n\t\t}\r\n\t\treturn this._cursorBlinking;\r\n\t}\r\n\r\n\tprivate _updateBlinking(): void {\r\n\t\tthis._startCursorBlinkAnimation.cancel();\r\n\t\tthis._cursorFlatBlinkInterval.cancel();\r\n\r\n\t\tconst blinkingStyle = this._getCursorBlinking();\r\n\r\n\t\t// hidden and solid are special as they involve no animations\r\n\t\tconst isHidden = (blinkingStyle === TextEditorCursorBlinkingStyle.Hidden);\r\n\t\tconst isSolid = (blinkingStyle === TextEditorCursorBlinkingStyle.Solid);\r\n\r\n\t\tif (isHidden) {\r\n\t\t\tthis._hide();\r\n\t\t} else {\r\n\t\t\tthis._show();\r\n\t\t}\r\n\r\n\t\tthis._blinkingEnabled = false;\r\n\t\tthis._updateDomClassName();\r\n\r\n\t\tif (!isHidden && !isSolid) {\r\n\t\t\tif (blinkingStyle === TextEditorCursorBlinkingStyle.Blink) {\r\n\t\t\t\t// flat blinking is handled by JavaScript to save battery life due to Chromium step timing issue https://bugs.chromium.org/p/chromium/issues/detail?id=361587\r\n\t\t\t\tthis._cursorFlatBlinkInterval.cancelAndSet(() => {\r\n\t\t\t\t\tif (this._isVisible) {\r\n\t\t\t\t\t\tthis._hide();\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tthis._show();\r\n\t\t\t\t\t}\r\n\t\t\t\t}, ViewCursors.BLINK_INTERVAL);\r\n\t\t\t} else {\r\n\t\t\t\tthis._startCursorBlinkAnimation.setIfNotSet(() => {\r\n\t\t\t\t\tthis._blinkingEnabled = true;\r\n\t\t\t\t\tthis._updateDomClassName();\r\n\t\t\t\t}, ViewCursors.BLINK_INTERVAL);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\t// --- end blinking logic\r\n\r\n\tprivate _updateDomClassName(): void {\r\n\t\tthis._domNode.setClassName(this._getClassName());\r\n\t}\r\n\r\n\tprivate _getClassName(): string {\r\n\t\tlet result = 'cursors-layer';\r\n\t\tif (!this._selectionIsEmpty) {\r\n\t\t\tresult += ' has-selection';\r\n\t\t}\r\n\t\tswitch (this._cursorStyle) {\r\n\t\t\tcase TextEditorCursorStyle.Line:\r\n\t\t\t\tresult += ' cursor-line-style';\r\n\t\t\t\tbreak;\r\n\t\t\tcase TextEditorCursorStyle.Block:\r\n\t\t\t\tresult += ' cursor-block-style';\r\n\t\t\t\tbreak;\r\n\t\t\tcase TextEditorCursorStyle.Underline:\r\n\t\t\t\tresult += ' cursor-underline-style';\r\n\t\t\t\tbreak;\r\n\t\t\tcase TextEditorCursorStyle.LineThin:\r\n\t\t\t\tresult += ' cursor-line-thin-style';\r\n\t\t\t\tbreak;\r\n\t\t\tcase TextEditorCursorStyle.BlockOutline:\r\n\t\t\t\tresult += ' cursor-block-outline-style';\r\n\t\t\t\tbreak;\r\n\t\t\tcase TextEditorCursorStyle.UnderlineThin:\r\n\t\t\t\tresult += ' cursor-underline-thin-style';\r\n\t\t\t\tbreak;\r\n\t\t\tdefault:\r\n\t\t\t\tresult += ' cursor-line-style';\r\n\t\t}\r\n\t\tif (this._blinkingEnabled) {\r\n\t\t\tswitch (this._getCursorBlinking()) {\r\n\t\t\t\tcase TextEditorCursorBlinkingStyle.Blink:\r\n\t\t\t\t\tresult += ' cursor-blink';\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase TextEditorCursorBlinkingStyle.Smooth:\r\n\t\t\t\t\tresult += ' cursor-smooth';\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase TextEditorCursorBlinkingStyle.Phase:\r\n\t\t\t\t\tresult += ' cursor-phase';\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase TextEditorCursorBlinkingStyle.Expand:\r\n\t\t\t\t\tresult += ' cursor-expand';\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase TextEditorCursorBlinkingStyle.Solid:\r\n\t\t\t\t\tresult += ' cursor-solid';\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tdefault:\r\n\t\t\t\t\tresult += ' cursor-solid';\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tresult += ' cursor-solid';\r\n\t\t}\r\n\t\tif (this._cursorSmoothCaretAnimation) {\r\n\t\t\tresult += ' cursor-smooth-caret-animation';\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate _show(): void {\r\n\t\tthis._primaryCursor.show();\r\n\t\tfor (let i = 0, len = this._secondaryCursors.length; i < len; i++) {\r\n\t\t\tthis._secondaryCursors[i].show();\r\n\t\t}\r\n\t\tthis._isVisible = true;\r\n\t}\r\n\r\n\tprivate _hide(): void {\r\n\t\tthis._primaryCursor.hide();\r\n\t\tfor (let i = 0, len = this._secondaryCursors.length; i < len; i++) {\r\n\t\t\tthis._secondaryCursors[i].hide();\r\n\t\t}\r\n\t\tthis._isVisible = false;\r\n\t}\r\n\r\n\t// ---- IViewPart implementation\r\n\r\n\tpublic prepareRender(ctx: RenderingContext): void {\r\n\t\tthis._primaryCursor.prepareRender(ctx);\r\n\t\tfor (let i = 0, len = this._secondaryCursors.length; i < len; i++) {\r\n\t\t\tthis._secondaryCursors[i].prepareRender(ctx);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic render(ctx: RestrictedRenderingContext): void {\r\n\t\tlet renderData: IViewCursorRenderData[] = [], renderDataLen = 0;\r\n\r\n\t\tconst primaryRenderData = this._primaryCursor.render(ctx);\r\n\t\tif (primaryRenderData) {\r\n\t\t\trenderData[renderDataLen++] = primaryRenderData;\r\n\t\t}\r\n\r\n\t\tfor (let i = 0, len = this._secondaryCursors.length; i < len; i++) {\r\n\t\t\tconst secondaryRenderData = this._secondaryCursors[i].render(ctx);\r\n\t\t\tif (secondaryRenderData) {\r\n\t\t\t\trenderData[renderDataLen++] = secondaryRenderData;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._renderData = renderData;\r\n\t}\r\n\r\n\tpublic getLastRenderData(): IViewCursorRenderData[] {\r\n\t\treturn this._renderData;\r\n\t}\r\n}\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst caret = theme.getColor(editorCursorForeground);\r\n\tif (caret) {\r\n\t\tlet caretBackground = theme.getColor(editorCursorBackground);\r\n\t\tif (!caretBackground) {\r\n\t\t\tcaretBackground = caret.opposite();\r\n\t\t}\r\n\t\tcollector.addRule(`.monaco-editor .cursors-layer .cursor { background-color: ${caret}; border-color: ${caret}; color: ${caretBackground}; }`);\r\n\t\tif (theme.type === 'hc') {\r\n\t\t\tcollector.addRule(`.monaco-editor .cursors-layer.has-selection .cursor { border-left: 1px solid ${caretBackground}; border-right: 1px solid ${caretBackground}; }`);\r\n\t\t}\r\n\t}\r\n\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IMarkerService, IMarker, MarkerSeverity, MarkerTag } from 'vs/platform/markers/common/markers';\r\nimport { Disposable, toDisposable } from 'vs/base/common/lifecycle';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { IModelDeltaDecoration, ITextModel, IModelDecorationOptions, TrackedRangeStickiness, OverviewRulerLane, IModelDecoration, MinimapPosition, IModelDecorationMinimapOptions } from 'vs/editor/common/model';\r\nimport { ClassName } from 'vs/editor/common/model/intervalTree';\r\nimport { themeColorFromId, ThemeColor } from 'vs/platform/theme/common/themeService';\r\nimport { overviewRulerWarning, overviewRulerInfo, overviewRulerError } from 'vs/editor/common/view/editorColorRegistry';\r\nimport { IModelService } from 'vs/editor/common/services/modelService';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService';\r\nimport { Schemas } from 'vs/base/common/network';\r\nimport { Emitter } from 'vs/base/common/event';\r\nimport { minimapWarning, minimapError } from 'vs/platform/theme/common/colorRegistry';\r\n\r\nfunction MODEL_ID(resource: URI): string {\r\n\treturn resource.toString();\r\n}\r\n\r\nclass MarkerDecorations extends Disposable {\r\n\r\n\tprivate readonly _markersData: Map = new Map();\r\n\r\n\tconstructor(\r\n\t\treadonly model: ITextModel\r\n\t) {\r\n\t\tsuper();\r\n\t\tthis._register(toDisposable(() => {\r\n\t\t\tthis.model.deltaDecorations([...this._markersData.keys()], []);\r\n\t\t\tthis._markersData.clear();\r\n\t\t}));\r\n\t}\r\n\r\n\tpublic update(markers: IMarker[], newDecorations: IModelDeltaDecoration[]): boolean {\r\n\t\tconst oldIds = [...this._markersData.keys()];\r\n\t\tthis._markersData.clear();\r\n\t\tconst ids = this.model.deltaDecorations(oldIds, newDecorations);\r\n\t\tfor (let index = 0; index < ids.length; index++) {\r\n\t\t\tthis._markersData.set(ids[index], markers[index]);\r\n\t\t}\r\n\t\treturn oldIds.length !== 0 || ids.length !== 0;\r\n\t}\r\n\r\n\tgetMarker(decoration: IModelDecoration): IMarker | undefined {\r\n\t\treturn this._markersData.get(decoration.id);\r\n\t}\r\n}\r\n\r\nexport class MarkerDecorationsService extends Disposable implements IMarkerDecorationsService {\r\n\r\n\tdeclare readonly _serviceBrand: undefined;\r\n\r\n\tprivate readonly _onDidChangeMarker = this._register(new Emitter());\r\n\r\n\tprivate readonly _markerDecorations = new Map();\r\n\r\n\tconstructor(\r\n\t\t@IModelService modelService: IModelService,\r\n\t\t@IMarkerService private readonly _markerService: IMarkerService\r\n\t) {\r\n\t\tsuper();\r\n\t\tmodelService.getModels().forEach(model => this._onModelAdded(model));\r\n\t\tthis._register(modelService.onModelAdded(this._onModelAdded, this));\r\n\t\tthis._register(modelService.onModelRemoved(this._onModelRemoved, this));\r\n\t\tthis._register(this._markerService.onMarkerChanged(this._handleMarkerChange, this));\r\n\t}\r\n\r\n\tdispose() {\r\n\t\tsuper.dispose();\r\n\t\tthis._markerDecorations.forEach(value => value.dispose());\r\n\t\tthis._markerDecorations.clear();\r\n\t}\r\n\r\n\tgetMarker(uri: URI, decoration: IModelDecoration): IMarker | null {\r\n\t\tconst markerDecorations = this._markerDecorations.get(MODEL_ID(uri));\r\n\t\treturn markerDecorations ? (markerDecorations.getMarker(decoration) || null) : null;\r\n\t}\r\n\r\n\tprivate _handleMarkerChange(changedResources: readonly URI[]): void {\r\n\t\tchangedResources.forEach((resource) => {\r\n\t\t\tconst markerDecorations = this._markerDecorations.get(MODEL_ID(resource));\r\n\t\t\tif (markerDecorations) {\r\n\t\t\t\tthis._updateDecorations(markerDecorations);\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _onModelAdded(model: ITextModel): void {\r\n\t\tconst markerDecorations = new MarkerDecorations(model);\r\n\t\tthis._markerDecorations.set(MODEL_ID(model.uri), markerDecorations);\r\n\t\tthis._updateDecorations(markerDecorations);\r\n\t}\r\n\r\n\tprivate _onModelRemoved(model: ITextModel): void {\r\n\t\tconst markerDecorations = this._markerDecorations.get(MODEL_ID(model.uri));\r\n\t\tif (markerDecorations) {\r\n\t\t\tmarkerDecorations.dispose();\r\n\t\t\tthis._markerDecorations.delete(MODEL_ID(model.uri));\r\n\t\t}\r\n\r\n\t\t// clean up markers for internal, transient models\r\n\t\tif (model.uri.scheme === Schemas.inMemory\r\n\t\t\t|| model.uri.scheme === Schemas.internal\r\n\t\t\t|| model.uri.scheme === Schemas.vscode) {\r\n\t\t\tif (this._markerService) {\r\n\t\t\t\tthis._markerService.read({ resource: model.uri }).map(marker => marker.owner).forEach(owner => this._markerService.remove(owner, [model.uri]));\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _updateDecorations(markerDecorations: MarkerDecorations): void {\r\n\t\t// Limit to the first 500 errors/warnings\r\n\t\tconst markers = this._markerService.read({ resource: markerDecorations.model.uri, take: 500 });\r\n\t\tlet newModelDecorations: IModelDeltaDecoration[] = markers.map((marker) => {\r\n\t\t\treturn {\r\n\t\t\t\trange: this._createDecorationRange(markerDecorations.model, marker),\r\n\t\t\t\toptions: this._createDecorationOption(marker)\r\n\t\t\t};\r\n\t\t});\r\n\t\tif (markerDecorations.update(markers, newModelDecorations)) {\r\n\t\t\tthis._onDidChangeMarker.fire(markerDecorations.model);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _createDecorationRange(model: ITextModel, rawMarker: IMarker): Range {\r\n\r\n\t\tlet ret = Range.lift(rawMarker);\r\n\r\n\t\tif (rawMarker.severity === MarkerSeverity.Hint && !this._hasMarkerTag(rawMarker, MarkerTag.Unnecessary) && !this._hasMarkerTag(rawMarker, MarkerTag.Deprecated)) {\r\n\t\t\t// * never render hints on multiple lines\r\n\t\t\t// * make enough space for three dots\r\n\t\t\tret = ret.setEndPosition(ret.startLineNumber, ret.startColumn + 2);\r\n\t\t}\r\n\r\n\t\tret = model.validateRange(ret);\r\n\r\n\t\tif (ret.isEmpty()) {\r\n\t\t\tlet word = model.getWordAtPosition(ret.getStartPosition());\r\n\t\t\tif (word) {\r\n\t\t\t\tret = new Range(ret.startLineNumber, word.startColumn, ret.endLineNumber, word.endColumn);\r\n\t\t\t} else {\r\n\t\t\t\tlet maxColumn = model.getLineLastNonWhitespaceColumn(ret.startLineNumber) ||\r\n\t\t\t\t\tmodel.getLineMaxColumn(ret.startLineNumber);\r\n\r\n\t\t\t\tif (maxColumn === 1) {\r\n\t\t\t\t\t// empty line\r\n\t\t\t\t\t// console.warn('marker on empty line:', marker);\r\n\t\t\t\t} else if (ret.endColumn >= maxColumn) {\r\n\t\t\t\t\t// behind eol\r\n\t\t\t\t\tret = new Range(ret.startLineNumber, maxColumn - 1, ret.endLineNumber, maxColumn);\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// extend marker to width = 1\r\n\t\t\t\t\tret = new Range(ret.startLineNumber, ret.startColumn, ret.endLineNumber, ret.endColumn + 1);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else if (rawMarker.endColumn === Number.MAX_VALUE && rawMarker.startColumn === 1 && ret.startLineNumber === ret.endLineNumber) {\r\n\t\t\tlet minColumn = model.getLineFirstNonWhitespaceColumn(rawMarker.startLineNumber);\r\n\t\t\tif (minColumn < ret.endColumn) {\r\n\t\t\t\tret = new Range(ret.startLineNumber, minColumn, ret.endLineNumber, ret.endColumn);\r\n\t\t\t\trawMarker.startColumn = minColumn;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn ret;\r\n\t}\r\n\r\n\tprivate _createDecorationOption(marker: IMarker): IModelDecorationOptions {\r\n\r\n\t\tlet className: string | undefined;\r\n\t\tlet color: ThemeColor | undefined = undefined;\r\n\t\tlet zIndex: number;\r\n\t\tlet inlineClassName: string | undefined = undefined;\r\n\t\tlet minimap: IModelDecorationMinimapOptions | undefined;\r\n\r\n\t\tswitch (marker.severity) {\r\n\t\t\tcase MarkerSeverity.Hint:\r\n\t\t\t\tif (this._hasMarkerTag(marker, MarkerTag.Deprecated)) {\r\n\t\t\t\t\tclassName = undefined;\r\n\t\t\t\t} else if (this._hasMarkerTag(marker, MarkerTag.Unnecessary)) {\r\n\t\t\t\t\tclassName = ClassName.EditorUnnecessaryDecoration;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tclassName = ClassName.EditorHintDecoration;\r\n\t\t\t\t}\r\n\t\t\t\tzIndex = 0;\r\n\t\t\t\tbreak;\r\n\t\t\tcase MarkerSeverity.Warning:\r\n\t\t\t\tclassName = ClassName.EditorWarningDecoration;\r\n\t\t\t\tcolor = themeColorFromId(overviewRulerWarning);\r\n\t\t\t\tzIndex = 20;\r\n\t\t\t\tminimap = {\r\n\t\t\t\t\tcolor: themeColorFromId(minimapWarning),\r\n\t\t\t\t\tposition: MinimapPosition.Inline\r\n\t\t\t\t};\r\n\t\t\t\tbreak;\r\n\t\t\tcase MarkerSeverity.Info:\r\n\t\t\t\tclassName = ClassName.EditorInfoDecoration;\r\n\t\t\t\tcolor = themeColorFromId(overviewRulerInfo);\r\n\t\t\t\tzIndex = 10;\r\n\t\t\t\tbreak;\r\n\t\t\tcase MarkerSeverity.Error:\r\n\t\t\tdefault:\r\n\t\t\t\tclassName = ClassName.EditorErrorDecoration;\r\n\t\t\t\tcolor = themeColorFromId(overviewRulerError);\r\n\t\t\t\tzIndex = 30;\r\n\t\t\t\tminimap = {\r\n\t\t\t\t\tcolor: themeColorFromId(minimapError),\r\n\t\t\t\t\tposition: MinimapPosition.Inline\r\n\t\t\t\t};\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tif (marker.tags) {\r\n\t\t\tif (marker.tags.indexOf(MarkerTag.Unnecessary) !== -1) {\r\n\t\t\t\tinlineClassName = ClassName.EditorUnnecessaryInlineDecoration;\r\n\t\t\t}\r\n\t\t\tif (marker.tags.indexOf(MarkerTag.Deprecated) !== -1) {\r\n\t\t\t\tinlineClassName = ClassName.EditorDeprecatedInlineDecoration;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,\r\n\t\t\tclassName,\r\n\t\t\tshowIfCollapsed: true,\r\n\t\t\toverviewRuler: {\r\n\t\t\t\tcolor,\r\n\t\t\t\tposition: OverviewRulerLane.Right\r\n\t\t\t},\r\n\t\t\tminimap,\r\n\t\t\tzIndex,\r\n\t\t\tinlineClassName,\r\n\t\t};\r\n\t}\r\n\r\n\tprivate _hasMarkerTag(marker: IMarker, tag: MarkerTag): boolean {\r\n\t\tif (marker.tags) {\r\n\t\t\treturn marker.tags.indexOf(tag) >= 0;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { GlobalMouseMoveMonitor, IStandardMouseMoveEventData, standardMouseMoveMerger } from 'vs/base/browser/globalMouseMoveMonitor';\r\nimport { Emitter } from 'vs/base/common/event';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport 'vs/css!./lightBulbWidget';\r\nimport { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';\r\nimport { IPosition } from 'vs/editor/common/core/position';\r\nimport { TextModel } from 'vs/editor/common/model/textModel';\r\nimport { CodeActionSet } from 'vs/editor/contrib/codeAction/codeAction';\r\nimport * as nls from 'vs/nls';\r\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { registerThemingParticipant, IColorTheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';\r\nimport { editorLightBulbForeground, editorLightBulbAutoFixForeground, editorBackground } from 'vs/platform/theme/common/colorRegistry';\r\nimport { Gesture } from 'vs/base/browser/touch';\r\nimport { CodeActionTrigger } from 'vs/editor/contrib/codeAction/types';\r\nimport { Codicon } from 'vs/base/common/codicons';\r\n\r\nnamespace LightBulbState {\r\n\r\n\texport const enum Type {\r\n\t\tHidden,\r\n\t\tShowing,\r\n\t}\r\n\r\n\texport const Hidden = { type: Type.Hidden } as const;\r\n\r\n\texport class Showing {\r\n\t\treadonly type = Type.Showing;\r\n\r\n\t\tconstructor(\r\n\t\t\tpublic readonly actions: CodeActionSet,\r\n\t\t\tpublic readonly trigger: CodeActionTrigger,\r\n\t\t\tpublic readonly editorPosition: IPosition,\r\n\t\t\tpublic readonly widgetPosition: IContentWidgetPosition,\r\n\t\t) { }\r\n\t}\r\n\r\n\texport type State = typeof Hidden | Showing;\r\n}\r\n\r\n\r\nexport class LightBulbWidget extends Disposable implements IContentWidget {\r\n\r\n\tprivate static readonly _posPref = [ContentWidgetPositionPreference.EXACT];\r\n\r\n\tprivate readonly _domNode: HTMLDivElement;\r\n\r\n\tprivate readonly _onClick = this._register(new Emitter<{ x: number; y: number; actions: CodeActionSet; trigger: CodeActionTrigger }>());\r\n\tpublic readonly onClick = this._onClick.event;\r\n\r\n\tprivate _state: LightBulbState.State = LightBulbState.Hidden;\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _editor: ICodeEditor,\r\n\t\tprivate readonly _quickFixActionId: string,\r\n\t\tprivate readonly _preferredFixActionId: string,\r\n\t\t@IKeybindingService private readonly _keybindingService: IKeybindingService\r\n\t) {\r\n\t\tsuper();\r\n\t\tthis._domNode = document.createElement('div');\r\n\t\tthis._domNode.className = Codicon.lightBulb.classNames;\r\n\r\n\t\tthis._editor.addContentWidget(this);\r\n\r\n\t\tthis._register(this._editor.onDidChangeModelContent(_ => {\r\n\t\t\t// cancel when the line in question has been removed\r\n\t\t\tconst editorModel = this._editor.getModel();\r\n\t\t\tif (this.state.type !== LightBulbState.Type.Showing || !editorModel || this.state.editorPosition.lineNumber >= editorModel.getLineCount()) {\r\n\t\t\t\tthis.hide();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tGesture.ignoreTarget(this._domNode);\r\n\t\tthis._register(dom.addStandardDisposableGenericMouseDownListner(this._domNode, e => {\r\n\t\t\tif (this.state.type !== LightBulbState.Type.Showing) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\t// Make sure that focus / cursor location is not lost when clicking widget icon\r\n\t\t\tthis._editor.focus();\r\n\t\t\te.preventDefault();\r\n\t\t\t// a bit of extra work to make sure the menu\r\n\t\t\t// doesn't cover the line-text\r\n\t\t\tconst { top, height } = dom.getDomNodePagePosition(this._domNode);\r\n\t\t\tconst lineHeight = this._editor.getOption(EditorOption.lineHeight);\r\n\r\n\t\t\tlet pad = Math.floor(lineHeight / 3);\r\n\t\t\tif (this.state.widgetPosition.position !== null && this.state.widgetPosition.position.lineNumber < this.state.editorPosition.lineNumber) {\r\n\t\t\t\tpad += lineHeight;\r\n\t\t\t}\r\n\r\n\t\t\tthis._onClick.fire({\r\n\t\t\t\tx: e.posx,\r\n\t\t\t\ty: top + height + pad,\r\n\t\t\t\tactions: this.state.actions,\r\n\t\t\t\ttrigger: this.state.trigger,\r\n\t\t\t});\r\n\t\t}));\r\n\t\tthis._register(dom.addDisposableListener(this._domNode, 'mouseenter', (e: MouseEvent) => {\r\n\t\t\tif ((e.buttons & 1) !== 1) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t// mouse enters lightbulb while the primary/left button\r\n\t\t\t// is being pressed -> hide the lightbulb and block future\r\n\t\t\t// showings until mouse is released\r\n\t\t\tthis.hide();\r\n\t\t\tconst monitor = new GlobalMouseMoveMonitor();\r\n\t\t\tmonitor.startMonitoring(e.target, e.buttons, standardMouseMoveMerger, () => { }, () => {\r\n\t\t\t\tmonitor.dispose();\r\n\t\t\t});\r\n\t\t}));\r\n\t\tthis._register(this._editor.onDidChangeConfiguration(e => {\r\n\t\t\t// hide when told to do so\r\n\t\t\tif (e.hasChanged(EditorOption.lightbulb) && !this._editor.getOption(EditorOption.lightbulb).enabled) {\r\n\t\t\t\tthis.hide();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._updateLightBulbTitleAndIcon();\r\n\t\tthis._register(this._keybindingService.onDidUpdateKeybindings(this._updateLightBulbTitleAndIcon, this));\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tsuper.dispose();\r\n\t\tthis._editor.removeContentWidget(this);\r\n\t}\r\n\r\n\tgetId(): string {\r\n\t\treturn 'LightBulbWidget';\r\n\t}\r\n\r\n\tgetDomNode(): HTMLElement {\r\n\t\treturn this._domNode;\r\n\t}\r\n\r\n\tgetPosition(): IContentWidgetPosition | null {\r\n\t\treturn this._state.type === LightBulbState.Type.Showing ? this._state.widgetPosition : null;\r\n\t}\r\n\r\n\tpublic update(actions: CodeActionSet, trigger: CodeActionTrigger, atPosition: IPosition) {\r\n\t\tif (actions.validActions.length <= 0) {\r\n\t\t\treturn this.hide();\r\n\t\t}\r\n\r\n\t\tconst options = this._editor.getOptions();\r\n\t\tif (!options.get(EditorOption.lightbulb).enabled) {\r\n\t\t\treturn this.hide();\r\n\t\t}\r\n\r\n\t\tconst model = this._editor.getModel();\r\n\t\tif (!model) {\r\n\t\t\treturn this.hide();\r\n\t\t}\r\n\r\n\t\tconst { lineNumber, column } = model.validatePosition(atPosition);\r\n\r\n\t\tconst tabSize = model.getOptions().tabSize;\r\n\t\tconst fontInfo = options.get(EditorOption.fontInfo);\r\n\t\tconst lineContent = model.getLineContent(lineNumber);\r\n\t\tconst indent = TextModel.computeIndentLevel(lineContent, tabSize);\r\n\t\tconst lineHasSpace = fontInfo.spaceWidth * indent > 22;\r\n\t\tconst isFolded = (lineNumber: number) => {\r\n\t\t\treturn lineNumber > 2 && this._editor.getTopForLineNumber(lineNumber) === this._editor.getTopForLineNumber(lineNumber - 1);\r\n\t\t};\r\n\r\n\t\tlet effectiveLineNumber = lineNumber;\r\n\t\tif (!lineHasSpace) {\r\n\t\t\tif (lineNumber > 1 && !isFolded(lineNumber - 1)) {\r\n\t\t\t\teffectiveLineNumber -= 1;\r\n\t\t\t} else if (!isFolded(lineNumber + 1)) {\r\n\t\t\t\teffectiveLineNumber += 1;\r\n\t\t\t} else if (column * fontInfo.spaceWidth < 22) {\r\n\t\t\t\t// cannot show lightbulb above/below and showing\r\n\t\t\t\t// it inline would overlay the cursor...\r\n\t\t\t\treturn this.hide();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis.state = new LightBulbState.Showing(actions, trigger, atPosition, {\r\n\t\t\tposition: { lineNumber: effectiveLineNumber, column: 1 },\r\n\t\t\tpreference: LightBulbWidget._posPref\r\n\t\t});\r\n\t\tthis._editor.layoutContentWidget(this);\r\n\t}\r\n\r\n\tpublic hide(): void {\r\n\t\tthis.state = LightBulbState.Hidden;\r\n\t\tthis._editor.layoutContentWidget(this);\r\n\t}\r\n\r\n\tprivate get state(): LightBulbState.State { return this._state; }\r\n\r\n\tprivate set state(value) {\r\n\t\tthis._state = value;\r\n\t\tthis._updateLightBulbTitleAndIcon();\r\n\t}\r\n\r\n\tprivate _updateLightBulbTitleAndIcon(): void {\r\n\t\tif (this.state.type === LightBulbState.Type.Showing && this.state.actions.hasAutoFix) {\r\n\t\t\t// update icon\r\n\t\t\tthis._domNode.classList.remove(...Codicon.lightBulb.classNamesArray);\r\n\t\t\tthis._domNode.classList.add(...Codicon.lightbulbAutofix.classNamesArray);\r\n\r\n\t\t\tconst preferredKb = this._keybindingService.lookupKeybinding(this._preferredFixActionId);\r\n\t\t\tif (preferredKb) {\r\n\t\t\t\tthis.title = nls.localize('prefferedQuickFixWithKb', \"Show Fixes. Preferred Fix Available ({0})\", preferredKb.getLabel());\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// update icon\r\n\t\tthis._domNode.classList.remove(...Codicon.lightbulbAutofix.classNamesArray);\r\n\t\tthis._domNode.classList.add(...Codicon.lightBulb.classNamesArray);\r\n\r\n\t\tconst kb = this._keybindingService.lookupKeybinding(this._quickFixActionId);\r\n\t\tif (kb) {\r\n\t\t\tthis.title = nls.localize('quickFixWithKb', \"Show Fixes ({0})\", kb.getLabel());\r\n\t\t} else {\r\n\t\t\tthis.title = nls.localize('quickFix', \"Show Fixes\");\r\n\t\t}\r\n\t}\r\n\r\n\tprivate set title(value: string) {\r\n\t\tthis._domNode.title = value;\r\n\t}\r\n}\r\n\r\nregisterThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) => {\r\n\r\n\tconst editorBackgroundColor = theme.getColor(editorBackground)?.transparent(0.7);\r\n\r\n\t// Lightbulb Icon\r\n\tconst editorLightBulbForegroundColor = theme.getColor(editorLightBulbForeground);\r\n\tif (editorLightBulbForegroundColor) {\r\n\t\tcollector.addRule(`\r\n\t\t.monaco-editor .contentWidgets ${Codicon.lightBulb.cssSelector} {\r\n\t\t\tcolor: ${editorLightBulbForegroundColor};\r\n\t\t\tbackground-color: ${editorBackgroundColor};\r\n\t\t}`);\r\n\t}\r\n\r\n\t// Lightbulb Auto Fix Icon\r\n\tconst editorLightBulbAutoFixForegroundColor = theme.getColor(editorLightBulbAutoFixForeground);\r\n\tif (editorLightBulbAutoFixForegroundColor) {\r\n\t\tcollector.addRule(`\r\n\t\t.monaco-editor .contentWidgets ${Codicon.lightbulbAutofix.cssSelector} {\r\n\t\t\tcolor: ${editorLightBulbAutoFixForegroundColor};\r\n\t\t\tbackground-color: ${editorBackgroundColor};\r\n\t\t}`);\r\n\t}\r\n\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./codelensWidget';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { IViewZone, IContentWidget, IActiveCodeEditor, IContentWidgetPosition, ContentWidgetPositionPreference, IViewZoneChangeAccessor } from 'vs/editor/browser/editorBrowser';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { IModelDecorationsChangeAccessor, IModelDeltaDecoration, ITextModel } from 'vs/editor/common/model';\r\nimport { ModelDecorationOptions } from 'vs/editor/common/model/textModel';\r\nimport { Command, CodeLens } from 'vs/editor/common/modes';\r\nimport { editorCodeLensForeground } from 'vs/editor/common/view/editorColorRegistry';\r\nimport { CodeLensItem } from 'vs/editor/contrib/codelens/codelens';\r\nimport { editorActiveLinkForeground } from 'vs/platform/theme/common/colorRegistry';\r\nimport { registerThemingParticipant } from 'vs/platform/theme/common/themeService';\r\nimport { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';\r\n\r\nclass CodeLensViewZone implements IViewZone {\r\n\r\n\treadonly suppressMouseDown: boolean;\r\n\treadonly domNode: HTMLElement;\r\n\r\n\tafterLineNumber: number;\r\n\theightInPx: number;\r\n\r\n\tprivate _lastHeight?: number;\r\n\tprivate readonly _onHeight: () => void;\r\n\r\n\tconstructor(afterLineNumber: number, heightInPx: number, onHeight: () => void) {\r\n\t\tthis.afterLineNumber = afterLineNumber;\r\n\t\tthis.heightInPx = heightInPx;\r\n\r\n\t\tthis._onHeight = onHeight;\r\n\t\tthis.suppressMouseDown = true;\r\n\t\tthis.domNode = document.createElement('div');\r\n\t}\r\n\r\n\tonComputedHeight(height: number): void {\r\n\t\tif (this._lastHeight === undefined) {\r\n\t\t\tthis._lastHeight = height;\r\n\t\t} else if (this._lastHeight !== height) {\r\n\t\t\tthis._lastHeight = height;\r\n\t\t\tthis._onHeight();\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass CodeLensContentWidget implements IContentWidget {\r\n\r\n\tprivate static _idPool: number = 0;\r\n\r\n\t// Editor.IContentWidget.allowEditorOverflow\r\n\treadonly allowEditorOverflow: boolean = false;\r\n\treadonly suppressMouseDown: boolean = true;\r\n\r\n\tprivate readonly _id: string;\r\n\tprivate readonly _domNode: HTMLElement;\r\n\tprivate readonly _editor: IActiveCodeEditor;\r\n\tprivate readonly _commands = new Map();\r\n\r\n\tprivate _widgetPosition?: IContentWidgetPosition;\r\n\tprivate _isEmpty: boolean = true;\r\n\r\n\tconstructor(\r\n\t\teditor: IActiveCodeEditor,\r\n\t\tclassName: string,\r\n\t\tline: number,\r\n\t) {\r\n\t\tthis._editor = editor;\r\n\t\tthis._id = `codelens.widget-${(CodeLensContentWidget._idPool++)}`;\r\n\r\n\t\tthis.updatePosition(line);\r\n\r\n\t\tthis._domNode = document.createElement('span');\r\n\t\tthis._domNode.className = `codelens-decoration ${className}`;\r\n\t}\r\n\r\n\twithCommands(lenses: Array, animate: boolean): void {\r\n\t\tthis._commands.clear();\r\n\r\n\t\tlet children: HTMLElement[] = [];\r\n\t\tlet hasSymbol = false;\r\n\t\tfor (let i = 0; i < lenses.length; i++) {\r\n\t\t\tconst lens = lenses[i];\r\n\t\t\tif (!lens) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\thasSymbol = true;\r\n\t\t\tif (lens.command) {\r\n\t\t\t\tconst title = renderLabelWithIcons(lens.command.title.trim());\r\n\t\t\t\tif (lens.command.id) {\r\n\t\t\t\t\tchildren.push(dom.$('a', { id: String(i) }, ...title));\r\n\t\t\t\t\tthis._commands.set(String(i), lens.command);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tchildren.push(dom.$('span', undefined, ...title));\r\n\t\t\t\t}\r\n\t\t\t\tif (i + 1 < lenses.length) {\r\n\t\t\t\t\tchildren.push(dom.$('span', undefined, '\\u00a0|\\u00a0'));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!hasSymbol) {\r\n\t\t\t// symbols but no commands\r\n\t\t\tdom.reset(this._domNode, dom.$('span', undefined, 'no commands'));\r\n\r\n\t\t} else {\r\n\t\t\t// symbols and commands\r\n\t\t\tdom.reset(this._domNode, ...children);\r\n\t\t\tif (this._isEmpty && animate) {\r\n\t\t\t\tthis._domNode.classList.add('fadein');\r\n\t\t\t}\r\n\t\t\tthis._isEmpty = false;\r\n\t\t}\r\n\t}\r\n\r\n\tgetCommand(link: HTMLLinkElement): Command | undefined {\r\n\t\treturn link.parentElement === this._domNode\r\n\t\t\t? this._commands.get(link.id)\r\n\t\t\t: undefined;\r\n\t}\r\n\r\n\tgetId(): string {\r\n\t\treturn this._id;\r\n\t}\r\n\r\n\tgetDomNode(): HTMLElement {\r\n\t\treturn this._domNode;\r\n\t}\r\n\r\n\tupdatePosition(line: number): void {\r\n\t\tconst column = this._editor.getModel().getLineFirstNonWhitespaceColumn(line);\r\n\t\tthis._widgetPosition = {\r\n\t\t\tposition: { lineNumber: line, column: column },\r\n\t\t\tpreference: [ContentWidgetPositionPreference.ABOVE]\r\n\t\t};\r\n\t}\r\n\r\n\tgetPosition(): IContentWidgetPosition | null {\r\n\t\treturn this._widgetPosition || null;\r\n\t}\r\n}\r\n\r\nexport interface IDecorationIdCallback {\r\n\t(decorationId: string): void;\r\n}\r\n\r\nexport class CodeLensHelper {\r\n\r\n\tprivate readonly _removeDecorations: string[];\r\n\tprivate readonly _addDecorations: IModelDeltaDecoration[];\r\n\tprivate readonly _addDecorationsCallbacks: IDecorationIdCallback[];\r\n\r\n\tconstructor() {\r\n\t\tthis._removeDecorations = [];\r\n\t\tthis._addDecorations = [];\r\n\t\tthis._addDecorationsCallbacks = [];\r\n\t}\r\n\r\n\taddDecoration(decoration: IModelDeltaDecoration, callback: IDecorationIdCallback): void {\r\n\t\tthis._addDecorations.push(decoration);\r\n\t\tthis._addDecorationsCallbacks.push(callback);\r\n\t}\r\n\r\n\tremoveDecoration(decorationId: string): void {\r\n\t\tthis._removeDecorations.push(decorationId);\r\n\t}\r\n\r\n\tcommit(changeAccessor: IModelDecorationsChangeAccessor): void {\r\n\t\tlet resultingDecorations = changeAccessor.deltaDecorations(this._removeDecorations, this._addDecorations);\r\n\t\tfor (let i = 0, len = resultingDecorations.length; i < len; i++) {\r\n\t\t\tthis._addDecorationsCallbacks[i](resultingDecorations[i]);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class CodeLensWidget {\r\n\r\n\tprivate readonly _editor: IActiveCodeEditor;\r\n\tprivate readonly _className: string;\r\n\tprivate readonly _viewZone: CodeLensViewZone;\r\n\tprivate readonly _viewZoneId: string;\r\n\r\n\tprivate _contentWidget?: CodeLensContentWidget;\r\n\tprivate _decorationIds: string[];\r\n\tprivate _data: CodeLensItem[];\r\n\tprivate _isDisposed: boolean = false;\r\n\r\n\tconstructor(\r\n\t\tdata: CodeLensItem[],\r\n\t\teditor: IActiveCodeEditor,\r\n\t\tclassName: string,\r\n\t\thelper: CodeLensHelper,\r\n\t\tviewZoneChangeAccessor: IViewZoneChangeAccessor,\r\n\t\theightInPx: number,\r\n\t\tupdateCallback: () => void\r\n\t) {\r\n\t\tthis._editor = editor;\r\n\t\tthis._className = className;\r\n\t\tthis._data = data;\r\n\r\n\t\t// create combined range, track all ranges with decorations,\r\n\t\t// check if there is already something to render\r\n\t\tthis._decorationIds = [];\r\n\t\tlet range: Range | undefined;\r\n\t\tlet lenses: CodeLens[] = [];\r\n\r\n\t\tthis._data.forEach((codeLensData, i) => {\r\n\r\n\t\t\tif (codeLensData.symbol.command) {\r\n\t\t\t\tlenses.push(codeLensData.symbol);\r\n\t\t\t}\r\n\r\n\t\t\thelper.addDecoration({\r\n\t\t\t\trange: codeLensData.symbol.range,\r\n\t\t\t\toptions: ModelDecorationOptions.EMPTY\r\n\t\t\t}, id => this._decorationIds[i] = id);\r\n\r\n\t\t\t// the range contains all lenses on this line\r\n\t\t\tif (!range) {\r\n\t\t\t\trange = Range.lift(codeLensData.symbol.range);\r\n\t\t\t} else {\r\n\t\t\t\trange = Range.plusRange(range, codeLensData.symbol.range);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tthis._viewZone = new CodeLensViewZone(range!.startLineNumber - 1, heightInPx, updateCallback);\r\n\t\tthis._viewZoneId = viewZoneChangeAccessor.addZone(this._viewZone);\r\n\r\n\t\tif (lenses.length > 0) {\r\n\t\t\tthis._createContentWidgetIfNecessary();\r\n\t\t\tthis._contentWidget!.withCommands(lenses, false);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _createContentWidgetIfNecessary(): void {\r\n\t\tif (!this._contentWidget) {\r\n\t\t\tthis._contentWidget = new CodeLensContentWidget(this._editor, this._className, this._viewZone.afterLineNumber + 1);\r\n\t\t\tthis._editor.addContentWidget(this._contentWidget);\r\n\t\t} else {\r\n\t\t\tthis._editor.layoutContentWidget(this._contentWidget);\r\n\t\t}\r\n\t}\r\n\r\n\tdispose(helper: CodeLensHelper, viewZoneChangeAccessor?: IViewZoneChangeAccessor): void {\r\n\t\tthis._decorationIds.forEach(helper.removeDecoration, helper);\r\n\t\tthis._decorationIds = [];\r\n\t\tif (viewZoneChangeAccessor) {\r\n\t\t\tviewZoneChangeAccessor.removeZone(this._viewZoneId);\r\n\t\t}\r\n\t\tif (this._contentWidget) {\r\n\t\t\tthis._editor.removeContentWidget(this._contentWidget);\r\n\t\t\tthis._contentWidget = undefined;\r\n\t\t}\r\n\t\tthis._isDisposed = true;\r\n\t}\r\n\r\n\tisDisposed(): boolean {\r\n\t\treturn this._isDisposed;\r\n\t}\r\n\r\n\tisValid(): boolean {\r\n\t\treturn this._decorationIds.some((id, i) => {\r\n\t\t\tconst range = this._editor.getModel().getDecorationRange(id);\r\n\t\t\tconst symbol = this._data[i].symbol;\r\n\t\t\treturn !!(range && Range.isEmpty(symbol.range) === range.isEmpty());\r\n\t\t});\r\n\t}\r\n\r\n\tupdateCodeLensSymbols(data: CodeLensItem[], helper: CodeLensHelper): void {\r\n\t\tthis._decorationIds.forEach(helper.removeDecoration, helper);\r\n\t\tthis._decorationIds = [];\r\n\t\tthis._data = data;\r\n\t\tthis._data.forEach((codeLensData, i) => {\r\n\t\t\thelper.addDecoration({\r\n\t\t\t\trange: codeLensData.symbol.range,\r\n\t\t\t\toptions: ModelDecorationOptions.EMPTY\r\n\t\t\t}, id => this._decorationIds[i] = id);\r\n\t\t});\r\n\t}\r\n\r\n\tupdateHeight(height: number, viewZoneChangeAccessor: IViewZoneChangeAccessor): void {\r\n\t\tthis._viewZone.heightInPx = height;\r\n\t\tviewZoneChangeAccessor.layoutZone(this._viewZoneId);\r\n\t\tif (this._contentWidget) {\r\n\t\t\tthis._editor.layoutContentWidget(this._contentWidget);\r\n\t\t}\r\n\t}\r\n\r\n\tcomputeIfNecessary(model: ITextModel): CodeLensItem[] | null {\r\n\t\tif (!this._viewZone.domNode.hasAttribute('monaco-visible-view-zone')) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\t// Read editor current state\r\n\t\tfor (let i = 0; i < this._decorationIds.length; i++) {\r\n\t\t\tconst range = model.getDecorationRange(this._decorationIds[i]);\r\n\t\t\tif (range) {\r\n\t\t\t\tthis._data[i].symbol.range = range;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this._data;\r\n\t}\r\n\r\n\tupdateCommands(symbols: Array): void {\r\n\r\n\t\tthis._createContentWidgetIfNecessary();\r\n\t\tthis._contentWidget!.withCommands(symbols, true);\r\n\r\n\t\tfor (let i = 0; i < this._data.length; i++) {\r\n\t\t\tconst resolved = symbols[i];\r\n\t\t\tif (resolved) {\r\n\t\t\t\tconst { symbol } = this._data[i];\r\n\t\t\t\tsymbol.command = resolved.command || symbol.command;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tgetCommand(link: HTMLLinkElement): Command | undefined {\r\n\t\treturn this._contentWidget?.getCommand(link);\r\n\t}\r\n\r\n\tgetLineNumber(): number {\r\n\t\tconst range = this._editor.getModel().getDecorationRange(this._decorationIds[0]);\r\n\t\tif (range) {\r\n\t\t\treturn range.startLineNumber;\r\n\t\t}\r\n\t\treturn -1;\r\n\t}\r\n\r\n\tupdate(viewZoneChangeAccessor: IViewZoneChangeAccessor): void {\r\n\t\tif (this.isValid()) {\r\n\t\t\tconst range = this._editor.getModel().getDecorationRange(this._decorationIds[0]);\r\n\t\t\tif (range) {\r\n\t\t\t\tthis._viewZone.afterLineNumber = range.startLineNumber - 1;\r\n\t\t\t\tviewZoneChangeAccessor.layoutZone(this._viewZoneId);\r\n\r\n\t\t\t\tif (this._contentWidget) {\r\n\t\t\t\t\tthis._contentWidget.updatePosition(range.startLineNumber);\r\n\t\t\t\t\tthis._editor.layoutContentWidget(this._contentWidget);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tgetItems(): CodeLensItem[] {\r\n\t\treturn this._data;\r\n\t}\r\n}\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst codeLensForeground = theme.getColor(editorCodeLensForeground);\r\n\tif (codeLensForeground) {\r\n\t\tcollector.addRule(`.monaco-editor .codelens-decoration { color: ${codeLensForeground}; }`);\r\n\t\tcollector.addRule(`.monaco-editor .codelens-decoration .codicon { color: ${codeLensForeground}; }`);\r\n\t}\r\n\tconst activeLinkForeground = theme.getColor(editorActiveLinkForeground);\r\n\tif (activeLinkForeground) {\r\n\t\tcollector.addRule(`.monaco-editor .codelens-decoration > a:hover { color: ${activeLinkForeground} !important; }`);\r\n\t\tcollector.addRule(`.monaco-editor .codelens-decoration > a:hover .codicon { color: ${activeLinkForeground} !important; }`);\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./colorPicker';\r\nimport { onDidChangeZoomLevel } from 'vs/base/browser/browser';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { GlobalMouseMoveMonitor, IStandardMouseMoveEventData, standardMouseMoveMerger } from 'vs/base/browser/globalMouseMoveMonitor';\r\nimport { Widget } from 'vs/base/browser/ui/widget';\r\nimport { Color, HSVA, RGBA } from 'vs/base/common/color';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { ColorPickerModel } from 'vs/editor/contrib/colorPicker/colorPickerModel';\r\nimport { editorHoverBackground } from 'vs/platform/theme/common/colorRegistry';\r\nimport { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';\r\n\r\nconst $ = dom.$;\r\n\r\nexport class ColorPickerHeader extends Disposable {\r\n\r\n\tprivate readonly domNode: HTMLElement;\r\n\tprivate readonly pickedColorNode: HTMLElement;\r\n\tprivate backgroundColor: Color;\r\n\r\n\tconstructor(container: HTMLElement, private readonly model: ColorPickerModel, themeService: IThemeService) {\r\n\t\tsuper();\r\n\r\n\t\tthis.domNode = $('.colorpicker-header');\r\n\t\tdom.append(container, this.domNode);\r\n\r\n\t\tthis.pickedColorNode = dom.append(this.domNode, $('.picked-color'));\r\n\r\n\t\tconst colorBox = dom.append(this.domNode, $('.original-color'));\r\n\t\tcolorBox.style.backgroundColor = Color.Format.CSS.format(this.model.originalColor) || '';\r\n\r\n\t\tthis.backgroundColor = themeService.getColorTheme().getColor(editorHoverBackground) || Color.white;\r\n\t\tthis._register(registerThemingParticipant((theme, collector) => {\r\n\t\t\tthis.backgroundColor = theme.getColor(editorHoverBackground) || Color.white;\r\n\t\t}));\r\n\r\n\t\tthis._register(dom.addDisposableListener(this.pickedColorNode, dom.EventType.CLICK, () => this.model.selectNextColorPresentation()));\r\n\t\tthis._register(dom.addDisposableListener(colorBox, dom.EventType.CLICK, () => {\r\n\t\t\tthis.model.color = this.model.originalColor;\r\n\t\t\tthis.model.flushColor();\r\n\t\t}));\r\n\t\tthis._register(model.onDidChangeColor(this.onDidChangeColor, this));\r\n\t\tthis._register(model.onDidChangePresentation(this.onDidChangePresentation, this));\r\n\t\tthis.pickedColorNode.style.backgroundColor = Color.Format.CSS.format(model.color) || '';\r\n\t\tthis.pickedColorNode.classList.toggle('light', model.color.rgba.a < 0.5 ? this.backgroundColor.isLighter() : model.color.isLighter());\r\n\t}\r\n\r\n\tprivate onDidChangeColor(color: Color): void {\r\n\t\tthis.pickedColorNode.style.backgroundColor = Color.Format.CSS.format(color) || '';\r\n\t\tthis.pickedColorNode.classList.toggle('light', color.rgba.a < 0.5 ? this.backgroundColor.isLighter() : color.isLighter());\r\n\t\tthis.onDidChangePresentation();\r\n\t}\r\n\r\n\tprivate onDidChangePresentation(): void {\r\n\t\tthis.pickedColorNode.textContent = this.model.presentation ? this.model.presentation.label : '';\r\n\t}\r\n}\r\n\r\nexport class ColorPickerBody extends Disposable {\r\n\r\n\tprivate readonly domNode: HTMLElement;\r\n\tprivate readonly saturationBox: SaturationBox;\r\n\tprivate readonly hueStrip: Strip;\r\n\tprivate readonly opacityStrip: Strip;\r\n\r\n\tconstructor(container: HTMLElement, private readonly model: ColorPickerModel, private pixelRatio: number) {\r\n\t\tsuper();\r\n\r\n\t\tthis.domNode = $('.colorpicker-body');\r\n\t\tdom.append(container, this.domNode);\r\n\r\n\t\tthis.saturationBox = new SaturationBox(this.domNode, this.model, this.pixelRatio);\r\n\t\tthis._register(this.saturationBox);\r\n\t\tthis._register(this.saturationBox.onDidChange(this.onDidSaturationValueChange, this));\r\n\t\tthis._register(this.saturationBox.onColorFlushed(this.flushColor, this));\r\n\r\n\t\tthis.opacityStrip = new OpacityStrip(this.domNode, this.model);\r\n\t\tthis._register(this.opacityStrip);\r\n\t\tthis._register(this.opacityStrip.onDidChange(this.onDidOpacityChange, this));\r\n\t\tthis._register(this.opacityStrip.onColorFlushed(this.flushColor, this));\r\n\r\n\t\tthis.hueStrip = new HueStrip(this.domNode, this.model);\r\n\t\tthis._register(this.hueStrip);\r\n\t\tthis._register(this.hueStrip.onDidChange(this.onDidHueChange, this));\r\n\t\tthis._register(this.hueStrip.onColorFlushed(this.flushColor, this));\r\n\t}\r\n\r\n\tprivate flushColor(): void {\r\n\t\tthis.model.flushColor();\r\n\t}\r\n\r\n\tprivate onDidSaturationValueChange({ s, v }: { s: number, v: number }): void {\r\n\t\tconst hsva = this.model.color.hsva;\r\n\t\tthis.model.color = new Color(new HSVA(hsva.h, s, v, hsva.a));\r\n\t}\r\n\r\n\tprivate onDidOpacityChange(a: number): void {\r\n\t\tconst hsva = this.model.color.hsva;\r\n\t\tthis.model.color = new Color(new HSVA(hsva.h, hsva.s, hsva.v, a));\r\n\t}\r\n\r\n\tprivate onDidHueChange(value: number): void {\r\n\t\tconst hsva = this.model.color.hsva;\r\n\t\tconst h = (1 - value) * 360;\r\n\r\n\t\tthis.model.color = new Color(new HSVA(h === 360 ? 0 : h, hsva.s, hsva.v, hsva.a));\r\n\t}\r\n\r\n\tlayout(): void {\r\n\t\tthis.saturationBox.layout();\r\n\t\tthis.opacityStrip.layout();\r\n\t\tthis.hueStrip.layout();\r\n\t}\r\n}\r\n\r\nclass SaturationBox extends Disposable {\r\n\r\n\tprivate readonly domNode: HTMLElement;\r\n\tprivate readonly selection: HTMLElement;\r\n\tprivate readonly canvas: HTMLCanvasElement;\r\n\tprivate width!: number;\r\n\tprivate height!: number;\r\n\r\n\tprivate monitor: GlobalMouseMoveMonitor | null;\r\n\tprivate readonly _onDidChange = new Emitter<{ s: number, v: number }>();\r\n\treadonly onDidChange: Event<{ s: number, v: number }> = this._onDidChange.event;\r\n\r\n\tprivate readonly _onColorFlushed = new Emitter();\r\n\treadonly onColorFlushed: Event = this._onColorFlushed.event;\r\n\r\n\tconstructor(container: HTMLElement, private readonly model: ColorPickerModel, private pixelRatio: number) {\r\n\t\tsuper();\r\n\r\n\t\tthis.domNode = $('.saturation-wrap');\r\n\t\tdom.append(container, this.domNode);\r\n\r\n\t\t// Create canvas, draw selected color\r\n\t\tthis.canvas = document.createElement('canvas');\r\n\t\tthis.canvas.className = 'saturation-box';\r\n\t\tdom.append(this.domNode, this.canvas);\r\n\r\n\t\t// Add selection circle\r\n\t\tthis.selection = $('.saturation-selection');\r\n\t\tdom.append(this.domNode, this.selection);\r\n\r\n\t\tthis.layout();\r\n\r\n\t\tthis._register(dom.addDisposableGenericMouseDownListner(this.domNode, e => this.onMouseDown(e)));\r\n\t\tthis._register(this.model.onDidChangeColor(this.onDidChangeColor, this));\r\n\t\tthis.monitor = null;\r\n\t}\r\n\r\n\tprivate onMouseDown(e: MouseEvent): void {\r\n\t\tthis.monitor = this._register(new GlobalMouseMoveMonitor());\r\n\t\tconst origin = dom.getDomNodePagePosition(this.domNode);\r\n\r\n\t\tif (e.target !== this.selection) {\r\n\t\t\tthis.onDidChangePosition(e.offsetX, e.offsetY);\r\n\t\t}\r\n\r\n\t\tthis.monitor.startMonitoring(e.target, e.buttons, standardMouseMoveMerger, event => this.onDidChangePosition(event.posx - origin.left, event.posy - origin.top), () => null);\r\n\r\n\t\tconst mouseUpListener = dom.addDisposableGenericMouseUpListner(document, () => {\r\n\t\t\tthis._onColorFlushed.fire();\r\n\t\t\tmouseUpListener.dispose();\r\n\t\t\tif (this.monitor) {\r\n\t\t\t\tthis.monitor.stopMonitoring(true);\r\n\t\t\t\tthis.monitor = null;\r\n\t\t\t}\r\n\t\t}, true);\r\n\t}\r\n\r\n\tprivate onDidChangePosition(left: number, top: number): void {\r\n\t\tconst s = Math.max(0, Math.min(1, left / this.width));\r\n\t\tconst v = Math.max(0, Math.min(1, 1 - (top / this.height)));\r\n\r\n\t\tthis.paintSelection(s, v);\r\n\t\tthis._onDidChange.fire({ s, v });\r\n\t}\r\n\r\n\tlayout(): void {\r\n\t\tthis.width = this.domNode.offsetWidth;\r\n\t\tthis.height = this.domNode.offsetHeight;\r\n\t\tthis.canvas.width = this.width * this.pixelRatio;\r\n\t\tthis.canvas.height = this.height * this.pixelRatio;\r\n\t\tthis.paint();\r\n\r\n\t\tconst hsva = this.model.color.hsva;\r\n\t\tthis.paintSelection(hsva.s, hsva.v);\r\n\t}\r\n\r\n\tprivate paint(): void {\r\n\t\tconst hsva = this.model.color.hsva;\r\n\t\tconst saturatedColor = new Color(new HSVA(hsva.h, 1, 1, 1));\r\n\t\tconst ctx = this.canvas.getContext('2d')!;\r\n\r\n\t\tconst whiteGradient = ctx.createLinearGradient(0, 0, this.canvas.width, 0);\r\n\t\twhiteGradient.addColorStop(0, 'rgba(255, 255, 255, 1)');\r\n\t\twhiteGradient.addColorStop(0.5, 'rgba(255, 255, 255, 0.5)');\r\n\t\twhiteGradient.addColorStop(1, 'rgba(255, 255, 255, 0)');\r\n\r\n\t\tconst blackGradient = ctx.createLinearGradient(0, 0, 0, this.canvas.height);\r\n\t\tblackGradient.addColorStop(0, 'rgba(0, 0, 0, 0)');\r\n\t\tblackGradient.addColorStop(1, 'rgba(0, 0, 0, 1)');\r\n\r\n\t\tctx.rect(0, 0, this.canvas.width, this.canvas.height);\r\n\t\tctx.fillStyle = Color.Format.CSS.format(saturatedColor)!;\r\n\t\tctx.fill();\r\n\t\tctx.fillStyle = whiteGradient;\r\n\t\tctx.fill();\r\n\t\tctx.fillStyle = blackGradient;\r\n\t\tctx.fill();\r\n\t}\r\n\r\n\tprivate paintSelection(s: number, v: number): void {\r\n\t\tthis.selection.style.left = `${s * this.width}px`;\r\n\t\tthis.selection.style.top = `${this.height - v * this.height}px`;\r\n\t}\r\n\r\n\tprivate onDidChangeColor(): void {\r\n\t\tif (this.monitor && this.monitor.isMonitoring()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis.paint();\r\n\t}\r\n}\r\n\r\nabstract class Strip extends Disposable {\r\n\r\n\tprotected domNode: HTMLElement;\r\n\tprotected overlay: HTMLElement;\r\n\tprotected slider: HTMLElement;\r\n\tprivate height!: number;\r\n\r\n\tprivate readonly _onDidChange = new Emitter();\r\n\treadonly onDidChange: Event = this._onDidChange.event;\r\n\r\n\tprivate readonly _onColorFlushed = new Emitter();\r\n\treadonly onColorFlushed: Event = this._onColorFlushed.event;\r\n\r\n\tconstructor(container: HTMLElement, protected model: ColorPickerModel) {\r\n\t\tsuper();\r\n\t\tthis.domNode = dom.append(container, $('.strip'));\r\n\t\tthis.overlay = dom.append(this.domNode, $('.overlay'));\r\n\t\tthis.slider = dom.append(this.domNode, $('.slider'));\r\n\t\tthis.slider.style.top = `0px`;\r\n\r\n\t\tthis._register(dom.addDisposableGenericMouseDownListner(this.domNode, e => this.onMouseDown(e)));\r\n\t\tthis.layout();\r\n\t}\r\n\r\n\tlayout(): void {\r\n\t\tthis.height = this.domNode.offsetHeight - this.slider.offsetHeight;\r\n\r\n\t\tconst value = this.getValue(this.model.color);\r\n\t\tthis.updateSliderPosition(value);\r\n\t}\r\n\r\n\tprivate onMouseDown(e: MouseEvent): void {\r\n\t\tconst monitor = this._register(new GlobalMouseMoveMonitor());\r\n\t\tconst origin = dom.getDomNodePagePosition(this.domNode);\r\n\t\tthis.domNode.classList.add('grabbing');\r\n\r\n\t\tif (e.target !== this.slider) {\r\n\t\t\tthis.onDidChangeTop(e.offsetY);\r\n\t\t}\r\n\r\n\t\tmonitor.startMonitoring(e.target, e.buttons, standardMouseMoveMerger, event => this.onDidChangeTop(event.posy - origin.top), () => null);\r\n\r\n\t\tconst mouseUpListener = dom.addDisposableGenericMouseUpListner(document, () => {\r\n\t\t\tthis._onColorFlushed.fire();\r\n\t\t\tmouseUpListener.dispose();\r\n\t\t\tmonitor.stopMonitoring(true);\r\n\t\t\tthis.domNode.classList.remove('grabbing');\r\n\t\t}, true);\r\n\t}\r\n\r\n\tprivate onDidChangeTop(top: number): void {\r\n\t\tconst value = Math.max(0, Math.min(1, 1 - (top / this.height)));\r\n\r\n\t\tthis.updateSliderPosition(value);\r\n\t\tthis._onDidChange.fire(value);\r\n\t}\r\n\r\n\tprivate updateSliderPosition(value: number): void {\r\n\t\tthis.slider.style.top = `${(1 - value) * this.height}px`;\r\n\t}\r\n\r\n\tprotected abstract getValue(color: Color): number;\r\n}\r\n\r\nclass OpacityStrip extends Strip {\r\n\r\n\tconstructor(container: HTMLElement, model: ColorPickerModel) {\r\n\t\tsuper(container, model);\r\n\t\tthis.domNode.classList.add('opacity-strip');\r\n\r\n\t\tthis._register(model.onDidChangeColor(this.onDidChangeColor, this));\r\n\t\tthis.onDidChangeColor(this.model.color);\r\n\t}\r\n\r\n\tprivate onDidChangeColor(color: Color): void {\r\n\t\tconst { r, g, b } = color.rgba;\r\n\t\tconst opaque = new Color(new RGBA(r, g, b, 1));\r\n\t\tconst transparent = new Color(new RGBA(r, g, b, 0));\r\n\r\n\t\tthis.overlay.style.background = `linear-gradient(to bottom, ${opaque} 0%, ${transparent} 100%)`;\r\n\t}\r\n\r\n\tprotected getValue(color: Color): number {\r\n\t\treturn color.hsva.a;\r\n\t}\r\n}\r\n\r\nclass HueStrip extends Strip {\r\n\r\n\tconstructor(container: HTMLElement, model: ColorPickerModel) {\r\n\t\tsuper(container, model);\r\n\t\tthis.domNode.classList.add('hue-strip');\r\n\t}\r\n\r\n\tprotected getValue(color: Color): number {\r\n\t\treturn 1 - (color.hsva.h / 360);\r\n\t}\r\n}\r\n\r\nexport class ColorPickerWidget extends Widget {\r\n\r\n\tbody: ColorPickerBody;\r\n\r\n\tconstructor(container: Node, readonly model: ColorPickerModel, private pixelRatio: number, themeService: IThemeService) {\r\n\t\tsuper();\r\n\r\n\t\tthis._register(onDidChangeZoomLevel(() => this.layout()));\r\n\r\n\t\tconst element = $('.colorpicker-widget');\r\n\t\tcontainer.appendChild(element);\r\n\r\n\t\tconst header = new ColorPickerHeader(element, this.model, themeService);\r\n\t\tthis.body = new ColorPickerBody(element, this.model, this.pixelRatio);\r\n\r\n\t\tthis._register(header);\r\n\t\tthis._register(this.body);\r\n\t}\r\n\r\n\tlayout(): void {\r\n\t\tthis.body.layout();\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { FindMatch, IModelDecorationsChangeAccessor, IModelDeltaDecoration, OverviewRulerLane, TrackedRangeStickiness, MinimapPosition } from 'vs/editor/common/model';\r\nimport { ModelDecorationOptions } from 'vs/editor/common/model/textModel';\r\nimport { overviewRulerFindMatchForeground, minimapFindMatch } from 'vs/platform/theme/common/colorRegistry';\r\nimport { themeColorFromId } from 'vs/platform/theme/common/themeService';\r\n\r\nexport class FindDecorations implements IDisposable {\r\n\r\n\tprivate readonly _editor: IActiveCodeEditor;\r\n\tprivate _decorations: string[];\r\n\tprivate _overviewRulerApproximateDecorations: string[];\r\n\tprivate _findScopeDecorationIds: string[];\r\n\tprivate _rangeHighlightDecorationId: string | null;\r\n\tprivate _highlightedDecorationId: string | null;\r\n\tprivate _startPosition: Position;\r\n\r\n\tconstructor(editor: IActiveCodeEditor) {\r\n\t\tthis._editor = editor;\r\n\t\tthis._decorations = [];\r\n\t\tthis._overviewRulerApproximateDecorations = [];\r\n\t\tthis._findScopeDecorationIds = [];\r\n\t\tthis._rangeHighlightDecorationId = null;\r\n\t\tthis._highlightedDecorationId = null;\r\n\t\tthis._startPosition = this._editor.getPosition();\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._editor.deltaDecorations(this._allDecorations(), []);\r\n\r\n\t\tthis._decorations = [];\r\n\t\tthis._overviewRulerApproximateDecorations = [];\r\n\t\tthis._findScopeDecorationIds = [];\r\n\t\tthis._rangeHighlightDecorationId = null;\r\n\t\tthis._highlightedDecorationId = null;\r\n\t}\r\n\r\n\tpublic reset(): void {\r\n\t\tthis._decorations = [];\r\n\t\tthis._overviewRulerApproximateDecorations = [];\r\n\t\tthis._findScopeDecorationIds = [];\r\n\t\tthis._rangeHighlightDecorationId = null;\r\n\t\tthis._highlightedDecorationId = null;\r\n\t}\r\n\r\n\tpublic getCount(): number {\r\n\t\treturn this._decorations.length;\r\n\t}\r\n\r\n\t/** @deprecated use getFindScopes to support multiple selections */\r\n\tpublic getFindScope(): Range | null {\r\n\t\tif (this._findScopeDecorationIds[0]) {\r\n\t\t\treturn this._editor.getModel().getDecorationRange(this._findScopeDecorationIds[0]);\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic getFindScopes(): Range[] | null {\r\n\t\tif (this._findScopeDecorationIds.length) {\r\n\t\t\tconst scopes = this._findScopeDecorationIds.map(findScopeDecorationId =>\r\n\t\t\t\tthis._editor.getModel().getDecorationRange(findScopeDecorationId)\r\n\t\t\t).filter(element => !!element);\r\n\t\t\tif (scopes.length) {\r\n\t\t\t\treturn scopes as Range[];\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic getStartPosition(): Position {\r\n\t\treturn this._startPosition;\r\n\t}\r\n\r\n\tpublic setStartPosition(newStartPosition: Position): void {\r\n\t\tthis._startPosition = newStartPosition;\r\n\t\tthis.setCurrentFindMatch(null);\r\n\t}\r\n\r\n\tprivate _getDecorationIndex(decorationId: string): number {\r\n\t\tconst index = this._decorations.indexOf(decorationId);\r\n\t\tif (index >= 0) {\r\n\t\t\treturn index + 1;\r\n\t\t}\r\n\t\treturn 1;\r\n\t}\r\n\r\n\tpublic getCurrentMatchesPosition(desiredRange: Range): number {\r\n\t\tlet candidates = this._editor.getModel().getDecorationsInRange(desiredRange);\r\n\t\tfor (const candidate of candidates) {\r\n\t\t\tconst candidateOpts = candidate.options;\r\n\t\t\tif (candidateOpts === FindDecorations._FIND_MATCH_DECORATION || candidateOpts === FindDecorations._CURRENT_FIND_MATCH_DECORATION) {\r\n\t\t\t\treturn this._getDecorationIndex(candidate.id);\r\n\t\t\t}\r\n\t\t}\r\n\t\t// We don't know the current match position, so returns zero to show '?' in find widget\r\n\t\treturn 0;\r\n\t}\r\n\r\n\tpublic setCurrentFindMatch(nextMatch: Range | null): number {\r\n\t\tlet newCurrentDecorationId: string | null = null;\r\n\t\tlet matchPosition = 0;\r\n\t\tif (nextMatch) {\r\n\t\t\tfor (let i = 0, len = this._decorations.length; i < len; i++) {\r\n\t\t\t\tlet range = this._editor.getModel().getDecorationRange(this._decorations[i]);\r\n\t\t\t\tif (nextMatch.equalsRange(range)) {\r\n\t\t\t\t\tnewCurrentDecorationId = this._decorations[i];\r\n\t\t\t\t\tmatchPosition = (i + 1);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (this._highlightedDecorationId !== null || newCurrentDecorationId !== null) {\r\n\t\t\tthis._editor.changeDecorations((changeAccessor: IModelDecorationsChangeAccessor) => {\r\n\t\t\t\tif (this._highlightedDecorationId !== null) {\r\n\t\t\t\t\tchangeAccessor.changeDecorationOptions(this._highlightedDecorationId, FindDecorations._FIND_MATCH_DECORATION);\r\n\t\t\t\t\tthis._highlightedDecorationId = null;\r\n\t\t\t\t}\r\n\t\t\t\tif (newCurrentDecorationId !== null) {\r\n\t\t\t\t\tthis._highlightedDecorationId = newCurrentDecorationId;\r\n\t\t\t\t\tchangeAccessor.changeDecorationOptions(this._highlightedDecorationId, FindDecorations._CURRENT_FIND_MATCH_DECORATION);\r\n\t\t\t\t}\r\n\t\t\t\tif (this._rangeHighlightDecorationId !== null) {\r\n\t\t\t\t\tchangeAccessor.removeDecoration(this._rangeHighlightDecorationId);\r\n\t\t\t\t\tthis._rangeHighlightDecorationId = null;\r\n\t\t\t\t}\r\n\t\t\t\tif (newCurrentDecorationId !== null) {\r\n\t\t\t\t\tlet rng = this._editor.getModel().getDecorationRange(newCurrentDecorationId)!;\r\n\t\t\t\t\tif (rng.startLineNumber !== rng.endLineNumber && rng.endColumn === 1) {\r\n\t\t\t\t\t\tlet lineBeforeEnd = rng.endLineNumber - 1;\r\n\t\t\t\t\t\tlet lineBeforeEndMaxColumn = this._editor.getModel().getLineMaxColumn(lineBeforeEnd);\r\n\t\t\t\t\t\trng = new Range(rng.startLineNumber, rng.startColumn, lineBeforeEnd, lineBeforeEndMaxColumn);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tthis._rangeHighlightDecorationId = changeAccessor.addDecoration(rng, FindDecorations._RANGE_HIGHLIGHT_DECORATION);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\treturn matchPosition;\r\n\t}\r\n\r\n\tpublic set(findMatches: FindMatch[], findScopes: Range[] | null): void {\r\n\t\tthis._editor.changeDecorations((accessor) => {\r\n\r\n\t\t\tlet findMatchesOptions: ModelDecorationOptions = FindDecorations._FIND_MATCH_DECORATION;\r\n\t\t\tlet newOverviewRulerApproximateDecorations: IModelDeltaDecoration[] = [];\r\n\r\n\t\t\tif (findMatches.length > 1000) {\r\n\t\t\t\t// we go into a mode where the overview ruler gets \"approximate\" decorations\r\n\t\t\t\t// the reason is that the overview ruler paints all the decorations in the file and we don't want to cause freezes\r\n\t\t\t\tfindMatchesOptions = FindDecorations._FIND_MATCH_NO_OVERVIEW_DECORATION;\r\n\r\n\t\t\t\t// approximate a distance in lines where matches should be merged\r\n\t\t\t\tconst lineCount = this._editor.getModel().getLineCount();\r\n\t\t\t\tconst height = this._editor.getLayoutInfo().height;\r\n\t\t\t\tconst approxPixelsPerLine = height / lineCount;\r\n\t\t\t\tconst mergeLinesDelta = Math.max(2, Math.ceil(3 / approxPixelsPerLine));\r\n\r\n\t\t\t\t// merge decorations as much as possible\r\n\t\t\t\tlet prevStartLineNumber = findMatches[0].range.startLineNumber;\r\n\t\t\t\tlet prevEndLineNumber = findMatches[0].range.endLineNumber;\r\n\t\t\t\tfor (let i = 1, len = findMatches.length; i < len; i++) {\r\n\t\t\t\t\tconst range = findMatches[i].range;\r\n\t\t\t\t\tif (prevEndLineNumber + mergeLinesDelta >= range.startLineNumber) {\r\n\t\t\t\t\t\tif (range.endLineNumber > prevEndLineNumber) {\r\n\t\t\t\t\t\t\tprevEndLineNumber = range.endLineNumber;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tnewOverviewRulerApproximateDecorations.push({\r\n\t\t\t\t\t\t\trange: new Range(prevStartLineNumber, 1, prevEndLineNumber, 1),\r\n\t\t\t\t\t\t\toptions: FindDecorations._FIND_MATCH_ONLY_OVERVIEW_DECORATION\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t\tprevStartLineNumber = range.startLineNumber;\r\n\t\t\t\t\t\tprevEndLineNumber = range.endLineNumber;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tnewOverviewRulerApproximateDecorations.push({\r\n\t\t\t\t\trange: new Range(prevStartLineNumber, 1, prevEndLineNumber, 1),\r\n\t\t\t\t\toptions: FindDecorations._FIND_MATCH_ONLY_OVERVIEW_DECORATION\r\n\t\t\t\t});\r\n\t\t\t}\r\n\r\n\t\t\t// Find matches\r\n\t\t\tlet newFindMatchesDecorations: IModelDeltaDecoration[] = new Array(findMatches.length);\r\n\t\t\tfor (let i = 0, len = findMatches.length; i < len; i++) {\r\n\t\t\t\tnewFindMatchesDecorations[i] = {\r\n\t\t\t\t\trange: findMatches[i].range,\r\n\t\t\t\t\toptions: findMatchesOptions\r\n\t\t\t\t};\r\n\t\t\t}\r\n\t\t\tthis._decorations = accessor.deltaDecorations(this._decorations, newFindMatchesDecorations);\r\n\r\n\t\t\t// Overview ruler approximate decorations\r\n\t\t\tthis._overviewRulerApproximateDecorations = accessor.deltaDecorations(this._overviewRulerApproximateDecorations, newOverviewRulerApproximateDecorations);\r\n\r\n\t\t\t// Range highlight\r\n\t\t\tif (this._rangeHighlightDecorationId) {\r\n\t\t\t\taccessor.removeDecoration(this._rangeHighlightDecorationId);\r\n\t\t\t\tthis._rangeHighlightDecorationId = null;\r\n\t\t\t}\r\n\r\n\t\t\t// Find scope\r\n\t\t\tif (this._findScopeDecorationIds.length) {\r\n\t\t\t\tthis._findScopeDecorationIds.forEach(findScopeDecorationId => accessor.removeDecoration(findScopeDecorationId));\r\n\t\t\t\tthis._findScopeDecorationIds = [];\r\n\t\t\t}\r\n\t\t\tif (findScopes?.length) {\r\n\t\t\t\tthis._findScopeDecorationIds = findScopes.map(findScope => accessor.addDecoration(findScope, FindDecorations._FIND_SCOPE_DECORATION));\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic matchBeforePosition(position: Position): Range | null {\r\n\t\tif (this._decorations.length === 0) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tfor (let i = this._decorations.length - 1; i >= 0; i--) {\r\n\t\t\tlet decorationId = this._decorations[i];\r\n\t\t\tlet r = this._editor.getModel().getDecorationRange(decorationId);\r\n\t\t\tif (!r || r.endLineNumber > position.lineNumber) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (r.endLineNumber < position.lineNumber) {\r\n\t\t\t\treturn r;\r\n\t\t\t}\r\n\t\t\tif (r.endColumn > position.column) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\treturn r;\r\n\t\t}\r\n\r\n\t\treturn this._editor.getModel().getDecorationRange(this._decorations[this._decorations.length - 1]);\r\n\t}\r\n\r\n\tpublic matchAfterPosition(position: Position): Range | null {\r\n\t\tif (this._decorations.length === 0) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tfor (let i = 0, len = this._decorations.length; i < len; i++) {\r\n\t\t\tlet decorationId = this._decorations[i];\r\n\t\t\tlet r = this._editor.getModel().getDecorationRange(decorationId);\r\n\t\t\tif (!r || r.startLineNumber < position.lineNumber) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (r.startLineNumber > position.lineNumber) {\r\n\t\t\t\treturn r;\r\n\t\t\t}\r\n\t\t\tif (r.startColumn < position.column) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\treturn r;\r\n\t\t}\r\n\r\n\t\treturn this._editor.getModel().getDecorationRange(this._decorations[0]);\r\n\t}\r\n\r\n\tprivate _allDecorations(): string[] {\r\n\t\tlet result: string[] = [];\r\n\t\tresult = result.concat(this._decorations);\r\n\t\tresult = result.concat(this._overviewRulerApproximateDecorations);\r\n\t\tif (this._findScopeDecorationIds.length) {\r\n\t\t\tresult.push(...this._findScopeDecorationIds);\r\n\t\t}\r\n\t\tif (this._rangeHighlightDecorationId) {\r\n\t\t\tresult.push(this._rangeHighlightDecorationId);\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic static readonly _CURRENT_FIND_MATCH_DECORATION = ModelDecorationOptions.register({\r\n\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,\r\n\t\tzIndex: 13,\r\n\t\tclassName: 'currentFindMatch',\r\n\t\tshowIfCollapsed: true,\r\n\t\toverviewRuler: {\r\n\t\t\tcolor: themeColorFromId(overviewRulerFindMatchForeground),\r\n\t\t\tposition: OverviewRulerLane.Center\r\n\t\t},\r\n\t\tminimap: {\r\n\t\t\tcolor: themeColorFromId(minimapFindMatch),\r\n\t\t\tposition: MinimapPosition.Inline\r\n\t\t}\r\n\t});\r\n\r\n\tpublic static readonly _FIND_MATCH_DECORATION = ModelDecorationOptions.register({\r\n\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,\r\n\t\tclassName: 'findMatch',\r\n\t\tshowIfCollapsed: true,\r\n\t\toverviewRuler: {\r\n\t\t\tcolor: themeColorFromId(overviewRulerFindMatchForeground),\r\n\t\t\tposition: OverviewRulerLane.Center\r\n\t\t},\r\n\t\tminimap: {\r\n\t\t\tcolor: themeColorFromId(minimapFindMatch),\r\n\t\t\tposition: MinimapPosition.Inline\r\n\t\t}\r\n\t});\r\n\r\n\tpublic static readonly _FIND_MATCH_NO_OVERVIEW_DECORATION = ModelDecorationOptions.register({\r\n\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,\r\n\t\tclassName: 'findMatch',\r\n\t\tshowIfCollapsed: true\r\n\t});\r\n\r\n\tprivate static readonly _FIND_MATCH_ONLY_OVERVIEW_DECORATION = ModelDecorationOptions.register({\r\n\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,\r\n\t\toverviewRuler: {\r\n\t\t\tcolor: themeColorFromId(overviewRulerFindMatchForeground),\r\n\t\t\tposition: OverviewRulerLane.Center\r\n\t\t}\r\n\t});\r\n\r\n\tprivate static readonly _RANGE_HIGHLIGHT_DECORATION = ModelDecorationOptions.register({\r\n\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,\r\n\t\tclassName: 'rangeHighlight',\r\n\t\tisWholeLine: true\r\n\t});\r\n\r\n\tprivate static readonly _FIND_SCOPE_DECORATION = ModelDecorationOptions.register({\r\n\t\tclassName: 'findScope',\r\n\t\tisWholeLine: true\r\n\t});\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { RunOnceScheduler, TimeoutTimer } from 'vs/base/common/async';\r\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { dispose, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { ReplaceCommand, ReplaceCommandThatPreservesSelection } from 'vs/editor/common/commands/replaceCommand';\r\nimport { CursorChangeReason, ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { Constants } from 'vs/base/common/uint';\r\nimport { ScrollType, ICommand } from 'vs/editor/common/editorCommon';\r\nimport { EndOfLinePreference, FindMatch, ITextModel } from 'vs/editor/common/model';\r\nimport { SearchParams } from 'vs/editor/common/model/textModelSearch';\r\nimport { FindDecorations } from 'vs/editor/contrib/find/findDecorations';\r\nimport { FindReplaceState, FindReplaceStateChangedEvent } from 'vs/editor/contrib/find/findState';\r\nimport { ReplaceAllCommand } from 'vs/editor/contrib/find/replaceAllCommand';\r\nimport { ReplacePattern, parseReplaceString } from 'vs/editor/contrib/find/replacePattern';\r\nimport { RawContextKey } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IKeybindings } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { findFirstInSorted } from 'vs/base/common/arrays';\r\n\r\nexport const CONTEXT_FIND_WIDGET_VISIBLE = new RawContextKey('findWidgetVisible', false);\r\n// Keep ContextKey use of 'Focussed' to not break when clauses\r\nexport const CONTEXT_FIND_INPUT_FOCUSED = new RawContextKey('findInputFocussed', false);\r\nexport const CONTEXT_REPLACE_INPUT_FOCUSED = new RawContextKey('replaceInputFocussed', false);\r\n\r\nexport const ToggleCaseSensitiveKeybinding: IKeybindings = {\r\n\tprimary: KeyMod.Alt | KeyCode.KEY_C,\r\n\tmac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_C }\r\n};\r\nexport const ToggleWholeWordKeybinding: IKeybindings = {\r\n\tprimary: KeyMod.Alt | KeyCode.KEY_W,\r\n\tmac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_W }\r\n};\r\nexport const ToggleRegexKeybinding: IKeybindings = {\r\n\tprimary: KeyMod.Alt | KeyCode.KEY_R,\r\n\tmac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_R }\r\n};\r\nexport const ToggleSearchScopeKeybinding: IKeybindings = {\r\n\tprimary: KeyMod.Alt | KeyCode.KEY_L,\r\n\tmac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_L }\r\n};\r\nexport const TogglePreserveCaseKeybinding: IKeybindings = {\r\n\tprimary: KeyMod.Alt | KeyCode.KEY_P,\r\n\tmac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_P }\r\n};\r\n\r\nexport const FIND_IDS = {\r\n\tStartFindAction: 'actions.find',\r\n\tStartFindWithSelection: 'actions.findWithSelection',\r\n\tNextMatchFindAction: 'editor.action.nextMatchFindAction',\r\n\tPreviousMatchFindAction: 'editor.action.previousMatchFindAction',\r\n\tNextSelectionMatchFindAction: 'editor.action.nextSelectionMatchFindAction',\r\n\tPreviousSelectionMatchFindAction: 'editor.action.previousSelectionMatchFindAction',\r\n\tStartFindReplaceAction: 'editor.action.startFindReplaceAction',\r\n\tCloseFindWidgetCommand: 'closeFindWidget',\r\n\tToggleCaseSensitiveCommand: 'toggleFindCaseSensitive',\r\n\tToggleWholeWordCommand: 'toggleFindWholeWord',\r\n\tToggleRegexCommand: 'toggleFindRegex',\r\n\tToggleSearchScopeCommand: 'toggleFindInSelection',\r\n\tTogglePreserveCaseCommand: 'togglePreserveCase',\r\n\tReplaceOneAction: 'editor.action.replaceOne',\r\n\tReplaceAllAction: 'editor.action.replaceAll',\r\n\tSelectAllMatchesAction: 'editor.action.selectAllMatches'\r\n};\r\n\r\nexport const MATCHES_LIMIT = 19999;\r\nconst RESEARCH_DELAY = 240;\r\n\r\nexport class FindModelBoundToEditorModel {\r\n\r\n\tprivate readonly _editor: IActiveCodeEditor;\r\n\tprivate readonly _state: FindReplaceState;\r\n\tprivate readonly _toDispose = new DisposableStore();\r\n\tprivate readonly _decorations: FindDecorations;\r\n\tprivate _ignoreModelContentChanged: boolean;\r\n\tprivate readonly _startSearchingTimer: TimeoutTimer;\r\n\r\n\tprivate readonly _updateDecorationsScheduler: RunOnceScheduler;\r\n\tprivate _isDisposed: boolean;\r\n\r\n\tconstructor(editor: IActiveCodeEditor, state: FindReplaceState) {\r\n\t\tthis._editor = editor;\r\n\t\tthis._state = state;\r\n\t\tthis._isDisposed = false;\r\n\t\tthis._startSearchingTimer = new TimeoutTimer();\r\n\r\n\t\tthis._decorations = new FindDecorations(editor);\r\n\t\tthis._toDispose.add(this._decorations);\r\n\r\n\t\tthis._updateDecorationsScheduler = new RunOnceScheduler(() => this.research(false), 100);\r\n\t\tthis._toDispose.add(this._updateDecorationsScheduler);\r\n\r\n\t\tthis._toDispose.add(this._editor.onDidChangeCursorPosition((e: ICursorPositionChangedEvent) => {\r\n\t\t\tif (\r\n\t\t\t\te.reason === CursorChangeReason.Explicit\r\n\t\t\t\t|| e.reason === CursorChangeReason.Undo\r\n\t\t\t\t|| e.reason === CursorChangeReason.Redo\r\n\t\t\t) {\r\n\t\t\t\tthis._decorations.setStartPosition(this._editor.getPosition());\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._ignoreModelContentChanged = false;\r\n\t\tthis._toDispose.add(this._editor.onDidChangeModelContent((e) => {\r\n\t\t\tif (this._ignoreModelContentChanged) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (e.isFlush) {\r\n\t\t\t\t// a model.setValue() was called\r\n\t\t\t\tthis._decorations.reset();\r\n\t\t\t}\r\n\t\t\tthis._decorations.setStartPosition(this._editor.getPosition());\r\n\t\t\tthis._updateDecorationsScheduler.schedule();\r\n\t\t}));\r\n\r\n\t\tthis._toDispose.add(this._state.onFindReplaceStateChange((e) => this._onStateChanged(e)));\r\n\r\n\t\tthis.research(false, this._state.searchScope);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._isDisposed = true;\r\n\t\tdispose(this._startSearchingTimer);\r\n\t\tthis._toDispose.dispose();\r\n\t}\r\n\r\n\tprivate _onStateChanged(e: FindReplaceStateChangedEvent): void {\r\n\t\tif (this._isDisposed) {\r\n\t\t\t// The find model is disposed during a find state changed event\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\t// The find model will be disposed momentarily\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (e.searchString || e.isReplaceRevealed || e.isRegex || e.wholeWord || e.matchCase || e.searchScope) {\r\n\t\t\tlet model = this._editor.getModel();\r\n\r\n\t\t\tif (model.isTooLargeForSyncing()) {\r\n\t\t\t\tthis._startSearchingTimer.cancel();\r\n\r\n\t\t\t\tthis._startSearchingTimer.setIfNotSet(() => {\r\n\t\t\t\t\tif (e.searchScope) {\r\n\t\t\t\t\t\tthis.research(e.moveCursor, this._state.searchScope);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tthis.research(e.moveCursor);\r\n\t\t\t\t\t}\r\n\t\t\t\t}, RESEARCH_DELAY);\r\n\t\t\t} else {\r\n\t\t\t\tif (e.searchScope) {\r\n\t\t\t\t\tthis.research(e.moveCursor, this._state.searchScope);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis.research(e.moveCursor);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static _getSearchRange(model: ITextModel, findScope: Range | null): Range {\r\n\t\t// If we have set now or before a find scope, use it for computing the search range\r\n\t\tif (findScope) {\r\n\t\t\treturn findScope;\r\n\t\t}\r\n\r\n\t\treturn model.getFullModelRange();\r\n\t}\r\n\r\n\tprivate research(moveCursor: boolean, newFindScope?: Range | Range[] | null): void {\r\n\t\tlet findScopes: Range[] | null = null;\r\n\t\tif (typeof newFindScope !== 'undefined') {\r\n\t\t\tif (newFindScope !== null) {\r\n\t\t\t\tif (!Array.isArray(newFindScope)) {\r\n\t\t\t\t\tfindScopes = [newFindScope as Range];\r\n\t\t\t\t} else {\r\n\t\t\t\t\tfindScopes = newFindScope;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tfindScopes = this._decorations.getFindScopes();\r\n\t\t}\r\n\t\tif (findScopes !== null) {\r\n\t\t\tfindScopes = findScopes.map(findScope => {\r\n\t\t\t\tif (findScope.startLineNumber !== findScope.endLineNumber) {\r\n\t\t\t\t\tlet endLineNumber = findScope.endLineNumber;\r\n\r\n\t\t\t\t\tif (findScope.endColumn === 1) {\r\n\t\t\t\t\t\tendLineNumber = endLineNumber - 1;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\treturn new Range(findScope.startLineNumber, 1, endLineNumber, this._editor.getModel().getLineMaxColumn(endLineNumber));\r\n\t\t\t\t}\r\n\t\t\t\treturn findScope;\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tlet findMatches = this._findMatches(findScopes, false, MATCHES_LIMIT);\r\n\t\tthis._decorations.set(findMatches, findScopes);\r\n\r\n\t\tconst editorSelection = this._editor.getSelection();\r\n\t\tlet currentMatchesPosition = this._decorations.getCurrentMatchesPosition(editorSelection);\r\n\t\tif (currentMatchesPosition === 0 && findMatches.length > 0) {\r\n\t\t\t// current selection is not on top of a match\r\n\t\t\t// try to find its nearest result from the top of the document\r\n\t\t\tconst matchAfterSelection = findFirstInSorted(findMatches.map(match => match.range), range => Range.compareRangesUsingStarts(range, editorSelection) >= 0);\r\n\t\t\tcurrentMatchesPosition = matchAfterSelection > 0 ? matchAfterSelection - 1 + 1 /** match position is one based */ : currentMatchesPosition;\r\n\t\t}\r\n\r\n\t\tthis._state.changeMatchInfo(\r\n\t\t\tcurrentMatchesPosition,\r\n\t\t\tthis._decorations.getCount(),\r\n\t\t\tundefined\r\n\t\t);\r\n\r\n\t\tif (moveCursor && this._editor.getOption(EditorOption.find).cursorMoveOnType) {\r\n\t\t\tthis._moveToNextMatch(this._decorations.getStartPosition());\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _hasMatches(): boolean {\r\n\t\treturn (this._state.matchesCount > 0);\r\n\t}\r\n\r\n\tprivate _cannotFind(): boolean {\r\n\t\tif (!this._hasMatches()) {\r\n\t\t\tlet findScope = this._decorations.getFindScope();\r\n\t\t\tif (findScope) {\r\n\t\t\t\t// Reveal the selection so user is reminded that 'selection find' is on.\r\n\t\t\t\tthis._editor.revealRangeInCenterIfOutsideViewport(findScope, ScrollType.Smooth);\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tprivate _setCurrentFindMatch(match: Range): void {\r\n\t\tlet matchesPosition = this._decorations.setCurrentFindMatch(match);\r\n\t\tthis._state.changeMatchInfo(\r\n\t\t\tmatchesPosition,\r\n\t\t\tthis._decorations.getCount(),\r\n\t\t\tmatch\r\n\t\t);\r\n\r\n\t\tthis._editor.setSelection(match);\r\n\t\tthis._editor.revealRangeInCenterIfOutsideViewport(match, ScrollType.Smooth);\r\n\t}\r\n\r\n\tprivate _prevSearchPosition(before: Position) {\r\n\t\tlet isUsingLineStops = this._state.isRegex && (\r\n\t\t\tthis._state.searchString.indexOf('^') >= 0\r\n\t\t\t|| this._state.searchString.indexOf('$') >= 0\r\n\t\t);\r\n\t\tlet { lineNumber, column } = before;\r\n\t\tlet model = this._editor.getModel();\r\n\r\n\t\tif (isUsingLineStops || column === 1) {\r\n\t\t\tif (lineNumber === 1) {\r\n\t\t\t\tlineNumber = model.getLineCount();\r\n\t\t\t} else {\r\n\t\t\t\tlineNumber--;\r\n\t\t\t}\r\n\t\t\tcolumn = model.getLineMaxColumn(lineNumber);\r\n\t\t} else {\r\n\t\t\tcolumn--;\r\n\t\t}\r\n\r\n\t\treturn new Position(lineNumber, column);\r\n\t}\r\n\r\n\tprivate _moveToPrevMatch(before: Position, isRecursed: boolean = false): void {\r\n\t\tif (!this._state.canNavigateBack()) {\r\n\t\t\t// we are beyond the first matched find result\r\n\t\t\t// instead of doing nothing, we should refocus the first item\r\n\t\t\tconst nextMatchRange = this._decorations.matchAfterPosition(before);\r\n\r\n\t\t\tif (nextMatchRange) {\r\n\t\t\t\tthis._setCurrentFindMatch(nextMatchRange);\r\n\t\t\t}\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (this._decorations.getCount() < MATCHES_LIMIT) {\r\n\t\t\tlet prevMatchRange = this._decorations.matchBeforePosition(before);\r\n\r\n\t\t\tif (prevMatchRange && prevMatchRange.isEmpty() && prevMatchRange.getStartPosition().equals(before)) {\r\n\t\t\t\tbefore = this._prevSearchPosition(before);\r\n\t\t\t\tprevMatchRange = this._decorations.matchBeforePosition(before);\r\n\t\t\t}\r\n\r\n\t\t\tif (prevMatchRange) {\r\n\t\t\t\tthis._setCurrentFindMatch(prevMatchRange);\r\n\t\t\t}\r\n\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this._cannotFind()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet findScope = this._decorations.getFindScope();\r\n\t\tlet searchRange = FindModelBoundToEditorModel._getSearchRange(this._editor.getModel(), findScope);\r\n\r\n\t\t// ...(----)...|...\r\n\t\tif (searchRange.getEndPosition().isBefore(before)) {\r\n\t\t\tbefore = searchRange.getEndPosition();\r\n\t\t}\r\n\r\n\t\t// ...|...(----)...\r\n\t\tif (before.isBefore(searchRange.getStartPosition())) {\r\n\t\t\tbefore = searchRange.getEndPosition();\r\n\t\t}\r\n\r\n\t\tlet { lineNumber, column } = before;\r\n\t\tlet model = this._editor.getModel();\r\n\r\n\t\tlet position = new Position(lineNumber, column);\r\n\r\n\t\tlet prevMatch = model.findPreviousMatch(this._state.searchString, position, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, false);\r\n\r\n\t\tif (prevMatch && prevMatch.range.isEmpty() && prevMatch.range.getStartPosition().equals(position)) {\r\n\t\t\t// Looks like we're stuck at this position, unacceptable!\r\n\t\t\tposition = this._prevSearchPosition(position);\r\n\t\t\tprevMatch = model.findPreviousMatch(this._state.searchString, position, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, false);\r\n\t\t}\r\n\r\n\t\tif (!prevMatch) {\r\n\t\t\t// there is precisely one match and selection is on top of it\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!isRecursed && !searchRange.containsRange(prevMatch.range)) {\r\n\t\t\treturn this._moveToPrevMatch(prevMatch.range.getStartPosition(), true);\r\n\t\t}\r\n\r\n\t\tthis._setCurrentFindMatch(prevMatch.range);\r\n\t}\r\n\r\n\tpublic moveToPrevMatch(): void {\r\n\t\tthis._moveToPrevMatch(this._editor.getSelection().getStartPosition());\r\n\t}\r\n\r\n\tprivate _nextSearchPosition(after: Position) {\r\n\t\tlet isUsingLineStops = this._state.isRegex && (\r\n\t\t\tthis._state.searchString.indexOf('^') >= 0\r\n\t\t\t|| this._state.searchString.indexOf('$') >= 0\r\n\t\t);\r\n\r\n\t\tlet { lineNumber, column } = after;\r\n\t\tlet model = this._editor.getModel();\r\n\r\n\t\tif (isUsingLineStops || column === model.getLineMaxColumn(lineNumber)) {\r\n\t\t\tif (lineNumber === model.getLineCount()) {\r\n\t\t\t\tlineNumber = 1;\r\n\t\t\t} else {\r\n\t\t\t\tlineNumber++;\r\n\t\t\t}\r\n\t\t\tcolumn = 1;\r\n\t\t} else {\r\n\t\t\tcolumn++;\r\n\t\t}\r\n\r\n\t\treturn new Position(lineNumber, column);\r\n\t}\r\n\r\n\tprivate _moveToNextMatch(after: Position): void {\r\n\t\tif (!this._state.canNavigateForward()) {\r\n\t\t\t// we are beyond the last matched find result\r\n\t\t\t// instead of doing nothing, we should refocus the last item\r\n\t\t\tconst prevMatchRange = this._decorations.matchBeforePosition(after);\r\n\r\n\t\t\tif (prevMatchRange) {\r\n\t\t\t\tthis._setCurrentFindMatch(prevMatchRange);\r\n\t\t\t}\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (this._decorations.getCount() < MATCHES_LIMIT) {\r\n\t\t\tlet nextMatchRange = this._decorations.matchAfterPosition(after);\r\n\r\n\t\t\tif (nextMatchRange && nextMatchRange.isEmpty() && nextMatchRange.getStartPosition().equals(after)) {\r\n\t\t\t\t// Looks like we're stuck at this position, unacceptable!\r\n\t\t\t\tafter = this._nextSearchPosition(after);\r\n\t\t\t\tnextMatchRange = this._decorations.matchAfterPosition(after);\r\n\t\t\t}\r\n\t\t\tif (nextMatchRange) {\r\n\t\t\t\tthis._setCurrentFindMatch(nextMatchRange);\r\n\t\t\t}\r\n\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet nextMatch = this._getNextMatch(after, false, true);\r\n\t\tif (nextMatch) {\r\n\t\t\tthis._setCurrentFindMatch(nextMatch.range);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _getNextMatch(after: Position, captureMatches: boolean, forceMove: boolean, isRecursed: boolean = false): FindMatch | null {\r\n\t\tif (this._cannotFind()) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet findScope = this._decorations.getFindScope();\r\n\t\tlet searchRange = FindModelBoundToEditorModel._getSearchRange(this._editor.getModel(), findScope);\r\n\r\n\t\t// ...(----)...|...\r\n\t\tif (searchRange.getEndPosition().isBefore(after)) {\r\n\t\t\tafter = searchRange.getStartPosition();\r\n\t\t}\r\n\r\n\t\t// ...|...(----)...\r\n\t\tif (after.isBefore(searchRange.getStartPosition())) {\r\n\t\t\tafter = searchRange.getStartPosition();\r\n\t\t}\r\n\r\n\t\tlet { lineNumber, column } = after;\r\n\t\tlet model = this._editor.getModel();\r\n\r\n\t\tlet position = new Position(lineNumber, column);\r\n\r\n\t\tlet nextMatch = model.findNextMatch(this._state.searchString, position, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, captureMatches);\r\n\r\n\t\tif (forceMove && nextMatch && nextMatch.range.isEmpty() && nextMatch.range.getStartPosition().equals(position)) {\r\n\t\t\t// Looks like we're stuck at this position, unacceptable!\r\n\t\t\tposition = this._nextSearchPosition(position);\r\n\t\t\tnextMatch = model.findNextMatch(this._state.searchString, position, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, captureMatches);\r\n\t\t}\r\n\r\n\t\tif (!nextMatch) {\r\n\t\t\t// there is precisely one match and selection is on top of it\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (!isRecursed && !searchRange.containsRange(nextMatch.range)) {\r\n\t\t\treturn this._getNextMatch(nextMatch.range.getEndPosition(), captureMatches, forceMove, true);\r\n\t\t}\r\n\r\n\t\treturn nextMatch;\r\n\t}\r\n\r\n\tpublic moveToNextMatch(): void {\r\n\t\tthis._moveToNextMatch(this._editor.getSelection().getEndPosition());\r\n\t}\r\n\r\n\tprivate _getReplacePattern(): ReplacePattern {\r\n\t\tif (this._state.isRegex) {\r\n\t\t\treturn parseReplaceString(this._state.replaceString);\r\n\t\t}\r\n\t\treturn ReplacePattern.fromStaticValue(this._state.replaceString);\r\n\t}\r\n\r\n\tpublic replace(): void {\r\n\t\tif (!this._hasMatches()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet replacePattern = this._getReplacePattern();\r\n\t\tlet selection = this._editor.getSelection();\r\n\t\tlet nextMatch = this._getNextMatch(selection.getStartPosition(), true, false);\r\n\t\tif (nextMatch) {\r\n\t\t\tif (selection.equalsRange(nextMatch.range)) {\r\n\t\t\t\t// selection sits on a find match => replace it!\r\n\t\t\t\tlet replaceString = replacePattern.buildReplaceString(nextMatch.matches, this._state.preserveCase);\r\n\r\n\t\t\t\tlet command = new ReplaceCommand(selection, replaceString);\r\n\r\n\t\t\t\tthis._executeEditorCommand('replace', command);\r\n\r\n\t\t\t\tthis._decorations.setStartPosition(new Position(selection.startLineNumber, selection.startColumn + replaceString.length));\r\n\t\t\t\tthis.research(true);\r\n\t\t\t} else {\r\n\t\t\t\tthis._decorations.setStartPosition(this._editor.getPosition());\r\n\t\t\t\tthis._setCurrentFindMatch(nextMatch.range);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _findMatches(findScopes: Range[] | null, captureMatches: boolean, limitResultCount: number): FindMatch[] {\r\n\t\tconst searchRanges = (findScopes as [] || [null]).map((scope: Range | null) =>\r\n\t\t\tFindModelBoundToEditorModel._getSearchRange(this._editor.getModel(), scope)\r\n\t\t);\r\n\r\n\t\treturn this._editor.getModel().findMatches(this._state.searchString, searchRanges, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, captureMatches, limitResultCount);\r\n\t}\r\n\r\n\tpublic replaceAll(): void {\r\n\t\tif (!this._hasMatches()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst findScopes = this._decorations.getFindScopes();\r\n\r\n\t\tif (findScopes === null && this._state.matchesCount >= MATCHES_LIMIT) {\r\n\t\t\t// Doing a replace on the entire file that is over ${MATCHES_LIMIT} matches\r\n\t\t\tthis._largeReplaceAll();\r\n\t\t} else {\r\n\t\t\tthis._regularReplaceAll(findScopes);\r\n\t\t}\r\n\r\n\t\tthis.research(false);\r\n\t}\r\n\r\n\tprivate _largeReplaceAll(): void {\r\n\t\tconst searchParams = new SearchParams(this._state.searchString, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null);\r\n\t\tconst searchData = searchParams.parseSearchRequest();\r\n\t\tif (!searchData) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet searchRegex = searchData.regex;\r\n\t\tif (!searchRegex.multiline) {\r\n\t\t\tlet mod = 'mu';\r\n\t\t\tif (searchRegex.ignoreCase) {\r\n\t\t\t\tmod += 'i';\r\n\t\t\t}\r\n\t\t\tif (searchRegex.global) {\r\n\t\t\t\tmod += 'g';\r\n\t\t\t}\r\n\t\t\tsearchRegex = new RegExp(searchRegex.source, mod);\r\n\t\t}\r\n\r\n\t\tconst model = this._editor.getModel();\r\n\t\tconst modelText = model.getValue(EndOfLinePreference.LF);\r\n\t\tconst fullModelRange = model.getFullModelRange();\r\n\r\n\t\tconst replacePattern = this._getReplacePattern();\r\n\t\tlet resultText: string;\r\n\t\tconst preserveCase = this._state.preserveCase;\r\n\r\n\t\tif (replacePattern.hasReplacementPatterns || preserveCase) {\r\n\t\t\tresultText = modelText.replace(searchRegex, function () {\r\n\t\t\t\treturn replacePattern.buildReplaceString(arguments, preserveCase);\r\n\t\t\t});\r\n\t\t} else {\r\n\t\t\tresultText = modelText.replace(searchRegex, replacePattern.buildReplaceString(null, preserveCase));\r\n\t\t}\r\n\r\n\t\tlet command = new ReplaceCommandThatPreservesSelection(fullModelRange, resultText, this._editor.getSelection());\r\n\t\tthis._executeEditorCommand('replaceAll', command);\r\n\t}\r\n\r\n\tprivate _regularReplaceAll(findScopes: Range[] | null): void {\r\n\t\tconst replacePattern = this._getReplacePattern();\r\n\t\t// Get all the ranges (even more than the highlighted ones)\r\n\t\tlet matches = this._findMatches(findScopes, replacePattern.hasReplacementPatterns || this._state.preserveCase, Constants.MAX_SAFE_SMALL_INTEGER);\r\n\r\n\t\tlet replaceStrings: string[] = [];\r\n\t\tfor (let i = 0, len = matches.length; i < len; i++) {\r\n\t\t\treplaceStrings[i] = replacePattern.buildReplaceString(matches[i].matches, this._state.preserveCase);\r\n\t\t}\r\n\r\n\t\tlet command = new ReplaceAllCommand(this._editor.getSelection(), matches.map(m => m.range), replaceStrings);\r\n\t\tthis._executeEditorCommand('replaceAll', command);\r\n\t}\r\n\r\n\tpublic selectAllMatches(): void {\r\n\t\tif (!this._hasMatches()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet findScopes = this._decorations.getFindScopes();\r\n\r\n\t\t// Get all the ranges (even more than the highlighted ones)\r\n\t\tlet matches = this._findMatches(findScopes, false, Constants.MAX_SAFE_SMALL_INTEGER);\r\n\t\tlet selections = matches.map(m => new Selection(m.range.startLineNumber, m.range.startColumn, m.range.endLineNumber, m.range.endColumn));\r\n\r\n\t\t// If one of the ranges is the editor selection, then maintain it as primary\r\n\t\tlet editorSelection = this._editor.getSelection();\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tlet sel = selections[i];\r\n\t\t\tif (sel.equalsRange(editorSelection)) {\r\n\t\t\t\tselections = [editorSelection].concat(selections.slice(0, i)).concat(selections.slice(i + 1));\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._editor.setSelections(selections);\r\n\t}\r\n\r\n\tprivate _executeEditorCommand(source: string, command: ICommand): void {\r\n\t\ttry {\r\n\t\t\tthis._ignoreModelContentChanged = true;\r\n\t\t\tthis._editor.pushUndoStop();\r\n\t\t\tthis._editor.executeCommand(source, command);\r\n\t\t\tthis._editor.pushUndoStop();\r\n\t\t} finally {\r\n\t\t\tthis._ignoreModelContentChanged = false;\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { CaseSensitiveCheckbox, RegexCheckbox, WholeWordsCheckbox } from 'vs/base/browser/ui/findinput/findInputCheckboxes';\r\nimport { Widget } from 'vs/base/browser/ui/widget';\r\nimport { RunOnceScheduler } from 'vs/base/common/async';\r\nimport { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';\r\nimport { FIND_IDS } from 'vs/editor/contrib/find/findModel';\r\nimport { FindReplaceState } from 'vs/editor/contrib/find/findState';\r\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\r\nimport { contrastBorder, editorWidgetBackground, inputActiveOptionBorder, inputActiveOptionBackground, widgetShadow, editorWidgetForeground, inputActiveOptionForeground } from 'vs/platform/theme/common/colorRegistry';\r\nimport { IColorTheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';\r\n\r\nexport class FindOptionsWidget extends Widget implements IOverlayWidget {\r\n\r\n\tprivate static readonly ID = 'editor.contrib.findOptionsWidget';\r\n\r\n\tprivate readonly _editor: ICodeEditor;\r\n\tprivate readonly _state: FindReplaceState;\r\n\tprivate readonly _keybindingService: IKeybindingService;\r\n\r\n\tprivate readonly _domNode: HTMLElement;\r\n\tprivate readonly regex: RegexCheckbox;\r\n\tprivate readonly wholeWords: WholeWordsCheckbox;\r\n\tprivate readonly caseSensitive: CaseSensitiveCheckbox;\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor,\r\n\t\tstate: FindReplaceState,\r\n\t\tkeybindingService: IKeybindingService,\r\n\t\tthemeService: IThemeService\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\tthis._editor = editor;\r\n\t\tthis._state = state;\r\n\t\tthis._keybindingService = keybindingService;\r\n\r\n\t\tthis._domNode = document.createElement('div');\r\n\t\tthis._domNode.className = 'findOptionsWidget';\r\n\t\tthis._domNode.style.display = 'none';\r\n\t\tthis._domNode.style.top = '10px';\r\n\t\tthis._domNode.setAttribute('role', 'presentation');\r\n\t\tthis._domNode.setAttribute('aria-hidden', 'true');\r\n\r\n\t\tconst inputActiveOptionBorderColor = themeService.getColorTheme().getColor(inputActiveOptionBorder);\r\n\t\tconst inputActiveOptionForegroundColor = themeService.getColorTheme().getColor(inputActiveOptionForeground);\r\n\t\tconst inputActiveOptionBackgroundColor = themeService.getColorTheme().getColor(inputActiveOptionBackground);\r\n\r\n\t\tthis.caseSensitive = this._register(new CaseSensitiveCheckbox({\r\n\t\t\tappendTitle: this._keybindingLabelFor(FIND_IDS.ToggleCaseSensitiveCommand),\r\n\t\t\tisChecked: this._state.matchCase,\r\n\t\t\tinputActiveOptionBorder: inputActiveOptionBorderColor,\r\n\t\t\tinputActiveOptionForeground: inputActiveOptionForegroundColor,\r\n\t\t\tinputActiveOptionBackground: inputActiveOptionBackgroundColor\r\n\t\t}));\r\n\t\tthis._domNode.appendChild(this.caseSensitive.domNode);\r\n\t\tthis._register(this.caseSensitive.onChange(() => {\r\n\t\t\tthis._state.change({\r\n\t\t\t\tmatchCase: this.caseSensitive.checked\r\n\t\t\t}, false);\r\n\t\t}));\r\n\r\n\t\tthis.wholeWords = this._register(new WholeWordsCheckbox({\r\n\t\t\tappendTitle: this._keybindingLabelFor(FIND_IDS.ToggleWholeWordCommand),\r\n\t\t\tisChecked: this._state.wholeWord,\r\n\t\t\tinputActiveOptionBorder: inputActiveOptionBorderColor,\r\n\t\t\tinputActiveOptionForeground: inputActiveOptionForegroundColor,\r\n\t\t\tinputActiveOptionBackground: inputActiveOptionBackgroundColor\r\n\t\t}));\r\n\t\tthis._domNode.appendChild(this.wholeWords.domNode);\r\n\t\tthis._register(this.wholeWords.onChange(() => {\r\n\t\t\tthis._state.change({\r\n\t\t\t\twholeWord: this.wholeWords.checked\r\n\t\t\t}, false);\r\n\t\t}));\r\n\r\n\t\tthis.regex = this._register(new RegexCheckbox({\r\n\t\t\tappendTitle: this._keybindingLabelFor(FIND_IDS.ToggleRegexCommand),\r\n\t\t\tisChecked: this._state.isRegex,\r\n\t\t\tinputActiveOptionBorder: inputActiveOptionBorderColor,\r\n\t\t\tinputActiveOptionForeground: inputActiveOptionForegroundColor,\r\n\t\t\tinputActiveOptionBackground: inputActiveOptionBackgroundColor\r\n\t\t}));\r\n\t\tthis._domNode.appendChild(this.regex.domNode);\r\n\t\tthis._register(this.regex.onChange(() => {\r\n\t\t\tthis._state.change({\r\n\t\t\t\tisRegex: this.regex.checked\r\n\t\t\t}, false);\r\n\t\t}));\r\n\r\n\t\tthis._editor.addOverlayWidget(this);\r\n\r\n\t\tthis._register(this._state.onFindReplaceStateChange((e) => {\r\n\t\t\tlet somethingChanged = false;\r\n\t\t\tif (e.isRegex) {\r\n\t\t\t\tthis.regex.checked = this._state.isRegex;\r\n\t\t\t\tsomethingChanged = true;\r\n\t\t\t}\r\n\t\t\tif (e.wholeWord) {\r\n\t\t\t\tthis.wholeWords.checked = this._state.wholeWord;\r\n\t\t\t\tsomethingChanged = true;\r\n\t\t\t}\r\n\t\t\tif (e.matchCase) {\r\n\t\t\t\tthis.caseSensitive.checked = this._state.matchCase;\r\n\t\t\t\tsomethingChanged = true;\r\n\t\t\t}\r\n\t\t\tif (!this._state.isRevealed && somethingChanged) {\r\n\t\t\t\tthis._revealTemporarily();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._register(dom.addDisposableNonBubblingMouseOutListener(this._domNode, (e) => this._onMouseOut()));\r\n\t\tthis._register(dom.addDisposableListener(this._domNode, 'mouseover', (e) => this._onMouseOver()));\r\n\r\n\t\tthis._applyTheme(themeService.getColorTheme());\r\n\t\tthis._register(themeService.onDidColorThemeChange(this._applyTheme.bind(this)));\r\n\t}\r\n\r\n\tprivate _keybindingLabelFor(actionId: string): string {\r\n\t\tlet kb = this._keybindingService.lookupKeybinding(actionId);\r\n\t\tif (!kb) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\treturn ` (${kb.getLabel()})`;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._editor.removeOverlayWidget(this);\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\t// ----- IOverlayWidget API\r\n\r\n\tpublic getId(): string {\r\n\t\treturn FindOptionsWidget.ID;\r\n\t}\r\n\r\n\tpublic getDomNode(): HTMLElement {\r\n\t\treturn this._domNode;\r\n\t}\r\n\r\n\tpublic getPosition(): IOverlayWidgetPosition {\r\n\t\treturn {\r\n\t\t\tpreference: OverlayWidgetPositionPreference.TOP_RIGHT_CORNER\r\n\t\t};\r\n\t}\r\n\r\n\tpublic highlightFindOptions(): void {\r\n\t\tthis._revealTemporarily();\r\n\t}\r\n\r\n\tprivate _hideSoon = this._register(new RunOnceScheduler(() => this._hide(), 2000));\r\n\r\n\tprivate _revealTemporarily(): void {\r\n\t\tthis._show();\r\n\t\tthis._hideSoon.schedule();\r\n\t}\r\n\r\n\tprivate _onMouseOut(): void {\r\n\t\tthis._hideSoon.schedule();\r\n\t}\r\n\r\n\tprivate _onMouseOver(): void {\r\n\t\tthis._hideSoon.cancel();\r\n\t}\r\n\r\n\tprivate _isVisible: boolean = false;\r\n\r\n\tprivate _show(): void {\r\n\t\tif (this._isVisible) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._isVisible = true;\r\n\t\tthis._domNode.style.display = 'block';\r\n\t}\r\n\r\n\tprivate _hide(): void {\r\n\t\tif (!this._isVisible) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._isVisible = false;\r\n\t\tthis._domNode.style.display = 'none';\r\n\t}\r\n\r\n\tprivate _applyTheme(theme: IColorTheme) {\r\n\t\tlet inputStyles = {\r\n\t\t\tinputActiveOptionBorder: theme.getColor(inputActiveOptionBorder),\r\n\t\t\tinputActiveOptionForeground: theme.getColor(inputActiveOptionForeground),\r\n\t\t\tinputActiveOptionBackground: theme.getColor(inputActiveOptionBackground)\r\n\t\t};\r\n\t\tthis.caseSensitive.style(inputStyles);\r\n\t\tthis.wholeWords.style(inputStyles);\r\n\t\tthis.regex.style(inputStyles);\r\n\t}\r\n}\r\n\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst widgetBackground = theme.getColor(editorWidgetBackground);\r\n\tif (widgetBackground) {\r\n\t\tcollector.addRule(`.monaco-editor .findOptionsWidget { background-color: ${widgetBackground}; }`);\r\n\t}\r\n\r\n\tconst widgetForeground = theme.getColor(editorWidgetForeground);\r\n\tif (widgetForeground) {\r\n\t\tcollector.addRule(`.monaco-editor .findOptionsWidget { color: ${widgetForeground}; }`);\r\n\t}\r\n\r\n\r\n\tconst widgetShadowColor = theme.getColor(widgetShadow);\r\n\tif (widgetShadowColor) {\r\n\t\tcollector.addRule(`.monaco-editor .findOptionsWidget { box-shadow: 0 0 8px 2px ${widgetShadowColor}; }`);\r\n\t}\r\n\r\n\tconst hcBorder = theme.getColor(contrastBorder);\r\n\tif (hcBorder) {\r\n\t\tcollector.addRule(`.monaco-editor .findOptionsWidget { border: 2px solid ${hcBorder}; }`);\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { MATCHES_LIMIT } from './findModel';\r\n\r\nexport interface FindReplaceStateChangedEvent {\r\n\tmoveCursor: boolean;\r\n\tupdateHistory: boolean;\r\n\r\n\tsearchString: boolean;\r\n\treplaceString: boolean;\r\n\tisRevealed: boolean;\r\n\tisReplaceRevealed: boolean;\r\n\tisRegex: boolean;\r\n\twholeWord: boolean;\r\n\tmatchCase: boolean;\r\n\tpreserveCase: boolean;\r\n\tsearchScope: boolean;\r\n\tmatchesPosition: boolean;\r\n\tmatchesCount: boolean;\r\n\tcurrentMatch: boolean;\r\n\tloop: boolean;\r\n}\r\n\r\nexport const enum FindOptionOverride {\r\n\tNotSet = 0,\r\n\tTrue = 1,\r\n\tFalse = 2\r\n}\r\n\r\nexport interface INewFindReplaceState {\r\n\tsearchString?: string;\r\n\treplaceString?: string;\r\n\tisRevealed?: boolean;\r\n\tisReplaceRevealed?: boolean;\r\n\tisRegex?: boolean;\r\n\tisRegexOverride?: FindOptionOverride;\r\n\twholeWord?: boolean;\r\n\twholeWordOverride?: FindOptionOverride;\r\n\tmatchCase?: boolean;\r\n\tmatchCaseOverride?: FindOptionOverride;\r\n\tpreserveCase?: boolean;\r\n\tpreserveCaseOverride?: FindOptionOverride;\r\n\tsearchScope?: Range[] | null;\r\n\tloop?: boolean;\r\n}\r\n\r\nfunction effectiveOptionValue(override: FindOptionOverride, value: boolean): boolean {\r\n\tif (override === FindOptionOverride.True) {\r\n\t\treturn true;\r\n\t}\r\n\tif (override === FindOptionOverride.False) {\r\n\t\treturn false;\r\n\t}\r\n\treturn value;\r\n}\r\n\r\nexport class FindReplaceState extends Disposable {\r\n\tprivate _searchString: string;\r\n\tprivate _replaceString: string;\r\n\tprivate _isRevealed: boolean;\r\n\tprivate _isReplaceRevealed: boolean;\r\n\tprivate _isRegex: boolean;\r\n\tprivate _isRegexOverride: FindOptionOverride;\r\n\tprivate _wholeWord: boolean;\r\n\tprivate _wholeWordOverride: FindOptionOverride;\r\n\tprivate _matchCase: boolean;\r\n\tprivate _matchCaseOverride: FindOptionOverride;\r\n\tprivate _preserveCase: boolean;\r\n\tprivate _preserveCaseOverride: FindOptionOverride;\r\n\tprivate _searchScope: Range[] | null;\r\n\tprivate _matchesPosition: number;\r\n\tprivate _matchesCount: number;\r\n\tprivate _currentMatch: Range | null;\r\n\tprivate _loop: boolean;\r\n\tprivate readonly _onFindReplaceStateChange = this._register(new Emitter());\r\n\r\n\tpublic get searchString(): string { return this._searchString; }\r\n\tpublic get replaceString(): string { return this._replaceString; }\r\n\tpublic get isRevealed(): boolean { return this._isRevealed; }\r\n\tpublic get isReplaceRevealed(): boolean { return this._isReplaceRevealed; }\r\n\tpublic get isRegex(): boolean { return effectiveOptionValue(this._isRegexOverride, this._isRegex); }\r\n\tpublic get wholeWord(): boolean { return effectiveOptionValue(this._wholeWordOverride, this._wholeWord); }\r\n\tpublic get matchCase(): boolean { return effectiveOptionValue(this._matchCaseOverride, this._matchCase); }\r\n\tpublic get preserveCase(): boolean { return effectiveOptionValue(this._preserveCaseOverride, this._preserveCase); }\r\n\r\n\tpublic get actualIsRegex(): boolean { return this._isRegex; }\r\n\tpublic get actualWholeWord(): boolean { return this._wholeWord; }\r\n\tpublic get actualMatchCase(): boolean { return this._matchCase; }\r\n\tpublic get actualPreserveCase(): boolean { return this._preserveCase; }\r\n\r\n\tpublic get searchScope(): Range[] | null { return this._searchScope; }\r\n\tpublic get matchesPosition(): number { return this._matchesPosition; }\r\n\tpublic get matchesCount(): number { return this._matchesCount; }\r\n\tpublic get currentMatch(): Range | null { return this._currentMatch; }\r\n\tpublic readonly onFindReplaceStateChange: Event = this._onFindReplaceStateChange.event;\r\n\r\n\tconstructor() {\r\n\t\tsuper();\r\n\t\tthis._searchString = '';\r\n\t\tthis._replaceString = '';\r\n\t\tthis._isRevealed = false;\r\n\t\tthis._isReplaceRevealed = false;\r\n\t\tthis._isRegex = false;\r\n\t\tthis._isRegexOverride = FindOptionOverride.NotSet;\r\n\t\tthis._wholeWord = false;\r\n\t\tthis._wholeWordOverride = FindOptionOverride.NotSet;\r\n\t\tthis._matchCase = false;\r\n\t\tthis._matchCaseOverride = FindOptionOverride.NotSet;\r\n\t\tthis._preserveCase = false;\r\n\t\tthis._preserveCaseOverride = FindOptionOverride.NotSet;\r\n\t\tthis._searchScope = null;\r\n\t\tthis._matchesPosition = 0;\r\n\t\tthis._matchesCount = 0;\r\n\t\tthis._currentMatch = null;\r\n\t\tthis._loop = true;\r\n\t}\r\n\r\n\tpublic changeMatchInfo(matchesPosition: number, matchesCount: number, currentMatch: Range | undefined): void {\r\n\t\tlet changeEvent: FindReplaceStateChangedEvent = {\r\n\t\t\tmoveCursor: false,\r\n\t\t\tupdateHistory: false,\r\n\t\t\tsearchString: false,\r\n\t\t\treplaceString: false,\r\n\t\t\tisRevealed: false,\r\n\t\t\tisReplaceRevealed: false,\r\n\t\t\tisRegex: false,\r\n\t\t\twholeWord: false,\r\n\t\t\tmatchCase: false,\r\n\t\t\tpreserveCase: false,\r\n\t\t\tsearchScope: false,\r\n\t\t\tmatchesPosition: false,\r\n\t\t\tmatchesCount: false,\r\n\t\t\tcurrentMatch: false,\r\n\t\t\tloop: false\r\n\t\t};\r\n\t\tlet somethingChanged = false;\r\n\r\n\t\tif (matchesCount === 0) {\r\n\t\t\tmatchesPosition = 0;\r\n\t\t}\r\n\t\tif (matchesPosition > matchesCount) {\r\n\t\t\tmatchesPosition = matchesCount;\r\n\t\t}\r\n\r\n\t\tif (this._matchesPosition !== matchesPosition) {\r\n\t\t\tthis._matchesPosition = matchesPosition;\r\n\t\t\tchangeEvent.matchesPosition = true;\r\n\t\t\tsomethingChanged = true;\r\n\t\t}\r\n\t\tif (this._matchesCount !== matchesCount) {\r\n\t\t\tthis._matchesCount = matchesCount;\r\n\t\t\tchangeEvent.matchesCount = true;\r\n\t\t\tsomethingChanged = true;\r\n\t\t}\r\n\r\n\t\tif (typeof currentMatch !== 'undefined') {\r\n\t\t\tif (!Range.equalsRange(this._currentMatch, currentMatch)) {\r\n\t\t\t\tthis._currentMatch = currentMatch;\r\n\t\t\t\tchangeEvent.currentMatch = true;\r\n\t\t\t\tsomethingChanged = true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (somethingChanged) {\r\n\t\t\tthis._onFindReplaceStateChange.fire(changeEvent);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic change(newState: INewFindReplaceState, moveCursor: boolean, updateHistory: boolean = true): void {\r\n\t\tlet changeEvent: FindReplaceStateChangedEvent = {\r\n\t\t\tmoveCursor: moveCursor,\r\n\t\t\tupdateHistory: updateHistory,\r\n\t\t\tsearchString: false,\r\n\t\t\treplaceString: false,\r\n\t\t\tisRevealed: false,\r\n\t\t\tisReplaceRevealed: false,\r\n\t\t\tisRegex: false,\r\n\t\t\twholeWord: false,\r\n\t\t\tmatchCase: false,\r\n\t\t\tpreserveCase: false,\r\n\t\t\tsearchScope: false,\r\n\t\t\tmatchesPosition: false,\r\n\t\t\tmatchesCount: false,\r\n\t\t\tcurrentMatch: false,\r\n\t\t\tloop: false\r\n\t\t};\r\n\t\tlet somethingChanged = false;\r\n\r\n\t\tconst oldEffectiveIsRegex = this.isRegex;\r\n\t\tconst oldEffectiveWholeWords = this.wholeWord;\r\n\t\tconst oldEffectiveMatchCase = this.matchCase;\r\n\t\tconst oldEffectivePreserveCase = this.preserveCase;\r\n\r\n\t\tif (typeof newState.searchString !== 'undefined') {\r\n\t\t\tif (this._searchString !== newState.searchString) {\r\n\t\t\t\tthis._searchString = newState.searchString;\r\n\t\t\t\tchangeEvent.searchString = true;\r\n\t\t\t\tsomethingChanged = true;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (typeof newState.replaceString !== 'undefined') {\r\n\t\t\tif (this._replaceString !== newState.replaceString) {\r\n\t\t\t\tthis._replaceString = newState.replaceString;\r\n\t\t\t\tchangeEvent.replaceString = true;\r\n\t\t\t\tsomethingChanged = true;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (typeof newState.isRevealed !== 'undefined') {\r\n\t\t\tif (this._isRevealed !== newState.isRevealed) {\r\n\t\t\t\tthis._isRevealed = newState.isRevealed;\r\n\t\t\t\tchangeEvent.isRevealed = true;\r\n\t\t\t\tsomethingChanged = true;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (typeof newState.isReplaceRevealed !== 'undefined') {\r\n\t\t\tif (this._isReplaceRevealed !== newState.isReplaceRevealed) {\r\n\t\t\t\tthis._isReplaceRevealed = newState.isReplaceRevealed;\r\n\t\t\t\tchangeEvent.isReplaceRevealed = true;\r\n\t\t\t\tsomethingChanged = true;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (typeof newState.isRegex !== 'undefined') {\r\n\t\t\tthis._isRegex = newState.isRegex;\r\n\t\t}\r\n\t\tif (typeof newState.wholeWord !== 'undefined') {\r\n\t\t\tthis._wholeWord = newState.wholeWord;\r\n\t\t}\r\n\t\tif (typeof newState.matchCase !== 'undefined') {\r\n\t\t\tthis._matchCase = newState.matchCase;\r\n\t\t}\r\n\t\tif (typeof newState.preserveCase !== 'undefined') {\r\n\t\t\tthis._preserveCase = newState.preserveCase;\r\n\t\t}\r\n\t\tif (typeof newState.searchScope !== 'undefined') {\r\n\t\t\tif (!newState.searchScope?.every((newSearchScope) => {\r\n\t\t\t\treturn this._searchScope?.some(existingSearchScope => {\r\n\t\t\t\t\treturn !Range.equalsRange(existingSearchScope, newSearchScope);\r\n\t\t\t\t});\r\n\t\t\t})) {\r\n\t\t\t\tthis._searchScope = newState.searchScope;\r\n\t\t\t\tchangeEvent.searchScope = true;\r\n\t\t\t\tsomethingChanged = true;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (typeof newState.loop !== 'undefined') {\r\n\t\t\tif (this._loop !== newState.loop) {\r\n\t\t\t\tthis._loop = newState.loop;\r\n\t\t\t\tchangeEvent.loop = true;\r\n\t\t\t\tsomethingChanged = true;\r\n\t\t\t}\r\n\t\t}\r\n\t\t// Overrides get set when they explicitly come in and get reset anytime something else changes\r\n\t\tthis._isRegexOverride = (typeof newState.isRegexOverride !== 'undefined' ? newState.isRegexOverride : FindOptionOverride.NotSet);\r\n\t\tthis._wholeWordOverride = (typeof newState.wholeWordOverride !== 'undefined' ? newState.wholeWordOverride : FindOptionOverride.NotSet);\r\n\t\tthis._matchCaseOverride = (typeof newState.matchCaseOverride !== 'undefined' ? newState.matchCaseOverride : FindOptionOverride.NotSet);\r\n\t\tthis._preserveCaseOverride = (typeof newState.preserveCaseOverride !== 'undefined' ? newState.preserveCaseOverride : FindOptionOverride.NotSet);\r\n\r\n\t\tif (oldEffectiveIsRegex !== this.isRegex) {\r\n\t\t\tsomethingChanged = true;\r\n\t\t\tchangeEvent.isRegex = true;\r\n\t\t}\r\n\t\tif (oldEffectiveWholeWords !== this.wholeWord) {\r\n\t\t\tsomethingChanged = true;\r\n\t\t\tchangeEvent.wholeWord = true;\r\n\t\t}\r\n\t\tif (oldEffectiveMatchCase !== this.matchCase) {\r\n\t\t\tsomethingChanged = true;\r\n\t\t\tchangeEvent.matchCase = true;\r\n\t\t}\r\n\r\n\t\tif (oldEffectivePreserveCase !== this.preserveCase) {\r\n\t\t\tsomethingChanged = true;\r\n\t\t\tchangeEvent.preserveCase = true;\r\n\t\t}\r\n\r\n\t\tif (somethingChanged) {\r\n\t\t\tthis._onFindReplaceStateChange.fire(changeEvent);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic canNavigateBack(): boolean {\r\n\t\treturn this.canNavigateInLoop() || (this.matchesPosition !== 1);\r\n\t}\r\n\r\n\tpublic canNavigateForward(): boolean {\r\n\t\treturn this.canNavigateInLoop() || (this.matchesPosition < this.matchesCount);\r\n\t}\r\n\r\n\tprivate canNavigateInLoop(): boolean {\r\n\t\treturn this._loop || (this.matchesCount >= MATCHES_LIMIT);\r\n\t}\r\n\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { ReferencesModel, FileReferences, OneReference } from '../referencesModel';\r\nimport { ITextModelService } from 'vs/editor/common/services/resolverService';\r\nimport { ITreeRenderer, ITreeNode, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree';\r\nimport { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel';\r\nimport { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';\r\nimport { ILabelService } from 'vs/platform/label/common/label';\r\nimport { IThemeService } from 'vs/platform/theme/common/themeService';\r\nimport { attachBadgeStyler } from 'vs/platform/theme/common/styler';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { localize } from 'vs/nls';\r\nimport { getBaseLabel } from 'vs/base/common/labels';\r\nimport { dirname, basename } from 'vs/base/common/resources';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';\r\nimport { IListVirtualDelegate, IKeyboardNavigationLabelProvider, IIdentityProvider } from 'vs/base/browser/ui/list/list';\r\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\r\nimport { FuzzyScore, createMatches, IMatch } from 'vs/base/common/filters';\r\nimport { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';\r\n\r\n//#region data source\r\n\r\nexport type TreeElement = FileReferences | OneReference;\r\n\r\nexport class DataSource implements IAsyncDataSource {\r\n\r\n\tconstructor(@ITextModelService private readonly _resolverService: ITextModelService) { }\r\n\r\n\thasChildren(element: ReferencesModel | FileReferences | TreeElement): boolean {\r\n\t\tif (element instanceof ReferencesModel) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (element instanceof FileReferences) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tgetChildren(element: ReferencesModel | FileReferences | TreeElement): TreeElement[] | Promise {\r\n\t\tif (element instanceof ReferencesModel) {\r\n\t\t\treturn element.groups;\r\n\t\t}\r\n\r\n\t\tif (element instanceof FileReferences) {\r\n\t\t\treturn element.resolve(this._resolverService).then(val => {\r\n\t\t\t\t// if (element.failure) {\r\n\t\t\t\t// \t// refresh the element on failure so that\r\n\t\t\t\t// \t// we can update its rendering\r\n\t\t\t\t// \treturn tree.refresh(element).then(() => val.children);\r\n\t\t\t\t// }\r\n\t\t\t\treturn val.children;\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tthrow new Error('bad tree');\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\nexport class Delegate implements IListVirtualDelegate {\r\n\tgetHeight(): number {\r\n\t\treturn 23;\r\n\t}\r\n\tgetTemplateId(element: FileReferences | OneReference): string {\r\n\t\tif (element instanceof FileReferences) {\r\n\t\t\treturn FileReferencesRenderer.id;\r\n\t\t} else {\r\n\t\t\treturn OneReferenceRenderer.id;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class StringRepresentationProvider implements IKeyboardNavigationLabelProvider {\r\n\r\n\tconstructor(@IKeybindingService private readonly _keybindingService: IKeybindingService) { }\r\n\r\n\tgetKeyboardNavigationLabel(element: TreeElement): { toString(): string; } {\r\n\t\tif (element instanceof OneReference) {\r\n\t\t\tconst parts = element.parent.getPreview(element)?.preview(element.range);\r\n\t\t\tif (parts) {\r\n\t\t\t\treturn parts.value;\r\n\t\t\t}\r\n\t\t}\r\n\t\t// FileReferences or unresolved OneReference\r\n\t\treturn basename(element.uri);\r\n\t}\r\n}\r\n\r\nexport class IdentityProvider implements IIdentityProvider {\r\n\r\n\tgetId(element: TreeElement): { toString(): string; } {\r\n\t\treturn element instanceof OneReference ? element.id : element.uri;\r\n\t}\r\n}\r\n\r\n//#region render: File\r\n\r\nclass FileReferencesTemplate extends Disposable {\r\n\r\n\treadonly file: IconLabel;\r\n\treadonly badge: CountBadge;\r\n\r\n\tconstructor(\r\n\t\tcontainer: HTMLElement,\r\n\t\t@ILabelService private readonly _uriLabel: ILabelService,\r\n\t\t@IThemeService themeService: IThemeService,\r\n\t) {\r\n\t\tsuper();\r\n\t\tconst parent = document.createElement('div');\r\n\t\tparent.classList.add('reference-file');\r\n\t\tthis.file = this._register(new IconLabel(parent, { supportHighlights: true }));\r\n\r\n\t\tthis.badge = new CountBadge(dom.append(parent, dom.$('.count')));\r\n\t\tthis._register(attachBadgeStyler(this.badge, themeService));\r\n\r\n\t\tcontainer.appendChild(parent);\r\n\t}\r\n\r\n\tset(element: FileReferences, matches: IMatch[]) {\r\n\t\tlet parent = dirname(element.uri);\r\n\t\tthis.file.setLabel(getBaseLabel(element.uri), this._uriLabel.getUriLabel(parent, { relative: true }), { title: this._uriLabel.getUriLabel(element.uri), matches });\r\n\t\tconst len = element.children.length;\r\n\t\tthis.badge.setCount(len);\r\n\t\tif (len > 1) {\r\n\t\t\tthis.badge.setTitleFormat(localize('referencesCount', \"{0} references\", len));\r\n\t\t} else {\r\n\t\t\tthis.badge.setTitleFormat(localize('referenceCount', \"{0} reference\", len));\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class FileReferencesRenderer implements ITreeRenderer {\r\n\r\n\tstatic readonly id = 'FileReferencesRenderer';\r\n\r\n\treadonly templateId: string = FileReferencesRenderer.id;\r\n\r\n\tconstructor(@IInstantiationService private readonly _instantiationService: IInstantiationService) { }\r\n\r\n\trenderTemplate(container: HTMLElement): FileReferencesTemplate {\r\n\t\treturn this._instantiationService.createInstance(FileReferencesTemplate, container);\r\n\t}\r\n\trenderElement(node: ITreeNode, index: number, template: FileReferencesTemplate): void {\r\n\t\ttemplate.set(node.element, createMatches(node.filterData));\r\n\t}\r\n\tdisposeTemplate(templateData: FileReferencesTemplate): void {\r\n\t\ttemplateData.dispose();\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n//#region render: Reference\r\nclass OneReferenceTemplate {\r\n\r\n\treadonly label: HighlightedLabel;\r\n\r\n\tconstructor(container: HTMLElement) {\r\n\t\tthis.label = new HighlightedLabel(container, false);\r\n\t}\r\n\r\n\tset(element: OneReference, score?: FuzzyScore): void {\r\n\t\tconst preview = element.parent.getPreview(element)?.preview(element.range);\r\n\t\tif (!preview || !preview.value) {\r\n\t\t\t// this means we FAILED to resolve the document or the value is the empty string\r\n\t\t\tthis.label.set(`${basename(element.uri)}:${element.range.startLineNumber + 1}:${element.range.startColumn + 1}`);\r\n\t\t} else {\r\n\t\t\t// render search match as highlight unless\r\n\t\t\t// we have score, then render the score\r\n\t\t\tconst { value, highlight } = preview;\r\n\t\t\tif (score && !FuzzyScore.isDefault(score)) {\r\n\t\t\t\tthis.label.element.classList.toggle('referenceMatch', false);\r\n\t\t\t\tthis.label.set(value, createMatches(score));\r\n\t\t\t} else {\r\n\t\t\t\tthis.label.element.classList.toggle('referenceMatch', true);\r\n\t\t\t\tthis.label.set(value, [highlight]);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class OneReferenceRenderer implements ITreeRenderer {\r\n\r\n\tstatic readonly id = 'OneReferenceRenderer';\r\n\r\n\treadonly templateId: string = OneReferenceRenderer.id;\r\n\r\n\trenderTemplate(container: HTMLElement): OneReferenceTemplate {\r\n\t\treturn new OneReferenceTemplate(container);\r\n\t}\r\n\trenderElement(node: ITreeNode, index: number, templateData: OneReferenceTemplate): void {\r\n\t\ttemplateData.set(node.element, node.filterData);\r\n\t}\r\n\tdisposeTemplate(): void {\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n\r\nexport class AccessibilityProvider implements IListAccessibilityProvider {\r\n\r\n\tgetWidgetAriaLabel(): string {\r\n\t\treturn localize('treeAriaLabel', \"References\");\r\n\t}\r\n\r\n\tgetAriaLabel(element: FileReferences | OneReference): string | null {\r\n\t\treturn element.ariaMessage;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IQuickAccessProvider } from 'vs/platform/quickinput/common/quickAccess';\r\nimport { IEditor, ScrollType, IDiffEditor } from 'vs/editor/common/editorCommon';\r\nimport { IModelDeltaDecoration, OverviewRulerLane, ITextModel } from 'vs/editor/common/model';\r\nimport { IRange } from 'vs/editor/common/core/range';\r\nimport { themeColorFromId } from 'vs/platform/theme/common/themeService';\r\nimport { overviewRulerRangeHighlight } from 'vs/editor/common/view/editorColorRegistry';\r\nimport { IQuickPick, IQuickPickItem, IKeyMods } from 'vs/platform/quickinput/common/quickInput';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { IDisposable, DisposableStore, toDisposable, MutableDisposable } from 'vs/base/common/lifecycle';\r\nimport { Event } from 'vs/base/common/event';\r\nimport { isDiffEditor, getCodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { withNullAsUndefined } from 'vs/base/common/types';\r\nimport { once } from 'vs/base/common/functional';\r\n\r\ninterface IEditorLineDecoration {\r\n\trangeHighlightId: string;\r\n\toverviewRulerDecorationId: string;\r\n}\r\n\r\nexport interface IEditorNavigationQuickAccessOptions {\r\n\tcanAcceptInBackground?: boolean;\r\n}\r\n\r\nexport interface IQuickAccessTextEditorContext {\r\n\r\n\t/**\r\n\t * The current active editor.\r\n\t */\r\n\treadonly editor: IEditor;\r\n\r\n\t/**\r\n\t * If defined, allows to restore the original view state\r\n\t * the text editor had before quick access opened.\r\n\t */\r\n\trestoreViewState?: () => void;\r\n}\r\n\r\n/**\r\n * A reusable quick access provider for the editor with support\r\n * for adding decorations for navigating in the currently active file\r\n * (for example \"Go to line\", \"Go to symbol\").\r\n */\r\nexport abstract class AbstractEditorNavigationQuickAccessProvider implements IQuickAccessProvider {\r\n\r\n\tconstructor(protected options?: IEditorNavigationQuickAccessOptions) { }\r\n\r\n\t//#region Provider methods\r\n\r\n\tprovide(picker: IQuickPick, token: CancellationToken): IDisposable {\r\n\t\tconst disposables = new DisposableStore();\r\n\r\n\t\t// Apply options if any\r\n\t\tpicker.canAcceptInBackground = !!this.options?.canAcceptInBackground;\r\n\r\n\t\t// Disable filtering & sorting, we control the results\r\n\t\tpicker.matchOnLabel = picker.matchOnDescription = picker.matchOnDetail = picker.sortByLabel = false;\r\n\r\n\t\t// Provide based on current active editor\r\n\t\tconst pickerDisposable = disposables.add(new MutableDisposable());\r\n\t\tpickerDisposable.value = this.doProvide(picker, token);\r\n\r\n\t\t// Re-create whenever the active editor changes\r\n\t\tdisposables.add(this.onDidActiveTextEditorControlChange(() => {\r\n\r\n\t\t\t// Clear old\r\n\t\t\tpickerDisposable.value = undefined;\r\n\r\n\t\t\t// Add new\r\n\t\t\tpickerDisposable.value = this.doProvide(picker, token);\r\n\t\t}));\r\n\r\n\t\treturn disposables;\r\n\t}\r\n\r\n\tprivate doProvide(picker: IQuickPick, token: CancellationToken): IDisposable {\r\n\t\tconst disposables = new DisposableStore();\r\n\r\n\t\t// With text control\r\n\t\tconst editor = this.activeTextEditorControl;\r\n\t\tif (editor && this.canProvideWithTextEditor(editor)) {\r\n\t\t\tconst context: IQuickAccessTextEditorContext = { editor };\r\n\r\n\t\t\t// Restore any view state if this picker was closed\r\n\t\t\t// without actually going to a line\r\n\t\t\tconst codeEditor = getCodeEditor(editor);\r\n\t\t\tif (codeEditor) {\r\n\r\n\t\t\t\t// Remember view state and update it when the cursor position\r\n\t\t\t\t// changes even later because it could be that the user has\r\n\t\t\t\t// configured quick access to remain open when focus is lost and\r\n\t\t\t\t// we always want to restore the current location.\r\n\t\t\t\tlet lastKnownEditorViewState = withNullAsUndefined(editor.saveViewState());\r\n\t\t\t\tdisposables.add(codeEditor.onDidChangeCursorPosition(() => {\r\n\t\t\t\t\tlastKnownEditorViewState = withNullAsUndefined(editor.saveViewState());\r\n\t\t\t\t}));\r\n\r\n\t\t\t\tcontext.restoreViewState = () => {\r\n\t\t\t\t\tif (lastKnownEditorViewState && editor === this.activeTextEditorControl) {\r\n\t\t\t\t\t\teditor.restoreViewState(lastKnownEditorViewState);\r\n\t\t\t\t\t}\r\n\t\t\t\t};\r\n\r\n\t\t\t\tdisposables.add(once(token.onCancellationRequested)(() => context.restoreViewState?.()));\r\n\t\t\t}\r\n\r\n\t\t\t// Clean up decorations on dispose\r\n\t\t\tdisposables.add(toDisposable(() => this.clearDecorations(editor)));\r\n\r\n\t\t\t// Ask subclass for entries\r\n\t\t\tdisposables.add(this.provideWithTextEditor(context, picker, token));\r\n\t\t}\r\n\r\n\t\t// Without text control\r\n\t\telse {\r\n\t\t\tdisposables.add(this.provideWithoutTextEditor(picker, token));\r\n\t\t}\r\n\r\n\t\treturn disposables;\r\n\t}\r\n\r\n\t/**\r\n\t * Subclasses to implement if they can operate on the text editor.\r\n\t */\r\n\tprotected canProvideWithTextEditor(editor: IEditor): boolean {\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t * Subclasses to implement to provide picks for the picker when an editor is active.\r\n\t */\r\n\tprotected abstract provideWithTextEditor(context: IQuickAccessTextEditorContext, picker: IQuickPick, token: CancellationToken): IDisposable;\r\n\r\n\t/**\r\n\t * Subclasses to implement to provide picks for the picker when no editor is active.\r\n\t */\r\n\tprotected abstract provideWithoutTextEditor(picker: IQuickPick, token: CancellationToken): IDisposable;\r\n\r\n\tprotected gotoLocation({ editor }: IQuickAccessTextEditorContext, options: { range: IRange, keyMods: IKeyMods, forceSideBySide?: boolean, preserveFocus?: boolean }): void {\r\n\t\teditor.setSelection(options.range);\r\n\t\teditor.revealRangeInCenter(options.range, ScrollType.Smooth);\r\n\t\tif (!options.preserveFocus) {\r\n\t\t\teditor.focus();\r\n\t\t}\r\n\t}\r\n\r\n\tprotected getModel(editor: IEditor | IDiffEditor): ITextModel | undefined {\r\n\t\treturn isDiffEditor(editor) ?\r\n\t\t\teditor.getModel()?.modified :\r\n\t\t\teditor.getModel() as ITextModel;\r\n\t}\r\n\r\n\t//#endregion\r\n\r\n\r\n\t//#region Editor access\r\n\r\n\t/**\r\n\t * Subclasses to provide an event when the active editor control changes.\r\n\t */\r\n\tprotected abstract readonly onDidActiveTextEditorControlChange: Event;\r\n\r\n\t/**\r\n\t * Subclasses to provide the current active editor control.\r\n\t */\r\n\tprotected abstract activeTextEditorControl: IEditor | undefined;\r\n\r\n\t//#endregion\r\n\r\n\r\n\t//#region Decorations Utils\r\n\r\n\tprivate rangeHighlightDecorationId: IEditorLineDecoration | undefined = undefined;\r\n\r\n\tprotected addDecorations(editor: IEditor, range: IRange): void {\r\n\t\teditor.changeDecorations(changeAccessor => {\r\n\r\n\t\t\t// Reset old decorations if any\r\n\t\t\tconst deleteDecorations: string[] = [];\r\n\t\t\tif (this.rangeHighlightDecorationId) {\r\n\t\t\t\tdeleteDecorations.push(this.rangeHighlightDecorationId.overviewRulerDecorationId);\r\n\t\t\t\tdeleteDecorations.push(this.rangeHighlightDecorationId.rangeHighlightId);\r\n\r\n\t\t\t\tthis.rangeHighlightDecorationId = undefined;\r\n\t\t\t}\r\n\r\n\t\t\t// Add new decorations for the range\r\n\t\t\tconst newDecorations: IModelDeltaDecoration[] = [\r\n\r\n\t\t\t\t// highlight the entire line on the range\r\n\t\t\t\t{\r\n\t\t\t\t\trange,\r\n\t\t\t\t\toptions: {\r\n\t\t\t\t\t\tclassName: 'rangeHighlight',\r\n\t\t\t\t\t\tisWholeLine: true\r\n\t\t\t\t\t}\r\n\t\t\t\t},\r\n\r\n\t\t\t\t// also add overview ruler highlight\r\n\t\t\t\t{\r\n\t\t\t\t\trange,\r\n\t\t\t\t\toptions: {\r\n\t\t\t\t\t\toverviewRuler: {\r\n\t\t\t\t\t\t\tcolor: themeColorFromId(overviewRulerRangeHighlight),\r\n\t\t\t\t\t\t\tposition: OverviewRulerLane.Full\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t];\r\n\r\n\t\t\tconst [rangeHighlightId, overviewRulerDecorationId] = changeAccessor.deltaDecorations(deleteDecorations, newDecorations);\r\n\r\n\t\t\tthis.rangeHighlightDecorationId = { rangeHighlightId, overviewRulerDecorationId };\r\n\t\t});\r\n\t}\r\n\r\n\tprotected clearDecorations(editor: IEditor): void {\r\n\t\tconst rangeHighlightDecorationId = this.rangeHighlightDecorationId;\r\n\t\tif (rangeHighlightDecorationId) {\r\n\t\t\teditor.changeDecorations(changeAccessor => {\r\n\t\t\t\tchangeAccessor.deltaDecorations([\r\n\t\t\t\t\trangeHighlightDecorationId.overviewRulerDecorationId,\r\n\t\t\t\t\trangeHighlightDecorationId.rangeHighlightId\r\n\t\t\t\t], []);\r\n\t\t\t});\r\n\r\n\t\t\tthis.rangeHighlightDecorationId = undefined;\r\n\t\t}\r\n\t}\r\n\r\n\t//#endregion\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { localize } from 'vs/nls';\r\nimport { IQuickPick, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { DisposableStore, IDisposable, Disposable, toDisposable } from 'vs/base/common/lifecycle';\r\nimport { IEditor, ScrollType } from 'vs/editor/common/editorCommon';\r\nimport { IRange } from 'vs/editor/common/core/range';\r\nimport { AbstractEditorNavigationQuickAccessProvider, IQuickAccessTextEditorContext } from 'vs/editor/contrib/quickAccess/editorNavigationQuickAccess';\r\nimport { IPosition } from 'vs/editor/common/core/position';\r\nimport { getCodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorOption, RenderLineNumbersType } from 'vs/editor/common/config/editorOptions';\r\n\r\ninterface IGotoLineQuickPickItem extends IQuickPickItem, Partial { }\r\n\r\nexport abstract class AbstractGotoLineQuickAccessProvider extends AbstractEditorNavigationQuickAccessProvider {\r\n\r\n\tstatic PREFIX = ':';\r\n\r\n\tconstructor() {\r\n\t\tsuper({ canAcceptInBackground: true });\r\n\t}\r\n\r\n\tprotected provideWithoutTextEditor(picker: IQuickPick): IDisposable {\r\n\t\tconst label = localize('cannotRunGotoLine', \"Open a text editor first to go to a line.\");\r\n\r\n\t\tpicker.items = [{ label }];\r\n\t\tpicker.ariaLabel = label;\r\n\r\n\t\treturn Disposable.None;\r\n\t}\r\n\r\n\tprotected provideWithTextEditor(context: IQuickAccessTextEditorContext, picker: IQuickPick, token: CancellationToken): IDisposable {\r\n\t\tconst editor = context.editor;\r\n\t\tconst disposables = new DisposableStore();\r\n\r\n\t\t// Goto line once picked\r\n\t\tdisposables.add(picker.onDidAccept(event => {\r\n\t\t\tconst [item] = picker.selectedItems;\r\n\t\t\tif (item) {\r\n\t\t\t\tif (!this.isValidLineNumber(editor, item.lineNumber)) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis.gotoLocation(context, { range: this.toRange(item.lineNumber, item.column), keyMods: picker.keyMods, preserveFocus: event.inBackground });\r\n\r\n\t\t\t\tif (!event.inBackground) {\r\n\t\t\t\t\tpicker.hide();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\t// React to picker changes\r\n\t\tconst updatePickerAndEditor = () => {\r\n\t\t\tconst position = this.parsePosition(editor, picker.value.trim().substr(AbstractGotoLineQuickAccessProvider.PREFIX.length));\r\n\t\t\tconst label = this.getPickLabel(editor, position.lineNumber, position.column);\r\n\r\n\t\t\t// Picker\r\n\t\t\tpicker.items = [{\r\n\t\t\t\tlineNumber: position.lineNumber,\r\n\t\t\t\tcolumn: position.column,\r\n\t\t\t\tlabel\r\n\t\t\t}];\r\n\r\n\t\t\t// ARIA Label\r\n\t\t\tpicker.ariaLabel = label;\r\n\r\n\t\t\t// Clear decorations for invalid range\r\n\t\t\tif (!this.isValidLineNumber(editor, position.lineNumber)) {\r\n\t\t\t\tthis.clearDecorations(editor);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\t// Reveal\r\n\t\t\tconst range = this.toRange(position.lineNumber, position.column);\r\n\t\t\teditor.revealRangeInCenter(range, ScrollType.Smooth);\r\n\r\n\t\t\t// Decorate\r\n\t\t\tthis.addDecorations(editor, range);\r\n\t\t};\r\n\t\tupdatePickerAndEditor();\r\n\t\tdisposables.add(picker.onDidChangeValue(() => updatePickerAndEditor()));\r\n\r\n\t\t// Adjust line number visibility as needed\r\n\t\tconst codeEditor = getCodeEditor(editor);\r\n\t\tif (codeEditor) {\r\n\t\t\tconst options = codeEditor.getOptions();\r\n\t\t\tconst lineNumbers = options.get(EditorOption.lineNumbers);\r\n\t\t\tif (lineNumbers.renderType === RenderLineNumbersType.Relative) {\r\n\t\t\t\tcodeEditor.updateOptions({ lineNumbers: 'on' });\r\n\r\n\t\t\t\tdisposables.add(toDisposable(() => codeEditor.updateOptions({ lineNumbers: 'relative' })));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn disposables;\r\n\t}\r\n\r\n\tprivate toRange(lineNumber = 1, column = 1): IRange {\r\n\t\treturn {\r\n\t\t\tstartLineNumber: lineNumber,\r\n\t\t\tstartColumn: column,\r\n\t\t\tendLineNumber: lineNumber,\r\n\t\t\tendColumn: column\r\n\t\t};\r\n\t}\r\n\r\n\tprivate parsePosition(editor: IEditor, value: string): IPosition {\r\n\r\n\t\t// Support line-col formats of `line,col`, `line:col`, `line#col`\r\n\t\tconst numbers = value.split(/,|:|#/).map(part => parseInt(part, 10)).filter(part => !isNaN(part));\r\n\t\tconst endLine = this.lineCount(editor) + 1;\r\n\r\n\t\treturn {\r\n\t\t\tlineNumber: numbers[0] > 0 ? numbers[0] : endLine + numbers[0],\r\n\t\t\tcolumn: numbers[1]\r\n\t\t};\r\n\t}\r\n\r\n\tprivate getPickLabel(editor: IEditor, lineNumber: number, column: number | undefined): string {\r\n\r\n\t\t// Location valid: indicate this as picker label\r\n\t\tif (this.isValidLineNumber(editor, lineNumber)) {\r\n\t\t\tif (this.isValidColumn(editor, lineNumber, column)) {\r\n\t\t\t\treturn localize('gotoLineColumnLabel', \"Go to line {0} and column {1}.\", lineNumber, column);\r\n\t\t\t}\r\n\r\n\t\t\treturn localize('gotoLineLabel', \"Go to line {0}.\", lineNumber);\r\n\t\t}\r\n\r\n\t\t// Location invalid: show generic label\r\n\t\tconst position = editor.getPosition() || { lineNumber: 1, column: 1 };\r\n\t\tconst lineCount = this.lineCount(editor);\r\n\t\tif (lineCount > 1) {\r\n\t\t\treturn localize('gotoLineLabelEmptyWithLimit', \"Current Line: {0}, Character: {1}. Type a line number between 1 and {2} to navigate to.\", position.lineNumber, position.column, lineCount);\r\n\t\t}\r\n\r\n\t\treturn localize('gotoLineLabelEmpty', \"Current Line: {0}, Character: {1}. Type a line number to navigate to.\", position.lineNumber, position.column);\r\n\t}\r\n\r\n\tprivate isValidLineNumber(editor: IEditor, lineNumber: number | undefined): boolean {\r\n\t\tif (!lineNumber || typeof lineNumber !== 'number') {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\treturn lineNumber > 0 && lineNumber <= this.lineCount(editor);\r\n\t}\r\n\r\n\tprivate isValidColumn(editor: IEditor, lineNumber: number, column: number | undefined): boolean {\r\n\t\tif (!column || typeof column !== 'number') {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tconst model = this.getModel(editor);\r\n\t\tif (!model) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tconst positionCandidate = { lineNumber, column };\r\n\r\n\t\treturn model.validatePosition(positionCandidate).equals(positionCandidate);\r\n\t}\r\n\r\n\tprivate lineCount(editor: IEditor): number {\r\n\t\treturn this.getModel(editor)?.getLineCount() ?? 0;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { localize } from 'vs/nls';\r\nimport { IQuickPick, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';\r\nimport { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\r\nimport { DisposableStore, IDisposable, Disposable, toDisposable } from 'vs/base/common/lifecycle';\r\nimport { ScrollType } from 'vs/editor/common/editorCommon';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { IRange, Range } from 'vs/editor/common/core/range';\r\nimport { AbstractEditorNavigationQuickAccessProvider, IEditorNavigationQuickAccessOptions, IQuickAccessTextEditorContext } from 'vs/editor/contrib/quickAccess/editorNavigationQuickAccess';\r\nimport { DocumentSymbol, SymbolKinds, SymbolTag, DocumentSymbolProviderRegistry, SymbolKind } from 'vs/editor/common/modes';\r\nimport { OutlineModel } from 'vs/editor/contrib/documentSymbols/outlineModel';\r\nimport { trim, format } from 'vs/base/common/strings';\r\nimport { prepareQuery, IPreparedQuery, pieceToQuery, scoreFuzzy2 } from 'vs/base/common/fuzzyScorer';\r\nimport { IMatch } from 'vs/base/common/filters';\r\nimport { Codicon } from 'vs/base/common/codicons';\r\n\r\nexport interface IGotoSymbolQuickPickItem extends IQuickPickItem {\r\n\tkind: SymbolKind,\r\n\tindex: number,\r\n\tscore?: number;\r\n\trange?: { decoration: IRange, selection: IRange }\r\n}\r\n\r\nexport interface IGotoSymbolQuickAccessProviderOptions extends IEditorNavigationQuickAccessOptions {\r\n\topenSideBySideDirection?: () => undefined | 'right' | 'down'\r\n}\r\n\r\nexport abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEditorNavigationQuickAccessProvider {\r\n\r\n\tstatic PREFIX = '@';\r\n\tstatic SCOPE_PREFIX = ':';\r\n\tstatic PREFIX_BY_CATEGORY = `${AbstractGotoSymbolQuickAccessProvider.PREFIX}${AbstractGotoSymbolQuickAccessProvider.SCOPE_PREFIX}`;\r\n\r\n\tconstructor(protected options: IGotoSymbolQuickAccessProviderOptions = Object.create(null)) {\r\n\t\tsuper(options);\r\n\r\n\t\toptions.canAcceptInBackground = true;\r\n\t}\r\n\r\n\tprotected provideWithoutTextEditor(picker: IQuickPick): IDisposable {\r\n\t\tthis.provideLabelPick(picker, localize('cannotRunGotoSymbolWithoutEditor', \"To go to a symbol, first open a text editor with symbol information.\"));\r\n\r\n\t\treturn Disposable.None;\r\n\t}\r\n\r\n\tprotected provideWithTextEditor(context: IQuickAccessTextEditorContext, picker: IQuickPick, token: CancellationToken): IDisposable {\r\n\t\tconst editor = context.editor;\r\n\t\tconst model = this.getModel(editor);\r\n\t\tif (!model) {\r\n\t\t\treturn Disposable.None;\r\n\t\t}\r\n\r\n\t\t// Provide symbols from model if available in registry\r\n\t\tif (DocumentSymbolProviderRegistry.has(model)) {\r\n\t\t\treturn this.doProvideWithEditorSymbols(context, model, picker, token);\r\n\t\t}\r\n\r\n\t\t// Otherwise show an entry for a model without registry\r\n\t\t// But give a chance to resolve the symbols at a later\r\n\t\t// point if possible\r\n\t\treturn this.doProvideWithoutEditorSymbols(context, model, picker, token);\r\n\t}\r\n\r\n\tprivate doProvideWithoutEditorSymbols(context: IQuickAccessTextEditorContext, model: ITextModel, picker: IQuickPick, token: CancellationToken): IDisposable {\r\n\t\tconst disposables = new DisposableStore();\r\n\r\n\t\t// Generic pick for not having any symbol information\r\n\t\tthis.provideLabelPick(picker, localize('cannotRunGotoSymbolWithoutSymbolProvider', \"The active text editor does not provide symbol information.\"));\r\n\r\n\t\t// Wait for changes to the registry and see if eventually\r\n\t\t// we do get symbols. This can happen if the picker is opened\r\n\t\t// very early after the model has loaded but before the\r\n\t\t// language registry is ready.\r\n\t\t// https://github.com/microsoft/vscode/issues/70607\r\n\t\t(async () => {\r\n\t\t\tconst result = await this.waitForLanguageSymbolRegistry(model, disposables);\r\n\t\t\tif (!result || token.isCancellationRequested) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tdisposables.add(this.doProvideWithEditorSymbols(context, model, picker, token));\r\n\t\t})();\r\n\r\n\t\treturn disposables;\r\n\t}\r\n\r\n\tprivate provideLabelPick(picker: IQuickPick, label: string): void {\r\n\t\tpicker.items = [{ label, index: 0, kind: SymbolKind.String }];\r\n\t\tpicker.ariaLabel = label;\r\n\t}\r\n\r\n\tprotected async waitForLanguageSymbolRegistry(model: ITextModel, disposables: DisposableStore): Promise {\r\n\t\tif (DocumentSymbolProviderRegistry.has(model)) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tlet symbolProviderRegistryPromiseResolve: (res: boolean) => void;\r\n\t\tconst symbolProviderRegistryPromise = new Promise(resolve => symbolProviderRegistryPromiseResolve = resolve);\r\n\r\n\t\t// Resolve promise when registry knows model\r\n\t\tconst symbolProviderListener = disposables.add(DocumentSymbolProviderRegistry.onDidChange(() => {\r\n\t\t\tif (DocumentSymbolProviderRegistry.has(model)) {\r\n\t\t\t\tsymbolProviderListener.dispose();\r\n\r\n\t\t\t\tsymbolProviderRegistryPromiseResolve(true);\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\t// Resolve promise when we get disposed too\r\n\t\tdisposables.add(toDisposable(() => symbolProviderRegistryPromiseResolve(false)));\r\n\r\n\t\treturn symbolProviderRegistryPromise;\r\n\t}\r\n\r\n\tprivate doProvideWithEditorSymbols(context: IQuickAccessTextEditorContext, model: ITextModel, picker: IQuickPick, token: CancellationToken): IDisposable {\r\n\t\tconst editor = context.editor;\r\n\t\tconst disposables = new DisposableStore();\r\n\r\n\t\t// Goto symbol once picked\r\n\t\tdisposables.add(picker.onDidAccept(event => {\r\n\t\t\tconst [item] = picker.selectedItems;\r\n\t\t\tif (item && item.range) {\r\n\t\t\t\tthis.gotoLocation(context, { range: item.range.selection, keyMods: picker.keyMods, preserveFocus: event.inBackground });\r\n\r\n\t\t\t\tif (!event.inBackground) {\r\n\t\t\t\t\tpicker.hide();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\t// Goto symbol side by side if enabled\r\n\t\tdisposables.add(picker.onDidTriggerItemButton(({ item }) => {\r\n\t\t\tif (item && item.range) {\r\n\t\t\t\tthis.gotoLocation(context, { range: item.range.selection, keyMods: picker.keyMods, forceSideBySide: true });\r\n\r\n\t\t\t\tpicker.hide();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\t// Resolve symbols from document once and reuse this\r\n\t\t// request for all filtering and typing then on\r\n\t\tconst symbolsPromise = this.getDocumentSymbols(model, token);\r\n\r\n\t\t// Set initial picks and update on type\r\n\t\tlet picksCts: CancellationTokenSource | undefined = undefined;\r\n\t\tconst updatePickerItems = async () => {\r\n\r\n\t\t\t// Cancel any previous ask for picks and busy\r\n\t\t\tpicksCts?.dispose(true);\r\n\t\t\tpicker.busy = false;\r\n\r\n\t\t\t// Create new cancellation source for this run\r\n\t\t\tpicksCts = new CancellationTokenSource(token);\r\n\r\n\t\t\t// Collect symbol picks\r\n\t\t\tpicker.busy = true;\r\n\t\t\ttry {\r\n\t\t\t\tconst query = prepareQuery(picker.value.substr(AbstractGotoSymbolQuickAccessProvider.PREFIX.length).trim());\r\n\t\t\t\tconst items = await this.doGetSymbolPicks(symbolsPromise, query, undefined, picksCts.token);\r\n\t\t\t\tif (token.isCancellationRequested) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (items.length > 0) {\r\n\t\t\t\t\tpicker.items = items;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tif (query.original.length > 0) {\r\n\t\t\t\t\t\tthis.provideLabelPick(picker, localize('noMatchingSymbolResults', \"No matching editor symbols\"));\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tthis.provideLabelPick(picker, localize('noSymbolResults', \"No editor symbols\"));\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} finally {\r\n\t\t\t\tif (!token.isCancellationRequested) {\r\n\t\t\t\t\tpicker.busy = false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\t\tdisposables.add(picker.onDidChangeValue(() => updatePickerItems()));\r\n\t\tupdatePickerItems();\r\n\r\n\t\t// Reveal and decorate when active item changes\r\n\t\t// However, ignore the very first event so that\r\n\t\t// opening the picker is not immediately revealing\r\n\t\t// and decorating the first entry.\r\n\t\tlet ignoreFirstActiveEvent = true;\r\n\t\tdisposables.add(picker.onDidChangeActive(() => {\r\n\t\t\tconst [item] = picker.activeItems;\r\n\t\t\tif (item && item.range) {\r\n\t\t\t\tif (ignoreFirstActiveEvent) {\r\n\t\t\t\t\tignoreFirstActiveEvent = false;\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Reveal\r\n\t\t\t\teditor.revealRangeInCenter(item.range.selection, ScrollType.Smooth);\r\n\r\n\t\t\t\t// Decorate\r\n\t\t\t\tthis.addDecorations(editor, item.range.decoration);\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\treturn disposables;\r\n\t}\r\n\r\n\tprotected async doGetSymbolPicks(symbolsPromise: Promise, query: IPreparedQuery, options: { extraContainerLabel?: string } | undefined, token: CancellationToken): Promise> {\r\n\t\tconst symbols = await symbolsPromise;\r\n\t\tif (token.isCancellationRequested) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tconst filterBySymbolKind = query.original.indexOf(AbstractGotoSymbolQuickAccessProvider.SCOPE_PREFIX) === 0;\r\n\t\tconst filterPos = filterBySymbolKind ? 1 : 0;\r\n\r\n\t\t// Split between symbol and container query\r\n\t\tlet symbolQuery: IPreparedQuery;\r\n\t\tlet containerQuery: IPreparedQuery | undefined;\r\n\t\tif (query.values && query.values.length > 1) {\r\n\t\t\tsymbolQuery = pieceToQuery(query.values[0]); \t\t // symbol: only match on first part\r\n\t\t\tcontainerQuery = pieceToQuery(query.values.slice(1)); // container: match on all but first parts\r\n\t\t} else {\r\n\t\t\tsymbolQuery = query;\r\n\t\t}\r\n\r\n\t\t// Convert to symbol picks and apply filtering\r\n\t\tconst filteredSymbolPicks: IGotoSymbolQuickPickItem[] = [];\r\n\t\tfor (let index = 0; index < symbols.length; index++) {\r\n\t\t\tconst symbol = symbols[index];\r\n\r\n\t\t\tconst symbolLabel = trim(symbol.name);\r\n\t\t\tconst symbolLabelWithIcon = `$(symbol-${SymbolKinds.toString(symbol.kind) || 'property'}) ${symbolLabel}`;\r\n\t\t\tconst symbolLabelIconOffset = symbolLabelWithIcon.length - symbolLabel.length;\r\n\r\n\t\t\tlet containerLabel = symbol.containerName;\r\n\t\t\tif (options?.extraContainerLabel) {\r\n\t\t\t\tif (containerLabel) {\r\n\t\t\t\t\tcontainerLabel = `${options.extraContainerLabel} • ${containerLabel}`;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tcontainerLabel = options.extraContainerLabel;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tlet symbolScore: number | undefined = undefined;\r\n\t\t\tlet symbolMatches: IMatch[] | undefined = undefined;\r\n\r\n\t\t\tlet containerScore: number | undefined = undefined;\r\n\t\t\tlet containerMatches: IMatch[] | undefined = undefined;\r\n\r\n\t\t\tif (query.original.length > filterPos) {\r\n\r\n\t\t\t\t// First: try to score on the entire query, it is possible that\r\n\t\t\t\t// the symbol matches perfectly (e.g. searching for \"change log\"\r\n\t\t\t\t// can be a match on a markdown symbol \"change log\"). In that\r\n\t\t\t\t// case we want to skip the container query altogether.\r\n\t\t\t\tlet skipContainerQuery = false;\r\n\t\t\t\tif (symbolQuery !== query) {\r\n\t\t\t\t\t[symbolScore, symbolMatches] = scoreFuzzy2(symbolLabelWithIcon, { ...query, values: undefined /* disable multi-query support */ }, filterPos, symbolLabelIconOffset);\r\n\t\t\t\t\tif (typeof symbolScore === 'number') {\r\n\t\t\t\t\t\tskipContainerQuery = true; // since we consumed the query, skip any container matching\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Otherwise: score on the symbol query and match on the container later\r\n\t\t\t\tif (typeof symbolScore !== 'number') {\r\n\t\t\t\t\t[symbolScore, symbolMatches] = scoreFuzzy2(symbolLabelWithIcon, symbolQuery, filterPos, symbolLabelIconOffset);\r\n\t\t\t\t\tif (typeof symbolScore !== 'number') {\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Score by container if specified\r\n\t\t\t\tif (!skipContainerQuery && containerQuery) {\r\n\t\t\t\t\tif (containerLabel && containerQuery.original.length > 0) {\r\n\t\t\t\t\t\t[containerScore, containerMatches] = scoreFuzzy2(containerLabel, containerQuery);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (typeof containerScore !== 'number') {\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (typeof symbolScore === 'number') {\r\n\t\t\t\t\t\tsymbolScore += containerScore; // boost symbolScore by containerScore\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tconst deprecated = symbol.tags && symbol.tags.indexOf(SymbolTag.Deprecated) >= 0;\r\n\r\n\t\t\tfilteredSymbolPicks.push({\r\n\t\t\t\tindex,\r\n\t\t\t\tkind: symbol.kind,\r\n\t\t\t\tscore: symbolScore,\r\n\t\t\t\tlabel: symbolLabelWithIcon,\r\n\t\t\t\tariaLabel: symbolLabel,\r\n\t\t\t\tdescription: containerLabel,\r\n\t\t\t\thighlights: deprecated ? undefined : {\r\n\t\t\t\t\tlabel: symbolMatches,\r\n\t\t\t\t\tdescription: containerMatches\r\n\t\t\t\t},\r\n\t\t\t\trange: {\r\n\t\t\t\t\tselection: Range.collapseToStart(symbol.selectionRange),\r\n\t\t\t\t\tdecoration: symbol.range\r\n\t\t\t\t},\r\n\t\t\t\tstrikethrough: deprecated,\r\n\t\t\t\tbuttons: (() => {\r\n\t\t\t\t\tconst openSideBySideDirection = this.options?.openSideBySideDirection ? this.options?.openSideBySideDirection() : undefined;\r\n\t\t\t\t\tif (!openSideBySideDirection) {\r\n\t\t\t\t\t\treturn undefined;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\treturn [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\ticonClass: openSideBySideDirection === 'right' ? Codicon.splitHorizontal.classNames : Codicon.splitVertical.classNames,\r\n\t\t\t\t\t\t\ttooltip: openSideBySideDirection === 'right' ? localize('openToSide', \"Open to the Side\") : localize('openToBottom', \"Open to the Bottom\")\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t];\r\n\t\t\t\t})()\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\t// Sort by score\r\n\t\tconst sortedFilteredSymbolPicks = filteredSymbolPicks.sort((symbolA, symbolB) => filterBySymbolKind ?\r\n\t\t\tthis.compareByKindAndScore(symbolA, symbolB) :\r\n\t\t\tthis.compareByScore(symbolA, symbolB)\r\n\t\t);\r\n\r\n\t\t// Add separator for types\r\n\t\t// - @ only total number of symbols\r\n\t\t// - @: grouped by symbol kind\r\n\t\tlet symbolPicks: Array = [];\r\n\t\tif (filterBySymbolKind) {\r\n\t\t\tlet lastSymbolKind: SymbolKind | undefined = undefined;\r\n\t\t\tlet lastSeparator: IQuickPickSeparator | undefined = undefined;\r\n\t\t\tlet lastSymbolKindCounter = 0;\r\n\r\n\t\t\tfunction updateLastSeparatorLabel(): void {\r\n\t\t\t\tif (lastSeparator && typeof lastSymbolKind === 'number' && lastSymbolKindCounter > 0) {\r\n\t\t\t\t\tlastSeparator.label = format(NLS_SYMBOL_KIND_CACHE[lastSymbolKind] || FALLBACK_NLS_SYMBOL_KIND, lastSymbolKindCounter);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tfor (const symbolPick of sortedFilteredSymbolPicks) {\r\n\r\n\t\t\t\t// Found new kind\r\n\t\t\t\tif (lastSymbolKind !== symbolPick.kind) {\r\n\r\n\t\t\t\t\t// Update last separator with number of symbols we found for kind\r\n\t\t\t\t\tupdateLastSeparatorLabel();\r\n\r\n\t\t\t\t\tlastSymbolKind = symbolPick.kind;\r\n\t\t\t\t\tlastSymbolKindCounter = 1;\r\n\r\n\t\t\t\t\t// Add new separator for new kind\r\n\t\t\t\t\tlastSeparator = { type: 'separator' };\r\n\t\t\t\t\tsymbolPicks.push(lastSeparator);\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Existing kind, keep counting\r\n\t\t\t\telse {\r\n\t\t\t\t\tlastSymbolKindCounter++;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Add to final result\r\n\t\t\t\tsymbolPicks.push(symbolPick);\r\n\t\t\t}\r\n\r\n\t\t\t// Update last separator with number of symbols we found for kind\r\n\t\t\tupdateLastSeparatorLabel();\r\n\t\t} else if (sortedFilteredSymbolPicks.length > 0) {\r\n\t\t\tsymbolPicks = [\r\n\t\t\t\t{ label: localize('symbols', \"symbols ({0})\", filteredSymbolPicks.length), type: 'separator' },\r\n\t\t\t\t...sortedFilteredSymbolPicks\r\n\t\t\t];\r\n\t\t}\r\n\r\n\t\treturn symbolPicks;\r\n\t}\r\n\r\n\tprivate compareByScore(symbolA: IGotoSymbolQuickPickItem, symbolB: IGotoSymbolQuickPickItem): number {\r\n\t\tif (typeof symbolA.score !== 'number' && typeof symbolB.score === 'number') {\r\n\t\t\treturn 1;\r\n\t\t} else if (typeof symbolA.score === 'number' && typeof symbolB.score !== 'number') {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\r\n\t\tif (typeof symbolA.score === 'number' && typeof symbolB.score === 'number') {\r\n\t\t\tif (symbolA.score > symbolB.score) {\r\n\t\t\t\treturn -1;\r\n\t\t\t} else if (symbolA.score < symbolB.score) {\r\n\t\t\t\treturn 1;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (symbolA.index < symbolB.index) {\r\n\t\t\treturn -1;\r\n\t\t} else if (symbolA.index > symbolB.index) {\r\n\t\t\treturn 1;\r\n\t\t}\r\n\r\n\t\treturn 0;\r\n\t}\r\n\r\n\tprivate compareByKindAndScore(symbolA: IGotoSymbolQuickPickItem, symbolB: IGotoSymbolQuickPickItem): number {\r\n\t\tconst kindA = NLS_SYMBOL_KIND_CACHE[symbolA.kind] || FALLBACK_NLS_SYMBOL_KIND;\r\n\t\tconst kindB = NLS_SYMBOL_KIND_CACHE[symbolB.kind] || FALLBACK_NLS_SYMBOL_KIND;\r\n\r\n\t\t// Sort by type first if scoped search\r\n\t\tconst result = kindA.localeCompare(kindB);\r\n\t\tif (result === 0) {\r\n\t\t\treturn this.compareByScore(symbolA, symbolB);\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprotected async getDocumentSymbols(document: ITextModel, token: CancellationToken): Promise {\r\n\t\tconst model = await OutlineModel.create(document, token);\r\n\t\treturn token.isCancellationRequested ? [] : model.asListOfDocumentSymbols();\r\n\t}\r\n}\r\n\r\n// #region NLS Helpers\r\n\r\nconst FALLBACK_NLS_SYMBOL_KIND = localize('property', \"properties ({0})\");\r\nconst NLS_SYMBOL_KIND_CACHE: { [type: number]: string } = {\r\n\t[SymbolKind.Method]: localize('method', \"methods ({0})\"),\r\n\t[SymbolKind.Function]: localize('function', \"functions ({0})\"),\r\n\t[SymbolKind.Constructor]: localize('_constructor', \"constructors ({0})\"),\r\n\t[SymbolKind.Variable]: localize('variable', \"variables ({0})\"),\r\n\t[SymbolKind.Class]: localize('class', \"classes ({0})\"),\r\n\t[SymbolKind.Struct]: localize('struct', \"structs ({0})\"),\r\n\t[SymbolKind.Event]: localize('event', \"events ({0})\"),\r\n\t[SymbolKind.Operator]: localize('operator', \"operators ({0})\"),\r\n\t[SymbolKind.Interface]: localize('interface', \"interfaces ({0})\"),\r\n\t[SymbolKind.Namespace]: localize('namespace', \"namespaces ({0})\"),\r\n\t[SymbolKind.Package]: localize('package', \"packages ({0})\"),\r\n\t[SymbolKind.TypeParameter]: localize('typeParameter', \"type parameters ({0})\"),\r\n\t[SymbolKind.Module]: localize('modules', \"modules ({0})\"),\r\n\t[SymbolKind.Property]: localize('property', \"properties ({0})\"),\r\n\t[SymbolKind.Enum]: localize('enum', \"enumerations ({0})\"),\r\n\t[SymbolKind.EnumMember]: localize('enumMember', \"enumeration members ({0})\"),\r\n\t[SymbolKind.String]: localize('string', \"strings ({0})\"),\r\n\t[SymbolKind.File]: localize('file', \"files ({0})\"),\r\n\t[SymbolKind.Array]: localize('array', \"arrays ({0})\"),\r\n\t[SymbolKind.Number]: localize('number', \"numbers ({0})\"),\r\n\t[SymbolKind.Boolean]: localize('boolean', \"booleans ({0})\"),\r\n\t[SymbolKind.Object]: localize('object', \"objects ({0})\"),\r\n\t[SymbolKind.Key]: localize('key', \"keys ({0})\"),\r\n\t[SymbolKind.Field]: localize('field', \"fields ({0})\"),\r\n\t[SymbolKind.Constant]: localize('constant', \"constants ({0})\")\r\n};\r\n\r\n//#endregion\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./renameInputField';\r\nimport { DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { IRange } from 'vs/editor/common/core/range';\r\nimport { ScrollType } from 'vs/editor/common/editorCommon';\r\nimport { localize } from 'vs/nls';\r\nimport { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';\r\nimport { inputBackground, inputBorder, inputForeground, widgetShadow, editorWidgetBackground } from 'vs/platform/theme/common/colorRegistry';\r\nimport { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\n\r\nexport const CONTEXT_RENAME_INPUT_VISIBLE = new RawContextKey('renameInputVisible', false);\r\n\r\nexport interface RenameInputFieldResult {\r\n\tnewName: string;\r\n\twantsPreview?: boolean;\r\n}\r\n\r\nexport class RenameInputField implements IContentWidget {\r\n\r\n\tprivate _position?: Position;\r\n\tprivate _domNode?: HTMLElement;\r\n\tprivate _input?: HTMLInputElement;\r\n\tprivate _label?: HTMLDivElement;\r\n\tprivate _visible?: boolean;\r\n\tprivate readonly _visibleContextKey: IContextKey;\r\n\tprivate readonly _disposables = new DisposableStore();\r\n\r\n\treadonly allowEditorOverflow: boolean = true;\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _editor: ICodeEditor,\r\n\t\tprivate readonly _acceptKeybindings: [string, string],\r\n\t\t@IThemeService private readonly _themeService: IThemeService,\r\n\t\t@IKeybindingService private readonly _keybindingService: IKeybindingService,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\r\n\t) {\r\n\t\tthis._visibleContextKey = CONTEXT_RENAME_INPUT_VISIBLE.bindTo(contextKeyService);\r\n\r\n\t\tthis._editor.addContentWidget(this);\r\n\r\n\t\tthis._disposables.add(this._editor.onDidChangeConfiguration(e => {\r\n\t\t\tif (e.hasChanged(EditorOption.fontInfo)) {\r\n\t\t\t\tthis._updateFont();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._disposables.add(_themeService.onDidColorThemeChange(this._updateStyles, this));\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._disposables.dispose();\r\n\t\tthis._editor.removeContentWidget(this);\r\n\t}\r\n\r\n\tgetId(): string {\r\n\t\treturn '__renameInputWidget';\r\n\t}\r\n\r\n\tgetDomNode(): HTMLElement {\r\n\t\tif (!this._domNode) {\r\n\t\t\tthis._domNode = document.createElement('div');\r\n\t\t\tthis._domNode.className = 'monaco-editor rename-box';\r\n\r\n\t\t\tthis._input = document.createElement('input');\r\n\t\t\tthis._input.className = 'rename-input';\r\n\t\t\tthis._input.type = 'text';\r\n\t\t\tthis._input.setAttribute('aria-label', localize('renameAriaLabel', \"Rename input. Type new name and press Enter to commit.\"));\r\n\t\t\tthis._domNode.appendChild(this._input);\r\n\r\n\t\t\tthis._label = document.createElement('div');\r\n\t\t\tthis._label.className = 'rename-label';\r\n\t\t\tthis._domNode.appendChild(this._label);\r\n\t\t\tconst updateLabel = () => {\r\n\t\t\t\tconst [accept, preview] = this._acceptKeybindings;\r\n\t\t\t\tthis._keybindingService.lookupKeybinding(accept);\r\n\t\t\t\tthis._label!.innerText = localize({ key: 'label', comment: ['placeholders are keybindings, e.g \"F2 to Rename, Shift+F2 to Preview\"'] }, \"{0} to Rename, {1} to Preview\", this._keybindingService.lookupKeybinding(accept)?.getLabel(), this._keybindingService.lookupKeybinding(preview)?.getLabel());\r\n\t\t\t};\r\n\t\t\tupdateLabel();\r\n\t\t\tthis._disposables.add(this._keybindingService.onDidUpdateKeybindings(updateLabel));\r\n\r\n\t\t\tthis._updateFont();\r\n\t\t\tthis._updateStyles(this._themeService.getColorTheme());\r\n\t\t}\r\n\t\treturn this._domNode;\r\n\t}\r\n\r\n\tprivate _updateStyles(theme: IColorTheme): void {\r\n\t\tif (!this._input || !this._domNode) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst widgetShadowColor = theme.getColor(widgetShadow);\r\n\t\tthis._domNode.style.backgroundColor = String(theme.getColor(editorWidgetBackground) ?? '');\r\n\t\tthis._domNode.style.boxShadow = widgetShadowColor ? ` 0 0 8px 2px ${widgetShadowColor}` : '';\r\n\t\tthis._domNode.style.color = String(theme.getColor(inputForeground) ?? '');\r\n\r\n\t\tthis._input.style.backgroundColor = String(theme.getColor(inputBackground) ?? '');\r\n\t\t// this._input.style.color = String(theme.getColor(inputForeground) ?? '');\r\n\t\tconst border = theme.getColor(inputBorder);\r\n\t\tthis._input.style.borderWidth = border ? '1px' : '0px';\r\n\t\tthis._input.style.borderStyle = border ? 'solid' : 'none';\r\n\t\tthis._input.style.borderColor = border?.toString() ?? 'none';\r\n\t}\r\n\r\n\tprivate _updateFont(): void {\r\n\t\tif (!this._input || !this._label) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst fontInfo = this._editor.getOption(EditorOption.fontInfo);\r\n\t\tthis._input.style.fontFamily = fontInfo.fontFamily;\r\n\t\tthis._input.style.fontWeight = fontInfo.fontWeight;\r\n\t\tthis._input.style.fontSize = `${fontInfo.fontSize}px`;\r\n\r\n\t\tthis._label.style.fontSize = `${fontInfo.fontSize * 0.8}px`;\r\n\t}\r\n\r\n\tgetPosition(): IContentWidgetPosition | null {\r\n\t\tif (!this._visible) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn {\r\n\t\t\tposition: this._position!,\r\n\t\t\tpreference: [ContentWidgetPositionPreference.BELOW, ContentWidgetPositionPreference.ABOVE]\r\n\t\t};\r\n\t}\r\n\r\n\tafterRender(position: ContentWidgetPositionPreference | null): void {\r\n\t\tif (!position) {\r\n\t\t\t// cancel rename when input widget isn't rendered anymore\r\n\t\t\tthis.cancelInput(true);\r\n\t\t}\r\n\t}\r\n\r\n\r\n\tprivate _currentAcceptInput?: (wantsPreview: boolean) => void;\r\n\tprivate _currentCancelInput?: (focusEditor: boolean) => void;\r\n\r\n\tacceptInput(wantsPreview: boolean): void {\r\n\t\tif (this._currentAcceptInput) {\r\n\t\t\tthis._currentAcceptInput(wantsPreview);\r\n\t\t}\r\n\t}\r\n\r\n\tcancelInput(focusEditor: boolean): void {\r\n\t\tif (this._currentCancelInput) {\r\n\t\t\tthis._currentCancelInput(focusEditor);\r\n\t\t}\r\n\t}\r\n\r\n\tgetInput(where: IRange, value: string, selectionStart: number, selectionEnd: number, supportPreview: boolean, token: CancellationToken): Promise {\r\n\r\n\t\tthis._domNode!.classList.toggle('preview', supportPreview);\r\n\r\n\t\tthis._position = new Position(where.startLineNumber, where.startColumn);\r\n\t\tthis._input!.value = value;\r\n\t\tthis._input!.setAttribute('selectionStart', selectionStart.toString());\r\n\t\tthis._input!.setAttribute('selectionEnd', selectionEnd.toString());\r\n\t\tthis._input!.size = Math.max((where.endColumn - where.startColumn) * 1.1, 20);\r\n\r\n\t\tconst disposeOnDone = new DisposableStore();\r\n\r\n\t\treturn new Promise(resolve => {\r\n\r\n\t\t\tthis._currentCancelInput = (focusEditor) => {\r\n\t\t\t\tthis._currentAcceptInput = undefined;\r\n\t\t\t\tthis._currentCancelInput = undefined;\r\n\t\t\t\tresolve(focusEditor);\r\n\t\t\t\treturn true;\r\n\t\t\t};\r\n\r\n\t\t\tthis._currentAcceptInput = (wantsPreview) => {\r\n\t\t\t\tif (this._input!.value.trim().length === 0 || this._input!.value === value) {\r\n\t\t\t\t\t// empty or whitespace only or not changed\r\n\t\t\t\t\tthis.cancelInput(true);\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis._currentAcceptInput = undefined;\r\n\t\t\t\tthis._currentCancelInput = undefined;\r\n\t\t\t\tresolve({\r\n\t\t\t\t\tnewName: this._input!.value,\r\n\t\t\t\t\twantsPreview: supportPreview && wantsPreview\r\n\t\t\t\t});\r\n\t\t\t};\r\n\r\n\t\t\ttoken.onCancellationRequested(() => this.cancelInput(true));\r\n\t\t\tdisposeOnDone.add(this._editor.onDidBlurEditorWidget(() => this.cancelInput(false)));\r\n\r\n\t\t\tthis._show();\r\n\r\n\t\t}).finally(() => {\r\n\t\t\tdisposeOnDone.dispose();\r\n\t\t\tthis._hide();\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _show(): void {\r\n\t\tthis._editor.revealLineInCenterIfOutsideViewport(this._position!.lineNumber, ScrollType.Smooth);\r\n\t\tthis._visible = true;\r\n\t\tthis._visibleContextKey.set(true);\r\n\t\tthis._editor.layoutContentWidget(this);\r\n\r\n\t\tsetTimeout(() => {\r\n\t\t\tthis._input!.focus();\r\n\t\t\tthis._input!.setSelectionRange(\r\n\t\t\t\tparseInt(this._input!.getAttribute('selectionStart')!),\r\n\t\t\t\tparseInt(this._input!.getAttribute('selectionEnd')!));\r\n\t\t}, 100);\r\n\t}\r\n\r\n\tprivate _hide(): void {\r\n\t\tthis._visible = false;\r\n\t\tthis._visibleContextKey.reset();\r\n\t\tthis._editor.layoutContentWidget(this);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { localize } from 'vs/nls';\r\nimport { registerThemingParticipant, IColorTheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';\r\nimport { registerColor, foreground } from 'vs/platform/theme/common/colorRegistry';\r\nimport { Codicon } from 'vs/base/common/codicons';\r\n\r\nexport const SYMBOL_ICON_ARRAY_FOREGROUND = registerColor('symbolIcon.arrayForeground', {\r\n\tdark: foreground,\r\n\tlight: foreground,\r\n\thc: foreground\r\n}, localize('symbolIcon.arrayForeground', 'The foreground color for array symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_BOOLEAN_FOREGROUND = registerColor('symbolIcon.booleanForeground', {\r\n\tdark: foreground,\r\n\tlight: foreground,\r\n\thc: foreground\r\n}, localize('symbolIcon.booleanForeground', 'The foreground color for boolean symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_CLASS_FOREGROUND = registerColor('symbolIcon.classForeground', {\r\n\tdark: '#EE9D28',\r\n\tlight: '#D67E00',\r\n\thc: '#EE9D28'\r\n}, localize('symbolIcon.classForeground', 'The foreground color for class symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_COLOR_FOREGROUND = registerColor('symbolIcon.colorForeground', {\r\n\tdark: foreground,\r\n\tlight: foreground,\r\n\thc: foreground\r\n}, localize('symbolIcon.colorForeground', 'The foreground color for color symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_CONSTANT_FOREGROUND = registerColor('symbolIcon.constantForeground', {\r\n\tdark: foreground,\r\n\tlight: foreground,\r\n\thc: foreground\r\n}, localize('symbolIcon.constantForeground', 'The foreground color for constant symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_CONSTRUCTOR_FOREGROUND = registerColor('symbolIcon.constructorForeground', {\r\n\tdark: '#B180D7',\r\n\tlight: '#652D90',\r\n\thc: '#B180D7'\r\n}, localize('symbolIcon.constructorForeground', 'The foreground color for constructor symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_ENUMERATOR_FOREGROUND = registerColor('symbolIcon.enumeratorForeground', {\r\n\tdark: '#EE9D28',\r\n\tlight: '#D67E00',\r\n\thc: '#EE9D28'\r\n}, localize('symbolIcon.enumeratorForeground', 'The foreground color for enumerator symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_ENUMERATOR_MEMBER_FOREGROUND = registerColor('symbolIcon.enumeratorMemberForeground', {\r\n\tdark: '#75BEFF',\r\n\tlight: '#007ACC',\r\n\thc: '#75BEFF'\r\n}, localize('symbolIcon.enumeratorMemberForeground', 'The foreground color for enumerator member symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_EVENT_FOREGROUND = registerColor('symbolIcon.eventForeground', {\r\n\tdark: '#EE9D28',\r\n\tlight: '#D67E00',\r\n\thc: '#EE9D28'\r\n}, localize('symbolIcon.eventForeground', 'The foreground color for event symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_FIELD_FOREGROUND = registerColor('symbolIcon.fieldForeground', {\r\n\tdark: '#75BEFF',\r\n\tlight: '#007ACC',\r\n\thc: '#75BEFF'\r\n}, localize('symbolIcon.fieldForeground', 'The foreground color for field symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_FILE_FOREGROUND = registerColor('symbolIcon.fileForeground', {\r\n\tdark: foreground,\r\n\tlight: foreground,\r\n\thc: foreground\r\n}, localize('symbolIcon.fileForeground', 'The foreground color for file symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_FOLDER_FOREGROUND = registerColor('symbolIcon.folderForeground', {\r\n\tdark: foreground,\r\n\tlight: foreground,\r\n\thc: foreground\r\n}, localize('symbolIcon.folderForeground', 'The foreground color for folder symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_FUNCTION_FOREGROUND = registerColor('symbolIcon.functionForeground', {\r\n\tdark: '#B180D7',\r\n\tlight: '#652D90',\r\n\thc: '#B180D7'\r\n}, localize('symbolIcon.functionForeground', 'The foreground color for function symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_INTERFACE_FOREGROUND = registerColor('symbolIcon.interfaceForeground', {\r\n\tdark: '#75BEFF',\r\n\tlight: '#007ACC',\r\n\thc: '#75BEFF'\r\n}, localize('symbolIcon.interfaceForeground', 'The foreground color for interface symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_KEY_FOREGROUND = registerColor('symbolIcon.keyForeground', {\r\n\tdark: foreground,\r\n\tlight: foreground,\r\n\thc: foreground\r\n}, localize('symbolIcon.keyForeground', 'The foreground color for key symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_KEYWORD_FOREGROUND = registerColor('symbolIcon.keywordForeground', {\r\n\tdark: foreground,\r\n\tlight: foreground,\r\n\thc: foreground\r\n}, localize('symbolIcon.keywordForeground', 'The foreground color for keyword symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_METHOD_FOREGROUND = registerColor('symbolIcon.methodForeground', {\r\n\tdark: '#B180D7',\r\n\tlight: '#652D90',\r\n\thc: '#B180D7'\r\n}, localize('symbolIcon.methodForeground', 'The foreground color for method symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_MODULE_FOREGROUND = registerColor('symbolIcon.moduleForeground', {\r\n\tdark: foreground,\r\n\tlight: foreground,\r\n\thc: foreground\r\n}, localize('symbolIcon.moduleForeground', 'The foreground color for module symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_NAMESPACE_FOREGROUND = registerColor('symbolIcon.namespaceForeground', {\r\n\tdark: foreground,\r\n\tlight: foreground,\r\n\thc: foreground\r\n}, localize('symbolIcon.namespaceForeground', 'The foreground color for namespace symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_NULL_FOREGROUND = registerColor('symbolIcon.nullForeground', {\r\n\tdark: foreground,\r\n\tlight: foreground,\r\n\thc: foreground\r\n}, localize('symbolIcon.nullForeground', 'The foreground color for null symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_NUMBER_FOREGROUND = registerColor('symbolIcon.numberForeground', {\r\n\tdark: foreground,\r\n\tlight: foreground,\r\n\thc: foreground\r\n}, localize('symbolIcon.numberForeground', 'The foreground color for number symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_OBJECT_FOREGROUND = registerColor('symbolIcon.objectForeground', {\r\n\tdark: foreground,\r\n\tlight: foreground,\r\n\thc: foreground\r\n}, localize('symbolIcon.objectForeground', 'The foreground color for object symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_OPERATOR_FOREGROUND = registerColor('symbolIcon.operatorForeground', {\r\n\tdark: foreground,\r\n\tlight: foreground,\r\n\thc: foreground\r\n}, localize('symbolIcon.operatorForeground', 'The foreground color for operator symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_PACKAGE_FOREGROUND = registerColor('symbolIcon.packageForeground', {\r\n\tdark: foreground,\r\n\tlight: foreground,\r\n\thc: foreground\r\n}, localize('symbolIcon.packageForeground', 'The foreground color for package symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_PROPERTY_FOREGROUND = registerColor('symbolIcon.propertyForeground', {\r\n\tdark: foreground,\r\n\tlight: foreground,\r\n\thc: foreground\r\n}, localize('symbolIcon.propertyForeground', 'The foreground color for property symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_REFERENCE_FOREGROUND = registerColor('symbolIcon.referenceForeground', {\r\n\tdark: foreground,\r\n\tlight: foreground,\r\n\thc: foreground\r\n}, localize('symbolIcon.referenceForeground', 'The foreground color for reference symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_SNIPPET_FOREGROUND = registerColor('symbolIcon.snippetForeground', {\r\n\tdark: foreground,\r\n\tlight: foreground,\r\n\thc: foreground\r\n}, localize('symbolIcon.snippetForeground', 'The foreground color for snippet symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_STRING_FOREGROUND = registerColor('symbolIcon.stringForeground', {\r\n\tdark: foreground,\r\n\tlight: foreground,\r\n\thc: foreground\r\n}, localize('symbolIcon.stringForeground', 'The foreground color for string symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_STRUCT_FOREGROUND = registerColor('symbolIcon.structForeground', {\r\n\tdark: foreground,\r\n\tlight: foreground,\r\n\thc: foreground\r\n}, localize('symbolIcon.structForeground', 'The foreground color for struct symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_TEXT_FOREGROUND = registerColor('symbolIcon.textForeground', {\r\n\tdark: foreground,\r\n\tlight: foreground,\r\n\thc: foreground\r\n}, localize('symbolIcon.textForeground', 'The foreground color for text symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_TYPEPARAMETER_FOREGROUND = registerColor('symbolIcon.typeParameterForeground', {\r\n\tdark: foreground,\r\n\tlight: foreground,\r\n\thc: foreground\r\n}, localize('symbolIcon.typeParameterForeground', 'The foreground color for type parameter symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_UNIT_FOREGROUND = registerColor('symbolIcon.unitForeground', {\r\n\tdark: foreground,\r\n\tlight: foreground,\r\n\thc: foreground\r\n}, localize('symbolIcon.unitForeground', 'The foreground color for unit symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nexport const SYMBOL_ICON_VARIABLE_FOREGROUND = registerColor('symbolIcon.variableForeground', {\r\n\tdark: '#75BEFF',\r\n\tlight: '#007ACC',\r\n\thc: '#75BEFF'\r\n}, localize('symbolIcon.variableForeground', 'The foreground color for variable symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\r\n\r\nregisterThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) => {\r\n\r\n\tconst symbolIconArrayColor = theme.getColor(SYMBOL_ICON_ARRAY_FOREGROUND);\r\n\tif (symbolIconArrayColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolArray.cssSelector} { color: ${symbolIconArrayColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconBooleanColor = theme.getColor(SYMBOL_ICON_BOOLEAN_FOREGROUND);\r\n\tif (symbolIconBooleanColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolBoolean.cssSelector} { color: ${symbolIconBooleanColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconClassColor = theme.getColor(SYMBOL_ICON_CLASS_FOREGROUND);\r\n\tif (symbolIconClassColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolClass.cssSelector} { color: ${symbolIconClassColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconMethodColor = theme.getColor(SYMBOL_ICON_METHOD_FOREGROUND);\r\n\tif (symbolIconMethodColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolMethod.cssSelector} { color: ${symbolIconMethodColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconColorColor = theme.getColor(SYMBOL_ICON_COLOR_FOREGROUND);\r\n\tif (symbolIconColorColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolColor.cssSelector} { color: ${symbolIconColorColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconConstantColor = theme.getColor(SYMBOL_ICON_CONSTANT_FOREGROUND);\r\n\tif (symbolIconConstantColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolConstant.cssSelector} { color: ${symbolIconConstantColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconConstructorColor = theme.getColor(SYMBOL_ICON_CONSTRUCTOR_FOREGROUND);\r\n\tif (symbolIconConstructorColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolConstructor.cssSelector} { color: ${symbolIconConstructorColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconEnumeratorColor = theme.getColor(SYMBOL_ICON_ENUMERATOR_FOREGROUND);\r\n\tif (symbolIconEnumeratorColor) {\r\n\t\tcollector.addRule(`\r\n\t\t\t${Codicon.symbolValue.cssSelector},${Codicon.symbolEnum.cssSelector} { color: ${symbolIconEnumeratorColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconEnumeratorMemberColor = theme.getColor(SYMBOL_ICON_ENUMERATOR_MEMBER_FOREGROUND);\r\n\tif (symbolIconEnumeratorMemberColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolEnumMember.cssSelector} { color: ${symbolIconEnumeratorMemberColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconEventColor = theme.getColor(SYMBOL_ICON_EVENT_FOREGROUND);\r\n\tif (symbolIconEventColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolEvent.cssSelector} { color: ${symbolIconEventColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconFieldColor = theme.getColor(SYMBOL_ICON_FIELD_FOREGROUND);\r\n\tif (symbolIconFieldColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolField.cssSelector} { color: ${symbolIconFieldColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconFileColor = theme.getColor(SYMBOL_ICON_FILE_FOREGROUND);\r\n\tif (symbolIconFileColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolFile.cssSelector} { color: ${symbolIconFileColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconFolderColor = theme.getColor(SYMBOL_ICON_FOLDER_FOREGROUND);\r\n\tif (symbolIconFolderColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolFolder.cssSelector} { color: ${symbolIconFolderColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconFunctionColor = theme.getColor(SYMBOL_ICON_FUNCTION_FOREGROUND);\r\n\tif (symbolIconFunctionColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolFunction.cssSelector} { color: ${symbolIconFunctionColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconInterfaceColor = theme.getColor(SYMBOL_ICON_INTERFACE_FOREGROUND);\r\n\tif (symbolIconInterfaceColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolInterface.cssSelector} { color: ${symbolIconInterfaceColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconKeyColor = theme.getColor(SYMBOL_ICON_KEY_FOREGROUND);\r\n\tif (symbolIconKeyColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolKey.cssSelector} { color: ${symbolIconKeyColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconKeywordColor = theme.getColor(SYMBOL_ICON_KEYWORD_FOREGROUND);\r\n\tif (symbolIconKeywordColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolKeyword.cssSelector} { color: ${symbolIconKeywordColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconModuleColor = theme.getColor(SYMBOL_ICON_MODULE_FOREGROUND);\r\n\tif (symbolIconModuleColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolModule.cssSelector} { color: ${symbolIconModuleColor}; }`);\r\n\t}\r\n\r\n\tconst outlineNamespaceColor = theme.getColor(SYMBOL_ICON_NAMESPACE_FOREGROUND);\r\n\tif (outlineNamespaceColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolNamespace.cssSelector} { color: ${outlineNamespaceColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconNullColor = theme.getColor(SYMBOL_ICON_NULL_FOREGROUND);\r\n\tif (symbolIconNullColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolNull.cssSelector} { color: ${symbolIconNullColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconNumberColor = theme.getColor(SYMBOL_ICON_NUMBER_FOREGROUND);\r\n\tif (symbolIconNumberColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolNumber.cssSelector} { color: ${symbolIconNumberColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconObjectColor = theme.getColor(SYMBOL_ICON_OBJECT_FOREGROUND);\r\n\tif (symbolIconObjectColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolObject.cssSelector} { color: ${symbolIconObjectColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconOperatorColor = theme.getColor(SYMBOL_ICON_OPERATOR_FOREGROUND);\r\n\tif (symbolIconOperatorColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolOperator.cssSelector} { color: ${symbolIconOperatorColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconPackageColor = theme.getColor(SYMBOL_ICON_PACKAGE_FOREGROUND);\r\n\tif (symbolIconPackageColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolPackage.cssSelector} { color: ${symbolIconPackageColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconPropertyColor = theme.getColor(SYMBOL_ICON_PROPERTY_FOREGROUND);\r\n\tif (symbolIconPropertyColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolProperty.cssSelector} { color: ${symbolIconPropertyColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconReferenceColor = theme.getColor(SYMBOL_ICON_REFERENCE_FOREGROUND);\r\n\tif (symbolIconReferenceColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolReference.cssSelector} { color: ${symbolIconReferenceColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconSnippetColor = theme.getColor(SYMBOL_ICON_SNIPPET_FOREGROUND);\r\n\tif (symbolIconSnippetColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolSnippet.cssSelector} { color: ${symbolIconSnippetColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconStringColor = theme.getColor(SYMBOL_ICON_STRING_FOREGROUND);\r\n\tif (symbolIconStringColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolString.cssSelector} { color: ${symbolIconStringColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconStructColor = theme.getColor(SYMBOL_ICON_STRUCT_FOREGROUND);\r\n\tif (symbolIconStructColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolStruct.cssSelector} { color: ${symbolIconStructColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconTextColor = theme.getColor(SYMBOL_ICON_TEXT_FOREGROUND);\r\n\tif (symbolIconTextColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolText.cssSelector} { color: ${symbolIconTextColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconTypeParameterColor = theme.getColor(SYMBOL_ICON_TYPEPARAMETER_FOREGROUND);\r\n\tif (symbolIconTypeParameterColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolTypeParameter.cssSelector} { color: ${symbolIconTypeParameterColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconUnitColor = theme.getColor(SYMBOL_ICON_UNIT_FOREGROUND);\r\n\tif (symbolIconUnitColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolUnit.cssSelector} { color: ${symbolIconUnitColor}; }`);\r\n\t}\r\n\r\n\tconst symbolIconVariableColor = theme.getColor(SYMBOL_ICON_VARIABLE_FOREGROUND);\r\n\tif (symbolIconVariableColor) {\r\n\t\tcollector.addRule(`${Codicon.symbolVariable.cssSelector} { color: ${symbolIconVariableColor}; }`);\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { windowOpenNoOpener } from 'vs/base/browser/dom';\r\nimport { Schemas } from 'vs/base/common/network';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { CodeEditorServiceImpl } from 'vs/editor/browser/services/codeEditorServiceImpl';\r\nimport { IRange } from 'vs/editor/common/core/range';\r\nimport { ScrollType } from 'vs/editor/common/editorCommon';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { IResourceEditorInput } from 'vs/platform/editor/common/editor';\r\n\r\nexport class StandaloneCodeEditorServiceImpl extends CodeEditorServiceImpl {\r\n\r\n\tpublic getActiveCodeEditor(): ICodeEditor | null {\r\n\t\treturn null; // not supported in the standalone case\r\n\t}\r\n\r\n\tpublic openCodeEditor(input: IResourceEditorInput, source: ICodeEditor | null, sideBySide?: boolean): Promise {\r\n\t\tif (!source) {\r\n\t\t\treturn Promise.resolve(null);\r\n\t\t}\r\n\r\n\t\treturn Promise.resolve(this.doOpenEditor(source, input));\r\n\t}\r\n\r\n\tprivate doOpenEditor(editor: ICodeEditor, input: IResourceEditorInput): ICodeEditor | null {\r\n\t\tconst model = this.findModel(editor, input.resource);\r\n\t\tif (!model) {\r\n\t\t\tif (input.resource) {\r\n\r\n\t\t\t\tconst schema = input.resource.scheme;\r\n\t\t\t\tif (schema === Schemas.http || schema === Schemas.https) {\r\n\t\t\t\t\t// This is a fully qualified http or https URL\r\n\t\t\t\t\twindowOpenNoOpener(input.resource.toString());\r\n\t\t\t\t\treturn editor;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst selection = (input.options ? input.options.selection : null);\r\n\t\tif (selection) {\r\n\t\t\tif (typeof selection.endLineNumber === 'number' && typeof selection.endColumn === 'number') {\r\n\t\t\t\teditor.setSelection(selection);\r\n\t\t\t\teditor.revealRangeInCenter(selection, ScrollType.Immediate);\r\n\t\t\t} else {\r\n\t\t\t\tconst pos = {\r\n\t\t\t\t\tlineNumber: selection.startLineNumber,\r\n\t\t\t\t\tcolumn: selection.startColumn\r\n\t\t\t\t};\r\n\t\t\t\teditor.setPosition(pos);\r\n\t\t\t\teditor.revealPositionInCenter(pos, ScrollType.Immediate);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn editor;\r\n\t}\r\n\r\n\tprivate findModel(editor: ICodeEditor, resource: URI): ITextModel | null {\r\n\t\tconst model = editor.getModel();\r\n\t\tif (model && model.uri.toString() !== resource.toString()) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\treturn model;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { editorActiveIndentGuides, editorIndentGuides } from 'vs/editor/common/view/editorColorRegistry';\r\nimport { IStandaloneThemeData } from 'vs/editor/standalone/common/standaloneThemeService';\r\nimport { editorBackground, editorForeground, editorInactiveSelection, editorSelectionHighlight } from 'vs/platform/theme/common/colorRegistry';\r\n\r\n/* -------------------------------- Begin vs theme -------------------------------- */\r\nexport const vs: IStandaloneThemeData = {\r\n\tbase: 'vs',\r\n\tinherit: false,\r\n\trules: [\r\n\t\t{ token: '', foreground: '000000', background: 'fffffe' },\r\n\t\t{ token: 'invalid', foreground: 'cd3131' },\r\n\t\t{ token: 'emphasis', fontStyle: 'italic' },\r\n\t\t{ token: 'strong', fontStyle: 'bold' },\r\n\r\n\t\t{ token: 'variable', foreground: '001188' },\r\n\t\t{ token: 'variable.predefined', foreground: '4864AA' },\r\n\t\t{ token: 'constant', foreground: 'dd0000' },\r\n\t\t{ token: 'comment', foreground: '008000' },\r\n\t\t{ token: 'number', foreground: '098658' },\r\n\t\t{ token: 'number.hex', foreground: '3030c0' },\r\n\t\t{ token: 'regexp', foreground: '800000' },\r\n\t\t{ token: 'annotation', foreground: '808080' },\r\n\t\t{ token: 'type', foreground: '008080' },\r\n\r\n\t\t{ token: 'delimiter', foreground: '000000' },\r\n\t\t{ token: 'delimiter.html', foreground: '383838' },\r\n\t\t{ token: 'delimiter.xml', foreground: '0000FF' },\r\n\r\n\t\t{ token: 'tag', foreground: '800000' },\r\n\t\t{ token: 'tag.id.pug', foreground: '4F76AC' },\r\n\t\t{ token: 'tag.class.pug', foreground: '4F76AC' },\r\n\t\t{ token: 'meta.scss', foreground: '800000' },\r\n\t\t{ token: 'metatag', foreground: 'e00000' },\r\n\t\t{ token: 'metatag.content.html', foreground: 'FF0000' },\r\n\t\t{ token: 'metatag.html', foreground: '808080' },\r\n\t\t{ token: 'metatag.xml', foreground: '808080' },\r\n\t\t{ token: 'metatag.php', fontStyle: 'bold' },\r\n\r\n\t\t{ token: 'key', foreground: '863B00' },\r\n\t\t{ token: 'string.key.json', foreground: 'A31515' },\r\n\t\t{ token: 'string.value.json', foreground: '0451A5' },\r\n\r\n\t\t{ token: 'attribute.name', foreground: 'FF0000' },\r\n\t\t{ token: 'attribute.value', foreground: '0451A5' },\r\n\t\t{ token: 'attribute.value.number', foreground: '098658' },\r\n\t\t{ token: 'attribute.value.unit', foreground: '098658' },\r\n\t\t{ token: 'attribute.value.html', foreground: '0000FF' },\r\n\t\t{ token: 'attribute.value.xml', foreground: '0000FF' },\r\n\r\n\t\t{ token: 'string', foreground: 'A31515' },\r\n\t\t{ token: 'string.html', foreground: '0000FF' },\r\n\t\t{ token: 'string.sql', foreground: 'FF0000' },\r\n\t\t{ token: 'string.yaml', foreground: '0451A5' },\r\n\r\n\t\t{ token: 'keyword', foreground: '0000FF' },\r\n\t\t{ token: 'keyword.json', foreground: '0451A5' },\r\n\t\t{ token: 'keyword.flow', foreground: 'AF00DB' },\r\n\t\t{ token: 'keyword.flow.scss', foreground: '0000FF' },\r\n\r\n\t\t{ token: 'operator.scss', foreground: '666666' },\r\n\t\t{ token: 'operator.sql', foreground: '778899' },\r\n\t\t{ token: 'operator.swift', foreground: '666666' },\r\n\t\t{ token: 'predefined.sql', foreground: 'C700C7' },\r\n\t],\r\n\tcolors: {\r\n\t\t[editorBackground]: '#FFFFFE',\r\n\t\t[editorForeground]: '#000000',\r\n\t\t[editorInactiveSelection]: '#E5EBF1',\r\n\t\t[editorIndentGuides]: '#D3D3D3',\r\n\t\t[editorActiveIndentGuides]: '#939393',\r\n\t\t[editorSelectionHighlight]: '#ADD6FF4D'\r\n\t}\r\n};\r\n/* -------------------------------- End vs theme -------------------------------- */\r\n\r\n\r\n/* -------------------------------- Begin vs-dark theme -------------------------------- */\r\nexport const vs_dark: IStandaloneThemeData = {\r\n\tbase: 'vs-dark',\r\n\tinherit: false,\r\n\trules: [\r\n\t\t{ token: '', foreground: 'D4D4D4', background: '1E1E1E' },\r\n\t\t{ token: 'invalid', foreground: 'f44747' },\r\n\t\t{ token: 'emphasis', fontStyle: 'italic' },\r\n\t\t{ token: 'strong', fontStyle: 'bold' },\r\n\r\n\t\t{ token: 'variable', foreground: '74B0DF' },\r\n\t\t{ token: 'variable.predefined', foreground: '4864AA' },\r\n\t\t{ token: 'variable.parameter', foreground: '9CDCFE' },\r\n\t\t{ token: 'constant', foreground: '569CD6' },\r\n\t\t{ token: 'comment', foreground: '608B4E' },\r\n\t\t{ token: 'number', foreground: 'B5CEA8' },\r\n\t\t{ token: 'number.hex', foreground: '5BB498' },\r\n\t\t{ token: 'regexp', foreground: 'B46695' },\r\n\t\t{ token: 'annotation', foreground: 'cc6666' },\r\n\t\t{ token: 'type', foreground: '3DC9B0' },\r\n\r\n\t\t{ token: 'delimiter', foreground: 'DCDCDC' },\r\n\t\t{ token: 'delimiter.html', foreground: '808080' },\r\n\t\t{ token: 'delimiter.xml', foreground: '808080' },\r\n\r\n\t\t{ token: 'tag', foreground: '569CD6' },\r\n\t\t{ token: 'tag.id.pug', foreground: '4F76AC' },\r\n\t\t{ token: 'tag.class.pug', foreground: '4F76AC' },\r\n\t\t{ token: 'meta.scss', foreground: 'A79873' },\r\n\t\t{ token: 'meta.tag', foreground: 'CE9178' },\r\n\t\t{ token: 'metatag', foreground: 'DD6A6F' },\r\n\t\t{ token: 'metatag.content.html', foreground: '9CDCFE' },\r\n\t\t{ token: 'metatag.html', foreground: '569CD6' },\r\n\t\t{ token: 'metatag.xml', foreground: '569CD6' },\r\n\t\t{ token: 'metatag.php', fontStyle: 'bold' },\r\n\r\n\t\t{ token: 'key', foreground: '9CDCFE' },\r\n\t\t{ token: 'string.key.json', foreground: '9CDCFE' },\r\n\t\t{ token: 'string.value.json', foreground: 'CE9178' },\r\n\r\n\t\t{ token: 'attribute.name', foreground: '9CDCFE' },\r\n\t\t{ token: 'attribute.value', foreground: 'CE9178' },\r\n\t\t{ token: 'attribute.value.number.css', foreground: 'B5CEA8' },\r\n\t\t{ token: 'attribute.value.unit.css', foreground: 'B5CEA8' },\r\n\t\t{ token: 'attribute.value.hex.css', foreground: 'D4D4D4' },\r\n\r\n\t\t{ token: 'string', foreground: 'CE9178' },\r\n\t\t{ token: 'string.sql', foreground: 'FF0000' },\r\n\r\n\t\t{ token: 'keyword', foreground: '569CD6' },\r\n\t\t{ token: 'keyword.flow', foreground: 'C586C0' },\r\n\t\t{ token: 'keyword.json', foreground: 'CE9178' },\r\n\t\t{ token: 'keyword.flow.scss', foreground: '569CD6' },\r\n\r\n\t\t{ token: 'operator.scss', foreground: '909090' },\r\n\t\t{ token: 'operator.sql', foreground: '778899' },\r\n\t\t{ token: 'operator.swift', foreground: '909090' },\r\n\t\t{ token: 'predefined.sql', foreground: 'FF00FF' },\r\n\t],\r\n\tcolors: {\r\n\t\t[editorBackground]: '#1E1E1E',\r\n\t\t[editorForeground]: '#D4D4D4',\r\n\t\t[editorInactiveSelection]: '#3A3D41',\r\n\t\t[editorIndentGuides]: '#404040',\r\n\t\t[editorActiveIndentGuides]: '#707070',\r\n\t\t[editorSelectionHighlight]: '#ADD6FF26'\r\n\t}\r\n};\r\n/* -------------------------------- End vs-dark theme -------------------------------- */\r\n\r\n\r\n\r\n/* -------------------------------- Begin hc-black theme -------------------------------- */\r\nexport const hc_black: IStandaloneThemeData = {\r\n\tbase: 'hc-black',\r\n\tinherit: false,\r\n\trules: [\r\n\t\t{ token: '', foreground: 'FFFFFF', background: '000000' },\r\n\t\t{ token: 'invalid', foreground: 'f44747' },\r\n\t\t{ token: 'emphasis', fontStyle: 'italic' },\r\n\t\t{ token: 'strong', fontStyle: 'bold' },\r\n\r\n\t\t{ token: 'variable', foreground: '1AEBFF' },\r\n\t\t{ token: 'variable.parameter', foreground: '9CDCFE' },\r\n\t\t{ token: 'constant', foreground: '569CD6' },\r\n\t\t{ token: 'comment', foreground: '608B4E' },\r\n\t\t{ token: 'number', foreground: 'FFFFFF' },\r\n\t\t{ token: 'regexp', foreground: 'C0C0C0' },\r\n\t\t{ token: 'annotation', foreground: '569CD6' },\r\n\t\t{ token: 'type', foreground: '3DC9B0' },\r\n\r\n\t\t{ token: 'delimiter', foreground: 'FFFF00' },\r\n\t\t{ token: 'delimiter.html', foreground: 'FFFF00' },\r\n\r\n\t\t{ token: 'tag', foreground: '569CD6' },\r\n\t\t{ token: 'tag.id.pug', foreground: '4F76AC' },\r\n\t\t{ token: 'tag.class.pug', foreground: '4F76AC' },\r\n\t\t{ token: 'meta', foreground: 'D4D4D4' },\r\n\t\t{ token: 'meta.tag', foreground: 'CE9178' },\r\n\t\t{ token: 'metatag', foreground: '569CD6' },\r\n\t\t{ token: 'metatag.content.html', foreground: '1AEBFF' },\r\n\t\t{ token: 'metatag.html', foreground: '569CD6' },\r\n\t\t{ token: 'metatag.xml', foreground: '569CD6' },\r\n\t\t{ token: 'metatag.php', fontStyle: 'bold' },\r\n\r\n\t\t{ token: 'key', foreground: '9CDCFE' },\r\n\t\t{ token: 'string.key', foreground: '9CDCFE' },\r\n\t\t{ token: 'string.value', foreground: 'CE9178' },\r\n\r\n\t\t{ token: 'attribute.name', foreground: '569CD6' },\r\n\t\t{ token: 'attribute.value', foreground: '3FF23F' },\r\n\r\n\t\t{ token: 'string', foreground: 'CE9178' },\r\n\t\t{ token: 'string.sql', foreground: 'FF0000' },\r\n\r\n\t\t{ token: 'keyword', foreground: '569CD6' },\r\n\t\t{ token: 'keyword.flow', foreground: 'C586C0' },\r\n\r\n\t\t{ token: 'operator.sql', foreground: '778899' },\r\n\t\t{ token: 'operator.swift', foreground: '909090' },\r\n\t\t{ token: 'predefined.sql', foreground: 'FF00FF' },\r\n\t],\r\n\tcolors: {\r\n\t\t[editorBackground]: '#000000',\r\n\t\t[editorForeground]: '#FFFFFF',\r\n\t\t[editorIndentGuides]: '#FFFFFF',\r\n\t\t[editorActiveIndentGuides]: '#FFFFFF',\r\n\t}\r\n};\r\n/* -------------------------------- End hc-black theme -------------------------------- */\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IAction, Separator, SubmenuAction } from 'vs/base/common/actions';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IContextKeyService, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';\r\nimport { ICommandService } from 'vs/platform/commands/common/commands';\r\nimport { IDisposable, toDisposable } from 'vs/base/common/lifecycle';\r\nimport { Event, Emitter } from 'vs/base/common/event';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { ThemeIcon } from 'vs/platform/theme/common/themeService';\r\nimport { Iterable } from 'vs/base/common/iterator';\r\nimport { LinkedList } from 'vs/base/common/linkedList';\r\nimport { CSSIcon } from 'vs/base/common/codicons';\r\n\r\nexport interface ILocalizedString {\r\n\t/**\r\n\t * The localized value of the string.\r\n\t */\r\n\tvalue: string;\r\n\t/**\r\n\t * The original (non localized value of the string)\r\n\t */\r\n\toriginal: string;\r\n}\r\n\r\nexport interface ICommandActionTitle extends ILocalizedString {\r\n}\r\n\r\nexport type Icon = { dark?: URI; light?: URI; } | ThemeIcon;\r\n\r\nexport interface ICommandAction {\r\n\tid: string;\r\n\ttitle: string | ICommandActionTitle;\r\n\ttooltip?: string;\r\n\ticon?: Icon;\r\n\tprecondition?: ContextKeyExpression;\r\n\ttoggled?: ContextKeyExpression | { condition: ContextKeyExpression, icon?: Icon, tooltip?: string };\r\n}\r\n\r\nexport interface IMenuItem {\r\n\tcommand: ICommandAction;\r\n\talt?: ICommandAction;\r\n\twhen?: ContextKeyExpression;\r\n\tgroup?: 'navigation' | string;\r\n\torder?: number;\r\n}\r\n\r\nexport interface ISubmenuItem {\r\n\ttitle: string | ICommandActionTitle;\r\n\tsubmenu: MenuId;\r\n\ticon?: Icon;\r\n\twhen?: ContextKeyExpression;\r\n\tgroup?: 'navigation' | string;\r\n\torder?: number;\r\n}\r\n\r\nexport function isIMenuItem(item: IMenuItem | ISubmenuItem): item is IMenuItem {\r\n\treturn (item as IMenuItem).command !== undefined;\r\n}\r\n\r\nexport class MenuId {\r\n\r\n\tprivate static _idPool = 0;\r\n\r\n\tstatic readonly CommandPalette = new MenuId('CommandPalette');\r\n\tstatic readonly EditorContext = new MenuId('EditorContext');\r\n\tstatic readonly EditorContextPeek = new MenuId('EditorContextPeek');\r\n\tstatic readonly MenubarEditMenu = new MenuId('MenubarEditMenu');\r\n\tstatic readonly MenubarGoMenu = new MenuId('MenubarGoMenu');\r\n\tstatic readonly MenubarSelectionMenu = new MenuId('MenubarSelectionMenu');\r\n\r\n\treadonly id: number;\r\n\treadonly _debugName: string;\r\n\r\n\tconstructor(debugName: string) {\r\n\t\tthis.id = MenuId._idPool++;\r\n\t\tthis._debugName = debugName;\r\n\t}\r\n}\r\n\r\nexport interface IMenuActionOptions {\r\n\targ?: any;\r\n\tshouldForwardArgs?: boolean;\r\n}\r\n\r\nexport interface IMenu extends IDisposable {\r\n\treadonly onDidChange: Event;\r\n\tgetActions(options?: IMenuActionOptions): [string, Array][];\r\n}\r\n\r\nexport const IMenuService = createDecorator('menuService');\r\n\r\nexport interface IMenuService {\r\n\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\tcreateMenu(id: MenuId, scopedKeybindingService: IContextKeyService): IMenu;\r\n}\r\n\r\nexport type ICommandsMap = Map;\r\n\r\nexport interface IMenuRegistryChangeEvent {\r\n\thas(id: MenuId): boolean;\r\n}\r\n\r\nexport interface IMenuRegistry {\r\n\treadonly onDidChangeMenu: Event;\r\n\tappendMenuItem(menu: MenuId, item: IMenuItem | ISubmenuItem): IDisposable;\r\n\tgetMenuItems(loc: MenuId): Array;\r\n}\r\n\r\nexport const MenuRegistry: IMenuRegistry = new class implements IMenuRegistry {\r\n\r\n\tprivate readonly _commands = new Map();\r\n\tprivate readonly _menuItems = new Map>();\r\n\tprivate readonly _onDidChangeMenu = new Emitter();\r\n\r\n\treadonly onDidChangeMenu: Event = this._onDidChangeMenu.event;\r\n\r\n\taddCommand(command: ICommandAction): IDisposable {\r\n\t\treturn this.addCommands(Iterable.single(command));\r\n\t}\r\n\r\n\tprivate readonly _commandPaletteChangeEvent: IMenuRegistryChangeEvent = {\r\n\t\thas: id => id === MenuId.CommandPalette\r\n\t};\r\n\r\n\taddCommands(commands: Iterable): IDisposable {\r\n\t\tfor (const command of commands) {\r\n\t\t\tthis._commands.set(command.id, command);\r\n\t\t}\r\n\t\tthis._onDidChangeMenu.fire(this._commandPaletteChangeEvent);\r\n\t\treturn toDisposable(() => {\r\n\t\t\tlet didChange = false;\r\n\t\t\tfor (const command of commands) {\r\n\t\t\t\tdidChange = this._commands.delete(command.id) || didChange;\r\n\t\t\t}\r\n\t\t\tif (didChange) {\r\n\t\t\t\tthis._onDidChangeMenu.fire(this._commandPaletteChangeEvent);\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tgetCommand(id: string): ICommandAction | undefined {\r\n\t\treturn this._commands.get(id);\r\n\t}\r\n\r\n\tgetCommands(): ICommandsMap {\r\n\t\tconst map = new Map();\r\n\t\tthis._commands.forEach((value, key) => map.set(key, value));\r\n\t\treturn map;\r\n\t}\r\n\r\n\tappendMenuItem(id: MenuId, item: IMenuItem | ISubmenuItem): IDisposable {\r\n\t\treturn this.appendMenuItems(Iterable.single({ id, item }));\r\n\t}\r\n\r\n\tappendMenuItems(items: Iterable<{ id: MenuId, item: IMenuItem | ISubmenuItem }>): IDisposable {\r\n\r\n\t\tconst changedIds = new Set();\r\n\t\tconst toRemove = new LinkedList();\r\n\r\n\t\tfor (const { id, item } of items) {\r\n\t\t\tlet list = this._menuItems.get(id);\r\n\t\t\tif (!list) {\r\n\t\t\t\tlist = new LinkedList();\r\n\t\t\t\tthis._menuItems.set(id, list);\r\n\t\t\t}\r\n\t\t\ttoRemove.push(list.push(item));\r\n\t\t\tchangedIds.add(id);\r\n\t\t}\r\n\r\n\t\tthis._onDidChangeMenu.fire(changedIds);\r\n\r\n\t\treturn toDisposable(() => {\r\n\t\t\tif (toRemove.size > 0) {\r\n\t\t\t\tfor (let fn of toRemove) {\r\n\t\t\t\t\tfn();\r\n\t\t\t\t}\r\n\t\t\t\tthis._onDidChangeMenu.fire(changedIds);\r\n\t\t\t\ttoRemove.clear();\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tgetMenuItems(id: MenuId): Array {\r\n\t\tlet result: Array;\r\n\t\tif (this._menuItems.has(id)) {\r\n\t\t\tresult = [...this._menuItems.get(id)!];\r\n\t\t} else {\r\n\t\t\tresult = [];\r\n\t\t}\r\n\t\tif (id === MenuId.CommandPalette) {\r\n\t\t\t// CommandPalette is special because it shows\r\n\t\t\t// all commands by default\r\n\t\t\tthis._appendImplicitItems(result);\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate _appendImplicitItems(result: Array) {\r\n\t\tconst set = new Set();\r\n\r\n\t\tfor (const item of result) {\r\n\t\t\tif (isIMenuItem(item)) {\r\n\t\t\t\tset.add(item.command.id);\r\n\t\t\t\tif (item.alt) {\r\n\t\t\t\t\tset.add(item.alt.id);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis._commands.forEach((command, id) => {\r\n\t\t\tif (!set.has(id)) {\r\n\t\t\t\tresult.push({ command });\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n};\r\n\r\nexport class SubmenuItemAction extends SubmenuAction {\r\n\r\n\treadonly item: ISubmenuItem;\r\n\r\n\tconstructor(\r\n\t\titem: ISubmenuItem,\r\n\t\tmenuService: IMenuService,\r\n\t\tcontextKeyService: IContextKeyService,\r\n\t\toptions?: IMenuActionOptions\r\n\t) {\r\n\t\tconst result: IAction[] = [];\r\n\t\tconst menu = menuService.createMenu(item.submenu, contextKeyService);\r\n\t\tconst groups = menu.getActions(options);\r\n\t\tmenu.dispose();\r\n\r\n\t\tfor (let group of groups) {\r\n\t\t\tconst [, actions] = group;\r\n\r\n\t\t\tif (actions.length > 0) {\r\n\t\t\t\tresult.push(...actions);\r\n\t\t\t\tresult.push(new Separator());\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (result.length) {\r\n\t\t\tresult.pop(); // remove last separator\r\n\t\t}\r\n\r\n\t\tsuper(`submenuitem.${item.submenu.id}`, typeof item.title === 'string' ? item.title : item.title.value, result, 'submenu');\r\n\t\tthis.item = item;\r\n\t}\r\n}\r\n\r\n// implements IAction, does NOT extend Action, so that no one\r\n// subscribes to events of Action or modified properties\r\nexport class MenuItemAction implements IAction {\r\n\r\n\treadonly item: ICommandAction;\r\n\treadonly alt: MenuItemAction | undefined;\r\n\r\n\tprivate readonly _options: IMenuActionOptions | undefined;\r\n\r\n\treadonly id: string;\r\n\treadonly label: string;\r\n\treadonly tooltip: string;\r\n\treadonly class: string | undefined;\r\n\treadonly enabled: boolean;\r\n\treadonly checked: boolean;\r\n\r\n\tconstructor(\r\n\t\titem: ICommandAction,\r\n\t\talt: ICommandAction | undefined,\r\n\t\toptions: IMenuActionOptions | undefined,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\r\n\t\t@ICommandService private _commandService: ICommandService\r\n\t) {\r\n\t\tthis.id = item.id;\r\n\t\tthis.label = typeof item.title === 'string' ? item.title : item.title.value;\r\n\t\tthis.tooltip = item.tooltip ?? '';\r\n\t\tthis.enabled = !item.precondition || contextKeyService.contextMatchesRules(item.precondition);\r\n\t\tthis.checked = false;\r\n\r\n\t\tif (item.toggled) {\r\n\t\t\tconst toggled = ((item.toggled as { condition: ContextKeyExpression }).condition ? item.toggled : { condition: item.toggled }) as {\r\n\t\t\t\tcondition: ContextKeyExpression, icon?: Icon, tooltip?: string | ILocalizedString\r\n\t\t\t};\r\n\t\t\tthis.checked = contextKeyService.contextMatchesRules(toggled.condition);\r\n\t\t\tif (this.checked && toggled.tooltip) {\r\n\t\t\t\tthis.tooltip = typeof toggled.tooltip === 'string' ? toggled.tooltip : toggled.tooltip.value;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis.item = item;\r\n\t\tthis.alt = alt ? new MenuItemAction(alt, undefined, options, contextKeyService, _commandService) : undefined;\r\n\t\tthis._options = options;\r\n\t\tif (ThemeIcon.isThemeIcon(item.icon)) {\r\n\t\t\tthis.class = CSSIcon.asClassName(item.icon);\r\n\t\t}\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\t// there is NOTHING to dispose and the MenuItemAction should\r\n\t\t// never have anything to dispose as it is a convenience type\r\n\t\t// to bridge into the rendering world.\r\n\t}\r\n\r\n\trun(...args: any[]): Promise {\r\n\t\tlet runArgs: any[] = [];\r\n\r\n\t\tif (this._options?.arg) {\r\n\t\t\trunArgs = [...runArgs, this._options.arg];\r\n\t\t}\r\n\r\n\t\tif (this._options?.shouldForwardArgs) {\r\n\t\t\trunArgs = [...runArgs, ...args];\r\n\t\t}\r\n\r\n\t\treturn this._commandService.executeCommand(this.id, ...runArgs);\r\n\t}\r\n}\r\n//#endregion\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { IEditorContribution, IDiffEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { IModelService } from 'vs/editor/common/services/modelService';\r\nimport { ITextModelService } from 'vs/editor/common/services/resolverService';\r\nimport { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';\r\nimport { CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands';\r\nimport { ContextKeyExpr, IContextKeyService, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IConstructorSignature1, ServicesAccessor as InstantiationServicesAccessor, BrandedService } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IKeybindings, KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { Registry } from 'vs/platform/registry/common/platform';\r\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\r\nimport { withNullAsUndefined, assertType } from 'vs/base/common/types';\r\nimport { ThemeIcon } from 'vs/platform/theme/common/themeService';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { KeyMod, KeyCode } from 'vs/base/common/keyCodes';\r\n\r\n\r\nexport type ServicesAccessor = InstantiationServicesAccessor;\r\nexport type IEditorContributionCtor = IConstructorSignature1;\r\nexport type IDiffEditorContributionCtor = IConstructorSignature1;\r\n\r\nexport interface IEditorContributionDescription {\r\n\tid: string;\r\n\tctor: IEditorContributionCtor;\r\n}\r\n\r\nexport interface IDiffEditorContributionDescription {\r\n\tctor: IDiffEditorContributionCtor;\r\n}\r\n\r\n//#region Command\r\n\r\nexport interface ICommandKeybindingsOptions extends IKeybindings {\r\n\tkbExpr?: ContextKeyExpression | null;\r\n\tweight: number;\r\n\t/**\r\n\t * the default keybinding arguments\r\n\t */\r\n\targs?: any;\r\n}\r\nexport interface ICommandMenuOptions {\r\n\tmenuId: MenuId;\r\n\tgroup: string;\r\n\torder: number;\r\n\twhen?: ContextKeyExpression;\r\n\ttitle: string;\r\n\ticon?: ThemeIcon\r\n}\r\nexport interface ICommandOptions {\r\n\tid: string;\r\n\tprecondition: ContextKeyExpression | undefined;\r\n\tkbOpts?: ICommandKeybindingsOptions;\r\n\tdescription?: ICommandHandlerDescription;\r\n\tmenuOpts?: ICommandMenuOptions | ICommandMenuOptions[];\r\n}\r\nexport abstract class Command {\r\n\tpublic readonly id: string;\r\n\tpublic readonly precondition: ContextKeyExpression | undefined;\r\n\tprivate readonly _kbOpts: ICommandKeybindingsOptions | undefined;\r\n\tprivate readonly _menuOpts: ICommandMenuOptions | ICommandMenuOptions[] | undefined;\r\n\tprivate readonly _description: ICommandHandlerDescription | undefined;\r\n\r\n\tconstructor(opts: ICommandOptions) {\r\n\t\tthis.id = opts.id;\r\n\t\tthis.precondition = opts.precondition;\r\n\t\tthis._kbOpts = opts.kbOpts;\r\n\t\tthis._menuOpts = opts.menuOpts;\r\n\t\tthis._description = opts.description;\r\n\t}\r\n\r\n\tpublic register(): void {\r\n\r\n\t\tif (Array.isArray(this._menuOpts)) {\r\n\t\t\tthis._menuOpts.forEach(this._registerMenuItem, this);\r\n\t\t} else if (this._menuOpts) {\r\n\t\t\tthis._registerMenuItem(this._menuOpts);\r\n\t\t}\r\n\r\n\t\tif (this._kbOpts) {\r\n\t\t\tlet kbWhen = this._kbOpts.kbExpr;\r\n\t\t\tif (this.precondition) {\r\n\t\t\t\tif (kbWhen) {\r\n\t\t\t\t\tkbWhen = ContextKeyExpr.and(kbWhen, this.precondition);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tkbWhen = this.precondition;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tKeybindingsRegistry.registerCommandAndKeybindingRule({\r\n\t\t\t\tid: this.id,\r\n\t\t\t\thandler: (accessor, args) => this.runCommand(accessor, args),\r\n\t\t\t\tweight: this._kbOpts.weight,\r\n\t\t\t\targs: this._kbOpts.args,\r\n\t\t\t\twhen: kbWhen,\r\n\t\t\t\tprimary: this._kbOpts.primary,\r\n\t\t\t\tsecondary: this._kbOpts.secondary,\r\n\t\t\t\twin: this._kbOpts.win,\r\n\t\t\t\tlinux: this._kbOpts.linux,\r\n\t\t\t\tmac: this._kbOpts.mac,\r\n\t\t\t\tdescription: this._description\r\n\t\t\t});\r\n\r\n\t\t} else {\r\n\r\n\t\t\tCommandsRegistry.registerCommand({\r\n\t\t\t\tid: this.id,\r\n\t\t\t\thandler: (accessor, args) => this.runCommand(accessor, args),\r\n\t\t\t\tdescription: this._description\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _registerMenuItem(item: ICommandMenuOptions): void {\r\n\t\tMenuRegistry.appendMenuItem(item.menuId, {\r\n\t\t\tgroup: item.group,\r\n\t\t\tcommand: {\r\n\t\t\t\tid: this.id,\r\n\t\t\t\ttitle: item.title,\r\n\t\t\t\ticon: item.icon,\r\n\t\t\t\tprecondition: this.precondition\r\n\t\t\t},\r\n\t\t\twhen: item.when,\r\n\t\t\torder: item.order\r\n\t\t});\r\n\t}\r\n\r\n\tpublic abstract runCommand(accessor: ServicesAccessor, args: any): void | Promise;\r\n}\r\n\r\n//#endregion Command\r\n\r\n//#region MultiplexingCommand\r\n\r\n/**\r\n * Potential override for a command.\r\n *\r\n * @return `true` if the command was successfully run. This stops other overrides from being executed.\r\n */\r\nexport type CommandImplementation = (accessor: ServicesAccessor, args: unknown) => boolean | Promise;\r\n\r\nexport class MultiCommand extends Command {\r\n\r\n\tprivate readonly _implementations: [number, CommandImplementation][] = [];\r\n\r\n\t/**\r\n\t * A higher priority gets to be looked at first\r\n\t */\r\n\tpublic addImplementation(priority: number, implementation: CommandImplementation): IDisposable {\r\n\t\tthis._implementations.push([priority, implementation]);\r\n\t\tthis._implementations.sort((a, b) => b[0] - a[0]);\r\n\t\treturn {\r\n\t\t\tdispose: () => {\r\n\t\t\t\tfor (let i = 0; i < this._implementations.length; i++) {\r\n\t\t\t\t\tif (this._implementations[i][1] === implementation) {\r\n\t\t\t\t\t\tthis._implementations.splice(i, 1);\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\tpublic runCommand(accessor: ServicesAccessor, args: any): void | Promise {\r\n\t\tfor (const impl of this._implementations) {\r\n\t\t\tconst result = impl[1](accessor, args);\r\n\t\t\tif (result) {\r\n\t\t\t\tif (typeof result === 'boolean') {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\treturn result;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\n//#endregion\r\n\r\n/**\r\n * A command that delegates to another command's implementation.\r\n *\r\n * This lets different commands be registered but share the same implementation\r\n */\r\nexport class ProxyCommand extends Command {\r\n\tconstructor(\r\n\t\tprivate readonly command: Command,\r\n\t\topts: ICommandOptions\r\n\t) {\r\n\t\tsuper(opts);\r\n\t}\r\n\r\n\tpublic runCommand(accessor: ServicesAccessor, args: any): void | Promise {\r\n\t\treturn this.command.runCommand(accessor, args);\r\n\t}\r\n}\r\n\r\n//#region EditorCommand\r\n\r\nexport interface IContributionCommandOptions extends ICommandOptions {\r\n\thandler: (controller: T, args: any) => void;\r\n}\r\nexport interface EditorControllerCommand {\r\n\tnew(opts: IContributionCommandOptions): EditorCommand;\r\n}\r\nexport abstract class EditorCommand extends Command {\r\n\r\n\t/**\r\n\t * Create a command class that is bound to a certain editor contribution.\r\n\t */\r\n\tpublic static bindToContribution(controllerGetter: (editor: ICodeEditor) => T): EditorControllerCommand {\r\n\t\treturn class EditorControllerCommandImpl extends EditorCommand {\r\n\t\t\tprivate readonly _callback: (controller: T, args: any) => void;\r\n\r\n\t\t\tconstructor(opts: IContributionCommandOptions) {\r\n\t\t\t\tsuper(opts);\r\n\r\n\t\t\t\tthis._callback = opts.handler;\r\n\t\t\t}\r\n\r\n\t\t\tpublic runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {\r\n\t\t\t\tconst controller = controllerGetter(editor);\r\n\t\t\t\tif (controller) {\r\n\t\t\t\t\tthis._callback(controllerGetter(editor), args);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\tpublic runCommand(accessor: ServicesAccessor, args: any): void | Promise {\r\n\t\tconst codeEditorService = accessor.get(ICodeEditorService);\r\n\r\n\t\t// Find the editor with text focus or active\r\n\t\tconst editor = codeEditorService.getFocusedCodeEditor() || codeEditorService.getActiveCodeEditor();\r\n\t\tif (!editor) {\r\n\t\t\t// well, at least we tried...\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\treturn editor.invokeWithinContext((editorAccessor) => {\r\n\t\t\tconst kbService = editorAccessor.get(IContextKeyService);\r\n\t\t\tif (!kbService.contextMatchesRules(withNullAsUndefined(this.precondition))) {\r\n\t\t\t\t// precondition does not hold\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\treturn this.runEditorCommand(editorAccessor, editor!, args);\r\n\t\t});\r\n\t}\r\n\r\n\tpublic abstract runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void | Promise;\r\n}\r\n\r\n//#endregion EditorCommand\r\n\r\n//#region EditorAction\r\n\r\nexport interface IEditorActionContextMenuOptions {\r\n\tgroup: string;\r\n\torder: number;\r\n\twhen?: ContextKeyExpression;\r\n\tmenuId?: MenuId;\r\n}\r\nexport interface IActionOptions extends ICommandOptions {\r\n\tlabel: string;\r\n\talias: string;\r\n\tcontextMenuOpts?: IEditorActionContextMenuOptions | IEditorActionContextMenuOptions[];\r\n}\r\n\r\nexport abstract class EditorAction extends EditorCommand {\r\n\r\n\tprivate static convertOptions(opts: IActionOptions): ICommandOptions {\r\n\r\n\t\tlet menuOpts: ICommandMenuOptions[];\r\n\t\tif (Array.isArray(opts.menuOpts)) {\r\n\t\t\tmenuOpts = opts.menuOpts;\r\n\t\t} else if (opts.menuOpts) {\r\n\t\t\tmenuOpts = [opts.menuOpts];\r\n\t\t} else {\r\n\t\t\tmenuOpts = [];\r\n\t\t}\r\n\r\n\t\tfunction withDefaults(item: Partial): ICommandMenuOptions {\r\n\t\t\tif (!item.menuId) {\r\n\t\t\t\titem.menuId = MenuId.EditorContext;\r\n\t\t\t}\r\n\t\t\tif (!item.title) {\r\n\t\t\t\titem.title = opts.label;\r\n\t\t\t}\r\n\t\t\titem.when = ContextKeyExpr.and(opts.precondition, item.when);\r\n\t\t\treturn item;\r\n\t\t}\r\n\r\n\t\tif (Array.isArray(opts.contextMenuOpts)) {\r\n\t\t\tmenuOpts.push(...opts.contextMenuOpts.map(withDefaults));\r\n\t\t} else if (opts.contextMenuOpts) {\r\n\t\t\tmenuOpts.push(withDefaults(opts.contextMenuOpts));\r\n\t\t}\r\n\r\n\t\topts.menuOpts = menuOpts;\r\n\t\treturn opts;\r\n\t}\r\n\r\n\tpublic readonly label: string;\r\n\tpublic readonly alias: string;\r\n\r\n\tconstructor(opts: IActionOptions) {\r\n\t\tsuper(EditorAction.convertOptions(opts));\r\n\t\tthis.label = opts.label;\r\n\t\tthis.alias = opts.alias;\r\n\t}\r\n\r\n\tpublic runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void | Promise {\r\n\t\tthis.reportTelemetry(accessor, editor);\r\n\t\treturn this.run(accessor, editor, args || {});\r\n\t}\r\n\r\n\tprotected reportTelemetry(accessor: ServicesAccessor, editor: ICodeEditor) {\r\n\t\ttype EditorActionInvokedClassification = {\r\n\t\t\tname: { classification: 'SystemMetaData', purpose: 'FeatureInsight', };\r\n\t\t\tid: { classification: 'SystemMetaData', purpose: 'FeatureInsight', };\r\n\t\t};\r\n\t\ttype EditorActionInvokedEvent = {\r\n\t\t\tname: string;\r\n\t\t\tid: string;\r\n\t\t};\r\n\t\taccessor.get(ITelemetryService).publicLog2('editorActionInvoked', { name: this.label, id: this.id });\r\n\t}\r\n\r\n\tpublic abstract run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void | Promise;\r\n}\r\n\r\nexport abstract class MultiEditorAction extends EditorAction {\r\n\tprivate readonly _implementations: [number, CommandImplementation][] = [];\r\n\r\n\tconstructor(opts: IActionOptions) {\r\n\t\tsuper(opts);\r\n\t}\r\n\r\n\tpublic runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void | Promise {\r\n\t\tthis.reportTelemetry(accessor, editor);\r\n\r\n\t\tfor (const impl of this._implementations) {\r\n\t\t\tif (impl[1](accessor, args)) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this.run(accessor, editor, args || {});\r\n\t}\r\n\r\n\tpublic abstract run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void | Promise;\r\n\r\n}\r\n\r\n//#endregion\r\n\r\n// --- Registration of commands and actions\r\n\r\n\r\nexport function registerModelAndPositionCommand(id: string, handler: (model: ITextModel, position: Position, ...args: any[]) => any) {\r\n\tCommandsRegistry.registerCommand(id, function (accessor, ...args) {\r\n\r\n\t\tconst [resource, position] = args;\r\n\t\tassertType(URI.isUri(resource));\r\n\t\tassertType(Position.isIPosition(position));\r\n\r\n\t\tconst model = accessor.get(IModelService).getModel(resource);\r\n\t\tif (model) {\r\n\t\t\tconst editorPosition = Position.lift(position);\r\n\t\t\treturn handler(model, editorPosition, ...args.slice(2));\r\n\t\t}\r\n\r\n\t\treturn accessor.get(ITextModelService).createModelReference(resource).then(reference => {\r\n\t\t\treturn new Promise((resolve, reject) => {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tconst result = handler(reference.object.textEditorModel, Position.lift(position), args.slice(2));\r\n\t\t\t\t\tresolve(result);\r\n\t\t\t\t} catch (err) {\r\n\t\t\t\t\treject(err);\r\n\t\t\t\t}\r\n\t\t\t}).finally(() => {\r\n\t\t\t\treference.dispose();\r\n\t\t\t});\r\n\t\t});\r\n\t});\r\n}\r\n\r\nexport function registerModelCommand(id: string, handler: (model: ITextModel, ...args: any[]) => any) {\r\n\tCommandsRegistry.registerCommand(id, function (accessor, ...args) {\r\n\r\n\t\tconst [resource] = args;\r\n\t\tassertType(URI.isUri(resource));\r\n\r\n\t\tconst model = accessor.get(IModelService).getModel(resource);\r\n\t\tif (model) {\r\n\t\t\treturn handler(model, ...args.slice(1));\r\n\t\t}\r\n\r\n\t\treturn accessor.get(ITextModelService).createModelReference(resource).then(reference => {\r\n\t\t\treturn new Promise((resolve, reject) => {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tconst result = handler(reference.object.textEditorModel, args.slice(1));\r\n\t\t\t\t\tresolve(result);\r\n\t\t\t\t} catch (err) {\r\n\t\t\t\t\treject(err);\r\n\t\t\t\t}\r\n\t\t\t}).finally(() => {\r\n\t\t\t\treference.dispose();\r\n\t\t\t});\r\n\t\t});\r\n\t});\r\n}\r\n\r\nexport function registerEditorCommand(editorCommand: T): T {\r\n\tEditorContributionRegistry.INSTANCE.registerEditorCommand(editorCommand);\r\n\treturn editorCommand;\r\n}\r\n\r\nexport function registerEditorAction(ctor: { new(): T; }): T {\r\n\tconst action = new ctor();\r\n\tEditorContributionRegistry.INSTANCE.registerEditorAction(action);\r\n\treturn action;\r\n}\r\n\r\nexport function registerMultiEditorAction(action: T): T {\r\n\tEditorContributionRegistry.INSTANCE.registerEditorAction(action);\r\n\treturn action;\r\n}\r\n\r\nexport function registerInstantiatedEditorAction(editorAction: EditorAction): void {\r\n\tEditorContributionRegistry.INSTANCE.registerEditorAction(editorAction);\r\n}\r\n\r\nexport function registerEditorContribution(id: string, ctor: { new(editor: ICodeEditor, ...services: Services): IEditorContribution }): void {\r\n\tEditorContributionRegistry.INSTANCE.registerEditorContribution(id, ctor);\r\n}\r\n\r\nexport namespace EditorExtensionsRegistry {\r\n\r\n\texport function getEditorCommand(commandId: string): EditorCommand {\r\n\t\treturn EditorContributionRegistry.INSTANCE.getEditorCommand(commandId);\r\n\t}\r\n\r\n\texport function getEditorActions(): EditorAction[] {\r\n\t\treturn EditorContributionRegistry.INSTANCE.getEditorActions();\r\n\t}\r\n\r\n\texport function getEditorContributions(): IEditorContributionDescription[] {\r\n\t\treturn EditorContributionRegistry.INSTANCE.getEditorContributions();\r\n\t}\r\n\r\n\texport function getSomeEditorContributions(ids: string[]): IEditorContributionDescription[] {\r\n\t\treturn EditorContributionRegistry.INSTANCE.getEditorContributions().filter(c => ids.indexOf(c.id) >= 0);\r\n\t}\r\n\r\n\texport function getDiffEditorContributions(): IDiffEditorContributionDescription[] {\r\n\t\treturn EditorContributionRegistry.INSTANCE.getDiffEditorContributions();\r\n\t}\r\n}\r\n\r\n// Editor extension points\r\nconst Extensions = {\r\n\tEditorCommonContributions: 'editor.contributions'\r\n};\r\n\r\nclass EditorContributionRegistry {\r\n\r\n\tpublic static readonly INSTANCE = new EditorContributionRegistry();\r\n\r\n\tprivate readonly editorContributions: IEditorContributionDescription[];\r\n\tprivate readonly diffEditorContributions: IDiffEditorContributionDescription[];\r\n\tprivate readonly editorActions: EditorAction[];\r\n\tprivate readonly editorCommands: { [commandId: string]: EditorCommand; };\r\n\r\n\tconstructor() {\r\n\t\tthis.editorContributions = [];\r\n\t\tthis.diffEditorContributions = [];\r\n\t\tthis.editorActions = [];\r\n\t\tthis.editorCommands = Object.create(null);\r\n\t}\r\n\r\n\tpublic registerEditorContribution(id: string, ctor: { new(editor: ICodeEditor, ...services: Services): IEditorContribution }): void {\r\n\t\tthis.editorContributions.push({ id, ctor: ctor as IEditorContributionCtor });\r\n\t}\r\n\r\n\tpublic getEditorContributions(): IEditorContributionDescription[] {\r\n\t\treturn this.editorContributions.slice(0);\r\n\t}\r\n\r\n\tpublic getDiffEditorContributions(): IDiffEditorContributionDescription[] {\r\n\t\treturn this.diffEditorContributions.slice(0);\r\n\t}\r\n\r\n\tpublic registerEditorAction(action: EditorAction) {\r\n\t\taction.register();\r\n\t\tthis.editorActions.push(action);\r\n\t}\r\n\r\n\tpublic getEditorActions(): EditorAction[] {\r\n\t\treturn this.editorActions.slice(0);\r\n\t}\r\n\r\n\tpublic registerEditorCommand(editorCommand: EditorCommand) {\r\n\t\teditorCommand.register();\r\n\t\tthis.editorCommands[editorCommand.id] = editorCommand;\r\n\t}\r\n\r\n\tpublic getEditorCommand(commandId: string): EditorCommand {\r\n\t\treturn (this.editorCommands[commandId] || null);\r\n\t}\r\n\r\n}\r\nRegistry.add(Extensions.EditorCommonContributions, EditorContributionRegistry.INSTANCE);\r\n\r\nfunction registerCommand(command: T): T {\r\n\tcommand.register();\r\n\treturn command;\r\n}\r\n\r\nexport const UndoCommand = registerCommand(new MultiCommand({\r\n\tid: 'undo',\r\n\tprecondition: undefined,\r\n\tkbOpts: {\r\n\t\tweight: KeybindingWeight.EditorCore,\r\n\t\tprimary: KeyMod.CtrlCmd | KeyCode.KEY_Z\r\n\t},\r\n\tmenuOpts: [{\r\n\t\tmenuId: MenuId.MenubarEditMenu,\r\n\t\tgroup: '1_do',\r\n\t\ttitle: nls.localize({ key: 'miUndo', comment: ['&& denotes a mnemonic'] }, \"&&Undo\"),\r\n\t\torder: 1\r\n\t}, {\r\n\t\tmenuId: MenuId.CommandPalette,\r\n\t\tgroup: '',\r\n\t\ttitle: nls.localize('undo', \"Undo\"),\r\n\t\torder: 1\r\n\t}]\r\n}));\r\n\r\nregisterCommand(new ProxyCommand(UndoCommand, { id: 'default:undo', precondition: undefined }));\r\n\r\nexport const RedoCommand = registerCommand(new MultiCommand({\r\n\tid: 'redo',\r\n\tprecondition: undefined,\r\n\tkbOpts: {\r\n\t\tweight: KeybindingWeight.EditorCore,\r\n\t\tprimary: KeyMod.CtrlCmd | KeyCode.KEY_Y,\r\n\t\tsecondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z],\r\n\t\tmac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z }\r\n\t},\r\n\tmenuOpts: [{\r\n\t\tmenuId: MenuId.MenubarEditMenu,\r\n\t\tgroup: '1_do',\r\n\t\ttitle: nls.localize({ key: 'miRedo', comment: ['&& denotes a mnemonic'] }, \"&&Redo\"),\r\n\t\torder: 2\r\n\t}, {\r\n\t\tmenuId: MenuId.CommandPalette,\r\n\t\tgroup: '',\r\n\t\ttitle: nls.localize('redo', \"Redo\"),\r\n\t\torder: 1\r\n\t}]\r\n}));\r\n\r\nregisterCommand(new ProxyCommand(RedoCommand, { id: 'default:redo', precondition: undefined }));\r\n\r\nexport const SelectAllCommand = registerCommand(new MultiCommand({\r\n\tid: 'editor.action.selectAll',\r\n\tprecondition: undefined,\r\n\tkbOpts: {\r\n\t\tweight: KeybindingWeight.EditorCore,\r\n\t\tkbExpr: null,\r\n\t\tprimary: KeyMod.CtrlCmd | KeyCode.KEY_A\r\n\t},\r\n\tmenuOpts: [{\r\n\t\tmenuId: MenuId.MenubarSelectionMenu,\r\n\t\tgroup: '1_basic',\r\n\t\ttitle: nls.localize({ key: 'miSelectAll', comment: ['&& denotes a mnemonic'] }, \"&&Select All\"),\r\n\t\torder: 1\r\n\t}, {\r\n\t\tmenuId: MenuId.CommandPalette,\r\n\t\tgroup: '',\r\n\t\ttitle: nls.localize('selectAll', \"Select All\"),\r\n\t\torder: 1\r\n\t}]\r\n}));\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { isFirefox } from 'vs/base/browser/browser';\r\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport * as types from 'vs/base/common/types';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { Command, EditorCommand, ICommandOptions, registerEditorCommand, MultiCommand, UndoCommand, RedoCommand, SelectAllCommand } from 'vs/editor/browser/editorExtensions';\r\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\r\nimport { ColumnSelection, IColumnSelectResult } from 'vs/editor/common/controller/cursorColumnSelection';\r\nimport { CursorState, EditOperationType, IColumnSelectData, PartialCursorState } from 'vs/editor/common/controller/cursorCommon';\r\nimport { DeleteOperations } from 'vs/editor/common/controller/cursorDeleteOperations';\r\nimport { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents';\r\nimport { CursorMove as CursorMove_, CursorMoveCommands } from 'vs/editor/common/controller/cursorMoveCommands';\r\nimport { TypeOperations } from 'vs/editor/common/controller/cursorTypeOperations';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Handler, ScrollType } from 'vs/editor/common/editorCommon';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { VerticalRevealType } from 'vs/editor/common/view/viewEvents';\r\nimport { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';\r\nimport { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';\r\nimport { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';\r\nimport { KeybindingWeight, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { IViewModel } from 'vs/editor/common/viewModel/viewModel';\r\n\r\nconst CORE_WEIGHT = KeybindingWeight.EditorCore;\r\n\r\nexport abstract class CoreEditorCommand extends EditorCommand {\r\n\tpublic runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void {\r\n\t\tconst viewModel = editor._getViewModel();\r\n\t\tif (!viewModel) {\r\n\t\t\t// the editor has no view => has no cursors\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis.runCoreEditorCommand(viewModel, args || {});\r\n\t}\r\n\r\n\tpublic abstract runCoreEditorCommand(viewModel: IViewModel, args: any): void;\r\n}\r\n\r\nexport namespace EditorScroll_ {\r\n\r\n\tconst isEditorScrollArgs = function (arg: any): boolean {\r\n\t\tif (!types.isObject(arg)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tconst scrollArg: RawArguments = arg;\r\n\r\n\t\tif (!types.isString(scrollArg.to)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tif (!types.isUndefined(scrollArg.by) && !types.isString(scrollArg.by)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tif (!types.isUndefined(scrollArg.value) && !types.isNumber(scrollArg.value)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tif (!types.isUndefined(scrollArg.revealCursor) && !types.isBoolean(scrollArg.revealCursor)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t};\r\n\r\n\texport const description = {\r\n\t\tdescription: 'Scroll editor in the given direction',\r\n\t\targs: [\r\n\t\t\t{\r\n\t\t\t\tname: 'Editor scroll argument object',\r\n\t\t\t\tdescription: `Property-value pairs that can be passed through this argument:\r\n\t\t\t\t\t* 'to': A mandatory direction value.\r\n\t\t\t\t\t\t\\`\\`\\`\r\n\t\t\t\t\t\t'up', 'down'\r\n\t\t\t\t\t\t\\`\\`\\`\r\n\t\t\t\t\t* 'by': Unit to move. Default is computed based on 'to' value.\r\n\t\t\t\t\t\t\\`\\`\\`\r\n\t\t\t\t\t\t'line', 'wrappedLine', 'page', 'halfPage'\r\n\t\t\t\t\t\t\\`\\`\\`\r\n\t\t\t\t\t* 'value': Number of units to move. Default is '1'.\r\n\t\t\t\t\t* 'revealCursor': If 'true' reveals the cursor if it is outside view port.\r\n\t\t\t\t`,\r\n\t\t\t\tconstraint: isEditorScrollArgs,\r\n\t\t\t\tschema: {\r\n\t\t\t\t\t'type': 'object',\r\n\t\t\t\t\t'required': ['to'],\r\n\t\t\t\t\t'properties': {\r\n\t\t\t\t\t\t'to': {\r\n\t\t\t\t\t\t\t'type': 'string',\r\n\t\t\t\t\t\t\t'enum': ['up', 'down']\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t'by': {\r\n\t\t\t\t\t\t\t'type': 'string',\r\n\t\t\t\t\t\t\t'enum': ['line', 'wrappedLine', 'page', 'halfPage']\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t'value': {\r\n\t\t\t\t\t\t\t'type': 'number',\r\n\t\t\t\t\t\t\t'default': 1\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t'revealCursor': {\r\n\t\t\t\t\t\t\t'type': 'boolean',\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t]\r\n\t};\r\n\r\n\t/**\r\n\t * Directions in the view for editor scroll command.\r\n\t */\r\n\texport const RawDirection = {\r\n\t\tUp: 'up',\r\n\t\tDown: 'down',\r\n\t};\r\n\r\n\t/**\r\n\t * Units for editor scroll 'by' argument\r\n\t */\r\n\texport const RawUnit = {\r\n\t\tLine: 'line',\r\n\t\tWrappedLine: 'wrappedLine',\r\n\t\tPage: 'page',\r\n\t\tHalfPage: 'halfPage'\r\n\t};\r\n\r\n\t/**\r\n\t * Arguments for editor scroll command\r\n\t */\r\n\texport interface RawArguments {\r\n\t\tto: string;\r\n\t\tby?: string;\r\n\t\tvalue?: number;\r\n\t\trevealCursor?: boolean;\r\n\t\tselect?: boolean;\r\n\t}\r\n\r\n\texport function parse(args: RawArguments): ParsedArguments | null {\r\n\t\tlet direction: Direction;\r\n\t\tswitch (args.to) {\r\n\t\t\tcase RawDirection.Up:\r\n\t\t\t\tdirection = Direction.Up;\r\n\t\t\t\tbreak;\r\n\t\t\tcase RawDirection.Down:\r\n\t\t\t\tdirection = Direction.Down;\r\n\t\t\t\tbreak;\r\n\t\t\tdefault:\r\n\t\t\t\t// Illegal arguments\r\n\t\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet unit: Unit;\r\n\t\tswitch (args.by) {\r\n\t\t\tcase RawUnit.Line:\r\n\t\t\t\tunit = Unit.Line;\r\n\t\t\t\tbreak;\r\n\t\t\tcase RawUnit.WrappedLine:\r\n\t\t\t\tunit = Unit.WrappedLine;\r\n\t\t\t\tbreak;\r\n\t\t\tcase RawUnit.Page:\r\n\t\t\t\tunit = Unit.Page;\r\n\t\t\t\tbreak;\r\n\t\t\tcase RawUnit.HalfPage:\r\n\t\t\t\tunit = Unit.HalfPage;\r\n\t\t\t\tbreak;\r\n\t\t\tdefault:\r\n\t\t\t\tunit = Unit.WrappedLine;\r\n\t\t}\r\n\r\n\t\tconst value = Math.floor(args.value || 1);\r\n\t\tconst revealCursor = !!args.revealCursor;\r\n\r\n\t\treturn {\r\n\t\t\tdirection: direction,\r\n\t\t\tunit: unit,\r\n\t\t\tvalue: value,\r\n\t\t\trevealCursor: revealCursor,\r\n\t\t\tselect: (!!args.select)\r\n\t\t};\r\n\t}\r\n\r\n\texport interface ParsedArguments {\r\n\t\tdirection: Direction;\r\n\t\tunit: Unit;\r\n\t\tvalue: number;\r\n\t\trevealCursor: boolean;\r\n\t\tselect: boolean;\r\n\t}\r\n\r\n\texport const enum Direction {\r\n\t\tUp = 1,\r\n\t\tDown = 2\r\n\t}\r\n\r\n\texport const enum Unit {\r\n\t\tLine = 1,\r\n\t\tWrappedLine = 2,\r\n\t\tPage = 3,\r\n\t\tHalfPage = 4\r\n\t}\r\n}\r\n\r\nexport namespace RevealLine_ {\r\n\r\n\tconst isRevealLineArgs = function (arg: any): boolean {\r\n\t\tif (!types.isObject(arg)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tconst reveaLineArg: RawArguments = arg;\r\n\r\n\t\tif (!types.isNumber(reveaLineArg.lineNumber) && !types.isString(reveaLineArg.lineNumber)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tif (!types.isUndefined(reveaLineArg.at) && !types.isString(reveaLineArg.at)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t};\r\n\r\n\texport const description = {\r\n\t\tdescription: 'Reveal the given line at the given logical position',\r\n\t\targs: [\r\n\t\t\t{\r\n\t\t\t\tname: 'Reveal line argument object',\r\n\t\t\t\tdescription: `Property-value pairs that can be passed through this argument:\r\n\t\t\t\t\t* 'lineNumber': A mandatory line number value.\r\n\t\t\t\t\t* 'at': Logical position at which line has to be revealed .\r\n\t\t\t\t\t\t\\`\\`\\`\r\n\t\t\t\t\t\t'top', 'center', 'bottom'\r\n\t\t\t\t\t\t\\`\\`\\`\r\n\t\t\t\t`,\r\n\t\t\t\tconstraint: isRevealLineArgs,\r\n\t\t\t\tschema: {\r\n\t\t\t\t\t'type': 'object',\r\n\t\t\t\t\t'required': ['lineNumber'],\r\n\t\t\t\t\t'properties': {\r\n\t\t\t\t\t\t'lineNumber': {\r\n\t\t\t\t\t\t\t'type': ['number', 'string'],\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t'at': {\r\n\t\t\t\t\t\t\t'type': 'string',\r\n\t\t\t\t\t\t\t'enum': ['top', 'center', 'bottom']\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t]\r\n\t};\r\n\r\n\t/**\r\n\t * Arguments for reveal line command\r\n\t */\r\n\texport interface RawArguments {\r\n\t\tlineNumber?: number | string;\r\n\t\tat?: string;\r\n\t}\r\n\r\n\t/**\r\n\t * Values for reveal line 'at' argument\r\n\t */\r\n\texport const RawAtArgument = {\r\n\t\tTop: 'top',\r\n\t\tCenter: 'center',\r\n\t\tBottom: 'bottom'\r\n\t};\r\n}\r\n\r\nabstract class EditorOrNativeTextInputCommand {\r\n\r\n\tconstructor(target: MultiCommand) {\r\n\t\t// 1. handle case when focus is in editor.\r\n\t\ttarget.addImplementation(10000, (accessor: ServicesAccessor, args: any) => {\r\n\t\t\t// Only if editor text focus (i.e. not if editor has widget focus).\r\n\t\t\tconst focusedEditor = accessor.get(ICodeEditorService).getFocusedCodeEditor();\r\n\t\t\tif (focusedEditor && focusedEditor.hasTextFocus()) {\r\n\t\t\t\treturn this._runEditorCommand(accessor, focusedEditor, args);\r\n\t\t\t}\r\n\t\t\treturn false;\r\n\t\t});\r\n\r\n\t\t// 2. handle case when focus is in some other `input` / `textarea`.\r\n\t\ttarget.addImplementation(1000, (accessor: ServicesAccessor, args: any) => {\r\n\t\t\t// Only if focused on an element that allows for entering text\r\n\t\t\tconst activeElement = document.activeElement;\r\n\t\t\tif (activeElement && ['input', 'textarea'].indexOf(activeElement.tagName.toLowerCase()) >= 0) {\r\n\t\t\t\tthis.runDOMCommand();\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t\treturn false;\r\n\t\t});\r\n\r\n\t\t// 3. (default) handle case when focus is somewhere else.\r\n\t\ttarget.addImplementation(0, (accessor: ServicesAccessor, args: any) => {\r\n\t\t\t// Redirecting to active editor\r\n\t\t\tconst activeEditor = accessor.get(ICodeEditorService).getActiveCodeEditor();\r\n\t\t\tif (activeEditor) {\r\n\t\t\t\tactiveEditor.focus();\r\n\t\t\t\treturn this._runEditorCommand(accessor, activeEditor, args);\r\n\t\t\t}\r\n\t\t\treturn false;\r\n\t\t});\r\n\t}\r\n\r\n\tpublic _runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): boolean | Promise {\r\n\t\tconst result = this.runEditorCommand(accessor, editor, args);\r\n\t\tif (result) {\r\n\t\t\treturn result;\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic abstract runDOMCommand(): void;\r\n\tpublic abstract runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void | Promise;\r\n}\r\n\r\nexport namespace CoreNavigationCommands {\r\n\r\n\tclass BaseMoveToCommand extends CoreEditorCommand {\r\n\r\n\t\tprivate readonly _inSelectionMode: boolean;\r\n\r\n\t\tconstructor(opts: ICommandOptions & { inSelectionMode: boolean; }) {\r\n\t\t\tsuper(opts);\r\n\t\t\tthis._inSelectionMode = opts.inSelectionMode;\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tviewModel.model.pushStackElement();\r\n\t\t\tviewModel.setCursorStates(\r\n\t\t\t\targs.source,\r\n\t\t\t\tCursorChangeReason.Explicit,\r\n\t\t\t\t[\r\n\t\t\t\t\tCursorMoveCommands.moveTo(viewModel, viewModel.getPrimaryCursorState(), this._inSelectionMode, args.position, args.viewPosition)\r\n\t\t\t\t]\r\n\t\t\t);\r\n\t\t\tviewModel.revealPrimaryCursor(args.source, true);\r\n\t\t}\r\n\t}\r\n\r\n\texport const MoveTo: CoreEditorCommand = registerEditorCommand(new BaseMoveToCommand({\r\n\t\tid: '_moveTo',\r\n\t\tinSelectionMode: false,\r\n\t\tprecondition: undefined\r\n\t}));\r\n\r\n\texport const MoveToSelect: CoreEditorCommand = registerEditorCommand(new BaseMoveToCommand({\r\n\t\tid: '_moveToSelect',\r\n\t\tinSelectionMode: true,\r\n\t\tprecondition: undefined\r\n\t}));\r\n\r\n\tabstract class ColumnSelectCommand extends CoreEditorCommand {\r\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tviewModel.model.pushStackElement();\r\n\t\t\tconst result = this._getColumnSelectResult(viewModel, viewModel.getPrimaryCursorState(), viewModel.getCursorColumnSelectData(), args);\r\n\t\t\tviewModel.setCursorStates(args.source, CursorChangeReason.Explicit, result.viewStates.map((viewState) => CursorState.fromViewState(viewState)));\r\n\t\t\tviewModel.setCursorColumnSelectData({\r\n\t\t\t\tisReal: true,\r\n\t\t\t\tfromViewLineNumber: result.fromLineNumber,\r\n\t\t\t\tfromViewVisualColumn: result.fromVisualColumn,\r\n\t\t\t\ttoViewLineNumber: result.toLineNumber,\r\n\t\t\t\ttoViewVisualColumn: result.toVisualColumn\r\n\t\t\t});\r\n\t\t\tif (result.reversed) {\r\n\t\t\t\tviewModel.revealTopMostCursor(args.source);\r\n\t\t\t} else {\r\n\t\t\t\tviewModel.revealBottomMostCursor(args.source);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprotected abstract _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult;\r\n\r\n\t}\r\n\r\n\texport const ColumnSelect: CoreEditorCommand = registerEditorCommand(new class extends ColumnSelectCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper({\r\n\t\t\t\tid: 'columnSelect',\r\n\t\t\t\tprecondition: undefined\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tprotected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult {\r\n\r\n\t\t\t// validate `args`\r\n\t\t\tconst validatedPosition = viewModel.model.validatePosition(args.position);\r\n\t\t\tconst validatedViewPosition = viewModel.coordinatesConverter.validateViewPosition(new Position(args.viewPosition.lineNumber, args.viewPosition.column), validatedPosition);\r\n\r\n\t\t\tlet fromViewLineNumber = args.doColumnSelect ? prevColumnSelectData.fromViewLineNumber : validatedViewPosition.lineNumber;\r\n\t\t\tlet fromViewVisualColumn = args.doColumnSelect ? prevColumnSelectData.fromViewVisualColumn : args.mouseColumn - 1;\r\n\t\t\treturn ColumnSelection.columnSelect(viewModel.cursorConfig, viewModel, fromViewLineNumber, fromViewVisualColumn, validatedViewPosition.lineNumber, args.mouseColumn - 1);\r\n\t\t}\r\n\t});\r\n\r\n\texport const CursorColumnSelectLeft: CoreEditorCommand = registerEditorCommand(new class extends ColumnSelectCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper({\r\n\t\t\t\tid: 'cursorColumnSelectLeft',\r\n\t\t\t\tprecondition: undefined,\r\n\t\t\t\tkbOpts: {\r\n\t\t\t\t\tweight: CORE_WEIGHT,\r\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.LeftArrow,\r\n\t\t\t\t\tlinux: { primary: 0 }\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tprotected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult {\r\n\t\t\treturn ColumnSelection.columnSelectLeft(viewModel.cursorConfig, viewModel, prevColumnSelectData);\r\n\t\t}\r\n\t});\r\n\r\n\texport const CursorColumnSelectRight: CoreEditorCommand = registerEditorCommand(new class extends ColumnSelectCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper({\r\n\t\t\t\tid: 'cursorColumnSelectRight',\r\n\t\t\t\tprecondition: undefined,\r\n\t\t\t\tkbOpts: {\r\n\t\t\t\t\tweight: CORE_WEIGHT,\r\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.RightArrow,\r\n\t\t\t\t\tlinux: { primary: 0 }\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tprotected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult {\r\n\t\t\treturn ColumnSelection.columnSelectRight(viewModel.cursorConfig, viewModel, prevColumnSelectData);\r\n\t\t}\r\n\t});\r\n\r\n\tclass ColumnSelectUpCommand extends ColumnSelectCommand {\r\n\r\n\t\tprivate readonly _isPaged: boolean;\r\n\r\n\t\tconstructor(opts: ICommandOptions & { isPaged: boolean; }) {\r\n\t\t\tsuper(opts);\r\n\t\t\tthis._isPaged = opts.isPaged;\r\n\t\t}\r\n\r\n\t\tprotected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult {\r\n\t\t\treturn ColumnSelection.columnSelectUp(viewModel.cursorConfig, viewModel, prevColumnSelectData, this._isPaged);\r\n\t\t}\r\n\t}\r\n\r\n\texport const CursorColumnSelectUp: CoreEditorCommand = registerEditorCommand(new ColumnSelectUpCommand({\r\n\t\tisPaged: false,\r\n\t\tid: 'cursorColumnSelectUp',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.UpArrow,\r\n\t\t\tlinux: { primary: 0 }\r\n\t\t}\r\n\t}));\r\n\r\n\texport const CursorColumnSelectPageUp: CoreEditorCommand = registerEditorCommand(new ColumnSelectUpCommand({\r\n\t\tisPaged: true,\r\n\t\tid: 'cursorColumnSelectPageUp',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.PageUp,\r\n\t\t\tlinux: { primary: 0 }\r\n\t\t}\r\n\t}));\r\n\r\n\tclass ColumnSelectDownCommand extends ColumnSelectCommand {\r\n\r\n\t\tprivate readonly _isPaged: boolean;\r\n\r\n\t\tconstructor(opts: ICommandOptions & { isPaged: boolean; }) {\r\n\t\t\tsuper(opts);\r\n\t\t\tthis._isPaged = opts.isPaged;\r\n\t\t}\r\n\r\n\t\tprotected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult {\r\n\t\t\treturn ColumnSelection.columnSelectDown(viewModel.cursorConfig, viewModel, prevColumnSelectData, this._isPaged);\r\n\t\t}\r\n\t}\r\n\r\n\texport const CursorColumnSelectDown: CoreEditorCommand = registerEditorCommand(new ColumnSelectDownCommand({\r\n\t\tisPaged: false,\r\n\t\tid: 'cursorColumnSelectDown',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.DownArrow,\r\n\t\t\tlinux: { primary: 0 }\r\n\t\t}\r\n\t}));\r\n\r\n\texport const CursorColumnSelectPageDown: CoreEditorCommand = registerEditorCommand(new ColumnSelectDownCommand({\r\n\t\tisPaged: true,\r\n\t\tid: 'cursorColumnSelectPageDown',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.PageDown,\r\n\t\t\tlinux: { primary: 0 }\r\n\t\t}\r\n\t}));\r\n\r\n\texport class CursorMoveImpl extends CoreEditorCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper({\r\n\t\t\t\tid: 'cursorMove',\r\n\t\t\t\tprecondition: undefined,\r\n\t\t\t\tdescription: CursorMove_.description\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tconst parsed = CursorMove_.parse(args);\r\n\t\t\tif (!parsed) {\r\n\t\t\t\t// illegal arguments\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tthis._runCursorMove(viewModel, args.source, parsed);\r\n\t\t}\r\n\r\n\t\tprivate _runCursorMove(viewModel: IViewModel, source: string | null | undefined, args: CursorMove_.ParsedArguments): void {\r\n\t\t\tviewModel.model.pushStackElement();\r\n\t\t\tviewModel.setCursorStates(\r\n\t\t\t\tsource,\r\n\t\t\t\tCursorChangeReason.Explicit,\r\n\t\t\t\tCursorMoveImpl._move(viewModel, viewModel.getCursorStates(), args)\r\n\t\t\t);\r\n\t\t\tviewModel.revealPrimaryCursor(source, true);\r\n\t\t}\r\n\r\n\t\tprivate static _move(viewModel: IViewModel, cursors: CursorState[], args: CursorMove_.ParsedArguments): PartialCursorState[] | null {\r\n\t\t\tconst inSelectionMode = args.select;\r\n\t\t\tconst value = args.value;\r\n\r\n\t\t\tswitch (args.direction) {\r\n\t\t\t\tcase CursorMove_.Direction.Left:\r\n\t\t\t\tcase CursorMove_.Direction.Right:\r\n\t\t\t\tcase CursorMove_.Direction.Up:\r\n\t\t\t\tcase CursorMove_.Direction.Down:\r\n\t\t\t\tcase CursorMove_.Direction.WrappedLineStart:\r\n\t\t\t\tcase CursorMove_.Direction.WrappedLineFirstNonWhitespaceCharacter:\r\n\t\t\t\tcase CursorMove_.Direction.WrappedLineColumnCenter:\r\n\t\t\t\tcase CursorMove_.Direction.WrappedLineEnd:\r\n\t\t\t\tcase CursorMove_.Direction.WrappedLineLastNonWhitespaceCharacter:\r\n\t\t\t\t\treturn CursorMoveCommands.simpleMove(viewModel, cursors, args.direction, inSelectionMode, value, args.unit);\r\n\r\n\t\t\t\tcase CursorMove_.Direction.ViewPortTop:\r\n\t\t\t\tcase CursorMove_.Direction.ViewPortBottom:\r\n\t\t\t\tcase CursorMove_.Direction.ViewPortCenter:\r\n\t\t\t\tcase CursorMove_.Direction.ViewPortIfOutside:\r\n\t\t\t\t\treturn CursorMoveCommands.viewportMove(viewModel, cursors, args.direction, inSelectionMode, value);\r\n\t\t\t\tdefault:\r\n\t\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\texport const CursorMove: CursorMoveImpl = registerEditorCommand(new CursorMoveImpl());\r\n\r\n\tconst enum Constants {\r\n\t\tPAGE_SIZE_MARKER = -1\r\n\t}\r\n\r\n\tclass CursorMoveBasedCommand extends CoreEditorCommand {\r\n\r\n\t\tprivate readonly _staticArgs: CursorMove_.SimpleMoveArguments;\r\n\r\n\t\tconstructor(opts: ICommandOptions & { args: CursorMove_.SimpleMoveArguments }) {\r\n\t\t\tsuper(opts);\r\n\t\t\tthis._staticArgs = opts.args;\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, dynamicArgs: any): void {\r\n\t\t\tlet args = this._staticArgs;\r\n\t\t\tif (this._staticArgs.value === Constants.PAGE_SIZE_MARKER) {\r\n\t\t\t\t// -1 is a marker for page size\r\n\t\t\t\targs = {\r\n\t\t\t\t\tdirection: this._staticArgs.direction,\r\n\t\t\t\t\tunit: this._staticArgs.unit,\r\n\t\t\t\t\tselect: this._staticArgs.select,\r\n\t\t\t\t\tvalue: viewModel.cursorConfig.pageSize\r\n\t\t\t\t};\r\n\t\t\t}\r\n\r\n\t\t\tviewModel.model.pushStackElement();\r\n\t\t\tviewModel.setCursorStates(\r\n\t\t\t\tdynamicArgs.source,\r\n\t\t\t\tCursorChangeReason.Explicit,\r\n\t\t\t\tCursorMoveCommands.simpleMove(viewModel, viewModel.getCursorStates(), args.direction, args.select, args.value, args.unit)\r\n\t\t\t);\r\n\t\t\tviewModel.revealPrimaryCursor(dynamicArgs.source, true);\r\n\t\t}\r\n\t}\r\n\r\n\texport const CursorLeft: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\r\n\t\targs: {\r\n\t\t\tdirection: CursorMove_.Direction.Left,\r\n\t\t\tunit: CursorMove_.Unit.None,\r\n\t\t\tselect: false,\r\n\t\t\tvalue: 1\r\n\t\t},\r\n\t\tid: 'cursorLeft',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyCode.LeftArrow,\r\n\t\t\tmac: { primary: KeyCode.LeftArrow, secondary: [KeyMod.WinCtrl | KeyCode.KEY_B] }\r\n\t\t}\r\n\t}));\r\n\r\n\texport const CursorLeftSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\r\n\t\targs: {\r\n\t\t\tdirection: CursorMove_.Direction.Left,\r\n\t\t\tunit: CursorMove_.Unit.None,\r\n\t\t\tselect: true,\r\n\t\t\tvalue: 1\r\n\t\t},\r\n\t\tid: 'cursorLeftSelect',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyMod.Shift | KeyCode.LeftArrow\r\n\t\t}\r\n\t}));\r\n\r\n\texport const CursorRight: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\r\n\t\targs: {\r\n\t\t\tdirection: CursorMove_.Direction.Right,\r\n\t\t\tunit: CursorMove_.Unit.None,\r\n\t\t\tselect: false,\r\n\t\t\tvalue: 1\r\n\t\t},\r\n\t\tid: 'cursorRight',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyCode.RightArrow,\r\n\t\t\tmac: { primary: KeyCode.RightArrow, secondary: [KeyMod.WinCtrl | KeyCode.KEY_F] }\r\n\t\t}\r\n\t}));\r\n\r\n\texport const CursorRightSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\r\n\t\targs: {\r\n\t\t\tdirection: CursorMove_.Direction.Right,\r\n\t\t\tunit: CursorMove_.Unit.None,\r\n\t\t\tselect: true,\r\n\t\t\tvalue: 1\r\n\t\t},\r\n\t\tid: 'cursorRightSelect',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyMod.Shift | KeyCode.RightArrow\r\n\t\t}\r\n\t}));\r\n\r\n\texport const CursorUp: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\r\n\t\targs: {\r\n\t\t\tdirection: CursorMove_.Direction.Up,\r\n\t\t\tunit: CursorMove_.Unit.WrappedLine,\r\n\t\t\tselect: false,\r\n\t\t\tvalue: 1\r\n\t\t},\r\n\t\tid: 'cursorUp',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyCode.UpArrow,\r\n\t\t\tmac: { primary: KeyCode.UpArrow, secondary: [KeyMod.WinCtrl | KeyCode.KEY_P] }\r\n\t\t}\r\n\t}));\r\n\r\n\texport const CursorUpSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\r\n\t\targs: {\r\n\t\t\tdirection: CursorMove_.Direction.Up,\r\n\t\t\tunit: CursorMove_.Unit.WrappedLine,\r\n\t\t\tselect: true,\r\n\t\t\tvalue: 1\r\n\t\t},\r\n\t\tid: 'cursorUpSelect',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyMod.Shift | KeyCode.UpArrow,\r\n\t\t\tsecondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow],\r\n\t\t\tmac: { primary: KeyMod.Shift | KeyCode.UpArrow },\r\n\t\t\tlinux: { primary: KeyMod.Shift | KeyCode.UpArrow }\r\n\t\t}\r\n\t}));\r\n\r\n\texport const CursorPageUp: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\r\n\t\targs: {\r\n\t\t\tdirection: CursorMove_.Direction.Up,\r\n\t\t\tunit: CursorMove_.Unit.WrappedLine,\r\n\t\t\tselect: false,\r\n\t\t\tvalue: Constants.PAGE_SIZE_MARKER\r\n\t\t},\r\n\t\tid: 'cursorPageUp',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyCode.PageUp\r\n\t\t}\r\n\t}));\r\n\r\n\texport const CursorPageUpSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\r\n\t\targs: {\r\n\t\t\tdirection: CursorMove_.Direction.Up,\r\n\t\t\tunit: CursorMove_.Unit.WrappedLine,\r\n\t\t\tselect: true,\r\n\t\t\tvalue: Constants.PAGE_SIZE_MARKER\r\n\t\t},\r\n\t\tid: 'cursorPageUpSelect',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyMod.Shift | KeyCode.PageUp\r\n\t\t}\r\n\t}));\r\n\r\n\texport const CursorDown: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\r\n\t\targs: {\r\n\t\t\tdirection: CursorMove_.Direction.Down,\r\n\t\t\tunit: CursorMove_.Unit.WrappedLine,\r\n\t\t\tselect: false,\r\n\t\t\tvalue: 1\r\n\t\t},\r\n\t\tid: 'cursorDown',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyCode.DownArrow,\r\n\t\t\tmac: { primary: KeyCode.DownArrow, secondary: [KeyMod.WinCtrl | KeyCode.KEY_N] }\r\n\t\t}\r\n\t}));\r\n\r\n\texport const CursorDownSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\r\n\t\targs: {\r\n\t\t\tdirection: CursorMove_.Direction.Down,\r\n\t\t\tunit: CursorMove_.Unit.WrappedLine,\r\n\t\t\tselect: true,\r\n\t\t\tvalue: 1\r\n\t\t},\r\n\t\tid: 'cursorDownSelect',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyMod.Shift | KeyCode.DownArrow,\r\n\t\t\tsecondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow],\r\n\t\t\tmac: { primary: KeyMod.Shift | KeyCode.DownArrow },\r\n\t\t\tlinux: { primary: KeyMod.Shift | KeyCode.DownArrow }\r\n\t\t}\r\n\t}));\r\n\r\n\texport const CursorPageDown: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\r\n\t\targs: {\r\n\t\t\tdirection: CursorMove_.Direction.Down,\r\n\t\t\tunit: CursorMove_.Unit.WrappedLine,\r\n\t\t\tselect: false,\r\n\t\t\tvalue: Constants.PAGE_SIZE_MARKER\r\n\t\t},\r\n\t\tid: 'cursorPageDown',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyCode.PageDown\r\n\t\t}\r\n\t}));\r\n\r\n\texport const CursorPageDownSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\r\n\t\targs: {\r\n\t\t\tdirection: CursorMove_.Direction.Down,\r\n\t\t\tunit: CursorMove_.Unit.WrappedLine,\r\n\t\t\tselect: true,\r\n\t\t\tvalue: Constants.PAGE_SIZE_MARKER\r\n\t\t},\r\n\t\tid: 'cursorPageDownSelect',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyMod.Shift | KeyCode.PageDown\r\n\t\t}\r\n\t}));\r\n\r\n\texport const CreateCursor: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper({\r\n\t\t\t\tid: 'createCursor',\r\n\t\t\t\tprecondition: undefined\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tlet newState: PartialCursorState;\r\n\t\t\tif (args.wholeLine) {\r\n\t\t\t\tnewState = CursorMoveCommands.line(viewModel, viewModel.getPrimaryCursorState(), false, args.position, args.viewPosition);\r\n\t\t\t} else {\r\n\t\t\t\tnewState = CursorMoveCommands.moveTo(viewModel, viewModel.getPrimaryCursorState(), false, args.position, args.viewPosition);\r\n\t\t\t}\r\n\r\n\t\t\tconst states: PartialCursorState[] = viewModel.getCursorStates();\r\n\r\n\t\t\t// Check if we should remove a cursor (sort of like a toggle)\r\n\t\t\tif (states.length > 1) {\r\n\t\t\t\tconst newModelPosition = (newState.modelState ? newState.modelState.position : null);\r\n\t\t\t\tconst newViewPosition = (newState.viewState ? newState.viewState.position : null);\r\n\r\n\t\t\t\tfor (let i = 0, len = states.length; i < len; i++) {\r\n\t\t\t\t\tconst state = states[i];\r\n\r\n\t\t\t\t\tif (newModelPosition && !state.modelState!.selection.containsPosition(newModelPosition)) {\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (newViewPosition && !state.viewState!.selection.containsPosition(newViewPosition)) {\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t// => Remove the cursor\r\n\t\t\t\t\tstates.splice(i, 1);\r\n\r\n\t\t\t\t\tviewModel.model.pushStackElement();\r\n\t\t\t\t\tviewModel.setCursorStates(\r\n\t\t\t\t\t\targs.source,\r\n\t\t\t\t\t\tCursorChangeReason.Explicit,\r\n\t\t\t\t\t\tstates\r\n\t\t\t\t\t);\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// => Add the new cursor\r\n\t\t\tstates.push(newState);\r\n\r\n\t\t\tviewModel.model.pushStackElement();\r\n\t\t\tviewModel.setCursorStates(\r\n\t\t\t\targs.source,\r\n\t\t\t\tCursorChangeReason.Explicit,\r\n\t\t\t\tstates\r\n\t\t\t);\r\n\t\t}\r\n\t});\r\n\r\n\texport const LastCursorMoveToSelect: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper({\r\n\t\t\t\tid: '_lastCursorMoveToSelect',\r\n\t\t\t\tprecondition: undefined\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tconst lastAddedCursorIndex = viewModel.getLastAddedCursorIndex();\r\n\r\n\t\t\tconst states = viewModel.getCursorStates();\r\n\t\t\tconst newStates: PartialCursorState[] = states.slice(0);\r\n\t\t\tnewStates[lastAddedCursorIndex] = CursorMoveCommands.moveTo(viewModel, states[lastAddedCursorIndex], true, args.position, args.viewPosition);\r\n\r\n\t\t\tviewModel.model.pushStackElement();\r\n\t\t\tviewModel.setCursorStates(\r\n\t\t\t\targs.source,\r\n\t\t\t\tCursorChangeReason.Explicit,\r\n\t\t\t\tnewStates\r\n\t\t\t);\r\n\t\t}\r\n\t});\r\n\r\n\tclass HomeCommand extends CoreEditorCommand {\r\n\r\n\t\tprivate readonly _inSelectionMode: boolean;\r\n\r\n\t\tconstructor(opts: ICommandOptions & { inSelectionMode: boolean; }) {\r\n\t\t\tsuper(opts);\r\n\t\t\tthis._inSelectionMode = opts.inSelectionMode;\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tviewModel.model.pushStackElement();\r\n\t\t\tviewModel.setCursorStates(\r\n\t\t\t\targs.source,\r\n\t\t\t\tCursorChangeReason.Explicit,\r\n\t\t\t\tCursorMoveCommands.moveToBeginningOfLine(viewModel, viewModel.getCursorStates(), this._inSelectionMode)\r\n\t\t\t);\r\n\t\t\tviewModel.revealPrimaryCursor(args.source, true);\r\n\t\t}\r\n\t}\r\n\r\n\texport const CursorHome: CoreEditorCommand = registerEditorCommand(new HomeCommand({\r\n\t\tinSelectionMode: false,\r\n\t\tid: 'cursorHome',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyCode.Home,\r\n\t\t\tmac: { primary: KeyCode.Home, secondary: [KeyMod.CtrlCmd | KeyCode.LeftArrow] }\r\n\t\t}\r\n\t}));\r\n\r\n\texport const CursorHomeSelect: CoreEditorCommand = registerEditorCommand(new HomeCommand({\r\n\t\tinSelectionMode: true,\r\n\t\tid: 'cursorHomeSelect',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyMod.Shift | KeyCode.Home,\r\n\t\t\tmac: { primary: KeyMod.Shift | KeyCode.Home, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.LeftArrow] }\r\n\t\t}\r\n\t}));\r\n\r\n\tclass LineStartCommand extends CoreEditorCommand {\r\n\r\n\t\tprivate readonly _inSelectionMode: boolean;\r\n\r\n\t\tconstructor(opts: ICommandOptions & { inSelectionMode: boolean; }) {\r\n\t\t\tsuper(opts);\r\n\t\t\tthis._inSelectionMode = opts.inSelectionMode;\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tviewModel.model.pushStackElement();\r\n\t\t\tviewModel.setCursorStates(\r\n\t\t\t\targs.source,\r\n\t\t\t\tCursorChangeReason.Explicit,\r\n\t\t\t\tthis._exec(viewModel.getCursorStates())\r\n\t\t\t);\r\n\t\t\tviewModel.revealPrimaryCursor(args.source, true);\r\n\t\t}\r\n\r\n\t\tprivate _exec(cursors: CursorState[]): PartialCursorState[] {\r\n\t\t\tconst result: PartialCursorState[] = [];\r\n\t\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\t\tconst cursor = cursors[i];\r\n\t\t\t\tconst lineNumber = cursor.modelState.position.lineNumber;\r\n\t\t\t\tresult[i] = CursorState.fromModelState(cursor.modelState.move(this._inSelectionMode, lineNumber, 1, 0));\r\n\t\t\t}\r\n\t\t\treturn result;\r\n\t\t}\r\n\t}\r\n\r\n\texport const CursorLineStart: CoreEditorCommand = registerEditorCommand(new LineStartCommand({\r\n\t\tinSelectionMode: false,\r\n\t\tid: 'cursorLineStart',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: 0,\r\n\t\t\tmac: { primary: KeyMod.WinCtrl | KeyCode.KEY_A }\r\n\t\t}\r\n\t}));\r\n\r\n\texport const CursorLineStartSelect: CoreEditorCommand = registerEditorCommand(new LineStartCommand({\r\n\t\tinSelectionMode: true,\r\n\t\tid: 'cursorLineStartSelect',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: 0,\r\n\t\t\tmac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_A }\r\n\t\t}\r\n\t}));\r\n\r\n\tclass EndCommand extends CoreEditorCommand {\r\n\r\n\t\tprivate readonly _inSelectionMode: boolean;\r\n\r\n\t\tconstructor(opts: ICommandOptions & { inSelectionMode: boolean; }) {\r\n\t\t\tsuper(opts);\r\n\t\t\tthis._inSelectionMode = opts.inSelectionMode;\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tviewModel.model.pushStackElement();\r\n\t\t\tviewModel.setCursorStates(\r\n\t\t\t\targs.source,\r\n\t\t\t\tCursorChangeReason.Explicit,\r\n\t\t\t\tCursorMoveCommands.moveToEndOfLine(viewModel, viewModel.getCursorStates(), this._inSelectionMode, args.sticky || false)\r\n\t\t\t);\r\n\t\t\tviewModel.revealPrimaryCursor(args.source, true);\r\n\t\t}\r\n\t}\r\n\r\n\texport const CursorEnd: CoreEditorCommand = registerEditorCommand(new EndCommand({\r\n\t\tinSelectionMode: false,\r\n\t\tid: 'cursorEnd',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\targs: { sticky: false },\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyCode.End,\r\n\t\t\tmac: { primary: KeyCode.End, secondary: [KeyMod.CtrlCmd | KeyCode.RightArrow] }\r\n\t\t},\r\n\t\tdescription: {\r\n\t\t\tdescription: `Go to End`,\r\n\t\t\targs: [{\r\n\t\t\t\tname: 'args',\r\n\t\t\t\tschema: {\r\n\t\t\t\t\ttype: 'object',\r\n\t\t\t\t\tproperties: {\r\n\t\t\t\t\t\t'sticky': {\r\n\t\t\t\t\t\t\tdescription: nls.localize('stickydesc', \"Stick to the end even when going to longer lines\"),\r\n\t\t\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\t\t\tdefault: false\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}]\r\n\t\t}\r\n\t}));\r\n\r\n\texport const CursorEndSelect: CoreEditorCommand = registerEditorCommand(new EndCommand({\r\n\t\tinSelectionMode: true,\r\n\t\tid: 'cursorEndSelect',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\targs: { sticky: false },\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyMod.Shift | KeyCode.End,\r\n\t\t\tmac: { primary: KeyMod.Shift | KeyCode.End, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.RightArrow] }\r\n\t\t},\r\n\t\tdescription: {\r\n\t\t\tdescription: `Select to End`,\r\n\t\t\targs: [{\r\n\t\t\t\tname: 'args',\r\n\t\t\t\tschema: {\r\n\t\t\t\t\ttype: 'object',\r\n\t\t\t\t\tproperties: {\r\n\t\t\t\t\t\t'sticky': {\r\n\t\t\t\t\t\t\tdescription: nls.localize('stickydesc', \"Stick to the end even when going to longer lines\"),\r\n\t\t\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\t\t\tdefault: false\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}]\r\n\t\t}\r\n\t}));\r\n\r\n\tclass LineEndCommand extends CoreEditorCommand {\r\n\r\n\t\tprivate readonly _inSelectionMode: boolean;\r\n\r\n\t\tconstructor(opts: ICommandOptions & { inSelectionMode: boolean; }) {\r\n\t\t\tsuper(opts);\r\n\t\t\tthis._inSelectionMode = opts.inSelectionMode;\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tviewModel.model.pushStackElement();\r\n\t\t\tviewModel.setCursorStates(\r\n\t\t\t\targs.source,\r\n\t\t\t\tCursorChangeReason.Explicit,\r\n\t\t\t\tthis._exec(viewModel, viewModel.getCursorStates())\r\n\t\t\t);\r\n\t\t\tviewModel.revealPrimaryCursor(args.source, true);\r\n\t\t}\r\n\r\n\t\tprivate _exec(viewModel: IViewModel, cursors: CursorState[]): PartialCursorState[] {\r\n\t\t\tconst result: PartialCursorState[] = [];\r\n\t\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\r\n\t\t\t\tconst cursor = cursors[i];\r\n\t\t\t\tconst lineNumber = cursor.modelState.position.lineNumber;\r\n\t\t\t\tconst maxColumn = viewModel.model.getLineMaxColumn(lineNumber);\r\n\t\t\t\tresult[i] = CursorState.fromModelState(cursor.modelState.move(this._inSelectionMode, lineNumber, maxColumn, 0));\r\n\t\t\t}\r\n\t\t\treturn result;\r\n\t\t}\r\n\t}\r\n\r\n\texport const CursorLineEnd: CoreEditorCommand = registerEditorCommand(new LineEndCommand({\r\n\t\tinSelectionMode: false,\r\n\t\tid: 'cursorLineEnd',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: 0,\r\n\t\t\tmac: { primary: KeyMod.WinCtrl | KeyCode.KEY_E }\r\n\t\t}\r\n\t}));\r\n\r\n\texport const CursorLineEndSelect: CoreEditorCommand = registerEditorCommand(new LineEndCommand({\r\n\t\tinSelectionMode: true,\r\n\t\tid: 'cursorLineEndSelect',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: 0,\r\n\t\t\tmac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_E }\r\n\t\t}\r\n\t}));\r\n\r\n\tclass TopCommand extends CoreEditorCommand {\r\n\r\n\t\tprivate readonly _inSelectionMode: boolean;\r\n\r\n\t\tconstructor(opts: ICommandOptions & { inSelectionMode: boolean; }) {\r\n\t\t\tsuper(opts);\r\n\t\t\tthis._inSelectionMode = opts.inSelectionMode;\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tviewModel.model.pushStackElement();\r\n\t\t\tviewModel.setCursorStates(\r\n\t\t\t\targs.source,\r\n\t\t\t\tCursorChangeReason.Explicit,\r\n\t\t\t\tCursorMoveCommands.moveToBeginningOfBuffer(viewModel, viewModel.getCursorStates(), this._inSelectionMode)\r\n\t\t\t);\r\n\t\t\tviewModel.revealPrimaryCursor(args.source, true);\r\n\t\t}\r\n\t}\r\n\r\n\texport const CursorTop: CoreEditorCommand = registerEditorCommand(new TopCommand({\r\n\t\tinSelectionMode: false,\r\n\t\tid: 'cursorTop',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.Home,\r\n\t\t\tmac: { primary: KeyMod.CtrlCmd | KeyCode.UpArrow }\r\n\t\t}\r\n\t}));\r\n\r\n\texport const CursorTopSelect: CoreEditorCommand = registerEditorCommand(new TopCommand({\r\n\t\tinSelectionMode: true,\r\n\t\tid: 'cursorTopSelect',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Home,\r\n\t\t\tmac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow }\r\n\t\t}\r\n\t}));\r\n\r\n\tclass BottomCommand extends CoreEditorCommand {\r\n\r\n\t\tprivate readonly _inSelectionMode: boolean;\r\n\r\n\t\tconstructor(opts: ICommandOptions & { inSelectionMode: boolean; }) {\r\n\t\t\tsuper(opts);\r\n\t\t\tthis._inSelectionMode = opts.inSelectionMode;\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tviewModel.model.pushStackElement();\r\n\t\t\tviewModel.setCursorStates(\r\n\t\t\t\targs.source,\r\n\t\t\t\tCursorChangeReason.Explicit,\r\n\t\t\t\tCursorMoveCommands.moveToEndOfBuffer(viewModel, viewModel.getCursorStates(), this._inSelectionMode)\r\n\t\t\t);\r\n\t\t\tviewModel.revealPrimaryCursor(args.source, true);\r\n\t\t}\r\n\t}\r\n\r\n\texport const CursorBottom: CoreEditorCommand = registerEditorCommand(new BottomCommand({\r\n\t\tinSelectionMode: false,\r\n\t\tid: 'cursorBottom',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.End,\r\n\t\t\tmac: { primary: KeyMod.CtrlCmd | KeyCode.DownArrow }\r\n\t\t}\r\n\t}));\r\n\r\n\texport const CursorBottomSelect: CoreEditorCommand = registerEditorCommand(new BottomCommand({\r\n\t\tinSelectionMode: true,\r\n\t\tid: 'cursorBottomSelect',\r\n\t\tprecondition: undefined,\r\n\t\tkbOpts: {\r\n\t\t\tweight: CORE_WEIGHT,\r\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.End,\r\n\t\t\tmac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow }\r\n\t\t}\r\n\t}));\r\n\r\n\texport class EditorScrollImpl extends CoreEditorCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper({\r\n\t\t\t\tid: 'editorScroll',\r\n\t\t\t\tprecondition: undefined,\r\n\t\t\t\tdescription: EditorScroll_.description\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tconst parsed = EditorScroll_.parse(args);\r\n\t\t\tif (!parsed) {\r\n\t\t\t\t// illegal arguments\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tthis._runEditorScroll(viewModel, args.source, parsed);\r\n\t\t}\r\n\r\n\t\t_runEditorScroll(viewModel: IViewModel, source: string | null | undefined, args: EditorScroll_.ParsedArguments): void {\r\n\r\n\t\t\tconst desiredScrollTop = this._computeDesiredScrollTop(viewModel, args);\r\n\r\n\t\t\tif (args.revealCursor) {\r\n\t\t\t\t// must ensure cursor is in new visible range\r\n\t\t\t\tconst desiredVisibleViewRange = viewModel.getCompletelyVisibleViewRangeAtScrollTop(desiredScrollTop);\r\n\t\t\t\tviewModel.setCursorStates(\r\n\t\t\t\t\tsource,\r\n\t\t\t\t\tCursorChangeReason.Explicit,\r\n\t\t\t\t\t[\r\n\t\t\t\t\t\tCursorMoveCommands.findPositionInViewportIfOutside(viewModel, viewModel.getPrimaryCursorState(), desiredVisibleViewRange, args.select)\r\n\t\t\t\t\t]\r\n\t\t\t\t);\r\n\t\t\t}\r\n\r\n\t\t\tviewModel.setScrollTop(desiredScrollTop, ScrollType.Smooth);\r\n\t\t}\r\n\r\n\t\tprivate _computeDesiredScrollTop(viewModel: IViewModel, args: EditorScroll_.ParsedArguments): number {\r\n\r\n\t\t\tif (args.unit === EditorScroll_.Unit.Line) {\r\n\t\t\t\t// scrolling by model lines\r\n\t\t\t\tconst visibleViewRange = viewModel.getCompletelyVisibleViewRange();\r\n\t\t\t\tconst visibleModelRange = viewModel.coordinatesConverter.convertViewRangeToModelRange(visibleViewRange);\r\n\r\n\t\t\t\tlet desiredTopModelLineNumber: number;\r\n\t\t\t\tif (args.direction === EditorScroll_.Direction.Up) {\r\n\t\t\t\t\t// must go x model lines up\r\n\t\t\t\t\tdesiredTopModelLineNumber = Math.max(1, visibleModelRange.startLineNumber - args.value);\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// must go x model lines down\r\n\t\t\t\t\tdesiredTopModelLineNumber = Math.min(viewModel.model.getLineCount(), visibleModelRange.startLineNumber + args.value);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst viewPosition = viewModel.coordinatesConverter.convertModelPositionToViewPosition(new Position(desiredTopModelLineNumber, 1));\r\n\t\t\t\treturn viewModel.getVerticalOffsetForLineNumber(viewPosition.lineNumber);\r\n\t\t\t}\r\n\r\n\t\t\tlet noOfLines: number;\r\n\t\t\tif (args.unit === EditorScroll_.Unit.Page) {\r\n\t\t\t\tnoOfLines = viewModel.cursorConfig.pageSize * args.value;\r\n\t\t\t} else if (args.unit === EditorScroll_.Unit.HalfPage) {\r\n\t\t\t\tnoOfLines = Math.round(viewModel.cursorConfig.pageSize / 2) * args.value;\r\n\t\t\t} else {\r\n\t\t\t\tnoOfLines = args.value;\r\n\t\t\t}\r\n\t\t\tconst deltaLines = (args.direction === EditorScroll_.Direction.Up ? -1 : 1) * noOfLines;\r\n\t\t\treturn viewModel.getScrollTop() + deltaLines * viewModel.cursorConfig.lineHeight;\r\n\t\t}\r\n\t}\r\n\r\n\texport const EditorScroll: EditorScrollImpl = registerEditorCommand(new EditorScrollImpl());\r\n\r\n\texport const ScrollLineUp: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper({\r\n\t\t\t\tid: 'scrollLineUp',\r\n\t\t\t\tprecondition: undefined,\r\n\t\t\t\tkbOpts: {\r\n\t\t\t\t\tweight: CORE_WEIGHT,\r\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.UpArrow,\r\n\t\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyCode.PageUp }\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\trunCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tEditorScroll._runEditorScroll(viewModel, args.source, {\r\n\t\t\t\tdirection: EditorScroll_.Direction.Up,\r\n\t\t\t\tunit: EditorScroll_.Unit.WrappedLine,\r\n\t\t\t\tvalue: 1,\r\n\t\t\t\trevealCursor: false,\r\n\t\t\t\tselect: false\r\n\t\t\t});\r\n\t\t}\r\n\t});\r\n\r\n\texport const ScrollPageUp: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper({\r\n\t\t\t\tid: 'scrollPageUp',\r\n\t\t\t\tprecondition: undefined,\r\n\t\t\t\tkbOpts: {\r\n\t\t\t\t\tweight: CORE_WEIGHT,\r\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.PageUp,\r\n\t\t\t\t\twin: { primary: KeyMod.Alt | KeyCode.PageUp },\r\n\t\t\t\t\tlinux: { primary: KeyMod.Alt | KeyCode.PageUp }\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\trunCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tEditorScroll._runEditorScroll(viewModel, args.source, {\r\n\t\t\t\tdirection: EditorScroll_.Direction.Up,\r\n\t\t\t\tunit: EditorScroll_.Unit.Page,\r\n\t\t\t\tvalue: 1,\r\n\t\t\t\trevealCursor: false,\r\n\t\t\t\tselect: false\r\n\t\t\t});\r\n\t\t}\r\n\t});\r\n\r\n\texport const ScrollLineDown: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper({\r\n\t\t\t\tid: 'scrollLineDown',\r\n\t\t\t\tprecondition: undefined,\r\n\t\t\t\tkbOpts: {\r\n\t\t\t\t\tweight: CORE_WEIGHT,\r\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.DownArrow,\r\n\t\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyCode.PageDown }\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\trunCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tEditorScroll._runEditorScroll(viewModel, args.source, {\r\n\t\t\t\tdirection: EditorScroll_.Direction.Down,\r\n\t\t\t\tunit: EditorScroll_.Unit.WrappedLine,\r\n\t\t\t\tvalue: 1,\r\n\t\t\t\trevealCursor: false,\r\n\t\t\t\tselect: false\r\n\t\t\t});\r\n\t\t}\r\n\t});\r\n\r\n\texport const ScrollPageDown: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper({\r\n\t\t\t\tid: 'scrollPageDown',\r\n\t\t\t\tprecondition: undefined,\r\n\t\t\t\tkbOpts: {\r\n\t\t\t\t\tweight: CORE_WEIGHT,\r\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.PageDown,\r\n\t\t\t\t\twin: { primary: KeyMod.Alt | KeyCode.PageDown },\r\n\t\t\t\t\tlinux: { primary: KeyMod.Alt | KeyCode.PageDown }\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\trunCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tEditorScroll._runEditorScroll(viewModel, args.source, {\r\n\t\t\t\tdirection: EditorScroll_.Direction.Down,\r\n\t\t\t\tunit: EditorScroll_.Unit.Page,\r\n\t\t\t\tvalue: 1,\r\n\t\t\t\trevealCursor: false,\r\n\t\t\t\tselect: false\r\n\t\t\t});\r\n\t\t}\r\n\t});\r\n\r\n\tclass WordCommand extends CoreEditorCommand {\r\n\r\n\t\tprivate readonly _inSelectionMode: boolean;\r\n\r\n\t\tconstructor(opts: ICommandOptions & { inSelectionMode: boolean; }) {\r\n\t\t\tsuper(opts);\r\n\t\t\tthis._inSelectionMode = opts.inSelectionMode;\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tviewModel.model.pushStackElement();\r\n\t\t\tviewModel.setCursorStates(\r\n\t\t\t\targs.source,\r\n\t\t\t\tCursorChangeReason.Explicit,\r\n\t\t\t\t[\r\n\t\t\t\t\tCursorMoveCommands.word(viewModel, viewModel.getPrimaryCursorState(), this._inSelectionMode, args.position)\r\n\t\t\t\t]\r\n\t\t\t);\r\n\t\t\tviewModel.revealPrimaryCursor(args.source, true);\r\n\t\t}\r\n\t}\r\n\r\n\texport const WordSelect: CoreEditorCommand = registerEditorCommand(new WordCommand({\r\n\t\tinSelectionMode: false,\r\n\t\tid: '_wordSelect',\r\n\t\tprecondition: undefined\r\n\t}));\r\n\r\n\texport const WordSelectDrag: CoreEditorCommand = registerEditorCommand(new WordCommand({\r\n\t\tinSelectionMode: true,\r\n\t\tid: '_wordSelectDrag',\r\n\t\tprecondition: undefined\r\n\t}));\r\n\r\n\texport const LastCursorWordSelect: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper({\r\n\t\t\t\tid: 'lastCursorWordSelect',\r\n\t\t\t\tprecondition: undefined\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tconst lastAddedCursorIndex = viewModel.getLastAddedCursorIndex();\r\n\r\n\t\t\tconst states = viewModel.getCursorStates();\r\n\t\t\tconst newStates: PartialCursorState[] = states.slice(0);\r\n\t\t\tconst lastAddedState = states[lastAddedCursorIndex];\r\n\t\t\tnewStates[lastAddedCursorIndex] = CursorMoveCommands.word(viewModel, lastAddedState, lastAddedState.modelState.hasSelection(), args.position);\r\n\r\n\t\t\tviewModel.model.pushStackElement();\r\n\t\t\tviewModel.setCursorStates(\r\n\t\t\t\targs.source,\r\n\t\t\t\tCursorChangeReason.Explicit,\r\n\t\t\t\tnewStates\r\n\t\t\t);\r\n\t\t}\r\n\t});\r\n\r\n\tclass LineCommand extends CoreEditorCommand {\r\n\t\tprivate readonly _inSelectionMode: boolean;\r\n\r\n\t\tconstructor(opts: ICommandOptions & { inSelectionMode: boolean; }) {\r\n\t\t\tsuper(opts);\r\n\t\t\tthis._inSelectionMode = opts.inSelectionMode;\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tviewModel.model.pushStackElement();\r\n\t\t\tviewModel.setCursorStates(\r\n\t\t\t\targs.source,\r\n\t\t\t\tCursorChangeReason.Explicit,\r\n\t\t\t\t[\r\n\t\t\t\t\tCursorMoveCommands.line(viewModel, viewModel.getPrimaryCursorState(), this._inSelectionMode, args.position, args.viewPosition)\r\n\t\t\t\t]\r\n\t\t\t);\r\n\t\t\tviewModel.revealPrimaryCursor(args.source, false);\r\n\t\t}\r\n\t}\r\n\r\n\texport const LineSelect: CoreEditorCommand = registerEditorCommand(new LineCommand({\r\n\t\tinSelectionMode: false,\r\n\t\tid: '_lineSelect',\r\n\t\tprecondition: undefined\r\n\t}));\r\n\r\n\texport const LineSelectDrag: CoreEditorCommand = registerEditorCommand(new LineCommand({\r\n\t\tinSelectionMode: true,\r\n\t\tid: '_lineSelectDrag',\r\n\t\tprecondition: undefined\r\n\t}));\r\n\r\n\tclass LastCursorLineCommand extends CoreEditorCommand {\r\n\t\tprivate readonly _inSelectionMode: boolean;\r\n\r\n\t\tconstructor(opts: ICommandOptions & { inSelectionMode: boolean; }) {\r\n\t\t\tsuper(opts);\r\n\t\t\tthis._inSelectionMode = opts.inSelectionMode;\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tconst lastAddedCursorIndex = viewModel.getLastAddedCursorIndex();\r\n\r\n\t\t\tconst states = viewModel.getCursorStates();\r\n\t\t\tconst newStates: PartialCursorState[] = states.slice(0);\r\n\t\t\tnewStates[lastAddedCursorIndex] = CursorMoveCommands.line(viewModel, states[lastAddedCursorIndex], this._inSelectionMode, args.position, args.viewPosition);\r\n\r\n\t\t\tviewModel.model.pushStackElement();\r\n\t\t\tviewModel.setCursorStates(\r\n\t\t\t\targs.source,\r\n\t\t\t\tCursorChangeReason.Explicit,\r\n\t\t\t\tnewStates\r\n\t\t\t);\r\n\t\t}\r\n\t}\r\n\r\n\texport const LastCursorLineSelect: CoreEditorCommand = registerEditorCommand(new LastCursorLineCommand({\r\n\t\tinSelectionMode: false,\r\n\t\tid: 'lastCursorLineSelect',\r\n\t\tprecondition: undefined\r\n\t}));\r\n\r\n\texport const LastCursorLineSelectDrag: CoreEditorCommand = registerEditorCommand(new LastCursorLineCommand({\r\n\t\tinSelectionMode: true,\r\n\t\tid: 'lastCursorLineSelectDrag',\r\n\t\tprecondition: undefined\r\n\t}));\r\n\r\n\texport const ExpandLineSelection: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper({\r\n\t\t\t\tid: 'expandLineSelection',\r\n\t\t\t\tprecondition: undefined,\r\n\t\t\t\tkbOpts: {\r\n\t\t\t\t\tweight: CORE_WEIGHT,\r\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.KEY_L\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tviewModel.model.pushStackElement();\r\n\t\t\tviewModel.setCursorStates(\r\n\t\t\t\targs.source,\r\n\t\t\t\tCursorChangeReason.Explicit,\r\n\t\t\t\tCursorMoveCommands.expandLineSelection(viewModel, viewModel.getCursorStates())\r\n\t\t\t);\r\n\t\t\tviewModel.revealPrimaryCursor(args.source, true);\r\n\t\t}\r\n\r\n\t});\r\n\r\n\texport const CancelSelection: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper({\r\n\t\t\t\tid: 'cancelSelection',\r\n\t\t\t\tprecondition: EditorContextKeys.hasNonEmptySelection,\r\n\t\t\t\tkbOpts: {\r\n\t\t\t\t\tweight: CORE_WEIGHT,\r\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\t\tprimary: KeyCode.Escape,\r\n\t\t\t\t\tsecondary: [KeyMod.Shift | KeyCode.Escape]\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tviewModel.model.pushStackElement();\r\n\t\t\tviewModel.setCursorStates(\r\n\t\t\t\targs.source,\r\n\t\t\t\tCursorChangeReason.Explicit,\r\n\t\t\t\t[\r\n\t\t\t\t\tCursorMoveCommands.cancelSelection(viewModel, viewModel.getPrimaryCursorState())\r\n\t\t\t\t]\r\n\t\t\t);\r\n\t\t\tviewModel.revealPrimaryCursor(args.source, true);\r\n\t\t}\r\n\t});\r\n\r\n\texport const RemoveSecondaryCursors: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper({\r\n\t\t\t\tid: 'removeSecondaryCursors',\r\n\t\t\t\tprecondition: EditorContextKeys.hasMultipleSelections,\r\n\t\t\t\tkbOpts: {\r\n\t\t\t\t\tweight: CORE_WEIGHT + 1,\r\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\t\tprimary: KeyCode.Escape,\r\n\t\t\t\t\tsecondary: [KeyMod.Shift | KeyCode.Escape]\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tviewModel.model.pushStackElement();\r\n\t\t\tviewModel.setCursorStates(\r\n\t\t\t\targs.source,\r\n\t\t\t\tCursorChangeReason.Explicit,\r\n\t\t\t\t[\r\n\t\t\t\t\tviewModel.getPrimaryCursorState()\r\n\t\t\t\t]\r\n\t\t\t);\r\n\t\t\tviewModel.revealPrimaryCursor(args.source, true);\r\n\t\t}\r\n\t});\r\n\r\n\texport const RevealLine: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper({\r\n\t\t\t\tid: 'revealLine',\r\n\t\t\t\tprecondition: undefined,\r\n\t\t\t\tdescription: RevealLine_.description\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tconst revealLineArg = args;\r\n\t\t\tconst lineNumberArg = revealLineArg.lineNumber || 0;\r\n\t\t\tlet lineNumber = typeof lineNumberArg === 'number' ? (lineNumberArg + 1) : (parseInt(lineNumberArg) + 1);\r\n\t\t\tif (lineNumber < 1) {\r\n\t\t\t\tlineNumber = 1;\r\n\t\t\t}\r\n\t\t\tconst lineCount = viewModel.model.getLineCount();\r\n\t\t\tif (lineNumber > lineCount) {\r\n\t\t\t\tlineNumber = lineCount;\r\n\t\t\t}\r\n\r\n\t\t\tconst range = new Range(\r\n\t\t\t\tlineNumber, 1,\r\n\t\t\t\tlineNumber, viewModel.model.getLineMaxColumn(lineNumber)\r\n\t\t\t);\r\n\r\n\t\t\tlet revealAt = VerticalRevealType.Simple;\r\n\t\t\tif (revealLineArg.at) {\r\n\t\t\t\tswitch (revealLineArg.at) {\r\n\t\t\t\t\tcase RevealLine_.RawAtArgument.Top:\r\n\t\t\t\t\t\trevealAt = VerticalRevealType.Top;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tcase RevealLine_.RawAtArgument.Center:\r\n\t\t\t\t\t\trevealAt = VerticalRevealType.Center;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tcase RevealLine_.RawAtArgument.Bottom:\r\n\t\t\t\t\t\trevealAt = VerticalRevealType.Bottom;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tdefault:\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tconst viewRange = viewModel.coordinatesConverter.convertModelRangeToViewRange(range);\r\n\r\n\t\t\tviewModel.revealRange(args.source, false, viewRange, revealAt, ScrollType.Smooth);\r\n\t\t}\r\n\t});\r\n\r\n\texport const SelectAll = new class extends EditorOrNativeTextInputCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper(SelectAllCommand);\r\n\t\t}\r\n\t\tpublic runDOMCommand(): void {\r\n\t\t\tif (isFirefox) {\r\n\t\t\t\t(document.activeElement).focus();\r\n\t\t\t\t(document.activeElement).select();\r\n\t\t\t}\r\n\r\n\t\t\tdocument.execCommand('selectAll');\r\n\t\t}\r\n\t\tpublic runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {\r\n\t\t\tconst viewModel = editor._getViewModel();\r\n\t\t\tif (!viewModel) {\r\n\t\t\t\t// the editor has no view => has no cursors\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tthis.runCoreEditorCommand(viewModel, args);\r\n\t\t}\r\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tviewModel.model.pushStackElement();\r\n\t\t\tviewModel.setCursorStates(\r\n\t\t\t\t'keyboard',\r\n\t\t\t\tCursorChangeReason.Explicit,\r\n\t\t\t\t[\r\n\t\t\t\t\tCursorMoveCommands.selectAll(viewModel, viewModel.getPrimaryCursorState())\r\n\t\t\t\t]\r\n\t\t\t);\r\n\t\t}\r\n\t}();\r\n\r\n\texport const SetSelection: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper({\r\n\t\t\t\tid: 'setSelection',\r\n\t\t\t\tprecondition: undefined\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: any): void {\r\n\t\t\tviewModel.model.pushStackElement();\r\n\t\t\tviewModel.setCursorStates(\r\n\t\t\t\targs.source,\r\n\t\t\t\tCursorChangeReason.Explicit,\r\n\t\t\t\t[\r\n\t\t\t\t\tCursorState.fromModelSelection(args.selection)\r\n\t\t\t\t]\r\n\t\t\t);\r\n\t\t}\r\n\t});\r\n}\r\n\r\nconst columnSelectionCondition = ContextKeyExpr.and(\r\n\tEditorContextKeys.textInputFocus,\r\n\tEditorContextKeys.columnSelection\r\n);\r\nfunction registerColumnSelection(id: string, keybinding: number): void {\r\n\tKeybindingsRegistry.registerKeybindingRule({\r\n\t\tid: id,\r\n\t\tprimary: keybinding,\r\n\t\twhen: columnSelectionCondition,\r\n\t\tweight: CORE_WEIGHT + 1\r\n\t});\r\n}\r\n\r\nregisterColumnSelection(CoreNavigationCommands.CursorColumnSelectLeft.id, KeyMod.Shift | KeyCode.LeftArrow);\r\nregisterColumnSelection(CoreNavigationCommands.CursorColumnSelectRight.id, KeyMod.Shift | KeyCode.RightArrow);\r\nregisterColumnSelection(CoreNavigationCommands.CursorColumnSelectUp.id, KeyMod.Shift | KeyCode.UpArrow);\r\nregisterColumnSelection(CoreNavigationCommands.CursorColumnSelectPageUp.id, KeyMod.Shift | KeyCode.PageUp);\r\nregisterColumnSelection(CoreNavigationCommands.CursorColumnSelectDown.id, KeyMod.Shift | KeyCode.DownArrow);\r\nregisterColumnSelection(CoreNavigationCommands.CursorColumnSelectPageDown.id, KeyMod.Shift | KeyCode.PageDown);\r\n\r\nfunction registerCommand(command: T): T {\r\n\tcommand.register();\r\n\treturn command;\r\n}\r\n\r\nexport namespace CoreEditingCommands {\r\n\r\n\texport abstract class CoreEditingCommand extends EditorCommand {\r\n\t\tpublic runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {\r\n\t\t\tconst viewModel = editor._getViewModel();\r\n\t\t\tif (!viewModel) {\r\n\t\t\t\t// the editor has no view => has no cursors\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tthis.runCoreEditingCommand(editor, viewModel, args || {});\r\n\t\t}\r\n\r\n\t\tpublic abstract runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: any): void;\r\n\t}\r\n\r\n\texport const LineBreakInsert: EditorCommand = registerEditorCommand(new class extends CoreEditingCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper({\r\n\t\t\t\tid: 'lineBreakInsert',\r\n\t\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\t\tkbOpts: {\r\n\t\t\t\t\tweight: CORE_WEIGHT,\r\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\t\tprimary: 0,\r\n\t\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyCode.KEY_O }\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: any): void {\r\n\t\t\teditor.pushUndoStop();\r\n\t\t\teditor.executeCommands(this.id, TypeOperations.lineBreakInsert(viewModel.cursorConfig, viewModel.model, viewModel.getCursorStates().map(s => s.modelState.selection)));\r\n\t\t}\r\n\t});\r\n\r\n\texport const Outdent: EditorCommand = registerEditorCommand(new class extends CoreEditingCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper({\r\n\t\t\t\tid: 'outdent',\r\n\t\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\t\tkbOpts: {\r\n\t\t\t\t\tweight: CORE_WEIGHT,\r\n\t\t\t\t\tkbExpr: ContextKeyExpr.and(\r\n\t\t\t\t\t\tEditorContextKeys.editorTextFocus,\r\n\t\t\t\t\t\tEditorContextKeys.tabDoesNotMoveFocus\r\n\t\t\t\t\t),\r\n\t\t\t\t\tprimary: KeyMod.Shift | KeyCode.Tab\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: any): void {\r\n\t\t\teditor.pushUndoStop();\r\n\t\t\teditor.executeCommands(this.id, TypeOperations.outdent(viewModel.cursorConfig, viewModel.model, viewModel.getCursorStates().map(s => s.modelState.selection)));\r\n\t\t\teditor.pushUndoStop();\r\n\t\t}\r\n\t});\r\n\r\n\texport const Tab: EditorCommand = registerEditorCommand(new class extends CoreEditingCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper({\r\n\t\t\t\tid: 'tab',\r\n\t\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\t\tkbOpts: {\r\n\t\t\t\t\tweight: CORE_WEIGHT,\r\n\t\t\t\t\tkbExpr: ContextKeyExpr.and(\r\n\t\t\t\t\t\tEditorContextKeys.editorTextFocus,\r\n\t\t\t\t\t\tEditorContextKeys.tabDoesNotMoveFocus\r\n\t\t\t\t\t),\r\n\t\t\t\t\tprimary: KeyCode.Tab\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: any): void {\r\n\t\t\teditor.pushUndoStop();\r\n\t\t\teditor.executeCommands(this.id, TypeOperations.tab(viewModel.cursorConfig, viewModel.model, viewModel.getCursorStates().map(s => s.modelState.selection)));\r\n\t\t\teditor.pushUndoStop();\r\n\t\t}\r\n\t});\r\n\r\n\texport const DeleteLeft: EditorCommand = registerEditorCommand(new class extends CoreEditingCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper({\r\n\t\t\t\tid: 'deleteLeft',\r\n\t\t\t\tprecondition: undefined,\r\n\t\t\t\tkbOpts: {\r\n\t\t\t\t\tweight: CORE_WEIGHT,\r\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\t\tprimary: KeyCode.Backspace,\r\n\t\t\t\t\tsecondary: [KeyMod.Shift | KeyCode.Backspace],\r\n\t\t\t\t\tmac: { primary: KeyCode.Backspace, secondary: [KeyMod.Shift | KeyCode.Backspace, KeyMod.WinCtrl | KeyCode.KEY_H, KeyMod.WinCtrl | KeyCode.Backspace] }\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: any): void {\r\n\t\t\tconst [shouldPushStackElementBefore, commands] = DeleteOperations.deleteLeft(viewModel.getPrevEditOperationType(), viewModel.cursorConfig, viewModel.model, viewModel.getCursorStates().map(s => s.modelState.selection));\r\n\t\t\tif (shouldPushStackElementBefore) {\r\n\t\t\t\teditor.pushUndoStop();\r\n\t\t\t}\r\n\t\t\teditor.executeCommands(this.id, commands);\r\n\t\t\tviewModel.setPrevEditOperationType(EditOperationType.DeletingLeft);\r\n\t\t}\r\n\t});\r\n\r\n\texport const DeleteRight: EditorCommand = registerEditorCommand(new class extends CoreEditingCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper({\r\n\t\t\t\tid: 'deleteRight',\r\n\t\t\t\tprecondition: undefined,\r\n\t\t\t\tkbOpts: {\r\n\t\t\t\t\tweight: CORE_WEIGHT,\r\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\t\tprimary: KeyCode.Delete,\r\n\t\t\t\t\tmac: { primary: KeyCode.Delete, secondary: [KeyMod.WinCtrl | KeyCode.KEY_D, KeyMod.WinCtrl | KeyCode.Delete] }\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tpublic runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: any): void {\r\n\t\t\tconst [shouldPushStackElementBefore, commands] = DeleteOperations.deleteRight(viewModel.getPrevEditOperationType(), viewModel.cursorConfig, viewModel.model, viewModel.getCursorStates().map(s => s.modelState.selection));\r\n\t\t\tif (shouldPushStackElementBefore) {\r\n\t\t\t\teditor.pushUndoStop();\r\n\t\t\t}\r\n\t\t\teditor.executeCommands(this.id, commands);\r\n\t\t\tviewModel.setPrevEditOperationType(EditOperationType.DeletingRight);\r\n\t\t}\r\n\t});\r\n\r\n\texport const Undo = new class extends EditorOrNativeTextInputCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper(UndoCommand);\r\n\t\t}\r\n\t\tpublic runDOMCommand(): void {\r\n\t\t\tdocument.execCommand('undo');\r\n\t\t}\r\n\t\tpublic runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void | Promise {\r\n\t\t\tif (!editor.hasModel() || editor.getOption(EditorOption.readOnly) === true) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\treturn editor.getModel().undo();\r\n\t\t}\r\n\t}();\r\n\r\n\texport const Redo = new class extends EditorOrNativeTextInputCommand {\r\n\t\tconstructor() {\r\n\t\t\tsuper(RedoCommand);\r\n\t\t}\r\n\t\tpublic runDOMCommand(): void {\r\n\t\t\tdocument.execCommand('redo');\r\n\t\t}\r\n\t\tpublic runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void | Promise {\r\n\t\t\tif (!editor.hasModel() || editor.getOption(EditorOption.readOnly) === true) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\treturn editor.getModel().redo();\r\n\t\t}\r\n\t}();\r\n}\r\n\r\n/**\r\n * A command that will invoke a command on the focused editor.\r\n */\r\nclass EditorHandlerCommand extends Command {\r\n\r\n\tprivate readonly _handlerId: string;\r\n\r\n\tconstructor(id: string, handlerId: string, description?: ICommandHandlerDescription) {\r\n\t\tsuper({\r\n\t\t\tid: id,\r\n\t\t\tprecondition: undefined,\r\n\t\t\tdescription: description\r\n\t\t});\r\n\t\tthis._handlerId = handlerId;\r\n\t}\r\n\r\n\tpublic runCommand(accessor: ServicesAccessor, args: any): void {\r\n\t\tconst editor = accessor.get(ICodeEditorService).getFocusedCodeEditor();\r\n\t\tif (!editor) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\teditor.trigger('keyboard', this._handlerId, args);\r\n\t}\r\n}\r\n\r\nfunction registerOverwritableCommand(handlerId: string, description?: ICommandHandlerDescription): void {\r\n\tregisterCommand(new EditorHandlerCommand('default:' + handlerId, handlerId));\r\n\tregisterCommand(new EditorHandlerCommand(handlerId, handlerId, description));\r\n}\r\n\r\nregisterOverwritableCommand(Handler.Type, {\r\n\tdescription: `Type`,\r\n\targs: [{\r\n\t\tname: 'args',\r\n\t\tschema: {\r\n\t\t\t'type': 'object',\r\n\t\t\t'required': ['text'],\r\n\t\t\t'properties': {\r\n\t\t\t\t'text': {\r\n\t\t\t\t\t'type': 'string'\r\n\t\t\t\t}\r\n\t\t\t},\r\n\t\t}\r\n\t}]\r\n});\r\nregisterOverwritableCommand(Handler.ReplacePreviousChar);\r\nregisterOverwritableCommand(Handler.CompositionStart);\r\nregisterOverwritableCommand(Handler.CompositionEnd);\r\nregisterOverwritableCommand(Handler.Paste);\r\nregisterOverwritableCommand(Handler.Cut);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { KeyCode } from 'vs/base/common/keyCodes';\r\nimport { EditorCommand, registerEditorCommand } from 'vs/editor/browser/editorExtensions';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';\r\nimport { LinkedList } from 'vs/base/common/linkedList';\r\nimport { createDecorator, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';\r\nimport { registerSingleton } from 'vs/platform/instantiation/common/extensions';\r\n\r\n\r\nconst IEditorCancellationTokens = createDecorator('IEditorCancelService');\r\n\r\ninterface IEditorCancellationTokens {\r\n\treadonly _serviceBrand: undefined;\r\n\tadd(editor: ICodeEditor, cts: CancellationTokenSource): () => void;\r\n\tcancel(editor: ICodeEditor): void;\r\n}\r\n\r\nconst ctxCancellableOperation = new RawContextKey('cancellableOperation', false);\r\n\r\nregisterSingleton(IEditorCancellationTokens, class implements IEditorCancellationTokens {\r\n\r\n\tdeclare readonly _serviceBrand: undefined;\r\n\r\n\tprivate readonly _tokens = new WeakMap, tokens: LinkedList }>();\r\n\r\n\tadd(editor: ICodeEditor, cts: CancellationTokenSource): () => void {\r\n\t\tlet data = this._tokens.get(editor);\r\n\t\tif (!data) {\r\n\t\t\tdata = editor.invokeWithinContext(accessor => {\r\n\t\t\t\tconst key = ctxCancellableOperation.bindTo(accessor.get(IContextKeyService));\r\n\t\t\t\tconst tokens = new LinkedList();\r\n\t\t\t\treturn { key, tokens };\r\n\t\t\t});\r\n\t\t\tthis._tokens.set(editor, data);\r\n\t\t}\r\n\r\n\t\tlet removeFn: Function | undefined;\r\n\r\n\t\tdata.key.set(true);\r\n\t\tremoveFn = data.tokens.push(cts);\r\n\r\n\t\treturn () => {\r\n\t\t\t// remove w/o cancellation\r\n\t\t\tif (removeFn) {\r\n\t\t\t\tremoveFn();\r\n\t\t\t\tdata!.key.set(!data!.tokens.isEmpty());\r\n\t\t\t\tremoveFn = undefined;\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\tcancel(editor: ICodeEditor): void {\r\n\t\tconst data = this._tokens.get(editor);\r\n\t\tif (!data) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\t// remove with cancellation\r\n\t\tconst cts = data.tokens.pop();\r\n\t\tif (cts) {\r\n\t\t\tcts.cancel();\r\n\t\t\tdata.key.set(!data.tokens.isEmpty());\r\n\t\t}\r\n\t}\r\n\r\n}, true);\r\n\r\nexport class EditorKeybindingCancellationTokenSource extends CancellationTokenSource {\r\n\r\n\tprivate readonly _unregister: Function;\r\n\r\n\tconstructor(readonly editor: ICodeEditor, parent?: CancellationToken) {\r\n\t\tsuper(parent);\r\n\t\tthis._unregister = editor.invokeWithinContext(accessor => accessor.get(IEditorCancellationTokens).add(editor, this));\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._unregister();\r\n\t\tsuper.dispose();\r\n\t}\r\n}\r\n\r\nregisterEditorCommand(new class extends EditorCommand {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.cancelOperation',\r\n\t\t\tkbOpts: {\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib,\r\n\t\t\t\tprimary: KeyCode.Escape\r\n\t\t\t},\r\n\t\t\tprecondition: ctxCancellableOperation\r\n\t\t});\r\n\t}\r\n\r\n\trunEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\taccessor.get(IEditorCancellationTokens).cancel(editor);\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { ICodeEditor, IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range, IRange } from 'vs/editor/common/core/range';\r\nimport { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';\r\nimport { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { EditorKeybindingCancellationTokenSource } from 'vs/editor/browser/core/keybindingCancellation';\r\n\r\nexport const enum CodeEditorStateFlag {\r\n\tValue = 1,\r\n\tSelection = 2,\r\n\tPosition = 4,\r\n\tScroll = 8\r\n}\r\n\r\nexport class EditorState {\r\n\r\n\tprivate readonly flags: number;\r\n\r\n\tprivate readonly position: Position | null;\r\n\tprivate readonly selection: Range | null;\r\n\tprivate readonly modelVersionId: string | null;\r\n\tprivate readonly scrollLeft: number;\r\n\tprivate readonly scrollTop: number;\r\n\r\n\tconstructor(editor: ICodeEditor, flags: number) {\r\n\t\tthis.flags = flags;\r\n\r\n\t\tif ((this.flags & CodeEditorStateFlag.Value) !== 0) {\r\n\t\t\tconst model = editor.getModel();\r\n\t\t\tthis.modelVersionId = model ? strings.format('{0}#{1}', model.uri.toString(), model.getVersionId()) : null;\r\n\t\t} else {\r\n\t\t\tthis.modelVersionId = null;\r\n\t\t}\r\n\t\tif ((this.flags & CodeEditorStateFlag.Position) !== 0) {\r\n\t\t\tthis.position = editor.getPosition();\r\n\t\t} else {\r\n\t\t\tthis.position = null;\r\n\t\t}\r\n\t\tif ((this.flags & CodeEditorStateFlag.Selection) !== 0) {\r\n\t\t\tthis.selection = editor.getSelection();\r\n\t\t} else {\r\n\t\t\tthis.selection = null;\r\n\t\t}\r\n\t\tif ((this.flags & CodeEditorStateFlag.Scroll) !== 0) {\r\n\t\t\tthis.scrollLeft = editor.getScrollLeft();\r\n\t\t\tthis.scrollTop = editor.getScrollTop();\r\n\t\t} else {\r\n\t\t\tthis.scrollLeft = -1;\r\n\t\t\tthis.scrollTop = -1;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _equals(other: any): boolean {\r\n\r\n\t\tif (!(other instanceof EditorState)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tconst state = other;\r\n\r\n\t\tif (this.modelVersionId !== state.modelVersionId) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (this.scrollLeft !== state.scrollLeft || this.scrollTop !== state.scrollTop) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (!this.position && state.position || this.position && !state.position || this.position && state.position && !this.position.equals(state.position)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (!this.selection && state.selection || this.selection && !state.selection || this.selection && state.selection && !this.selection.equalsRange(state.selection)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic validate(editor: ICodeEditor): boolean {\r\n\t\treturn this._equals(new EditorState(editor, this.flags));\r\n\t}\r\n}\r\n\r\n/**\r\n * A cancellation token source that cancels when the editor changes as expressed\r\n * by the provided flags\r\n * @param range If provided, changes in position and selection within this range will not trigger cancellation\r\n */\r\nexport class EditorStateCancellationTokenSource extends EditorKeybindingCancellationTokenSource implements IDisposable {\r\n\r\n\tprivate readonly _listener = new DisposableStore();\r\n\r\n\tconstructor(readonly editor: IActiveCodeEditor, flags: CodeEditorStateFlag, range?: IRange, parent?: CancellationToken) {\r\n\t\tsuper(editor, parent);\r\n\r\n\t\tif (flags & CodeEditorStateFlag.Position) {\r\n\t\t\tthis._listener.add(editor.onDidChangeCursorPosition(e => {\r\n\t\t\t\tif (!range || !Range.containsPosition(range, e.position)) {\r\n\t\t\t\t\tthis.cancel();\r\n\t\t\t\t}\r\n\t\t\t}));\r\n\t\t}\r\n\t\tif (flags & CodeEditorStateFlag.Selection) {\r\n\t\t\tthis._listener.add(editor.onDidChangeCursorSelection(e => {\r\n\t\t\t\tif (!range || !Range.containsRange(range, e.selection)) {\r\n\t\t\t\t\tthis.cancel();\r\n\t\t\t\t}\r\n\t\t\t}));\r\n\t\t}\r\n\t\tif (flags & CodeEditorStateFlag.Scroll) {\r\n\t\t\tthis._listener.add(editor.onDidScrollChange(_ => this.cancel()));\r\n\t\t}\r\n\t\tif (flags & CodeEditorStateFlag.Value) {\r\n\t\t\tthis._listener.add(editor.onDidChangeModel(_ => this.cancel()));\r\n\t\t\tthis._listener.add(editor.onDidChangeModelContent(_ => this.cancel()));\r\n\t\t}\r\n\t}\r\n\r\n\tdispose() {\r\n\t\tthis._listener.dispose();\r\n\t\tsuper.dispose();\r\n\t}\r\n}\r\n\r\n/**\r\n * A cancellation token source that cancels when the provided model changes\r\n */\r\nexport class TextModelCancellationTokenSource extends CancellationTokenSource implements IDisposable {\r\n\r\n\tprivate _listener: IDisposable;\r\n\r\n\tconstructor(model: ITextModel, parent?: CancellationToken) {\r\n\t\tsuper(parent);\r\n\t\tthis._listener = model.onDidChangeContent(() => this.cancel());\r\n\t}\r\n\r\n\tdispose() {\r\n\t\tthis._listener.dispose();\r\n\t\tsuper.dispose();\r\n\t}\r\n}\r\n\r\nexport class StableEditorScrollState {\r\n\r\n\tpublic static capture(editor: ICodeEditor): StableEditorScrollState {\r\n\t\tlet visiblePosition: Position | null = null;\r\n\t\tlet visiblePositionScrollDelta = 0;\r\n\t\tif (editor.getScrollTop() !== 0) {\r\n\t\t\tconst visibleRanges = editor.getVisibleRanges();\r\n\t\t\tif (visibleRanges.length > 0) {\r\n\t\t\t\tvisiblePosition = visibleRanges[0].getStartPosition();\r\n\t\t\t\tconst visiblePositionScrollTop = editor.getTopForPosition(visiblePosition.lineNumber, visiblePosition.column);\r\n\t\t\t\tvisiblePositionScrollDelta = editor.getScrollTop() - visiblePositionScrollTop;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn new StableEditorScrollState(visiblePosition, visiblePositionScrollDelta, editor.getPosition());\r\n\t}\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _visiblePosition: Position | null,\r\n\t\tprivate readonly _visiblePositionScrollDelta: number,\r\n\t\tprivate readonly _cursorPosition: Position | null\r\n\t) {\r\n\t}\r\n\r\n\tpublic restore(editor: ICodeEditor): void {\r\n\t\tif (this._visiblePosition) {\r\n\t\t\tconst visiblePositionScrollTop = editor.getTopForPosition(this._visiblePosition.lineNumber, this._visiblePosition.column);\r\n\t\t\teditor.setScrollTop(visiblePositionScrollTop + this._visiblePositionScrollDelta);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic restoreRelativeVerticalPositionOfCursor(editor: ICodeEditor): void {\r\n\t\tconst currentCursorPosition = editor.getPosition();\r\n\r\n\t\tif (!this._cursorPosition || !currentCursorPosition) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst offset = editor.getTopForLineNumber(currentCursorPosition.lineNumber) - editor.getTopForLineNumber(this._cursorPosition.lineNumber);\r\n\t\teditor.setScrollTop(editor.getScrollTop() + offset);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { CoreNavigationCommands } from 'vs/editor/browser/controller/coreCommands';\r\nimport { IEditorMouseEvent, IPartialEditorMouseEvent } from 'vs/editor/browser/editorBrowser';\r\nimport { ViewUserInputEvents } from 'vs/editor/browser/view/viewUserInputEvents';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { IConfiguration } from 'vs/editor/common/editorCommon';\r\nimport { IViewModel } from 'vs/editor/common/viewModel/viewModel';\r\nimport { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport * as platform from 'vs/base/common/platform';\r\n\r\nexport interface IMouseDispatchData {\r\n\tposition: Position;\r\n\t/**\r\n\t * Desired mouse column (e.g. when position.column gets clamped to text length -- clicking after text on a line).\r\n\t */\r\n\tmouseColumn: number;\r\n\tstartedOnLineNumbers: boolean;\r\n\r\n\tinSelectionMode: boolean;\r\n\tmouseDownCount: number;\r\n\taltKey: boolean;\r\n\tctrlKey: boolean;\r\n\tmetaKey: boolean;\r\n\tshiftKey: boolean;\r\n\r\n\tleftButton: boolean;\r\n\tmiddleButton: boolean;\r\n}\r\n\r\nexport interface ICommandDelegate {\r\n\tpaste(text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null): void;\r\n\ttype(text: string): void;\r\n\treplacePreviousChar(text: string, replaceCharCnt: number): void;\r\n\tstartComposition(): void;\r\n\tendComposition(): void;\r\n\tcut(): void;\r\n}\r\n\r\nexport class ViewController {\r\n\r\n\tprivate readonly configuration: IConfiguration;\r\n\tprivate readonly viewModel: IViewModel;\r\n\tprivate readonly userInputEvents: ViewUserInputEvents;\r\n\tprivate readonly commandDelegate: ICommandDelegate;\r\n\r\n\tconstructor(\r\n\t\tconfiguration: IConfiguration,\r\n\t\tviewModel: IViewModel,\r\n\t\tuserInputEvents: ViewUserInputEvents,\r\n\t\tcommandDelegate: ICommandDelegate\r\n\t) {\r\n\t\tthis.configuration = configuration;\r\n\t\tthis.viewModel = viewModel;\r\n\t\tthis.userInputEvents = userInputEvents;\r\n\t\tthis.commandDelegate = commandDelegate;\r\n\t}\r\n\r\n\tpublic paste(text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null): void {\r\n\t\tthis.commandDelegate.paste(text, pasteOnNewLine, multicursorText, mode);\r\n\t}\r\n\r\n\tpublic type(text: string): void {\r\n\t\tthis.commandDelegate.type(text);\r\n\t}\r\n\r\n\tpublic replacePreviousChar(text: string, replaceCharCnt: number): void {\r\n\t\tthis.commandDelegate.replacePreviousChar(text, replaceCharCnt);\r\n\t}\r\n\r\n\tpublic compositionStart(): void {\r\n\t\tthis.commandDelegate.startComposition();\r\n\t}\r\n\r\n\tpublic compositionEnd(): void {\r\n\t\tthis.commandDelegate.endComposition();\r\n\t}\r\n\r\n\tpublic cut(): void {\r\n\t\tthis.commandDelegate.cut();\r\n\t}\r\n\r\n\tpublic setSelection(modelSelection: Selection): void {\r\n\t\tCoreNavigationCommands.SetSelection.runCoreEditorCommand(this.viewModel, {\r\n\t\t\tsource: 'keyboard',\r\n\t\t\tselection: modelSelection\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _validateViewColumn(viewPosition: Position): Position {\r\n\t\tconst minColumn = this.viewModel.getLineMinColumn(viewPosition.lineNumber);\r\n\t\tif (viewPosition.column < minColumn) {\r\n\t\t\treturn new Position(viewPosition.lineNumber, minColumn);\r\n\t\t}\r\n\t\treturn viewPosition;\r\n\t}\r\n\r\n\tprivate _hasMulticursorModifier(data: IMouseDispatchData): boolean {\r\n\t\tswitch (this.configuration.options.get(EditorOption.multiCursorModifier)) {\r\n\t\t\tcase 'altKey':\r\n\t\t\t\treturn data.altKey;\r\n\t\t\tcase 'ctrlKey':\r\n\t\t\t\treturn data.ctrlKey;\r\n\t\t\tcase 'metaKey':\r\n\t\t\t\treturn data.metaKey;\r\n\t\t\tdefault:\r\n\t\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _hasNonMulticursorModifier(data: IMouseDispatchData): boolean {\r\n\t\tswitch (this.configuration.options.get(EditorOption.multiCursorModifier)) {\r\n\t\t\tcase 'altKey':\r\n\t\t\t\treturn data.ctrlKey || data.metaKey;\r\n\t\t\tcase 'ctrlKey':\r\n\t\t\t\treturn data.altKey || data.metaKey;\r\n\t\t\tcase 'metaKey':\r\n\t\t\t\treturn data.ctrlKey || data.altKey;\r\n\t\t\tdefault:\r\n\t\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic dispatchMouse(data: IMouseDispatchData): void {\r\n\t\tconst options = this.configuration.options;\r\n\t\tconst selectionClipboardIsOn = (platform.isLinux && options.get(EditorOption.selectionClipboard));\r\n\t\tconst columnSelection = options.get(EditorOption.columnSelection);\r\n\t\tif (data.middleButton && !selectionClipboardIsOn) {\r\n\t\t\tthis._columnSelect(data.position, data.mouseColumn, data.inSelectionMode);\r\n\t\t} else if (data.startedOnLineNumbers) {\r\n\t\t\t// If the dragging started on the gutter, then have operations work on the entire line\r\n\t\t\tif (this._hasMulticursorModifier(data)) {\r\n\t\t\t\tif (data.inSelectionMode) {\r\n\t\t\t\t\tthis._lastCursorLineSelect(data.position);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis._createCursor(data.position, true);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tif (data.inSelectionMode) {\r\n\t\t\t\t\tthis._lineSelectDrag(data.position);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis._lineSelect(data.position);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else if (data.mouseDownCount >= 4) {\r\n\t\t\tthis._selectAll();\r\n\t\t} else if (data.mouseDownCount === 3) {\r\n\t\t\tif (this._hasMulticursorModifier(data)) {\r\n\t\t\t\tif (data.inSelectionMode) {\r\n\t\t\t\t\tthis._lastCursorLineSelectDrag(data.position);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis._lastCursorLineSelect(data.position);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tif (data.inSelectionMode) {\r\n\t\t\t\t\tthis._lineSelectDrag(data.position);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis._lineSelect(data.position);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else if (data.mouseDownCount === 2) {\r\n\t\t\tif (this._hasMulticursorModifier(data)) {\r\n\t\t\t\tthis._lastCursorWordSelect(data.position);\r\n\t\t\t} else {\r\n\t\t\t\tif (data.inSelectionMode) {\r\n\t\t\t\t\tthis._wordSelectDrag(data.position);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis._wordSelect(data.position);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tif (this._hasMulticursorModifier(data)) {\r\n\t\t\t\tif (!this._hasNonMulticursorModifier(data)) {\r\n\t\t\t\t\tif (data.shiftKey) {\r\n\t\t\t\t\t\tthis._columnSelect(data.position, data.mouseColumn, true);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t// Do multi-cursor operations only when purely alt is pressed\r\n\t\t\t\t\t\tif (data.inSelectionMode) {\r\n\t\t\t\t\t\t\tthis._lastCursorMoveToSelect(data.position);\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tthis._createCursor(data.position, false);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tif (data.inSelectionMode) {\r\n\t\t\t\t\tif (data.altKey) {\r\n\t\t\t\t\t\tthis._columnSelect(data.position, data.mouseColumn, true);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tif (columnSelection) {\r\n\t\t\t\t\t\t\tthis._columnSelect(data.position, data.mouseColumn, true);\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tthis._moveToSelect(data.position);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis.moveTo(data.position);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _usualArgs(viewPosition: Position) {\r\n\t\tviewPosition = this._validateViewColumn(viewPosition);\r\n\t\treturn {\r\n\t\t\tsource: 'mouse',\r\n\t\t\tposition: this._convertViewToModelPosition(viewPosition),\r\n\t\t\tviewPosition: viewPosition\r\n\t\t};\r\n\t}\r\n\r\n\tpublic moveTo(viewPosition: Position): void {\r\n\t\tCoreNavigationCommands.MoveTo.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));\r\n\t}\r\n\r\n\tprivate _moveToSelect(viewPosition: Position): void {\r\n\t\tCoreNavigationCommands.MoveToSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));\r\n\t}\r\n\r\n\tprivate _columnSelect(viewPosition: Position, mouseColumn: number, doColumnSelect: boolean): void {\r\n\t\tviewPosition = this._validateViewColumn(viewPosition);\r\n\t\tCoreNavigationCommands.ColumnSelect.runCoreEditorCommand(this.viewModel, {\r\n\t\t\tsource: 'mouse',\r\n\t\t\tposition: this._convertViewToModelPosition(viewPosition),\r\n\t\t\tviewPosition: viewPosition,\r\n\t\t\tmouseColumn: mouseColumn,\r\n\t\t\tdoColumnSelect: doColumnSelect\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _createCursor(viewPosition: Position, wholeLine: boolean): void {\r\n\t\tviewPosition = this._validateViewColumn(viewPosition);\r\n\t\tCoreNavigationCommands.CreateCursor.runCoreEditorCommand(this.viewModel, {\r\n\t\t\tsource: 'mouse',\r\n\t\t\tposition: this._convertViewToModelPosition(viewPosition),\r\n\t\t\tviewPosition: viewPosition,\r\n\t\t\twholeLine: wholeLine\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _lastCursorMoveToSelect(viewPosition: Position): void {\r\n\t\tCoreNavigationCommands.LastCursorMoveToSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));\r\n\t}\r\n\r\n\tprivate _wordSelect(viewPosition: Position): void {\r\n\t\tCoreNavigationCommands.WordSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));\r\n\t}\r\n\r\n\tprivate _wordSelectDrag(viewPosition: Position): void {\r\n\t\tCoreNavigationCommands.WordSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));\r\n\t}\r\n\r\n\tprivate _lastCursorWordSelect(viewPosition: Position): void {\r\n\t\tCoreNavigationCommands.LastCursorWordSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));\r\n\t}\r\n\r\n\tprivate _lineSelect(viewPosition: Position): void {\r\n\t\tCoreNavigationCommands.LineSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));\r\n\t}\r\n\r\n\tprivate _lineSelectDrag(viewPosition: Position): void {\r\n\t\tCoreNavigationCommands.LineSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));\r\n\t}\r\n\r\n\tprivate _lastCursorLineSelect(viewPosition: Position): void {\r\n\t\tCoreNavigationCommands.LastCursorLineSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));\r\n\t}\r\n\r\n\tprivate _lastCursorLineSelectDrag(viewPosition: Position): void {\r\n\t\tCoreNavigationCommands.LastCursorLineSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));\r\n\t}\r\n\r\n\tprivate _selectAll(): void {\r\n\t\tCoreNavigationCommands.SelectAll.runCoreEditorCommand(this.viewModel, { source: 'mouse' });\r\n\t}\r\n\r\n\t// ----------------------\r\n\r\n\tprivate _convertViewToModelPosition(viewPosition: Position): Position {\r\n\t\treturn this.viewModel.coordinatesConverter.convertViewPositionToModelPosition(viewPosition);\r\n\t}\r\n\r\n\tpublic emitKeyDown(e: IKeyboardEvent): void {\r\n\t\tthis.userInputEvents.emitKeyDown(e);\r\n\t}\r\n\r\n\tpublic emitKeyUp(e: IKeyboardEvent): void {\r\n\t\tthis.userInputEvents.emitKeyUp(e);\r\n\t}\r\n\r\n\tpublic emitContextMenu(e: IEditorMouseEvent): void {\r\n\t\tthis.userInputEvents.emitContextMenu(e);\r\n\t}\r\n\r\n\tpublic emitMouseMove(e: IEditorMouseEvent): void {\r\n\t\tthis.userInputEvents.emitMouseMove(e);\r\n\t}\r\n\r\n\tpublic emitMouseLeave(e: IPartialEditorMouseEvent): void {\r\n\t\tthis.userInputEvents.emitMouseLeave(e);\r\n\t}\r\n\r\n\tpublic emitMouseUp(e: IEditorMouseEvent): void {\r\n\t\tthis.userInputEvents.emitMouseUp(e);\r\n\t}\r\n\r\n\tpublic emitMouseDown(e: IEditorMouseEvent): void {\r\n\t\tthis.userInputEvents.emitMouseDown(e);\r\n\t}\r\n\r\n\tpublic emitMouseDrag(e: IEditorMouseEvent): void {\r\n\t\tthis.userInputEvents.emitMouseDrag(e);\r\n\t}\r\n\r\n\tpublic emitMouseDrop(e: IPartialEditorMouseEvent): void {\r\n\t\tthis.userInputEvents.emitMouseDrop(e);\r\n\t}\r\n\r\n\tpublic emitMouseDropCanceled(): void {\r\n\t\tthis.userInputEvents.emitMouseDropCanceled();\r\n\t}\r\n\r\n\tpublic emitMouseWheel(e: IMouseWheelEvent): void {\r\n\t\tthis.userInputEvents.emitMouseWheel(e);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport * as browser from 'vs/base/browser/browser';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { IMouseEvent } from 'vs/base/browser/mouseEvent';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { IPointerHandlerHelper } from 'vs/editor/browser/controller/mouseHandler';\r\nimport { PointerHandler } from 'vs/editor/browser/controller/pointerHandler';\r\nimport { ITextAreaHandlerHelper, TextAreaHandler } from 'vs/editor/browser/controller/textAreaHandler';\r\nimport { IContentWidget, IContentWidgetPosition, IOverlayWidget, IOverlayWidgetPosition, IMouseTarget, IViewZoneChangeAccessor, IEditorAriaOptions } from 'vs/editor/browser/editorBrowser';\r\nimport { ICommandDelegate, ViewController } from 'vs/editor/browser/view/viewController';\r\nimport { ViewUserInputEvents } from 'vs/editor/browser/view/viewUserInputEvents';\r\nimport { ContentViewOverlays, MarginViewOverlays } from 'vs/editor/browser/view/viewOverlays';\r\nimport { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/view/viewPart';\r\nimport { ViewContentWidgets } from 'vs/editor/browser/viewParts/contentWidgets/contentWidgets';\r\nimport { CurrentLineHighlightOverlay, CurrentLineMarginHighlightOverlay } from 'vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight';\r\nimport { DecorationsOverlay } from 'vs/editor/browser/viewParts/decorations/decorations';\r\nimport { EditorScrollbar } from 'vs/editor/browser/viewParts/editorScrollbar/editorScrollbar';\r\nimport { GlyphMarginOverlay } from 'vs/editor/browser/viewParts/glyphMargin/glyphMargin';\r\nimport { IndentGuidesOverlay } from 'vs/editor/browser/viewParts/indentGuides/indentGuides';\r\nimport { LineNumbersOverlay } from 'vs/editor/browser/viewParts/lineNumbers/lineNumbers';\r\nimport { ViewLines } from 'vs/editor/browser/viewParts/lines/viewLines';\r\nimport { LinesDecorationsOverlay } from 'vs/editor/browser/viewParts/linesDecorations/linesDecorations';\r\nimport { Margin } from 'vs/editor/browser/viewParts/margin/margin';\r\nimport { MarginViewLineDecorationsOverlay } from 'vs/editor/browser/viewParts/marginDecorations/marginDecorations';\r\nimport { Minimap } from 'vs/editor/browser/viewParts/minimap/minimap';\r\nimport { ViewOverlayWidgets } from 'vs/editor/browser/viewParts/overlayWidgets/overlayWidgets';\r\nimport { DecorationsOverviewRuler } from 'vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler';\r\nimport { OverviewRuler } from 'vs/editor/browser/viewParts/overviewRuler/overviewRuler';\r\nimport { Rulers } from 'vs/editor/browser/viewParts/rulers/rulers';\r\nimport { ScrollDecorationViewPart } from 'vs/editor/browser/viewParts/scrollDecoration/scrollDecoration';\r\nimport { SelectionsOverlay } from 'vs/editor/browser/viewParts/selections/selections';\r\nimport { ViewCursors } from 'vs/editor/browser/viewParts/viewCursors/viewCursors';\r\nimport { ViewZones } from 'vs/editor/browser/viewParts/viewZones/viewZones';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { IConfiguration, ScrollType } from 'vs/editor/common/editorCommon';\r\nimport { RenderingContext } from 'vs/editor/common/view/renderingContext';\r\nimport { ViewContext } from 'vs/editor/common/view/viewContext';\r\nimport * as viewEvents from 'vs/editor/common/view/viewEvents';\r\nimport { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';\r\nimport { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler';\r\nimport { IViewModel } from 'vs/editor/common/viewModel/viewModel';\r\nimport { IThemeService, getThemeTypeSelector } from 'vs/platform/theme/common/themeService';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { PointerHandlerLastRenderData } from 'vs/editor/browser/controller/mouseTarget';\r\n\r\n\r\nexport interface IContentWidgetData {\r\n\twidget: IContentWidget;\r\n\tposition: IContentWidgetPosition | null;\r\n}\r\n\r\nexport interface IOverlayWidgetData {\r\n\twidget: IOverlayWidget;\r\n\tposition: IOverlayWidgetPosition | null;\r\n}\r\n\r\nexport class View extends ViewEventHandler {\r\n\r\n\tprivate readonly _scrollbar: EditorScrollbar;\r\n\tprivate readonly _context: ViewContext;\r\n\tprivate _configPixelRatio: number;\r\n\tprivate _selections: Selection[];\r\n\r\n\t// The view lines\r\n\tprivate readonly _viewLines: ViewLines;\r\n\r\n\t// These are parts, but we must do some API related calls on them, so we keep a reference\r\n\tprivate readonly _viewZones: ViewZones;\r\n\tprivate readonly _contentWidgets: ViewContentWidgets;\r\n\tprivate readonly _overlayWidgets: ViewOverlayWidgets;\r\n\tprivate readonly _viewCursors: ViewCursors;\r\n\tprivate readonly _viewParts: ViewPart[];\r\n\r\n\tprivate readonly _textAreaHandler: TextAreaHandler;\r\n\tprivate readonly _pointerHandler: PointerHandler;\r\n\r\n\t// Dom nodes\r\n\tprivate readonly _linesContent: FastDomNode;\r\n\tpublic readonly domNode: FastDomNode;\r\n\tprivate readonly _overflowGuardContainer: FastDomNode;\r\n\r\n\t// Actual mutable state\r\n\tprivate _renderAnimationFrame: IDisposable | null;\r\n\r\n\tconstructor(\r\n\t\tcommandDelegate: ICommandDelegate,\r\n\t\tconfiguration: IConfiguration,\r\n\t\tthemeService: IThemeService,\r\n\t\tmodel: IViewModel,\r\n\t\tuserInputEvents: ViewUserInputEvents,\r\n\t\toverflowWidgetsDomNode: HTMLElement | undefined\r\n\t) {\r\n\t\tsuper();\r\n\t\tthis._selections = [new Selection(1, 1, 1, 1)];\r\n\t\tthis._renderAnimationFrame = null;\r\n\r\n\t\tconst viewController = new ViewController(configuration, model, userInputEvents, commandDelegate);\r\n\r\n\t\t// The view context is passed on to most classes (basically to reduce param. counts in ctors)\r\n\t\tthis._context = new ViewContext(configuration, themeService.getColorTheme(), model);\r\n\t\tthis._configPixelRatio = this._configPixelRatio = this._context.configuration.options.get(EditorOption.pixelRatio);\r\n\r\n\t\t// Ensure the view is the first event handler in order to update the layout\r\n\t\tthis._context.addEventHandler(this);\r\n\r\n\t\tthis._register(themeService.onDidColorThemeChange(theme => {\r\n\t\t\tthis._context.theme.update(theme);\r\n\t\t\tthis._context.model.onDidColorThemeChange();\r\n\t\t\tthis.render(true, false);\r\n\t\t}));\r\n\r\n\t\tthis._viewParts = [];\r\n\r\n\t\t// Keyboard handler\r\n\t\tthis._textAreaHandler = new TextAreaHandler(this._context, viewController, this._createTextAreaHandlerHelper());\r\n\t\tthis._viewParts.push(this._textAreaHandler);\r\n\r\n\t\t// These two dom nodes must be constructed up front, since references are needed in the layout provider (scrolling & co.)\r\n\t\tthis._linesContent = createFastDomNode(document.createElement('div'));\r\n\t\tthis._linesContent.setClassName('lines-content' + ' monaco-editor-background');\r\n\t\tthis._linesContent.setPosition('absolute');\r\n\r\n\t\tthis.domNode = createFastDomNode(document.createElement('div'));\r\n\t\tthis.domNode.setClassName(this._getEditorClassName());\r\n\t\t// Set role 'code' for better screen reader support https://github.com/microsoft/vscode/issues/93438\r\n\t\tthis.domNode.setAttribute('role', 'code');\r\n\r\n\t\tthis._overflowGuardContainer = createFastDomNode(document.createElement('div'));\r\n\t\tPartFingerprints.write(this._overflowGuardContainer, PartFingerprint.OverflowGuard);\r\n\t\tthis._overflowGuardContainer.setClassName('overflow-guard');\r\n\r\n\t\tthis._scrollbar = new EditorScrollbar(this._context, this._linesContent, this.domNode, this._overflowGuardContainer);\r\n\t\tthis._viewParts.push(this._scrollbar);\r\n\r\n\t\t// View Lines\r\n\t\tthis._viewLines = new ViewLines(this._context, this._linesContent);\r\n\r\n\t\t// View Zones\r\n\t\tthis._viewZones = new ViewZones(this._context);\r\n\t\tthis._viewParts.push(this._viewZones);\r\n\r\n\t\t// Decorations overview ruler\r\n\t\tconst decorationsOverviewRuler = new DecorationsOverviewRuler(this._context);\r\n\t\tthis._viewParts.push(decorationsOverviewRuler);\r\n\r\n\r\n\t\tconst scrollDecoration = new ScrollDecorationViewPart(this._context);\r\n\t\tthis._viewParts.push(scrollDecoration);\r\n\r\n\t\tconst contentViewOverlays = new ContentViewOverlays(this._context);\r\n\t\tthis._viewParts.push(contentViewOverlays);\r\n\t\tcontentViewOverlays.addDynamicOverlay(new CurrentLineHighlightOverlay(this._context));\r\n\t\tcontentViewOverlays.addDynamicOverlay(new SelectionsOverlay(this._context));\r\n\t\tcontentViewOverlays.addDynamicOverlay(new IndentGuidesOverlay(this._context));\r\n\t\tcontentViewOverlays.addDynamicOverlay(new DecorationsOverlay(this._context));\r\n\r\n\t\tconst marginViewOverlays = new MarginViewOverlays(this._context);\r\n\t\tthis._viewParts.push(marginViewOverlays);\r\n\t\tmarginViewOverlays.addDynamicOverlay(new CurrentLineMarginHighlightOverlay(this._context));\r\n\t\tmarginViewOverlays.addDynamicOverlay(new GlyphMarginOverlay(this._context));\r\n\t\tmarginViewOverlays.addDynamicOverlay(new MarginViewLineDecorationsOverlay(this._context));\r\n\t\tmarginViewOverlays.addDynamicOverlay(new LinesDecorationsOverlay(this._context));\r\n\t\tmarginViewOverlays.addDynamicOverlay(new LineNumbersOverlay(this._context));\r\n\r\n\t\tconst margin = new Margin(this._context);\r\n\t\tmargin.getDomNode().appendChild(this._viewZones.marginDomNode);\r\n\t\tmargin.getDomNode().appendChild(marginViewOverlays.getDomNode());\r\n\t\tthis._viewParts.push(margin);\r\n\r\n\t\t// Content widgets\r\n\t\tthis._contentWidgets = new ViewContentWidgets(this._context, this.domNode);\r\n\t\tthis._viewParts.push(this._contentWidgets);\r\n\r\n\t\tthis._viewCursors = new ViewCursors(this._context);\r\n\t\tthis._viewParts.push(this._viewCursors);\r\n\r\n\t\t// Overlay widgets\r\n\t\tthis._overlayWidgets = new ViewOverlayWidgets(this._context);\r\n\t\tthis._viewParts.push(this._overlayWidgets);\r\n\r\n\t\tconst rulers = new Rulers(this._context);\r\n\t\tthis._viewParts.push(rulers);\r\n\r\n\t\tconst minimap = new Minimap(this._context);\r\n\t\tthis._viewParts.push(minimap);\r\n\r\n\t\t// -------------- Wire dom nodes up\r\n\r\n\t\tif (decorationsOverviewRuler) {\r\n\t\t\tconst overviewRulerData = this._scrollbar.getOverviewRulerLayoutInfo();\r\n\t\t\toverviewRulerData.parent.insertBefore(decorationsOverviewRuler.getDomNode(), overviewRulerData.insertBefore);\r\n\t\t}\r\n\r\n\t\tthis._linesContent.appendChild(contentViewOverlays.getDomNode());\r\n\t\tthis._linesContent.appendChild(rulers.domNode);\r\n\t\tthis._linesContent.appendChild(this._viewZones.domNode);\r\n\t\tthis._linesContent.appendChild(this._viewLines.getDomNode());\r\n\t\tthis._linesContent.appendChild(this._contentWidgets.domNode);\r\n\t\tthis._linesContent.appendChild(this._viewCursors.getDomNode());\r\n\t\tthis._overflowGuardContainer.appendChild(margin.getDomNode());\r\n\t\tthis._overflowGuardContainer.appendChild(this._scrollbar.getDomNode());\r\n\t\tthis._overflowGuardContainer.appendChild(scrollDecoration.getDomNode());\r\n\t\tthis._overflowGuardContainer.appendChild(this._textAreaHandler.textArea);\r\n\t\tthis._overflowGuardContainer.appendChild(this._textAreaHandler.textAreaCover);\r\n\t\tthis._overflowGuardContainer.appendChild(this._overlayWidgets.getDomNode());\r\n\t\tthis._overflowGuardContainer.appendChild(minimap.getDomNode());\r\n\t\tthis.domNode.appendChild(this._overflowGuardContainer);\r\n\r\n\t\tif (overflowWidgetsDomNode) {\r\n\t\t\toverflowWidgetsDomNode.appendChild(this._contentWidgets.overflowingContentWidgetsDomNode.domNode);\r\n\t\t} else {\r\n\t\t\tthis.domNode.appendChild(this._contentWidgets.overflowingContentWidgetsDomNode);\r\n\t\t}\r\n\r\n\t\tthis._applyLayout();\r\n\r\n\t\t// Pointer handler\r\n\t\tthis._pointerHandler = this._register(new PointerHandler(this._context, viewController, this._createPointerHandlerHelper()));\r\n\t}\r\n\r\n\tprivate _flushAccumulatedAndRenderNow(): void {\r\n\t\tthis._renderNow();\r\n\t}\r\n\r\n\tprivate _createPointerHandlerHelper(): IPointerHandlerHelper {\r\n\t\treturn {\r\n\t\t\tviewDomNode: this.domNode.domNode,\r\n\t\t\tlinesContentDomNode: this._linesContent.domNode,\r\n\r\n\t\t\tfocusTextArea: () => {\r\n\t\t\t\tthis.focus();\r\n\t\t\t},\r\n\r\n\t\t\tgetLastRenderData: (): PointerHandlerLastRenderData => {\r\n\t\t\t\tconst lastViewCursorsRenderData = this._viewCursors.getLastRenderData() || [];\r\n\t\t\t\tconst lastTextareaPosition = this._textAreaHandler.getLastRenderData();\r\n\t\t\t\treturn new PointerHandlerLastRenderData(lastViewCursorsRenderData, lastTextareaPosition);\r\n\t\t\t},\r\n\t\t\tshouldSuppressMouseDownOnViewZone: (viewZoneId: string) => {\r\n\t\t\t\treturn this._viewZones.shouldSuppressMouseDownOnViewZone(viewZoneId);\r\n\t\t\t},\r\n\t\t\tshouldSuppressMouseDownOnWidget: (widgetId: string) => {\r\n\t\t\t\treturn this._contentWidgets.shouldSuppressMouseDownOnWidget(widgetId);\r\n\t\t\t},\r\n\t\t\tgetPositionFromDOMInfo: (spanNode: HTMLElement, offset: number) => {\r\n\t\t\t\tthis._flushAccumulatedAndRenderNow();\r\n\t\t\t\treturn this._viewLines.getPositionFromDOMInfo(spanNode, offset);\r\n\t\t\t},\r\n\r\n\t\t\tvisibleRangeForPosition: (lineNumber: number, column: number) => {\r\n\t\t\t\tthis._flushAccumulatedAndRenderNow();\r\n\t\t\t\treturn this._viewLines.visibleRangeForPosition(new Position(lineNumber, column));\r\n\t\t\t},\r\n\r\n\t\t\tgetLineWidth: (lineNumber: number) => {\r\n\t\t\t\tthis._flushAccumulatedAndRenderNow();\r\n\t\t\t\treturn this._viewLines.getLineWidth(lineNumber);\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\tprivate _createTextAreaHandlerHelper(): ITextAreaHandlerHelper {\r\n\t\treturn {\r\n\t\t\tvisibleRangeForPositionRelativeToEditor: (lineNumber: number, column: number) => {\r\n\t\t\t\tthis._flushAccumulatedAndRenderNow();\r\n\t\t\t\treturn this._viewLines.visibleRangeForPosition(new Position(lineNumber, column));\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\tprivate _applyLayout(): void {\r\n\t\tconst options = this._context.configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\r\n\t\tthis.domNode.setWidth(layoutInfo.width);\r\n\t\tthis.domNode.setHeight(layoutInfo.height);\r\n\r\n\t\tthis._overflowGuardContainer.setWidth(layoutInfo.width);\r\n\t\tthis._overflowGuardContainer.setHeight(layoutInfo.height);\r\n\r\n\t\tthis._linesContent.setWidth(1000000);\r\n\t\tthis._linesContent.setHeight(1000000);\r\n\t}\r\n\r\n\tprivate _getEditorClassName() {\r\n\t\tconst focused = this._textAreaHandler.isFocused() ? ' focused' : '';\r\n\t\treturn this._context.configuration.options.get(EditorOption.editorClassName) + ' ' + getThemeTypeSelector(this._context.theme.type) + focused;\r\n\t}\r\n\r\n\t// --- begin event handlers\r\n\tpublic handleEvents(events: viewEvents.ViewEvent[]): void {\r\n\t\tsuper.handleEvents(events);\r\n\t\tthis._scheduleRender();\r\n\t}\r\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\r\n\t\tthis._configPixelRatio = this._context.configuration.options.get(EditorOption.pixelRatio);\r\n\t\tthis.domNode.setClassName(this._getEditorClassName());\r\n\t\tthis._applyLayout();\r\n\t\treturn false;\r\n\t}\r\n\tpublic onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {\r\n\t\tthis._selections = e.selections;\r\n\t\treturn false;\r\n\t}\r\n\tpublic onFocusChanged(e: viewEvents.ViewFocusChangedEvent): boolean {\r\n\t\tthis.domNode.setClassName(this._getEditorClassName());\r\n\t\treturn false;\r\n\t}\r\n\tpublic onThemeChanged(e: viewEvents.ViewThemeChangedEvent): boolean {\r\n\t\tthis.domNode.setClassName(this._getEditorClassName());\r\n\t\treturn false;\r\n\t}\r\n\r\n\t// --- end event handlers\r\n\r\n\tpublic dispose(): void {\r\n\t\tif (this._renderAnimationFrame !== null) {\r\n\t\t\tthis._renderAnimationFrame.dispose();\r\n\t\t\tthis._renderAnimationFrame = null;\r\n\t\t}\r\n\r\n\t\tthis._contentWidgets.overflowingContentWidgetsDomNode.domNode.remove();\r\n\r\n\t\tthis._context.removeEventHandler(this);\r\n\r\n\t\tthis._viewLines.dispose();\r\n\r\n\t\t// Destroy view parts\r\n\t\tfor (const viewPart of this._viewParts) {\r\n\t\t\tviewPart.dispose();\r\n\t\t}\r\n\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tprivate _scheduleRender(): void {\r\n\t\tif (this._renderAnimationFrame === null) {\r\n\t\t\tthis._renderAnimationFrame = dom.runAtThisOrScheduleAtNextAnimationFrame(this._onRenderScheduled.bind(this), 100);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _onRenderScheduled(): void {\r\n\t\tthis._renderAnimationFrame = null;\r\n\t\tthis._flushAccumulatedAndRenderNow();\r\n\t}\r\n\r\n\tprivate _renderNow(): void {\r\n\t\tsafeInvokeNoArg(() => this._actualRender());\r\n\t}\r\n\r\n\tprivate _getViewPartsToRender(): ViewPart[] {\r\n\t\tlet result: ViewPart[] = [], resultLen = 0;\r\n\t\tfor (const viewPart of this._viewParts) {\r\n\t\t\tif (viewPart.shouldRender()) {\r\n\t\t\t\tresult[resultLen++] = viewPart;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate _actualRender(): void {\r\n\t\tif (!dom.isInDOM(this.domNode.domNode)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet viewPartsToRender = this._getViewPartsToRender();\r\n\r\n\t\tif (!this._viewLines.shouldRender() && viewPartsToRender.length === 0) {\r\n\t\t\t// Nothing to render\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst partialViewportData = this._context.viewLayout.getLinesViewportData();\r\n\t\tthis._context.model.setViewport(partialViewportData.startLineNumber, partialViewportData.endLineNumber, partialViewportData.centeredLineNumber);\r\n\r\n\t\tconst viewportData = new ViewportData(\r\n\t\t\tthis._selections,\r\n\t\t\tpartialViewportData,\r\n\t\t\tthis._context.viewLayout.getWhitespaceViewportData(),\r\n\t\t\tthis._context.model\r\n\t\t);\r\n\r\n\t\tif (this._contentWidgets.shouldRender()) {\r\n\t\t\t// Give the content widgets a chance to set their max width before a possible synchronous layout\r\n\t\t\tthis._contentWidgets.onBeforeRender(viewportData);\r\n\t\t}\r\n\r\n\t\tif (this._viewLines.shouldRender()) {\r\n\t\t\tthis._viewLines.renderText(viewportData);\r\n\t\t\tthis._viewLines.onDidRender();\r\n\r\n\t\t\t// Rendering of viewLines might cause scroll events to occur, so collect view parts to render again\r\n\t\t\tviewPartsToRender = this._getViewPartsToRender();\r\n\t\t}\r\n\r\n\t\tconst renderingContext = new RenderingContext(this._context.viewLayout, viewportData, this._viewLines);\r\n\r\n\t\t// Render the rest of the parts\r\n\t\tfor (const viewPart of viewPartsToRender) {\r\n\t\t\tviewPart.prepareRender(renderingContext);\r\n\t\t}\r\n\r\n\t\tfor (const viewPart of viewPartsToRender) {\r\n\t\t\tviewPart.render(renderingContext);\r\n\t\t\tviewPart.onDidRender();\r\n\t\t}\r\n\r\n\t\t// Try to detect browser zooming and paint again if necessary\r\n\t\tif (Math.abs(browser.getPixelRatio() - this._configPixelRatio) > 0.001) {\r\n\t\t\t// looks like the pixel ratio has changed\r\n\t\t\tthis._context.configuration.updatePixelRatio();\r\n\t\t}\r\n\t}\r\n\r\n\t// --- BEGIN CodeEditor helpers\r\n\r\n\tpublic delegateVerticalScrollbarMouseDown(browserEvent: IMouseEvent): void {\r\n\t\tthis._scrollbar.delegateVerticalScrollbarMouseDown(browserEvent);\r\n\t}\r\n\r\n\tpublic restoreState(scrollPosition: { scrollLeft: number; scrollTop: number; }): void {\r\n\t\tthis._context.model.setScrollPosition({ scrollTop: scrollPosition.scrollTop }, ScrollType.Immediate);\r\n\t\tthis._context.model.tokenizeViewport();\r\n\t\tthis._renderNow();\r\n\t\tthis._viewLines.updateLineWidths();\r\n\t\tthis._context.model.setScrollPosition({ scrollLeft: scrollPosition.scrollLeft }, ScrollType.Immediate);\r\n\t}\r\n\r\n\tpublic getOffsetForColumn(modelLineNumber: number, modelColumn: number): number {\r\n\t\tconst modelPosition = this._context.model.validateModelPosition({\r\n\t\t\tlineNumber: modelLineNumber,\r\n\t\t\tcolumn: modelColumn\r\n\t\t});\r\n\t\tconst viewPosition = this._context.model.coordinatesConverter.convertModelPositionToViewPosition(modelPosition);\r\n\t\tthis._flushAccumulatedAndRenderNow();\r\n\t\tconst visibleRange = this._viewLines.visibleRangeForPosition(new Position(viewPosition.lineNumber, viewPosition.column));\r\n\t\tif (!visibleRange) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\treturn visibleRange.left;\r\n\t}\r\n\r\n\tpublic getTargetAtClientPoint(clientX: number, clientY: number): IMouseTarget | null {\r\n\t\tconst mouseTarget = this._pointerHandler.getTargetAtClientPoint(clientX, clientY);\r\n\t\tif (!mouseTarget) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn ViewUserInputEvents.convertViewToModelMouseTarget(mouseTarget, this._context.model.coordinatesConverter);\r\n\t}\r\n\r\n\tpublic createOverviewRuler(cssClassName: string): OverviewRuler {\r\n\t\treturn new OverviewRuler(this._context, cssClassName);\r\n\t}\r\n\r\n\tpublic change(callback: (changeAccessor: IViewZoneChangeAccessor) => any): void {\r\n\t\tthis._viewZones.changeViewZones(callback);\r\n\t\tthis._scheduleRender();\r\n\t}\r\n\r\n\tpublic render(now: boolean, everything: boolean): void {\r\n\t\tif (everything) {\r\n\t\t\t// Force everything to render...\r\n\t\t\tthis._viewLines.forceShouldRender();\r\n\t\t\tfor (const viewPart of this._viewParts) {\r\n\t\t\t\tviewPart.forceShouldRender();\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (now) {\r\n\t\t\tthis._flushAccumulatedAndRenderNow();\r\n\t\t} else {\r\n\t\t\tthis._scheduleRender();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic focus(): void {\r\n\t\tthis._textAreaHandler.focusTextArea();\r\n\t}\r\n\r\n\tpublic isFocused(): boolean {\r\n\t\treturn this._textAreaHandler.isFocused();\r\n\t}\r\n\r\n\tpublic setAriaOptions(options: IEditorAriaOptions): void {\r\n\t\tthis._textAreaHandler.setAriaOptions(options);\r\n\t}\r\n\r\n\tpublic addContentWidget(widgetData: IContentWidgetData): void {\r\n\t\tthis._contentWidgets.addWidget(widgetData.widget);\r\n\t\tthis.layoutContentWidget(widgetData);\r\n\t\tthis._scheduleRender();\r\n\t}\r\n\r\n\tpublic layoutContentWidget(widgetData: IContentWidgetData): void {\r\n\t\tlet newRange = widgetData.position ? widgetData.position.range || null : null;\r\n\t\tif (newRange === null) {\r\n\t\t\tconst newPosition = widgetData.position ? widgetData.position.position : null;\r\n\t\t\tif (newPosition !== null) {\r\n\t\t\t\tnewRange = new Range(newPosition.lineNumber, newPosition.column, newPosition.lineNumber, newPosition.column);\r\n\t\t\t}\r\n\t\t}\r\n\t\tconst newPreference = widgetData.position ? widgetData.position.preference : null;\r\n\t\tthis._contentWidgets.setWidgetPosition(widgetData.widget, newRange, newPreference);\r\n\t\tthis._scheduleRender();\r\n\t}\r\n\r\n\tpublic removeContentWidget(widgetData: IContentWidgetData): void {\r\n\t\tthis._contentWidgets.removeWidget(widgetData.widget);\r\n\t\tthis._scheduleRender();\r\n\t}\r\n\r\n\tpublic addOverlayWidget(widgetData: IOverlayWidgetData): void {\r\n\t\tthis._overlayWidgets.addWidget(widgetData.widget);\r\n\t\tthis.layoutOverlayWidget(widgetData);\r\n\t\tthis._scheduleRender();\r\n\t}\r\n\r\n\tpublic layoutOverlayWidget(widgetData: IOverlayWidgetData): void {\r\n\t\tconst newPreference = widgetData.position ? widgetData.position.preference : null;\r\n\t\tconst shouldRender = this._overlayWidgets.setWidgetPosition(widgetData.widget, newPreference);\r\n\t\tif (shouldRender) {\r\n\t\t\tthis._scheduleRender();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic removeOverlayWidget(widgetData: IOverlayWidgetData): void {\r\n\t\tthis._overlayWidgets.removeWidget(widgetData.widget);\r\n\t\tthis._scheduleRender();\r\n\t}\r\n\r\n\t// --- END CodeEditor helpers\r\n\r\n}\r\n\r\nfunction safeInvokeNoArg(func: Function): any {\r\n\ttry {\r\n\t\treturn func();\r\n\t} catch (e) {\r\n\t\tonUnexpectedError(e);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./media/editor';\r\nimport * as nls from 'vs/nls';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { IMouseEvent, IMouseWheelEvent } from 'vs/base/browser/mouseEvent';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';\r\nimport { Schemas } from 'vs/base/common/network';\r\nimport { Configuration } from 'vs/editor/browser/config/configuration';\r\nimport * as editorBrowser from 'vs/editor/browser/editorBrowser';\r\nimport { EditorExtensionsRegistry, IEditorContributionDescription } from 'vs/editor/browser/editorExtensions';\r\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\r\nimport { ICommandDelegate } from 'vs/editor/browser/view/viewController';\r\nimport { IContentWidgetData, IOverlayWidgetData, View } from 'vs/editor/browser/view/viewImpl';\r\nimport { ViewUserInputEvents } from 'vs/editor/browser/view/viewUserInputEvents';\r\nimport { ConfigurationChangedEvent, EditorLayoutInfo, IEditorOptions, EditorOption, IComputedEditorOptions, FindComputedEditorOptionValueById, filterValidationDecorations } from 'vs/editor/common/config/editorOptions';\r\nimport { Cursor } from 'vs/editor/common/controller/cursor';\r\nimport { CursorColumns } from 'vs/editor/common/controller/cursorCommon';\r\nimport { CursorChangeReason, ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';\r\nimport { IPosition, Position } from 'vs/editor/common/core/position';\r\nimport { IRange, Range } from 'vs/editor/common/core/range';\r\nimport { ISelection, Selection } from 'vs/editor/common/core/selection';\r\nimport { InternalEditorAction } from 'vs/editor/common/editorAction';\r\nimport * as editorCommon from 'vs/editor/common/editorCommon';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { EndOfLinePreference, IIdentifiedSingleEditOperation, IModelDecoration, IModelDecorationsChangeAccessor, IModelDeltaDecoration, ITextModel, ICursorStateComputer, IWordAtPosition } from 'vs/editor/common/model';\r\nimport { ClassName } from 'vs/editor/common/model/intervalTree';\r\nimport { IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelLanguageConfigurationChangedEvent, IModelOptionsChangedEvent } from 'vs/editor/common/model/textModelEvents';\r\nimport * as modes from 'vs/editor/common/modes';\r\nimport { editorUnnecessaryCodeBorder, editorUnnecessaryCodeOpacity } from 'vs/editor/common/view/editorColorRegistry';\r\nimport { editorErrorBorder, editorErrorForeground, editorHintBorder, editorHintForeground, editorInfoBorder, editorInfoForeground, editorWarningBorder, editorWarningForeground, editorForeground, editorErrorBackground, editorInfoBackground, editorWarningBackground } from 'vs/platform/theme/common/colorRegistry';\r\nimport { VerticalRevealType } from 'vs/editor/common/view/viewEvents';\r\nimport { IEditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout';\r\nimport { ViewModel } from 'vs/editor/common/viewModel/viewModelImpl';\r\nimport { ICommandService } from 'vs/platform/commands/common/commands';\r\nimport { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';\r\nimport { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';\r\nimport { INotificationService } from 'vs/platform/notification/common/notification';\r\nimport { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';\r\nimport { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';\r\nimport { withNullAsUndefined } from 'vs/base/common/types';\r\nimport { MonospaceLineBreaksComputerFactory } from 'vs/editor/common/viewModel/monospaceLineBreaksComputer';\r\nimport { DOMLineBreaksComputerFactory } from 'vs/editor/browser/view/domLineBreaksComputer';\r\nimport { WordOperations } from 'vs/editor/common/controller/cursorWordOperations';\r\nimport { IViewModel } from 'vs/editor/common/viewModel/viewModel';\r\nimport { OutgoingViewModelEventKind } from 'vs/editor/common/viewModel/viewModelEventDispatcher';\r\n\r\nlet EDITOR_ID = 0;\r\n\r\nexport interface ICodeEditorWidgetOptions {\r\n\t/**\r\n\t * Is this a simple widget (not a real code editor) ?\r\n\t * Defaults to false.\r\n\t */\r\n\tisSimpleWidget?: boolean;\r\n\r\n\t/**\r\n\t * Contributions to instantiate.\r\n\t * Defaults to EditorExtensionsRegistry.getEditorContributions().\r\n\t */\r\n\tcontributions?: IEditorContributionDescription[];\r\n\r\n\t/**\r\n\t * Telemetry data associated with this CodeEditorWidget.\r\n\t * Defaults to null.\r\n\t */\r\n\ttelemetryData?: object;\r\n}\r\n\r\nclass ModelData {\r\n\tpublic readonly model: ITextModel;\r\n\tpublic readonly viewModel: ViewModel;\r\n\tpublic readonly view: View;\r\n\tpublic readonly hasRealView: boolean;\r\n\tpublic readonly listenersToRemove: IDisposable[];\r\n\r\n\tconstructor(model: ITextModel, viewModel: ViewModel, view: View, hasRealView: boolean, listenersToRemove: IDisposable[]) {\r\n\t\tthis.model = model;\r\n\t\tthis.viewModel = viewModel;\r\n\t\tthis.view = view;\r\n\t\tthis.hasRealView = hasRealView;\r\n\t\tthis.listenersToRemove = listenersToRemove;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tdispose(this.listenersToRemove);\r\n\t\tthis.model.onBeforeDetached();\r\n\t\tif (this.hasRealView) {\r\n\t\t\tthis.view.dispose();\r\n\t\t}\r\n\t\tthis.viewModel.dispose();\r\n\t}\r\n}\r\n\r\nexport class CodeEditorWidget extends Disposable implements editorBrowser.ICodeEditor {\r\n\r\n\t//#region Eventing\r\n\tprivate readonly _onDidDispose: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidDispose: Event = this._onDidDispose.event;\r\n\r\n\tprivate readonly _onDidChangeModelContent: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidChangeModelContent: Event = this._onDidChangeModelContent.event;\r\n\r\n\tprivate readonly _onDidChangeModelLanguage: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidChangeModelLanguage: Event = this._onDidChangeModelLanguage.event;\r\n\r\n\tprivate readonly _onDidChangeModelLanguageConfiguration: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidChangeModelLanguageConfiguration: Event = this._onDidChangeModelLanguageConfiguration.event;\r\n\r\n\tprivate readonly _onDidChangeModelOptions: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidChangeModelOptions: Event = this._onDidChangeModelOptions.event;\r\n\r\n\tprivate readonly _onDidChangeModelDecorations: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidChangeModelDecorations: Event = this._onDidChangeModelDecorations.event;\r\n\r\n\tprivate readonly _onDidChangeConfiguration: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event;\r\n\r\n\tprotected readonly _onDidChangeModel: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidChangeModel: Event = this._onDidChangeModel.event;\r\n\r\n\tprivate readonly _onDidChangeCursorPosition: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidChangeCursorPosition: Event = this._onDidChangeCursorPosition.event;\r\n\r\n\tprivate readonly _onDidChangeCursorSelection: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidChangeCursorSelection: Event = this._onDidChangeCursorSelection.event;\r\n\r\n\tprivate readonly _onDidAttemptReadOnlyEdit: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidAttemptReadOnlyEdit: Event = this._onDidAttemptReadOnlyEdit.event;\r\n\r\n\tprivate readonly _onDidLayoutChange: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidLayoutChange: Event = this._onDidLayoutChange.event;\r\n\r\n\tprivate readonly _editorTextFocus: BooleanEventEmitter = this._register(new BooleanEventEmitter());\r\n\tpublic readonly onDidFocusEditorText: Event = this._editorTextFocus.onDidChangeToTrue;\r\n\tpublic readonly onDidBlurEditorText: Event = this._editorTextFocus.onDidChangeToFalse;\r\n\r\n\tprivate readonly _editorWidgetFocus: BooleanEventEmitter = this._register(new BooleanEventEmitter());\r\n\tpublic readonly onDidFocusEditorWidget: Event = this._editorWidgetFocus.onDidChangeToTrue;\r\n\tpublic readonly onDidBlurEditorWidget: Event = this._editorWidgetFocus.onDidChangeToFalse;\r\n\r\n\tprivate readonly _onWillType: Emitter = this._register(new Emitter());\r\n\tpublic readonly onWillType = this._onWillType.event;\r\n\r\n\tprivate readonly _onDidType: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidType = this._onDidType.event;\r\n\r\n\tprivate readonly _onDidCompositionStart: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidCompositionStart = this._onDidCompositionStart.event;\r\n\r\n\tprivate readonly _onDidCompositionEnd: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidCompositionEnd = this._onDidCompositionEnd.event;\r\n\r\n\tprivate readonly _onDidPaste: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidPaste = this._onDidPaste.event;\r\n\r\n\tprivate readonly _onMouseUp: Emitter = this._register(new Emitter());\r\n\tpublic readonly onMouseUp: Event = this._onMouseUp.event;\r\n\r\n\tprivate readonly _onMouseDown: Emitter = this._register(new Emitter());\r\n\tpublic readonly onMouseDown: Event = this._onMouseDown.event;\r\n\r\n\tprivate readonly _onMouseDrag: Emitter = this._register(new Emitter());\r\n\tpublic readonly onMouseDrag: Event = this._onMouseDrag.event;\r\n\r\n\tprivate readonly _onMouseDrop: Emitter = this._register(new Emitter());\r\n\tpublic readonly onMouseDrop: Event = this._onMouseDrop.event;\r\n\r\n\tprivate readonly _onMouseDropCanceled: Emitter = this._register(new Emitter());\r\n\tpublic readonly onMouseDropCanceled: Event = this._onMouseDropCanceled.event;\r\n\r\n\tprivate readonly _onContextMenu: Emitter = this._register(new Emitter());\r\n\tpublic readonly onContextMenu: Event = this._onContextMenu.event;\r\n\r\n\tprivate readonly _onMouseMove: Emitter = this._register(new Emitter());\r\n\tpublic readonly onMouseMove: Event = this._onMouseMove.event;\r\n\r\n\tprivate readonly _onMouseLeave: Emitter = this._register(new Emitter());\r\n\tpublic readonly onMouseLeave: Event = this._onMouseLeave.event;\r\n\r\n\tprivate readonly _onMouseWheel: Emitter = this._register(new Emitter());\r\n\tpublic readonly onMouseWheel: Event = this._onMouseWheel.event;\r\n\r\n\tprivate readonly _onKeyUp: Emitter = this._register(new Emitter());\r\n\tpublic readonly onKeyUp: Event = this._onKeyUp.event;\r\n\r\n\tprivate readonly _onKeyDown: Emitter = this._register(new Emitter());\r\n\tpublic readonly onKeyDown: Event = this._onKeyDown.event;\r\n\r\n\tprivate readonly _onDidContentSizeChange: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidContentSizeChange: Event = this._onDidContentSizeChange.event;\r\n\r\n\tprivate readonly _onDidScrollChange: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidScrollChange: Event = this._onDidScrollChange.event;\r\n\r\n\tprivate readonly _onDidChangeViewZones: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidChangeViewZones: Event = this._onDidChangeViewZones.event;\r\n\t//#endregion\r\n\r\n\tpublic readonly isSimpleWidget: boolean;\r\n\tprivate readonly _telemetryData?: object;\r\n\r\n\tprivate readonly _domElement: HTMLElement;\r\n\tprivate readonly _overflowWidgetsDomNode: HTMLElement | undefined;\r\n\tprivate readonly _id: number;\r\n\tprivate readonly _configuration: editorCommon.IConfiguration;\r\n\r\n\tprotected readonly _contributions: { [key: string]: editorCommon.IEditorContribution; };\r\n\tprotected readonly _actions: { [key: string]: editorCommon.IEditorAction; };\r\n\r\n\t// --- Members logically associated to a model\r\n\tprotected _modelData: ModelData | null;\r\n\r\n\tprotected readonly _instantiationService: IInstantiationService;\r\n\tprotected readonly _contextKeyService: IContextKeyService;\r\n\tprivate readonly _notificationService: INotificationService;\r\n\tprivate readonly _codeEditorService: ICodeEditorService;\r\n\tprivate readonly _commandService: ICommandService;\r\n\tprivate readonly _themeService: IThemeService;\r\n\r\n\tprivate readonly _focusTracker: CodeEditorWidgetFocusTracker;\r\n\r\n\tprivate readonly _contentWidgets: { [key: string]: IContentWidgetData; };\r\n\tprivate readonly _overlayWidgets: { [key: string]: IOverlayWidgetData; };\r\n\r\n\t/**\r\n\t * map from \"parent\" decoration type to live decoration ids.\r\n\t */\r\n\tprivate _decorationTypeKeysToIds: { [decorationTypeKey: string]: string[] };\r\n\tprivate _decorationTypeSubtypes: { [decorationTypeKey: string]: { [subtype: string]: boolean } };\r\n\r\n\tconstructor(\r\n\t\tdomElement: HTMLElement,\r\n\t\t_options: Readonly,\r\n\t\tcodeEditorWidgetOptions: ICodeEditorWidgetOptions,\r\n\t\t@IInstantiationService instantiationService: IInstantiationService,\r\n\t\t@ICodeEditorService codeEditorService: ICodeEditorService,\r\n\t\t@ICommandService commandService: ICommandService,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\r\n\t\t@IThemeService themeService: IThemeService,\r\n\t\t@INotificationService notificationService: INotificationService,\r\n\t\t@IAccessibilityService accessibilityService: IAccessibilityService\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\tconst options = { ..._options };\r\n\r\n\t\tthis._domElement = domElement;\r\n\t\tthis._overflowWidgetsDomNode = options.overflowWidgetsDomNode;\r\n\t\tdelete options.overflowWidgetsDomNode;\r\n\t\tthis._id = (++EDITOR_ID);\r\n\t\tthis._decorationTypeKeysToIds = {};\r\n\t\tthis._decorationTypeSubtypes = {};\r\n\t\tthis.isSimpleWidget = codeEditorWidgetOptions.isSimpleWidget || false;\r\n\t\tthis._telemetryData = codeEditorWidgetOptions.telemetryData;\r\n\r\n\t\tthis._configuration = this._register(this._createConfiguration(options, accessibilityService));\r\n\t\tthis._register(this._configuration.onDidChange((e) => {\r\n\t\t\tthis._onDidChangeConfiguration.fire(e);\r\n\r\n\t\t\tconst options = this._configuration.options;\r\n\t\t\tif (e.hasChanged(EditorOption.layoutInfo)) {\r\n\t\t\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\t\t\t\tthis._onDidLayoutChange.fire(layoutInfo);\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._contextKeyService = this._register(contextKeyService.createScoped(this._domElement));\r\n\t\tthis._notificationService = notificationService;\r\n\t\tthis._codeEditorService = codeEditorService;\r\n\t\tthis._commandService = commandService;\r\n\t\tthis._themeService = themeService;\r\n\t\tthis._register(new EditorContextKeysManager(this, this._contextKeyService));\r\n\t\tthis._register(new EditorModeContext(this, this._contextKeyService));\r\n\r\n\t\tthis._instantiationService = instantiationService.createChild(new ServiceCollection([IContextKeyService, this._contextKeyService]));\r\n\r\n\t\tthis._modelData = null;\r\n\r\n\t\tthis._contributions = {};\r\n\t\tthis._actions = {};\r\n\r\n\t\tthis._focusTracker = new CodeEditorWidgetFocusTracker(domElement);\r\n\t\tthis._focusTracker.onChange(() => {\r\n\t\t\tthis._editorWidgetFocus.setValue(this._focusTracker.hasFocus());\r\n\t\t});\r\n\r\n\t\tthis._contentWidgets = {};\r\n\t\tthis._overlayWidgets = {};\r\n\r\n\t\tlet contributions: IEditorContributionDescription[];\r\n\t\tif (Array.isArray(codeEditorWidgetOptions.contributions)) {\r\n\t\t\tcontributions = codeEditorWidgetOptions.contributions;\r\n\t\t} else {\r\n\t\t\tcontributions = EditorExtensionsRegistry.getEditorContributions();\r\n\t\t}\r\n\t\tfor (const desc of contributions) {\r\n\t\t\ttry {\r\n\t\t\t\tconst contribution = this._instantiationService.createInstance(desc.ctor, this);\r\n\t\t\t\tthis._contributions[desc.id] = contribution;\r\n\t\t\t} catch (err) {\r\n\t\t\t\tonUnexpectedError(err);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tEditorExtensionsRegistry.getEditorActions().forEach((action) => {\r\n\t\t\tconst internalAction = new InternalEditorAction(\r\n\t\t\t\taction.id,\r\n\t\t\t\taction.label,\r\n\t\t\t\taction.alias,\r\n\t\t\t\twithNullAsUndefined(action.precondition),\r\n\t\t\t\t(): Promise => {\r\n\t\t\t\t\treturn this._instantiationService.invokeFunction((accessor) => {\r\n\t\t\t\t\t\treturn Promise.resolve(action.runEditorCommand(accessor, this, null));\r\n\t\t\t\t\t});\r\n\t\t\t\t},\r\n\t\t\t\tthis._contextKeyService\r\n\t\t\t);\r\n\t\t\tthis._actions[internalAction.id] = internalAction;\r\n\t\t});\r\n\r\n\t\tthis._codeEditorService.addCodeEditor(this);\r\n\t}\r\n\r\n\tprotected _createConfiguration(options: Readonly, accessibilityService: IAccessibilityService): editorCommon.IConfiguration {\r\n\t\treturn new Configuration(this.isSimpleWidget, options, this._domElement, accessibilityService);\r\n\t}\r\n\r\n\tpublic getId(): string {\r\n\t\treturn this.getEditorType() + ':' + this._id;\r\n\t}\r\n\r\n\tpublic getEditorType(): string {\r\n\t\treturn editorCommon.EditorType.ICodeEditor;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._codeEditorService.removeCodeEditor(this);\r\n\r\n\t\tthis._focusTracker.dispose();\r\n\r\n\t\tconst keys = Object.keys(this._contributions);\r\n\t\tfor (let i = 0, len = keys.length; i < len; i++) {\r\n\t\t\tconst contributionId = keys[i];\r\n\t\t\tthis._contributions[contributionId].dispose();\r\n\t\t}\r\n\r\n\t\tthis._removeDecorationTypes();\r\n\t\tthis._postDetachModelCleanup(this._detachModel());\r\n\r\n\t\tthis._onDidDispose.fire();\r\n\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tpublic invokeWithinContext(fn: (accessor: ServicesAccessor) => T): T {\r\n\t\treturn this._instantiationService.invokeFunction(fn);\r\n\t}\r\n\r\n\tpublic updateOptions(newOptions: Readonly): void {\r\n\t\tthis._configuration.updateOptions(newOptions);\r\n\t}\r\n\r\n\tpublic getOptions(): IComputedEditorOptions {\r\n\t\treturn this._configuration.options;\r\n\t}\r\n\r\n\tpublic getOption(id: T): FindComputedEditorOptionValueById {\r\n\t\treturn this._configuration.options.get(id);\r\n\t}\r\n\r\n\tpublic getRawOptions(): IEditorOptions {\r\n\t\treturn this._configuration.getRawOptions();\r\n\t}\r\n\r\n\tpublic getOverflowWidgetsDomNode(): HTMLElement | undefined {\r\n\t\treturn this._overflowWidgetsDomNode;\r\n\t}\r\n\r\n\tpublic getConfiguredWordAtPosition(position: Position): IWordAtPosition | null {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn WordOperations.getWordAtPosition(this._modelData.model, this._configuration.options.get(EditorOption.wordSeparators), position);\r\n\t}\r\n\r\n\tpublic getValue(options: { preserveBOM: boolean; lineEnding: string; } | null = null): string {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\r\n\t\tconst preserveBOM: boolean = (options && options.preserveBOM) ? true : false;\r\n\t\tlet eolPreference = EndOfLinePreference.TextDefined;\r\n\t\tif (options && options.lineEnding && options.lineEnding === '\\n') {\r\n\t\t\teolPreference = EndOfLinePreference.LF;\r\n\t\t} else if (options && options.lineEnding && options.lineEnding === '\\r\\n') {\r\n\t\t\teolPreference = EndOfLinePreference.CRLF;\r\n\t\t}\r\n\t\treturn this._modelData.model.getValue(eolPreference, preserveBOM);\r\n\t}\r\n\r\n\tpublic setValue(newValue: string): void {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._modelData.model.setValue(newValue);\r\n\t}\r\n\r\n\tpublic getModel(): ITextModel | null {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn this._modelData.model;\r\n\t}\r\n\r\n\tpublic setModel(_model: ITextModel | editorCommon.IDiffEditorModel | null = null): void {\r\n\t\tconst model = _model;\r\n\t\tif (this._modelData === null && model === null) {\r\n\t\t\t// Current model is the new model\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (this._modelData && this._modelData.model === model) {\r\n\t\t\t// Current model is the new model\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst hasTextFocus = this.hasTextFocus();\r\n\t\tconst detachedModel = this._detachModel();\r\n\t\tthis._attachModel(model);\r\n\t\tif (hasTextFocus && this.hasModel()) {\r\n\t\t\tthis.focus();\r\n\t\t}\r\n\r\n\t\tconst e: editorCommon.IModelChangedEvent = {\r\n\t\t\toldModelUrl: detachedModel ? detachedModel.uri : null,\r\n\t\t\tnewModelUrl: model ? model.uri : null\r\n\t\t};\r\n\r\n\t\tthis._removeDecorationTypes();\r\n\t\tthis._onDidChangeModel.fire(e);\r\n\t\tthis._postDetachModelCleanup(detachedModel);\r\n\t}\r\n\r\n\tprivate _removeDecorationTypes(): void {\r\n\t\tthis._decorationTypeKeysToIds = {};\r\n\t\tif (this._decorationTypeSubtypes) {\r\n\t\t\tfor (let decorationType in this._decorationTypeSubtypes) {\r\n\t\t\t\tconst subTypes = this._decorationTypeSubtypes[decorationType];\r\n\t\t\t\tfor (let subType in subTypes) {\r\n\t\t\t\t\tthis._removeDecorationType(decorationType + '-' + subType);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tthis._decorationTypeSubtypes = {};\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getVisibleRanges(): Range[] {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\t\treturn this._modelData.viewModel.getVisibleRanges();\r\n\t}\r\n\r\n\tpublic getVisibleRangesPlusViewportAboveBelow(): Range[] {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\t\treturn this._modelData.viewModel.getVisibleRangesPlusViewportAboveBelow();\r\n\t}\r\n\r\n\tpublic getWhitespaces(): IEditorWhitespace[] {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\t\treturn this._modelData.viewModel.viewLayout.getWhitespaces();\r\n\t}\r\n\r\n\tprivate static _getVerticalOffsetForPosition(modelData: ModelData, modelLineNumber: number, modelColumn: number): number {\r\n\t\tconst modelPosition = modelData.model.validatePosition({\r\n\t\t\tlineNumber: modelLineNumber,\r\n\t\t\tcolumn: modelColumn\r\n\t\t});\r\n\t\tconst viewPosition = modelData.viewModel.coordinatesConverter.convertModelPositionToViewPosition(modelPosition);\r\n\t\treturn modelData.viewModel.viewLayout.getVerticalOffsetForLineNumber(viewPosition.lineNumber);\r\n\t}\r\n\r\n\tpublic getTopForLineNumber(lineNumber: number): number {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\treturn CodeEditorWidget._getVerticalOffsetForPosition(this._modelData, lineNumber, 1);\r\n\t}\r\n\r\n\tpublic getTopForPosition(lineNumber: number, column: number): number {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\treturn CodeEditorWidget._getVerticalOffsetForPosition(this._modelData, lineNumber, column);\r\n\t}\r\n\r\n\tpublic setHiddenAreas(ranges: IRange[]): void {\r\n\t\tif (this._modelData) {\r\n\t\t\tthis._modelData.viewModel.setHiddenAreas(ranges.map(r => Range.lift(r)));\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getVisibleColumnFromPosition(rawPosition: IPosition): number {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn rawPosition.column;\r\n\t\t}\r\n\r\n\t\tconst position = this._modelData.model.validatePosition(rawPosition);\r\n\t\tconst tabSize = this._modelData.model.getOptions().tabSize;\r\n\r\n\t\treturn CursorColumns.visibleColumnFromColumn(this._modelData.model.getLineContent(position.lineNumber), position.column, tabSize) + 1;\r\n\t}\r\n\r\n\tpublic getPosition(): Position | null {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn this._modelData.viewModel.getPosition();\r\n\t}\r\n\r\n\tpublic setPosition(position: IPosition): void {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (!Position.isIPosition(position)) {\r\n\t\t\tthrow new Error('Invalid arguments');\r\n\t\t}\r\n\t\tthis._modelData.viewModel.setSelections('api', [{\r\n\t\t\tselectionStartLineNumber: position.lineNumber,\r\n\t\t\tselectionStartColumn: position.column,\r\n\t\t\tpositionLineNumber: position.lineNumber,\r\n\t\t\tpositionColumn: position.column\r\n\t\t}]);\r\n\t}\r\n\r\n\tprivate _sendRevealRange(modelRange: Range, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType): void {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (!Range.isIRange(modelRange)) {\r\n\t\t\tthrow new Error('Invalid arguments');\r\n\t\t}\r\n\t\tconst validatedModelRange = this._modelData.model.validateRange(modelRange);\r\n\t\tconst viewRange = this._modelData.viewModel.coordinatesConverter.convertModelRangeToViewRange(validatedModelRange);\r\n\r\n\t\tthis._modelData.viewModel.revealRange('api', revealHorizontal, viewRange, verticalType, scrollType);\r\n\t}\r\n\r\n\tpublic revealLine(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._revealLine(lineNumber, VerticalRevealType.Simple, scrollType);\r\n\t}\r\n\r\n\tpublic revealLineInCenter(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._revealLine(lineNumber, VerticalRevealType.Center, scrollType);\r\n\t}\r\n\r\n\tpublic revealLineInCenterIfOutsideViewport(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._revealLine(lineNumber, VerticalRevealType.CenterIfOutsideViewport, scrollType);\r\n\t}\r\n\r\n\tpublic revealLineNearTop(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._revealLine(lineNumber, VerticalRevealType.NearTop, scrollType);\r\n\t}\r\n\r\n\tprivate _revealLine(lineNumber: number, revealType: VerticalRevealType, scrollType: editorCommon.ScrollType): void {\r\n\t\tif (typeof lineNumber !== 'number') {\r\n\t\t\tthrow new Error('Invalid arguments');\r\n\t\t}\r\n\r\n\t\tthis._sendRevealRange(\r\n\t\t\tnew Range(lineNumber, 1, lineNumber, 1),\r\n\t\t\trevealType,\r\n\t\t\tfalse,\r\n\t\t\tscrollType\r\n\t\t);\r\n\t}\r\n\r\n\tpublic revealPosition(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._revealPosition(\r\n\t\t\tposition,\r\n\t\t\tVerticalRevealType.Simple,\r\n\t\t\ttrue,\r\n\t\t\tscrollType\r\n\t\t);\r\n\t}\r\n\r\n\tpublic revealPositionInCenter(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._revealPosition(\r\n\t\t\tposition,\r\n\t\t\tVerticalRevealType.Center,\r\n\t\t\ttrue,\r\n\t\t\tscrollType\r\n\t\t);\r\n\t}\r\n\r\n\tpublic revealPositionInCenterIfOutsideViewport(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._revealPosition(\r\n\t\t\tposition,\r\n\t\t\tVerticalRevealType.CenterIfOutsideViewport,\r\n\t\t\ttrue,\r\n\t\t\tscrollType\r\n\t\t);\r\n\t}\r\n\r\n\tpublic revealPositionNearTop(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._revealPosition(\r\n\t\t\tposition,\r\n\t\t\tVerticalRevealType.NearTop,\r\n\t\t\ttrue,\r\n\t\t\tscrollType\r\n\t\t);\r\n\t}\r\n\r\n\tprivate _revealPosition(position: IPosition, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType): void {\r\n\t\tif (!Position.isIPosition(position)) {\r\n\t\t\tthrow new Error('Invalid arguments');\r\n\t\t}\r\n\r\n\t\tthis._sendRevealRange(\r\n\t\t\tnew Range(position.lineNumber, position.column, position.lineNumber, position.column),\r\n\t\t\tverticalType,\r\n\t\t\trevealHorizontal,\r\n\t\t\tscrollType\r\n\t\t);\r\n\t}\r\n\r\n\tpublic getSelection(): Selection | null {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn this._modelData.viewModel.getSelection();\r\n\t}\r\n\r\n\tpublic getSelections(): Selection[] | null {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn this._modelData.viewModel.getSelections();\r\n\t}\r\n\r\n\tpublic setSelection(range: IRange): void;\r\n\tpublic setSelection(editorRange: Range): void;\r\n\tpublic setSelection(selection: ISelection): void;\r\n\tpublic setSelection(editorSelection: Selection): void;\r\n\tpublic setSelection(something: any): void {\r\n\t\tconst isSelection = Selection.isISelection(something);\r\n\t\tconst isRange = Range.isIRange(something);\r\n\r\n\t\tif (!isSelection && !isRange) {\r\n\t\t\tthrow new Error('Invalid arguments');\r\n\t\t}\r\n\r\n\t\tif (isSelection) {\r\n\t\t\tthis._setSelectionImpl(something);\r\n\t\t} else if (isRange) {\r\n\t\t\t// act as if it was an IRange\r\n\t\t\tconst selection: ISelection = {\r\n\t\t\t\tselectionStartLineNumber: something.startLineNumber,\r\n\t\t\t\tselectionStartColumn: something.startColumn,\r\n\t\t\t\tpositionLineNumber: something.endLineNumber,\r\n\t\t\t\tpositionColumn: something.endColumn\r\n\t\t\t};\r\n\t\t\tthis._setSelectionImpl(selection);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _setSelectionImpl(sel: ISelection): void {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst selection = new Selection(sel.selectionStartLineNumber, sel.selectionStartColumn, sel.positionLineNumber, sel.positionColumn);\r\n\t\tthis._modelData.viewModel.setSelections('api', [selection]);\r\n\t}\r\n\r\n\tpublic revealLines(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._revealLines(\r\n\t\t\tstartLineNumber,\r\n\t\t\tendLineNumber,\r\n\t\t\tVerticalRevealType.Simple,\r\n\t\t\tscrollType\r\n\t\t);\r\n\t}\r\n\r\n\tpublic revealLinesInCenter(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._revealLines(\r\n\t\t\tstartLineNumber,\r\n\t\t\tendLineNumber,\r\n\t\t\tVerticalRevealType.Center,\r\n\t\t\tscrollType\r\n\t\t);\r\n\t}\r\n\r\n\tpublic revealLinesInCenterIfOutsideViewport(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._revealLines(\r\n\t\t\tstartLineNumber,\r\n\t\t\tendLineNumber,\r\n\t\t\tVerticalRevealType.CenterIfOutsideViewport,\r\n\t\t\tscrollType\r\n\t\t);\r\n\t}\r\n\r\n\tpublic revealLinesNearTop(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._revealLines(\r\n\t\t\tstartLineNumber,\r\n\t\t\tendLineNumber,\r\n\t\t\tVerticalRevealType.NearTop,\r\n\t\t\tscrollType\r\n\t\t);\r\n\t}\r\n\r\n\tprivate _revealLines(startLineNumber: number, endLineNumber: number, verticalType: VerticalRevealType, scrollType: editorCommon.ScrollType): void {\r\n\t\tif (typeof startLineNumber !== 'number' || typeof endLineNumber !== 'number') {\r\n\t\t\tthrow new Error('Invalid arguments');\r\n\t\t}\r\n\r\n\t\tthis._sendRevealRange(\r\n\t\t\tnew Range(startLineNumber, 1, endLineNumber, 1),\r\n\t\t\tverticalType,\r\n\t\t\tfalse,\r\n\t\t\tscrollType\r\n\t\t);\r\n\t}\r\n\r\n\tpublic revealRange(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth, revealVerticalInCenter: boolean = false, revealHorizontal: boolean = true): void {\r\n\t\tthis._revealRange(\r\n\t\t\trange,\r\n\t\t\trevealVerticalInCenter ? VerticalRevealType.Center : VerticalRevealType.Simple,\r\n\t\t\trevealHorizontal,\r\n\t\t\tscrollType\r\n\t\t);\r\n\t}\r\n\r\n\tpublic revealRangeInCenter(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._revealRange(\r\n\t\t\trange,\r\n\t\t\tVerticalRevealType.Center,\r\n\t\t\ttrue,\r\n\t\t\tscrollType\r\n\t\t);\r\n\t}\r\n\r\n\tpublic revealRangeInCenterIfOutsideViewport(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._revealRange(\r\n\t\t\trange,\r\n\t\t\tVerticalRevealType.CenterIfOutsideViewport,\r\n\t\t\ttrue,\r\n\t\t\tscrollType\r\n\t\t);\r\n\t}\r\n\r\n\tpublic revealRangeNearTop(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._revealRange(\r\n\t\t\trange,\r\n\t\t\tVerticalRevealType.NearTop,\r\n\t\t\ttrue,\r\n\t\t\tscrollType\r\n\t\t);\r\n\t}\r\n\r\n\tpublic revealRangeNearTopIfOutsideViewport(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._revealRange(\r\n\t\t\trange,\r\n\t\t\tVerticalRevealType.NearTopIfOutsideViewport,\r\n\t\t\ttrue,\r\n\t\t\tscrollType\r\n\t\t);\r\n\t}\r\n\r\n\tpublic revealRangeAtTop(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._revealRange(\r\n\t\t\trange,\r\n\t\t\tVerticalRevealType.Top,\r\n\t\t\ttrue,\r\n\t\t\tscrollType\r\n\t\t);\r\n\t}\r\n\r\n\tprivate _revealRange(range: IRange, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType): void {\r\n\t\tif (!Range.isIRange(range)) {\r\n\t\t\tthrow new Error('Invalid arguments');\r\n\t\t}\r\n\r\n\t\tthis._sendRevealRange(\r\n\t\t\tRange.lift(range),\r\n\t\t\tverticalType,\r\n\t\t\trevealHorizontal,\r\n\t\t\tscrollType\r\n\t\t);\r\n\t}\r\n\r\n\tpublic setSelections(ranges: readonly ISelection[], source: string = 'api', reason = CursorChangeReason.NotSet): void {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (!ranges || ranges.length === 0) {\r\n\t\t\tthrow new Error('Invalid arguments');\r\n\t\t}\r\n\t\tfor (let i = 0, len = ranges.length; i < len; i++) {\r\n\t\t\tif (!Selection.isISelection(ranges[i])) {\r\n\t\t\t\tthrow new Error('Invalid arguments');\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis._modelData.viewModel.setSelections(source, ranges, reason);\r\n\t}\r\n\r\n\tpublic getContentWidth(): number {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\treturn this._modelData.viewModel.viewLayout.getContentWidth();\r\n\t}\r\n\r\n\tpublic getScrollWidth(): number {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\treturn this._modelData.viewModel.viewLayout.getScrollWidth();\r\n\t}\r\n\tpublic getScrollLeft(): number {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\treturn this._modelData.viewModel.viewLayout.getCurrentScrollLeft();\r\n\t}\r\n\r\n\tpublic getContentHeight(): number {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\treturn this._modelData.viewModel.viewLayout.getContentHeight();\r\n\t}\r\n\r\n\tpublic getScrollHeight(): number {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\treturn this._modelData.viewModel.viewLayout.getScrollHeight();\r\n\t}\r\n\tpublic getScrollTop(): number {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\treturn this._modelData.viewModel.viewLayout.getCurrentScrollTop();\r\n\t}\r\n\r\n\tpublic setScrollLeft(newScrollLeft: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Immediate): void {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (typeof newScrollLeft !== 'number') {\r\n\t\t\tthrow new Error('Invalid arguments');\r\n\t\t}\r\n\t\tthis._modelData.viewModel.setScrollPosition({\r\n\t\t\tscrollLeft: newScrollLeft\r\n\t\t}, scrollType);\r\n\t}\r\n\tpublic setScrollTop(newScrollTop: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Immediate): void {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (typeof newScrollTop !== 'number') {\r\n\t\t\tthrow new Error('Invalid arguments');\r\n\t\t}\r\n\t\tthis._modelData.viewModel.setScrollPosition({\r\n\t\t\tscrollTop: newScrollTop\r\n\t\t}, scrollType);\r\n\t}\r\n\tpublic setScrollPosition(position: editorCommon.INewScrollPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Immediate): void {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._modelData.viewModel.setScrollPosition(position, scrollType);\r\n\t}\r\n\r\n\tpublic saveViewState(): editorCommon.ICodeEditorViewState | null {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tconst contributionsState: { [key: string]: any } = {};\r\n\r\n\t\tconst keys = Object.keys(this._contributions);\r\n\t\tfor (const id of keys) {\r\n\t\t\tconst contribution = this._contributions[id];\r\n\t\t\tif (typeof contribution.saveViewState === 'function') {\r\n\t\t\t\tcontributionsState[id] = contribution.saveViewState();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst cursorState = this._modelData.viewModel.saveCursorState();\r\n\t\tconst viewState = this._modelData.viewModel.saveState();\r\n\t\treturn {\r\n\t\t\tcursorState: cursorState,\r\n\t\t\tviewState: viewState,\r\n\t\t\tcontributionsState: contributionsState\r\n\t\t};\r\n\t}\r\n\r\n\tpublic restoreViewState(s: editorCommon.IEditorViewState | null): void {\r\n\t\tif (!this._modelData || !this._modelData.hasRealView) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst codeEditorState = s as editorCommon.ICodeEditorViewState | null;\r\n\t\tif (codeEditorState && codeEditorState.cursorState && codeEditorState.viewState) {\r\n\t\t\tconst cursorState = codeEditorState.cursorState;\r\n\t\t\tif (Array.isArray(cursorState)) {\r\n\t\t\t\tthis._modelData.viewModel.restoreCursorState(cursorState);\r\n\t\t\t} else {\r\n\t\t\t\t// Backwards compatibility\r\n\t\t\t\tthis._modelData.viewModel.restoreCursorState([cursorState]);\r\n\t\t\t}\r\n\r\n\t\t\tconst contributionsState = codeEditorState.contributionsState || {};\r\n\t\t\tconst keys = Object.keys(this._contributions);\r\n\t\t\tfor (let i = 0, len = keys.length; i < len; i++) {\r\n\t\t\t\tconst id = keys[i];\r\n\t\t\t\tconst contribution = this._contributions[id];\r\n\t\t\t\tif (typeof contribution.restoreViewState === 'function') {\r\n\t\t\t\t\tcontribution.restoreViewState(contributionsState[id]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tconst reducedState = this._modelData.viewModel.reduceRestoreState(codeEditorState.viewState);\r\n\t\t\tthis._modelData.view.restoreState(reducedState);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getContribution(id: string): T {\r\n\t\treturn (this._contributions[id] || null);\r\n\t}\r\n\r\n\tpublic getActions(): editorCommon.IEditorAction[] {\r\n\t\tconst result: editorCommon.IEditorAction[] = [];\r\n\r\n\t\tconst keys = Object.keys(this._actions);\r\n\t\tfor (let i = 0, len = keys.length; i < len; i++) {\r\n\t\t\tconst id = keys[i];\r\n\t\t\tresult.push(this._actions[id]);\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic getSupportedActions(): editorCommon.IEditorAction[] {\r\n\t\tlet result = this.getActions();\r\n\r\n\t\tresult = result.filter(action => action.isSupported());\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic getAction(id: string): editorCommon.IEditorAction {\r\n\t\treturn this._actions[id] || null;\r\n\t}\r\n\r\n\tpublic trigger(source: string | null | undefined, handlerId: string, payload: any): void {\r\n\t\tpayload = payload || {};\r\n\r\n\t\tswitch (handlerId) {\r\n\t\t\tcase editorCommon.Handler.CompositionStart:\r\n\t\t\t\tthis._startComposition();\r\n\t\t\t\treturn;\r\n\t\t\tcase editorCommon.Handler.CompositionEnd:\r\n\t\t\t\tthis._endComposition(source);\r\n\t\t\t\treturn;\r\n\t\t\tcase editorCommon.Handler.Type: {\r\n\t\t\t\tconst args = >payload;\r\n\t\t\t\tthis._type(source, args.text || '');\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tcase editorCommon.Handler.ReplacePreviousChar: {\r\n\t\t\t\tconst args = >payload;\r\n\t\t\t\tthis._replacePreviousChar(source, args.text || '', args.replaceCharCnt || 0);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tcase editorCommon.Handler.Paste: {\r\n\t\t\t\tconst args = >payload;\r\n\t\t\t\tthis._paste(source, args.text || '', args.pasteOnNewLine || false, args.multicursorText || null, args.mode || null);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tcase editorCommon.Handler.Cut:\r\n\t\t\t\tthis._cut(source);\r\n\t\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst action = this.getAction(handlerId);\r\n\t\tif (action) {\r\n\t\t\tPromise.resolve(action.run()).then(undefined, onUnexpectedError);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this._triggerEditorCommand(source, handlerId, payload)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._commandService.executeCommand(handlerId, payload);\r\n\t}\r\n\r\n\tprivate _startComposition(): void {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._modelData.viewModel.startComposition();\r\n\t\tthis._onDidCompositionStart.fire();\r\n\t}\r\n\r\n\tprivate _endComposition(source: string | null | undefined): void {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._modelData.viewModel.endComposition(source);\r\n\t\tthis._onDidCompositionEnd.fire();\r\n\t}\r\n\r\n\tprivate _type(source: string | null | undefined, text: string): void {\r\n\t\tif (!this._modelData || text.length === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (source === 'keyboard') {\r\n\t\t\tthis._onWillType.fire(text);\r\n\t\t}\r\n\t\tthis._modelData.viewModel.type(text, source);\r\n\t\tif (source === 'keyboard') {\r\n\t\t\tthis._onDidType.fire(text);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _replacePreviousChar(source: string | null | undefined, text: string, replaceCharCnt: number): void {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._modelData.viewModel.replacePreviousChar(text, replaceCharCnt, source);\r\n\t}\r\n\r\n\tprivate _paste(source: string | null | undefined, text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null): void {\r\n\t\tif (!this._modelData || text.length === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst startPosition = this._modelData.viewModel.getSelection().getStartPosition();\r\n\t\tthis._modelData.viewModel.paste(text, pasteOnNewLine, multicursorText, source);\r\n\t\tconst endPosition = this._modelData.viewModel.getSelection().getStartPosition();\r\n\t\tif (source === 'keyboard') {\r\n\t\t\tthis._onDidPaste.fire({\r\n\t\t\t\trange: new Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column),\r\n\t\t\t\tmode: mode\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _cut(source: string | null | undefined): void {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._modelData.viewModel.cut(source);\r\n\t}\r\n\r\n\tprivate _triggerEditorCommand(source: string | null | undefined, handlerId: string, payload: any): boolean {\r\n\t\tconst command = EditorExtensionsRegistry.getEditorCommand(handlerId);\r\n\t\tif (command) {\r\n\t\t\tpayload = payload || {};\r\n\t\t\tpayload.source = source;\r\n\t\t\tthis._instantiationService.invokeFunction((accessor) => {\r\n\t\t\t\tPromise.resolve(command.runEditorCommand(accessor, this, payload)).then(undefined, onUnexpectedError);\r\n\t\t\t});\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic _getViewModel(): IViewModel | null {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn this._modelData.viewModel;\r\n\t}\r\n\r\n\tpublic pushUndoStop(): boolean {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (this._configuration.options.get(EditorOption.readOnly)) {\r\n\t\t\t// read only editor => sorry!\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tthis._modelData.model.pushStackElement();\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic popUndoStop(): boolean {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (this._configuration.options.get(EditorOption.readOnly)) {\r\n\t\t\t// read only editor => sorry!\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tthis._modelData.model.popStackElement();\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic executeEdits(source: string | null | undefined, edits: IIdentifiedSingleEditOperation[], endCursorState?: ICursorStateComputer | Selection[]): boolean {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (this._configuration.options.get(EditorOption.readOnly)) {\r\n\t\t\t// read only editor => sorry!\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tlet cursorStateComputer: ICursorStateComputer;\r\n\t\tif (!endCursorState) {\r\n\t\t\tcursorStateComputer = () => null;\r\n\t\t} else if (Array.isArray(endCursorState)) {\r\n\t\t\tcursorStateComputer = () => endCursorState;\r\n\t\t} else {\r\n\t\t\tcursorStateComputer = endCursorState;\r\n\t\t}\r\n\r\n\t\tthis._modelData.viewModel.executeEdits(source, edits, cursorStateComputer);\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic executeCommand(source: string | null | undefined, command: editorCommon.ICommand): void {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._modelData.viewModel.executeCommand(command, source);\r\n\t}\r\n\r\n\tpublic executeCommands(source: string | null | undefined, commands: editorCommon.ICommand[]): void {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._modelData.viewModel.executeCommands(commands, source);\r\n\t}\r\n\r\n\tpublic changeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => any): any {\r\n\t\tif (!this._modelData) {\r\n\t\t\t// callback will not be called\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn this._modelData.model.changeDecorations(callback, this._id);\r\n\t}\r\n\r\n\tpublic getLineDecorations(lineNumber: number): IModelDecoration[] | null {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn this._modelData.model.getLineDecorations(lineNumber, this._id, filterValidationDecorations(this._configuration.options));\r\n\t}\r\n\r\n\tpublic deltaDecorations(oldDecorations: string[], newDecorations: IModelDeltaDecoration[]): string[] {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tif (oldDecorations.length === 0 && newDecorations.length === 0) {\r\n\t\t\treturn oldDecorations;\r\n\t\t}\r\n\r\n\t\treturn this._modelData.model.deltaDecorations(oldDecorations, newDecorations, this._id);\r\n\t}\r\n\r\n\tpublic removeDecorations(decorationTypeKey: string): void {\r\n\t\t// remove decorations for type and sub type\r\n\t\tconst oldDecorationsIds = this._decorationTypeKeysToIds[decorationTypeKey];\r\n\t\tif (oldDecorationsIds) {\r\n\t\t\tthis.deltaDecorations(oldDecorationsIds, []);\r\n\t\t}\r\n\t\tif (this._decorationTypeKeysToIds.hasOwnProperty(decorationTypeKey)) {\r\n\t\t\tdelete this._decorationTypeKeysToIds[decorationTypeKey];\r\n\t\t}\r\n\t\tif (this._decorationTypeSubtypes.hasOwnProperty(decorationTypeKey)) {\r\n\t\t\tdelete this._decorationTypeSubtypes[decorationTypeKey];\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getLayoutInfo(): EditorLayoutInfo {\r\n\t\tconst options = this._configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\t\treturn layoutInfo;\r\n\t}\r\n\r\n\tpublic createOverviewRuler(cssClassName: string): editorBrowser.IOverviewRuler | null {\r\n\t\tif (!this._modelData || !this._modelData.hasRealView) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn this._modelData.view.createOverviewRuler(cssClassName);\r\n\t}\r\n\r\n\tpublic getContainerDomNode(): HTMLElement {\r\n\t\treturn this._domElement;\r\n\t}\r\n\r\n\tpublic getDomNode(): HTMLElement | null {\r\n\t\tif (!this._modelData || !this._modelData.hasRealView) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn this._modelData.view.domNode.domNode;\r\n\t}\r\n\r\n\tpublic delegateVerticalScrollbarMouseDown(browserEvent: IMouseEvent): void {\r\n\t\tif (!this._modelData || !this._modelData.hasRealView) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._modelData.view.delegateVerticalScrollbarMouseDown(browserEvent);\r\n\t}\r\n\r\n\tpublic layout(dimension?: editorCommon.IDimension): void {\r\n\t\tthis._configuration.observeReferenceElement(dimension);\r\n\t\tthis.render();\r\n\t}\r\n\r\n\tpublic focus(): void {\r\n\t\tif (!this._modelData || !this._modelData.hasRealView) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._modelData.view.focus();\r\n\t}\r\n\r\n\tpublic hasTextFocus(): boolean {\r\n\t\tif (!this._modelData || !this._modelData.hasRealView) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn this._modelData.view.isFocused();\r\n\t}\r\n\r\n\tpublic hasWidgetFocus(): boolean {\r\n\t\treturn this._focusTracker && this._focusTracker.hasFocus();\r\n\t}\r\n\r\n\tpublic addContentWidget(widget: editorBrowser.IContentWidget): void {\r\n\t\tconst widgetData: IContentWidgetData = {\r\n\t\t\twidget: widget,\r\n\t\t\tposition: widget.getPosition()\r\n\t\t};\r\n\r\n\t\tif (this._contentWidgets.hasOwnProperty(widget.getId())) {\r\n\t\t\tconsole.warn('Overwriting a content widget with the same id.');\r\n\t\t}\r\n\r\n\t\tthis._contentWidgets[widget.getId()] = widgetData;\r\n\r\n\t\tif (this._modelData && this._modelData.hasRealView) {\r\n\t\t\tthis._modelData.view.addContentWidget(widgetData);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic layoutContentWidget(widget: editorBrowser.IContentWidget): void {\r\n\t\tconst widgetId = widget.getId();\r\n\t\tif (this._contentWidgets.hasOwnProperty(widgetId)) {\r\n\t\t\tconst widgetData = this._contentWidgets[widgetId];\r\n\t\t\twidgetData.position = widget.getPosition();\r\n\t\t\tif (this._modelData && this._modelData.hasRealView) {\r\n\t\t\t\tthis._modelData.view.layoutContentWidget(widgetData);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic removeContentWidget(widget: editorBrowser.IContentWidget): void {\r\n\t\tconst widgetId = widget.getId();\r\n\t\tif (this._contentWidgets.hasOwnProperty(widgetId)) {\r\n\t\t\tconst widgetData = this._contentWidgets[widgetId];\r\n\t\t\tdelete this._contentWidgets[widgetId];\r\n\t\t\tif (this._modelData && this._modelData.hasRealView) {\r\n\t\t\t\tthis._modelData.view.removeContentWidget(widgetData);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic addOverlayWidget(widget: editorBrowser.IOverlayWidget): void {\r\n\t\tconst widgetData: IOverlayWidgetData = {\r\n\t\t\twidget: widget,\r\n\t\t\tposition: widget.getPosition()\r\n\t\t};\r\n\r\n\t\tif (this._overlayWidgets.hasOwnProperty(widget.getId())) {\r\n\t\t\tconsole.warn('Overwriting an overlay widget with the same id.');\r\n\t\t}\r\n\r\n\t\tthis._overlayWidgets[widget.getId()] = widgetData;\r\n\r\n\t\tif (this._modelData && this._modelData.hasRealView) {\r\n\t\t\tthis._modelData.view.addOverlayWidget(widgetData);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic layoutOverlayWidget(widget: editorBrowser.IOverlayWidget): void {\r\n\t\tconst widgetId = widget.getId();\r\n\t\tif (this._overlayWidgets.hasOwnProperty(widgetId)) {\r\n\t\t\tconst widgetData = this._overlayWidgets[widgetId];\r\n\t\t\twidgetData.position = widget.getPosition();\r\n\t\t\tif (this._modelData && this._modelData.hasRealView) {\r\n\t\t\t\tthis._modelData.view.layoutOverlayWidget(widgetData);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic removeOverlayWidget(widget: editorBrowser.IOverlayWidget): void {\r\n\t\tconst widgetId = widget.getId();\r\n\t\tif (this._overlayWidgets.hasOwnProperty(widgetId)) {\r\n\t\t\tconst widgetData = this._overlayWidgets[widgetId];\r\n\t\t\tdelete this._overlayWidgets[widgetId];\r\n\t\t\tif (this._modelData && this._modelData.hasRealView) {\r\n\t\t\t\tthis._modelData.view.removeOverlayWidget(widgetData);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic changeViewZones(callback: (accessor: editorBrowser.IViewZoneChangeAccessor) => void): void {\r\n\t\tif (!this._modelData || !this._modelData.hasRealView) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._modelData.view.change(callback);\r\n\t}\r\n\r\n\tpublic getTargetAtClientPoint(clientX: number, clientY: number): editorBrowser.IMouseTarget | null {\r\n\t\tif (!this._modelData || !this._modelData.hasRealView) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn this._modelData.view.getTargetAtClientPoint(clientX, clientY);\r\n\t}\r\n\r\n\tpublic getScrolledVisiblePosition(rawPosition: IPosition): { top: number; left: number; height: number; } | null {\r\n\t\tif (!this._modelData || !this._modelData.hasRealView) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst position = this._modelData.model.validatePosition(rawPosition);\r\n\t\tconst options = this._configuration.options;\r\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\r\n\r\n\t\tconst top = CodeEditorWidget._getVerticalOffsetForPosition(this._modelData, position.lineNumber, position.column) - this.getScrollTop();\r\n\t\tconst left = this._modelData.view.getOffsetForColumn(position.lineNumber, position.column) + layoutInfo.glyphMarginWidth + layoutInfo.lineNumbersWidth + layoutInfo.decorationsWidth - this.getScrollLeft();\r\n\r\n\t\treturn {\r\n\t\t\ttop: top,\r\n\t\t\tleft: left,\r\n\t\t\theight: options.get(EditorOption.lineHeight)\r\n\t\t};\r\n\t}\r\n\r\n\tpublic getOffsetForColumn(lineNumber: number, column: number): number {\r\n\t\tif (!this._modelData || !this._modelData.hasRealView) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\treturn this._modelData.view.getOffsetForColumn(lineNumber, column);\r\n\t}\r\n\r\n\tpublic render(forceRedraw: boolean = false): void {\r\n\t\tif (!this._modelData || !this._modelData.hasRealView) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._modelData.view.render(true, forceRedraw);\r\n\t}\r\n\r\n\tpublic setAriaOptions(options: editorBrowser.IEditorAriaOptions): void {\r\n\t\tif (!this._modelData || !this._modelData.hasRealView) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._modelData.view.setAriaOptions(options);\r\n\t}\r\n\r\n\tpublic applyFontInfo(target: HTMLElement): void {\r\n\t\tConfiguration.applyFontInfoSlow(target, this._configuration.options.get(EditorOption.fontInfo));\r\n\t}\r\n\r\n\tprotected _attachModel(model: ITextModel | null): void {\r\n\t\tif (!model) {\r\n\t\t\tthis._modelData = null;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst listenersToRemove: IDisposable[] = [];\r\n\r\n\t\tthis._domElement.setAttribute('data-mode-id', model.getLanguageIdentifier().language);\r\n\t\tthis._configuration.setIsDominatedByLongLines(model.isDominatedByLongLines());\r\n\t\tthis._configuration.setMaxLineNumber(model.getLineCount());\r\n\r\n\t\tmodel.onBeforeAttached();\r\n\r\n\t\tconst viewModel = new ViewModel(\r\n\t\t\tthis._id,\r\n\t\t\tthis._configuration,\r\n\t\t\tmodel,\r\n\t\t\tDOMLineBreaksComputerFactory.create(),\r\n\t\t\tMonospaceLineBreaksComputerFactory.create(this._configuration.options),\r\n\t\t\t(callback) => dom.scheduleAtNextAnimationFrame(callback)\r\n\t\t);\r\n\r\n\t\tlistenersToRemove.push(model.onDidChangeDecorations((e) => this._onDidChangeModelDecorations.fire(e)));\r\n\t\tlistenersToRemove.push(model.onDidChangeLanguage((e) => {\r\n\t\t\tthis._domElement.setAttribute('data-mode-id', model.getLanguageIdentifier().language);\r\n\t\t\tthis._onDidChangeModelLanguage.fire(e);\r\n\t\t}));\r\n\t\tlistenersToRemove.push(model.onDidChangeLanguageConfiguration((e) => this._onDidChangeModelLanguageConfiguration.fire(e)));\r\n\t\tlistenersToRemove.push(model.onDidChangeContent((e) => this._onDidChangeModelContent.fire(e)));\r\n\t\tlistenersToRemove.push(model.onDidChangeOptions((e) => this._onDidChangeModelOptions.fire(e)));\r\n\t\t// Someone might destroy the model from under the editor, so prevent any exceptions by setting a null model\r\n\t\tlistenersToRemove.push(model.onWillDispose(() => this.setModel(null)));\r\n\r\n\t\tlistenersToRemove.push(viewModel.onEvent((e) => {\r\n\t\t\tswitch (e.kind) {\r\n\t\t\t\tcase OutgoingViewModelEventKind.ContentSizeChanged:\r\n\t\t\t\t\tthis._onDidContentSizeChange.fire(e);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase OutgoingViewModelEventKind.FocusChanged:\r\n\t\t\t\t\tthis._editorTextFocus.setValue(e.hasFocus);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase OutgoingViewModelEventKind.ScrollChanged:\r\n\t\t\t\t\tthis._onDidScrollChange.fire(e);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase OutgoingViewModelEventKind.ViewZonesChanged:\r\n\t\t\t\t\tthis._onDidChangeViewZones.fire();\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase OutgoingViewModelEventKind.ReadOnlyEditAttempt:\r\n\t\t\t\t\tthis._onDidAttemptReadOnlyEdit.fire();\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase OutgoingViewModelEventKind.CursorStateChanged: {\r\n\t\t\t\t\tif (e.reachedMaxCursorCount) {\r\n\t\t\t\t\t\tthis._notificationService.warn(nls.localize('cursors.maximum', \"The number of cursors has been limited to {0}.\", Cursor.MAX_CURSOR_COUNT));\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tconst positions: Position[] = [];\r\n\t\t\t\t\tfor (let i = 0, len = e.selections.length; i < len; i++) {\r\n\t\t\t\t\t\tpositions[i] = e.selections[i].getPosition();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tconst e1: ICursorPositionChangedEvent = {\r\n\t\t\t\t\t\tposition: positions[0],\r\n\t\t\t\t\t\tsecondaryPositions: positions.slice(1),\r\n\t\t\t\t\t\treason: e.reason,\r\n\t\t\t\t\t\tsource: e.source\r\n\t\t\t\t\t};\r\n\t\t\t\t\tthis._onDidChangeCursorPosition.fire(e1);\r\n\r\n\t\t\t\t\tconst e2: ICursorSelectionChangedEvent = {\r\n\t\t\t\t\t\tselection: e.selections[0],\r\n\t\t\t\t\t\tsecondarySelections: e.selections.slice(1),\r\n\t\t\t\t\t\tmodelVersionId: e.modelVersionId,\r\n\t\t\t\t\t\toldSelections: e.oldSelections,\r\n\t\t\t\t\t\toldModelVersionId: e.oldModelVersionId,\r\n\t\t\t\t\t\tsource: e.source,\r\n\t\t\t\t\t\treason: e.reason\r\n\t\t\t\t\t};\r\n\t\t\t\t\tthis._onDidChangeCursorSelection.fire(e2);\r\n\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tconst [view, hasRealView] = this._createView(viewModel);\r\n\t\tif (hasRealView) {\r\n\t\t\tthis._domElement.appendChild(view.domNode.domNode);\r\n\r\n\t\t\tlet keys = Object.keys(this._contentWidgets);\r\n\t\t\tfor (let i = 0, len = keys.length; i < len; i++) {\r\n\t\t\t\tconst widgetId = keys[i];\r\n\t\t\t\tview.addContentWidget(this._contentWidgets[widgetId]);\r\n\t\t\t}\r\n\r\n\t\t\tkeys = Object.keys(this._overlayWidgets);\r\n\t\t\tfor (let i = 0, len = keys.length; i < len; i++) {\r\n\t\t\t\tconst widgetId = keys[i];\r\n\t\t\t\tview.addOverlayWidget(this._overlayWidgets[widgetId]);\r\n\t\t\t}\r\n\r\n\t\t\tview.render(false, true);\r\n\t\t\tview.domNode.domNode.setAttribute('data-uri', model.uri.toString());\r\n\t\t}\r\n\r\n\t\tthis._modelData = new ModelData(model, viewModel, view, hasRealView, listenersToRemove);\r\n\t}\r\n\r\n\tprotected _createView(viewModel: ViewModel): [View, boolean] {\r\n\t\tlet commandDelegate: ICommandDelegate;\r\n\t\tif (this.isSimpleWidget) {\r\n\t\t\tcommandDelegate = {\r\n\t\t\t\tpaste: (text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null) => {\r\n\t\t\t\t\tthis._paste('keyboard', text, pasteOnNewLine, multicursorText, mode);\r\n\t\t\t\t},\r\n\t\t\t\ttype: (text: string) => {\r\n\t\t\t\t\tthis._type('keyboard', text);\r\n\t\t\t\t},\r\n\t\t\t\treplacePreviousChar: (text: string, replaceCharCnt: number) => {\r\n\t\t\t\t\tthis._replacePreviousChar('keyboard', text, replaceCharCnt);\r\n\t\t\t\t},\r\n\t\t\t\tstartComposition: () => {\r\n\t\t\t\t\tthis._startComposition();\r\n\t\t\t\t},\r\n\t\t\t\tendComposition: () => {\r\n\t\t\t\t\tthis._endComposition('keyboard');\r\n\t\t\t\t},\r\n\t\t\t\tcut: () => {\r\n\t\t\t\t\tthis._cut('keyboard');\r\n\t\t\t\t}\r\n\t\t\t};\r\n\t\t} else {\r\n\t\t\tcommandDelegate = {\r\n\t\t\t\tpaste: (text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null) => {\r\n\t\t\t\t\tconst payload: editorCommon.PastePayload = { text, pasteOnNewLine, multicursorText, mode };\r\n\t\t\t\t\tthis._commandService.executeCommand(editorCommon.Handler.Paste, payload);\r\n\t\t\t\t},\r\n\t\t\t\ttype: (text: string) => {\r\n\t\t\t\t\tconst payload: editorCommon.TypePayload = { text };\r\n\t\t\t\t\tthis._commandService.executeCommand(editorCommon.Handler.Type, payload);\r\n\t\t\t\t},\r\n\t\t\t\treplacePreviousChar: (text: string, replaceCharCnt: number) => {\r\n\t\t\t\t\tconst payload: editorCommon.ReplacePreviousCharPayload = { text, replaceCharCnt };\r\n\t\t\t\t\tthis._commandService.executeCommand(editorCommon.Handler.ReplacePreviousChar, payload);\r\n\t\t\t\t},\r\n\t\t\t\tstartComposition: () => {\r\n\t\t\t\t\tthis._commandService.executeCommand(editorCommon.Handler.CompositionStart, {});\r\n\t\t\t\t},\r\n\t\t\t\tendComposition: () => {\r\n\t\t\t\t\tthis._commandService.executeCommand(editorCommon.Handler.CompositionEnd, {});\r\n\t\t\t\t},\r\n\t\t\t\tcut: () => {\r\n\t\t\t\t\tthis._commandService.executeCommand(editorCommon.Handler.Cut, {});\r\n\t\t\t\t}\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tconst viewUserInputEvents = new ViewUserInputEvents(viewModel.coordinatesConverter);\r\n\t\tviewUserInputEvents.onKeyDown = (e) => this._onKeyDown.fire(e);\r\n\t\tviewUserInputEvents.onKeyUp = (e) => this._onKeyUp.fire(e);\r\n\t\tviewUserInputEvents.onContextMenu = (e) => this._onContextMenu.fire(e);\r\n\t\tviewUserInputEvents.onMouseMove = (e) => this._onMouseMove.fire(e);\r\n\t\tviewUserInputEvents.onMouseLeave = (e) => this._onMouseLeave.fire(e);\r\n\t\tviewUserInputEvents.onMouseDown = (e) => this._onMouseDown.fire(e);\r\n\t\tviewUserInputEvents.onMouseUp = (e) => this._onMouseUp.fire(e);\r\n\t\tviewUserInputEvents.onMouseDrag = (e) => this._onMouseDrag.fire(e);\r\n\t\tviewUserInputEvents.onMouseDrop = (e) => this._onMouseDrop.fire(e);\r\n\t\tviewUserInputEvents.onMouseDropCanceled = (e) => this._onMouseDropCanceled.fire(e);\r\n\t\tviewUserInputEvents.onMouseWheel = (e) => this._onMouseWheel.fire(e);\r\n\r\n\t\tconst view = new View(\r\n\t\t\tcommandDelegate,\r\n\t\t\tthis._configuration,\r\n\t\t\tthis._themeService,\r\n\t\t\tviewModel,\r\n\t\t\tviewUserInputEvents,\r\n\t\t\tthis._overflowWidgetsDomNode\r\n\t\t);\r\n\r\n\t\treturn [view, true];\r\n\t}\r\n\r\n\tprotected _postDetachModelCleanup(detachedModel: ITextModel | null): void {\r\n\t\tif (detachedModel) {\r\n\t\t\tdetachedModel.removeAllDecorationsWithOwnerId(this._id);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _detachModel(): ITextModel | null {\r\n\t\tif (!this._modelData) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tconst model = this._modelData.model;\r\n\t\tconst removeDomNode = this._modelData.hasRealView ? this._modelData.view.domNode.domNode : null;\r\n\r\n\t\tthis._modelData.dispose();\r\n\t\tthis._modelData = null;\r\n\r\n\t\tthis._domElement.removeAttribute('data-mode-id');\r\n\t\tif (removeDomNode && this._domElement.contains(removeDomNode)) {\r\n\t\t\tthis._domElement.removeChild(removeDomNode);\r\n\t\t}\r\n\r\n\t\treturn model;\r\n\t}\r\n\r\n\tprivate _removeDecorationType(key: string): void {\r\n\t\tthis._codeEditorService.removeDecorationType(key);\r\n\t}\r\n\r\n\tpublic hasModel(): this is editorBrowser.IActiveCodeEditor {\r\n\t\treturn (this._modelData !== null);\r\n\t}\r\n}\r\n\r\nconst enum BooleanEventValue {\r\n\tNotSet,\r\n\tFalse,\r\n\tTrue\r\n}\r\n\r\nexport class BooleanEventEmitter extends Disposable {\r\n\tprivate readonly _onDidChangeToTrue: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidChangeToTrue: Event = this._onDidChangeToTrue.event;\r\n\r\n\tprivate readonly _onDidChangeToFalse: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidChangeToFalse: Event = this._onDidChangeToFalse.event;\r\n\r\n\tprivate _value: BooleanEventValue;\r\n\r\n\tconstructor() {\r\n\t\tsuper();\r\n\t\tthis._value = BooleanEventValue.NotSet;\r\n\t}\r\n\r\n\tpublic setValue(_value: boolean) {\r\n\t\tconst value = (_value ? BooleanEventValue.True : BooleanEventValue.False);\r\n\t\tif (this._value === value) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._value = value;\r\n\t\tif (this._value === BooleanEventValue.True) {\r\n\t\t\tthis._onDidChangeToTrue.fire();\r\n\t\t} else if (this._value === BooleanEventValue.False) {\r\n\t\t\tthis._onDidChangeToFalse.fire();\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass EditorContextKeysManager extends Disposable {\r\n\r\n\tprivate readonly _editor: CodeEditorWidget;\r\n\tprivate readonly _editorSimpleInput: IContextKey;\r\n\tprivate readonly _editorFocus: IContextKey;\r\n\tprivate readonly _textInputFocus: IContextKey;\r\n\tprivate readonly _editorTextFocus: IContextKey;\r\n\tprivate readonly _editorTabMovesFocus: IContextKey;\r\n\tprivate readonly _editorReadonly: IContextKey;\r\n\tprivate readonly _inDiffEditor: IContextKey;\r\n\tprivate readonly _editorColumnSelection: IContextKey;\r\n\tprivate readonly _hasMultipleSelections: IContextKey;\r\n\tprivate readonly _hasNonEmptySelection: IContextKey;\r\n\tprivate readonly _canUndo: IContextKey;\r\n\tprivate readonly _canRedo: IContextKey;\r\n\r\n\tconstructor(\r\n\t\teditor: CodeEditorWidget,\r\n\t\tcontextKeyService: IContextKeyService\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\tthis._editor = editor;\r\n\r\n\t\tcontextKeyService.createKey('editorId', editor.getId());\r\n\r\n\t\tthis._editorSimpleInput = EditorContextKeys.editorSimpleInput.bindTo(contextKeyService);\r\n\t\tthis._editorFocus = EditorContextKeys.focus.bindTo(contextKeyService);\r\n\t\tthis._textInputFocus = EditorContextKeys.textInputFocus.bindTo(contextKeyService);\r\n\t\tthis._editorTextFocus = EditorContextKeys.editorTextFocus.bindTo(contextKeyService);\r\n\t\tthis._editorTabMovesFocus = EditorContextKeys.tabMovesFocus.bindTo(contextKeyService);\r\n\t\tthis._editorReadonly = EditorContextKeys.readOnly.bindTo(contextKeyService);\r\n\t\tthis._inDiffEditor = EditorContextKeys.inDiffEditor.bindTo(contextKeyService);\r\n\t\tthis._editorColumnSelection = EditorContextKeys.columnSelection.bindTo(contextKeyService);\r\n\t\tthis._hasMultipleSelections = EditorContextKeys.hasMultipleSelections.bindTo(contextKeyService);\r\n\t\tthis._hasNonEmptySelection = EditorContextKeys.hasNonEmptySelection.bindTo(contextKeyService);\r\n\t\tthis._canUndo = EditorContextKeys.canUndo.bindTo(contextKeyService);\r\n\t\tthis._canRedo = EditorContextKeys.canRedo.bindTo(contextKeyService);\r\n\r\n\t\tthis._register(this._editor.onDidChangeConfiguration(() => this._updateFromConfig()));\r\n\t\tthis._register(this._editor.onDidChangeCursorSelection(() => this._updateFromSelection()));\r\n\t\tthis._register(this._editor.onDidFocusEditorWidget(() => this._updateFromFocus()));\r\n\t\tthis._register(this._editor.onDidBlurEditorWidget(() => this._updateFromFocus()));\r\n\t\tthis._register(this._editor.onDidFocusEditorText(() => this._updateFromFocus()));\r\n\t\tthis._register(this._editor.onDidBlurEditorText(() => this._updateFromFocus()));\r\n\t\tthis._register(this._editor.onDidChangeModel(() => this._updateFromModel()));\r\n\t\tthis._register(this._editor.onDidChangeConfiguration(() => this._updateFromModel()));\r\n\r\n\t\tthis._updateFromConfig();\r\n\t\tthis._updateFromSelection();\r\n\t\tthis._updateFromFocus();\r\n\t\tthis._updateFromModel();\r\n\r\n\t\tthis._editorSimpleInput.set(this._editor.isSimpleWidget);\r\n\t}\r\n\r\n\tprivate _updateFromConfig(): void {\r\n\t\tconst options = this._editor.getOptions();\r\n\r\n\t\tthis._editorTabMovesFocus.set(options.get(EditorOption.tabFocusMode));\r\n\t\tthis._editorReadonly.set(options.get(EditorOption.readOnly));\r\n\t\tthis._inDiffEditor.set(options.get(EditorOption.inDiffEditor));\r\n\t\tthis._editorColumnSelection.set(options.get(EditorOption.columnSelection));\r\n\t}\r\n\r\n\tprivate _updateFromSelection(): void {\r\n\t\tconst selections = this._editor.getSelections();\r\n\t\tif (!selections) {\r\n\t\t\tthis._hasMultipleSelections.reset();\r\n\t\t\tthis._hasNonEmptySelection.reset();\r\n\t\t} else {\r\n\t\t\tthis._hasMultipleSelections.set(selections.length > 1);\r\n\t\t\tthis._hasNonEmptySelection.set(selections.some(s => !s.isEmpty()));\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _updateFromFocus(): void {\r\n\t\tthis._editorFocus.set(this._editor.hasWidgetFocus() && !this._editor.isSimpleWidget);\r\n\t\tthis._editorTextFocus.set(this._editor.hasTextFocus() && !this._editor.isSimpleWidget);\r\n\t\tthis._textInputFocus.set(this._editor.hasTextFocus());\r\n\t}\r\n\r\n\tprivate _updateFromModel(): void {\r\n\t\tconst model = this._editor.getModel();\r\n\t\tthis._canUndo.set(Boolean(model && model.canUndo()));\r\n\t\tthis._canRedo.set(Boolean(model && model.canRedo()));\r\n\t}\r\n}\r\n\r\nexport class EditorModeContext extends Disposable {\r\n\r\n\tprivate readonly _langId: IContextKey;\r\n\tprivate readonly _hasCompletionItemProvider: IContextKey;\r\n\tprivate readonly _hasCodeActionsProvider: IContextKey;\r\n\tprivate readonly _hasCodeLensProvider: IContextKey;\r\n\tprivate readonly _hasDefinitionProvider: IContextKey;\r\n\tprivate readonly _hasDeclarationProvider: IContextKey;\r\n\tprivate readonly _hasImplementationProvider: IContextKey;\r\n\tprivate readonly _hasTypeDefinitionProvider: IContextKey;\r\n\tprivate readonly _hasHoverProvider: IContextKey;\r\n\tprivate readonly _hasDocumentHighlightProvider: IContextKey;\r\n\tprivate readonly _hasDocumentSymbolProvider: IContextKey;\r\n\tprivate readonly _hasReferenceProvider: IContextKey;\r\n\tprivate readonly _hasRenameProvider: IContextKey;\r\n\tprivate readonly _hasDocumentFormattingProvider: IContextKey;\r\n\tprivate readonly _hasDocumentSelectionFormattingProvider: IContextKey;\r\n\tprivate readonly _hasMultipleDocumentFormattingProvider: IContextKey;\r\n\tprivate readonly _hasMultipleDocumentSelectionFormattingProvider: IContextKey;\r\n\tprivate readonly _hasSignatureHelpProvider: IContextKey;\r\n\tprivate readonly _hasInlineHintsProvider: IContextKey;\r\n\tprivate readonly _isInWalkThrough: IContextKey;\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _editor: CodeEditorWidget,\r\n\t\tprivate readonly _contextKeyService: IContextKeyService\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\tthis._langId = EditorContextKeys.languageId.bindTo(_contextKeyService);\r\n\t\tthis._hasCompletionItemProvider = EditorContextKeys.hasCompletionItemProvider.bindTo(_contextKeyService);\r\n\t\tthis._hasCodeActionsProvider = EditorContextKeys.hasCodeActionsProvider.bindTo(_contextKeyService);\r\n\t\tthis._hasCodeLensProvider = EditorContextKeys.hasCodeLensProvider.bindTo(_contextKeyService);\r\n\t\tthis._hasDefinitionProvider = EditorContextKeys.hasDefinitionProvider.bindTo(_contextKeyService);\r\n\t\tthis._hasDeclarationProvider = EditorContextKeys.hasDeclarationProvider.bindTo(_contextKeyService);\r\n\t\tthis._hasImplementationProvider = EditorContextKeys.hasImplementationProvider.bindTo(_contextKeyService);\r\n\t\tthis._hasTypeDefinitionProvider = EditorContextKeys.hasTypeDefinitionProvider.bindTo(_contextKeyService);\r\n\t\tthis._hasHoverProvider = EditorContextKeys.hasHoverProvider.bindTo(_contextKeyService);\r\n\t\tthis._hasDocumentHighlightProvider = EditorContextKeys.hasDocumentHighlightProvider.bindTo(_contextKeyService);\r\n\t\tthis._hasDocumentSymbolProvider = EditorContextKeys.hasDocumentSymbolProvider.bindTo(_contextKeyService);\r\n\t\tthis._hasReferenceProvider = EditorContextKeys.hasReferenceProvider.bindTo(_contextKeyService);\r\n\t\tthis._hasRenameProvider = EditorContextKeys.hasRenameProvider.bindTo(_contextKeyService);\r\n\t\tthis._hasSignatureHelpProvider = EditorContextKeys.hasSignatureHelpProvider.bindTo(_contextKeyService);\r\n\t\tthis._hasInlineHintsProvider = EditorContextKeys.hasInlineHintsProvider.bindTo(_contextKeyService);\r\n\t\tthis._hasDocumentFormattingProvider = EditorContextKeys.hasDocumentFormattingProvider.bindTo(_contextKeyService);\r\n\t\tthis._hasDocumentSelectionFormattingProvider = EditorContextKeys.hasDocumentSelectionFormattingProvider.bindTo(_contextKeyService);\r\n\t\tthis._hasMultipleDocumentFormattingProvider = EditorContextKeys.hasMultipleDocumentFormattingProvider.bindTo(_contextKeyService);\r\n\t\tthis._hasMultipleDocumentSelectionFormattingProvider = EditorContextKeys.hasMultipleDocumentSelectionFormattingProvider.bindTo(_contextKeyService);\r\n\t\tthis._isInWalkThrough = EditorContextKeys.isInWalkThroughSnippet.bindTo(_contextKeyService);\r\n\r\n\t\tconst update = () => this._update();\r\n\r\n\t\t// update when model/mode changes\r\n\t\tthis._register(_editor.onDidChangeModel(update));\r\n\t\tthis._register(_editor.onDidChangeModelLanguage(update));\r\n\r\n\t\t// update when registries change\r\n\t\tthis._register(modes.CompletionProviderRegistry.onDidChange(update));\r\n\t\tthis._register(modes.CodeActionProviderRegistry.onDidChange(update));\r\n\t\tthis._register(modes.CodeLensProviderRegistry.onDidChange(update));\r\n\t\tthis._register(modes.DefinitionProviderRegistry.onDidChange(update));\r\n\t\tthis._register(modes.DeclarationProviderRegistry.onDidChange(update));\r\n\t\tthis._register(modes.ImplementationProviderRegistry.onDidChange(update));\r\n\t\tthis._register(modes.TypeDefinitionProviderRegistry.onDidChange(update));\r\n\t\tthis._register(modes.HoverProviderRegistry.onDidChange(update));\r\n\t\tthis._register(modes.DocumentHighlightProviderRegistry.onDidChange(update));\r\n\t\tthis._register(modes.DocumentSymbolProviderRegistry.onDidChange(update));\r\n\t\tthis._register(modes.ReferenceProviderRegistry.onDidChange(update));\r\n\t\tthis._register(modes.RenameProviderRegistry.onDidChange(update));\r\n\t\tthis._register(modes.DocumentFormattingEditProviderRegistry.onDidChange(update));\r\n\t\tthis._register(modes.DocumentRangeFormattingEditProviderRegistry.onDidChange(update));\r\n\t\tthis._register(modes.SignatureHelpProviderRegistry.onDidChange(update));\r\n\t\tthis._register(modes.InlineHintsProviderRegistry.onDidChange(update));\r\n\r\n\t\tupdate();\r\n\t}\r\n\r\n\tdispose() {\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\treset() {\r\n\t\tthis._contextKeyService.bufferChangeEvents(() => {\r\n\t\t\tthis._langId.reset();\r\n\t\t\tthis._hasCompletionItemProvider.reset();\r\n\t\t\tthis._hasCodeActionsProvider.reset();\r\n\t\t\tthis._hasCodeLensProvider.reset();\r\n\t\t\tthis._hasDefinitionProvider.reset();\r\n\t\t\tthis._hasDeclarationProvider.reset();\r\n\t\t\tthis._hasImplementationProvider.reset();\r\n\t\t\tthis._hasTypeDefinitionProvider.reset();\r\n\t\t\tthis._hasHoverProvider.reset();\r\n\t\t\tthis._hasDocumentHighlightProvider.reset();\r\n\t\t\tthis._hasDocumentSymbolProvider.reset();\r\n\t\t\tthis._hasReferenceProvider.reset();\r\n\t\t\tthis._hasRenameProvider.reset();\r\n\t\t\tthis._hasDocumentFormattingProvider.reset();\r\n\t\t\tthis._hasDocumentSelectionFormattingProvider.reset();\r\n\t\t\tthis._hasSignatureHelpProvider.reset();\r\n\t\t\tthis._isInWalkThrough.reset();\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _update() {\r\n\t\tconst model = this._editor.getModel();\r\n\t\tif (!model) {\r\n\t\t\tthis.reset();\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._contextKeyService.bufferChangeEvents(() => {\r\n\t\t\tthis._langId.set(model.getLanguageIdentifier().language);\r\n\t\t\tthis._hasCompletionItemProvider.set(modes.CompletionProviderRegistry.has(model));\r\n\t\t\tthis._hasCodeActionsProvider.set(modes.CodeActionProviderRegistry.has(model));\r\n\t\t\tthis._hasCodeLensProvider.set(modes.CodeLensProviderRegistry.has(model));\r\n\t\t\tthis._hasDefinitionProvider.set(modes.DefinitionProviderRegistry.has(model));\r\n\t\t\tthis._hasDeclarationProvider.set(modes.DeclarationProviderRegistry.has(model));\r\n\t\t\tthis._hasImplementationProvider.set(modes.ImplementationProviderRegistry.has(model));\r\n\t\t\tthis._hasTypeDefinitionProvider.set(modes.TypeDefinitionProviderRegistry.has(model));\r\n\t\t\tthis._hasHoverProvider.set(modes.HoverProviderRegistry.has(model));\r\n\t\t\tthis._hasDocumentHighlightProvider.set(modes.DocumentHighlightProviderRegistry.has(model));\r\n\t\t\tthis._hasDocumentSymbolProvider.set(modes.DocumentSymbolProviderRegistry.has(model));\r\n\t\t\tthis._hasReferenceProvider.set(modes.ReferenceProviderRegistry.has(model));\r\n\t\t\tthis._hasRenameProvider.set(modes.RenameProviderRegistry.has(model));\r\n\t\t\tthis._hasSignatureHelpProvider.set(modes.SignatureHelpProviderRegistry.has(model));\r\n\t\t\tthis._hasInlineHintsProvider.set(modes.InlineHintsProviderRegistry.has(model));\r\n\t\t\tthis._hasDocumentFormattingProvider.set(modes.DocumentFormattingEditProviderRegistry.has(model) || modes.DocumentRangeFormattingEditProviderRegistry.has(model));\r\n\t\t\tthis._hasDocumentSelectionFormattingProvider.set(modes.DocumentRangeFormattingEditProviderRegistry.has(model));\r\n\t\t\tthis._hasMultipleDocumentFormattingProvider.set(modes.DocumentFormattingEditProviderRegistry.all(model).length + modes.DocumentRangeFormattingEditProviderRegistry.all(model).length > 1);\r\n\t\t\tthis._hasMultipleDocumentSelectionFormattingProvider.set(modes.DocumentRangeFormattingEditProviderRegistry.all(model).length > 1);\r\n\t\t\tthis._isInWalkThrough.set(model.uri.scheme === Schemas.walkThroughSnippet);\r\n\t\t});\r\n\t}\r\n}\r\n\r\nclass CodeEditorWidgetFocusTracker extends Disposable {\r\n\r\n\tprivate _hasFocus: boolean;\r\n\tprivate readonly _domFocusTracker: dom.IFocusTracker;\r\n\r\n\tprivate readonly _onChange: Emitter = this._register(new Emitter());\r\n\tpublic readonly onChange: Event = this._onChange.event;\r\n\r\n\tconstructor(domElement: HTMLElement) {\r\n\t\tsuper();\r\n\r\n\t\tthis._hasFocus = false;\r\n\t\tthis._domFocusTracker = this._register(dom.trackFocus(domElement));\r\n\r\n\t\tthis._register(this._domFocusTracker.onDidFocus(() => {\r\n\t\t\tthis._hasFocus = true;\r\n\t\t\tthis._onChange.fire(undefined);\r\n\t\t}));\r\n\t\tthis._register(this._domFocusTracker.onDidBlur(() => {\r\n\t\t\tthis._hasFocus = false;\r\n\t\t\tthis._onChange.fire(undefined);\r\n\t\t}));\r\n\t}\r\n\r\n\tpublic hasFocus(): boolean {\r\n\t\treturn this._hasFocus;\r\n\t}\r\n}\r\n\r\nconst squigglyStart = encodeURIComponent(``);\r\n\r\nfunction getSquigglySVGData(color: Color) {\r\n\treturn squigglyStart + encodeURIComponent(color.toString()) + squigglyEnd;\r\n}\r\n\r\nconst dotdotdotStart = encodeURIComponent(``);\r\n\r\nfunction getDotDotDotSVGData(color: Color) {\r\n\treturn dotdotdotStart + encodeURIComponent(color.toString()) + dotdotdotEnd;\r\n}\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst errorBorderColor = theme.getColor(editorErrorBorder);\r\n\tif (errorBorderColor) {\r\n\t\tcollector.addRule(`.monaco-editor .${ClassName.EditorErrorDecoration} { border-bottom: 4px double ${errorBorderColor}; }`);\r\n\t}\r\n\tconst errorForeground = theme.getColor(editorErrorForeground);\r\n\tif (errorForeground) {\r\n\t\tcollector.addRule(`.monaco-editor .${ClassName.EditorErrorDecoration} { background: url(\"data:image/svg+xml,${getSquigglySVGData(errorForeground)}\") repeat-x bottom left; }`);\r\n\t}\r\n\tconst errorBackground = theme.getColor(editorErrorBackground);\r\n\tif (errorBackground) {\r\n\t\tcollector.addRule(`.monaco-editor .${ClassName.EditorErrorDecoration}::before { display: block; content: ''; width: 100%; height: 100%; background: ${errorBackground}; }`);\r\n\t}\r\n\r\n\tconst warningBorderColor = theme.getColor(editorWarningBorder);\r\n\tif (warningBorderColor) {\r\n\t\tcollector.addRule(`.monaco-editor .${ClassName.EditorWarningDecoration} { border-bottom: 4px double ${warningBorderColor}; }`);\r\n\t}\r\n\tconst warningForeground = theme.getColor(editorWarningForeground);\r\n\tif (warningForeground) {\r\n\t\tcollector.addRule(`.monaco-editor .${ClassName.EditorWarningDecoration} { background: url(\"data:image/svg+xml,${getSquigglySVGData(warningForeground)}\") repeat-x bottom left; }`);\r\n\t}\r\n\tconst warningBackground = theme.getColor(editorWarningBackground);\r\n\tif (warningBackground) {\r\n\t\tcollector.addRule(`.monaco-editor .${ClassName.EditorWarningDecoration}::before { display: block; content: ''; width: 100%; height: 100%; background: ${warningBackground}; }`);\r\n\t}\r\n\r\n\tconst infoBorderColor = theme.getColor(editorInfoBorder);\r\n\tif (infoBorderColor) {\r\n\t\tcollector.addRule(`.monaco-editor .${ClassName.EditorInfoDecoration} { border-bottom: 4px double ${infoBorderColor}; }`);\r\n\t}\r\n\tconst infoForeground = theme.getColor(editorInfoForeground);\r\n\tif (infoForeground) {\r\n\t\tcollector.addRule(`.monaco-editor .${ClassName.EditorInfoDecoration} { background: url(\"data:image/svg+xml,${getSquigglySVGData(infoForeground)}\") repeat-x bottom left; }`);\r\n\t}\r\n\tconst infoBackground = theme.getColor(editorInfoBackground);\r\n\tif (infoBackground) {\r\n\t\tcollector.addRule(`.monaco-editor .${ClassName.EditorInfoDecoration}::before { display: block; content: ''; width: 100%; height: 100%; background: ${infoBackground}; }`);\r\n\t}\r\n\r\n\tconst hintBorderColor = theme.getColor(editorHintBorder);\r\n\tif (hintBorderColor) {\r\n\t\tcollector.addRule(`.monaco-editor .${ClassName.EditorHintDecoration} { border-bottom: 2px dotted ${hintBorderColor}; }`);\r\n\t}\r\n\tconst hintForeground = theme.getColor(editorHintForeground);\r\n\tif (hintForeground) {\r\n\t\tcollector.addRule(`.monaco-editor .${ClassName.EditorHintDecoration} { background: url(\"data:image/svg+xml,${getDotDotDotSVGData(hintForeground)}\") no-repeat bottom left; }`);\r\n\t}\r\n\r\n\tconst unnecessaryForeground = theme.getColor(editorUnnecessaryCodeOpacity);\r\n\tif (unnecessaryForeground) {\r\n\t\tcollector.addRule(`.monaco-editor.showUnused .${ClassName.EditorUnnecessaryInlineDecoration} { opacity: ${unnecessaryForeground.rgba.a}; }`);\r\n\t}\r\n\r\n\tconst unnecessaryBorder = theme.getColor(editorUnnecessaryCodeBorder);\r\n\tif (unnecessaryBorder) {\r\n\t\tcollector.addRule(`.monaco-editor.showUnused .${ClassName.EditorUnnecessaryDecoration} { border-bottom: 2px dashed ${unnecessaryBorder}; }`);\r\n\t}\r\n\r\n\tconst deprecatedForeground = theme.getColor(editorForeground) || 'inherit';\r\n\tcollector.addRule(`.monaco-editor.showDeprecated .${ClassName.EditorDeprecatedInlineDecoration} { text-decoration: line-through; text-decoration-color: ${deprecatedForeground}}`);\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as objects from 'vs/base/common/objects';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\r\nimport { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';\r\nimport { ConfigurationChangedEvent, IEditorOptions } from 'vs/editor/common/config/editorOptions';\r\nimport { ICommandService } from 'vs/platform/commands/common/commands';\r\nimport { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\r\nimport { INotificationService } from 'vs/platform/notification/common/notification';\r\nimport { IThemeService } from 'vs/platform/theme/common/themeService';\r\nimport { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';\r\n\r\nexport class EmbeddedCodeEditorWidget extends CodeEditorWidget {\r\n\r\n\tprivate readonly _parentEditor: ICodeEditor;\r\n\tprivate readonly _overwriteOptions: IEditorOptions;\r\n\r\n\tconstructor(\r\n\t\tdomElement: HTMLElement,\r\n\t\toptions: IEditorOptions,\r\n\t\tparentEditor: ICodeEditor,\r\n\t\t@IInstantiationService instantiationService: IInstantiationService,\r\n\t\t@ICodeEditorService codeEditorService: ICodeEditorService,\r\n\t\t@ICommandService commandService: ICommandService,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\r\n\t\t@IThemeService themeService: IThemeService,\r\n\t\t@INotificationService notificationService: INotificationService,\r\n\t\t@IAccessibilityService accessibilityService: IAccessibilityService\r\n\t) {\r\n\t\tsuper(domElement, { ...parentEditor.getRawOptions(), overflowWidgetsDomNode: parentEditor.getOverflowWidgetsDomNode() }, {}, instantiationService, codeEditorService, commandService, contextKeyService, themeService, notificationService, accessibilityService);\r\n\r\n\t\tthis._parentEditor = parentEditor;\r\n\t\tthis._overwriteOptions = options;\r\n\r\n\t\t// Overwrite parent's options\r\n\t\tsuper.updateOptions(this._overwriteOptions);\r\n\r\n\t\tthis._register(parentEditor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => this._onParentConfigurationChanged(e)));\r\n\t}\r\n\r\n\tgetParentEditor(): ICodeEditor {\r\n\t\treturn this._parentEditor;\r\n\t}\r\n\r\n\tprivate _onParentConfigurationChanged(e: ConfigurationChangedEvent): void {\r\n\t\tsuper.updateOptions(this._parentEditor.getRawOptions());\r\n\t\tsuper.updateOptions(this._overwriteOptions);\r\n\t}\r\n\r\n\tupdateOptions(newOptions: IEditorOptions): void {\r\n\t\tobjects.mixin(this._overwriteOptions, newOptions, true);\r\n\t\tsuper.updateOptions(this._overwriteOptions);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./anchorSelect';\r\nimport { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions';\r\nimport { localize } from 'vs/nls';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { TrackedRangeStickiness } from 'vs/editor/common/model';\r\nimport { MarkdownString } from 'vs/base/common/htmlContent';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { alert } from 'vs/base/browser/ui/aria/aria';\r\n\r\nexport const SelectionAnchorSet = new RawContextKey('selectionAnchorSet', false);\r\n\r\nclass SelectionAnchorController implements IEditorContribution {\r\n\r\n\tpublic static readonly ID = 'editor.contrib.selectionAnchorController';\r\n\r\n\tstatic get(editor: ICodeEditor): SelectionAnchorController {\r\n\t\treturn editor.getContribution(SelectionAnchorController.ID);\r\n\t}\r\n\r\n\tprivate decorationId: string | undefined;\r\n\tprivate selectionAnchorSetContextKey: IContextKey;\r\n\tprivate modelChangeListener: IDisposable;\r\n\r\n\tconstructor(\r\n\t\tprivate editor: ICodeEditor,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService\r\n\t) {\r\n\t\tthis.selectionAnchorSetContextKey = SelectionAnchorSet.bindTo(contextKeyService);\r\n\t\tthis.modelChangeListener = editor.onDidChangeModel(() => this.selectionAnchorSetContextKey.reset());\r\n\t}\r\n\r\n\tsetSelectionAnchor(): void {\r\n\t\tif (this.editor.hasModel()) {\r\n\t\t\tconst position = this.editor.getPosition();\r\n\t\t\tconst previousDecorations = this.decorationId ? [this.decorationId] : [];\r\n\t\t\tconst newDecorationId = this.editor.deltaDecorations(previousDecorations, [{\r\n\t\t\t\trange: Selection.fromPositions(position, position),\r\n\t\t\t\toptions: {\r\n\t\t\t\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,\r\n\t\t\t\t\thoverMessage: new MarkdownString().appendText(localize('selectionAnchor', \"Selection Anchor\")),\r\n\t\t\t\t\tclassName: 'selection-anchor'\r\n\t\t\t\t}\r\n\t\t\t}]);\r\n\t\t\tthis.decorationId = newDecorationId[0];\r\n\t\t\tthis.selectionAnchorSetContextKey.set(!!this.decorationId);\r\n\t\t\talert(localize('anchorSet', \"Anchor set at {0}:{1}\", position.lineNumber, position.column));\r\n\t\t}\r\n\t}\r\n\r\n\tgoToSelectionAnchor(): void {\r\n\t\tif (this.editor.hasModel() && this.decorationId) {\r\n\t\t\tconst anchorPosition = this.editor.getModel().getDecorationRange(this.decorationId);\r\n\t\t\tif (anchorPosition) {\r\n\t\t\t\tthis.editor.setPosition(anchorPosition.getStartPosition());\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tselectFromAnchorToCursor(): void {\r\n\t\tif (this.editor.hasModel() && this.decorationId) {\r\n\t\t\tconst start = this.editor.getModel().getDecorationRange(this.decorationId);\r\n\t\t\tif (start) {\r\n\t\t\t\tconst end = this.editor.getPosition();\r\n\t\t\t\tthis.editor.setSelection(Selection.fromPositions(start.getStartPosition(), end));\r\n\t\t\t\tthis.cancelSelectionAnchor();\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tcancelSelectionAnchor(): void {\r\n\t\tif (this.decorationId) {\r\n\t\t\tthis.editor.deltaDecorations([this.decorationId], []);\r\n\t\t\tthis.decorationId = undefined;\r\n\t\t\tthis.selectionAnchorSetContextKey.set(false);\r\n\t\t}\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis.cancelSelectionAnchor();\r\n\t\tthis.modelChangeListener.dispose();\r\n\t}\r\n}\r\n\r\nclass SetSelectionAnchor extends EditorAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.setSelectionAnchor',\r\n\t\t\tlabel: localize('setSelectionAnchor', \"Set Selection Anchor\"),\r\n\t\t\talias: 'Set Selection Anchor',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_B),\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tasync run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise {\r\n\t\tconst controller = SelectionAnchorController.get(editor);\r\n\t\tcontroller.setSelectionAnchor();\r\n\t}\r\n}\r\n\r\nclass GoToSelectionAnchor extends EditorAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.goToSelectionAnchor',\r\n\t\t\tlabel: localize('goToSelectionAnchor', \"Go to Selection Anchor\"),\r\n\t\t\talias: 'Go to Selection Anchor',\r\n\t\t\tprecondition: SelectionAnchorSet,\r\n\t\t});\r\n\t}\r\n\r\n\tasync run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise {\r\n\t\tconst controller = SelectionAnchorController.get(editor);\r\n\t\tcontroller.goToSelectionAnchor();\r\n\t}\r\n}\r\n\r\nclass SelectFromAnchorToCursor extends EditorAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.selectFromAnchorToCursor',\r\n\t\t\tlabel: localize('selectFromAnchorToCursor', \"Select from Anchor to Cursor\"),\r\n\t\t\talias: 'Select from Anchor to Cursor',\r\n\t\t\tprecondition: SelectionAnchorSet,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_K),\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tasync run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise {\r\n\t\tconst controller = SelectionAnchorController.get(editor);\r\n\t\tcontroller.selectFromAnchorToCursor();\r\n\t}\r\n}\r\n\r\nclass CancelSelectionAnchor extends EditorAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.cancelSelectionAnchor',\r\n\t\t\tlabel: localize('cancelSelectionAnchor', \"Cancel Selection Anchor\"),\r\n\t\t\talias: 'Cancel Selection Anchor',\r\n\t\t\tprecondition: SelectionAnchorSet,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyCode.Escape,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tasync run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise {\r\n\t\tconst controller = SelectionAnchorController.get(editor);\r\n\t\tcontroller.cancelSelectionAnchor();\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(SelectionAnchorController.ID, SelectionAnchorController);\r\nregisterEditorAction(SetSelectionAnchor);\r\nregisterEditorAction(GoToSelectionAnchor);\r\nregisterEditorAction(SelectFromAnchorToCursor);\r\nregisterEditorAction(CancelSelectionAnchor);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./bracketMatching';\r\nimport * as nls from 'vs/nls';\r\nimport { RunOnceScheduler } from 'vs/base/common/async';\r\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { IModelDeltaDecoration, OverviewRulerLane, TrackedRangeStickiness } from 'vs/editor/common/model';\r\nimport { ModelDecorationOptions } from 'vs/editor/common/model/textModel';\r\nimport { editorBracketMatchBackground, editorBracketMatchBorder } from 'vs/editor/common/view/editorColorRegistry';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { registerColor } from 'vs/platform/theme/common/colorRegistry';\r\nimport { registerThemingParticipant, themeColorFromId } from 'vs/platform/theme/common/themeService';\r\nimport { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\nconst overviewRulerBracketMatchForeground = registerColor('editorOverviewRuler.bracketMatchForeground', { dark: '#A0A0A0', light: '#A0A0A0', hc: '#A0A0A0' }, nls.localize('overviewRulerBracketMatchForeground', 'Overview ruler marker color for matching brackets.'));\r\n\r\nclass JumpToBracketAction extends EditorAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.jumpToBracket',\r\n\t\t\tlabel: nls.localize('smartSelect.jumpBracket', \"Go to Bracket\"),\r\n\t\t\talias: 'Go to Bracket',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_BACKSLASH,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tlet controller = BracketMatchingController.get(editor);\r\n\t\tif (!controller) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tcontroller.jumpToBracket();\r\n\t}\r\n}\r\n\r\nclass SelectToBracketAction extends EditorAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.selectToBracket',\r\n\t\t\tlabel: nls.localize('smartSelect.selectToBracket', \"Select to Bracket\"),\r\n\t\t\talias: 'Select to Bracket',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tdescription: {\r\n\t\t\t\tdescription: `Select to Bracket`,\r\n\t\t\t\targs: [{\r\n\t\t\t\t\tname: 'args',\r\n\t\t\t\t\tschema: {\r\n\t\t\t\t\t\ttype: 'object',\r\n\t\t\t\t\t\tproperties: {\r\n\t\t\t\t\t\t\t'selectBrackets': {\r\n\t\t\t\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t\t\t\t\tdefault: true\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t}\r\n\t\t\t\t}]\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {\r\n\t\tconst controller = BracketMatchingController.get(editor);\r\n\t\tif (!controller) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet selectBrackets = true;\r\n\t\tif (args && args.selectBrackets === false) {\r\n\t\t\tselectBrackets = false;\r\n\t\t}\r\n\t\tcontroller.selectToBracket(selectBrackets);\r\n\t}\r\n}\r\n\r\ntype Brackets = [Range, Range];\r\n\r\nclass BracketsData {\r\n\tpublic readonly position: Position;\r\n\tpublic readonly brackets: Brackets | null;\r\n\tpublic readonly options: ModelDecorationOptions;\r\n\r\n\tconstructor(position: Position, brackets: Brackets | null, options: ModelDecorationOptions) {\r\n\t\tthis.position = position;\r\n\t\tthis.brackets = brackets;\r\n\t\tthis.options = options;\r\n\t}\r\n}\r\n\r\nexport class BracketMatchingController extends Disposable implements IEditorContribution {\r\n\tpublic static readonly ID = 'editor.contrib.bracketMatchingController';\r\n\r\n\tpublic static get(editor: ICodeEditor): BracketMatchingController {\r\n\t\treturn editor.getContribution(BracketMatchingController.ID);\r\n\t}\r\n\r\n\tprivate readonly _editor: ICodeEditor;\r\n\r\n\tprivate _lastBracketsData: BracketsData[];\r\n\tprivate _lastVersionId: number;\r\n\tprivate _decorations: string[];\r\n\tprivate readonly _updateBracketsSoon: RunOnceScheduler;\r\n\tprivate _matchBrackets: 'never' | 'near' | 'always';\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor\r\n\t) {\r\n\t\tsuper();\r\n\t\tthis._editor = editor;\r\n\t\tthis._lastBracketsData = [];\r\n\t\tthis._lastVersionId = 0;\r\n\t\tthis._decorations = [];\r\n\t\tthis._updateBracketsSoon = this._register(new RunOnceScheduler(() => this._updateBrackets(), 50));\r\n\t\tthis._matchBrackets = this._editor.getOption(EditorOption.matchBrackets);\r\n\r\n\t\tthis._updateBracketsSoon.schedule();\r\n\t\tthis._register(editor.onDidChangeCursorPosition((e) => {\r\n\r\n\t\t\tif (this._matchBrackets === 'never') {\r\n\t\t\t\t// Early exit if nothing needs to be done!\r\n\t\t\t\t// Leave some form of early exit check here if you wish to continue being a cursor position change listener ;)\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tthis._updateBracketsSoon.schedule();\r\n\t\t}));\r\n\t\tthis._register(editor.onDidChangeModelContent((e) => {\r\n\t\t\tthis._updateBracketsSoon.schedule();\r\n\t\t}));\r\n\t\tthis._register(editor.onDidChangeModel((e) => {\r\n\t\t\tthis._lastBracketsData = [];\r\n\t\t\tthis._decorations = [];\r\n\t\t\tthis._updateBracketsSoon.schedule();\r\n\t\t}));\r\n\t\tthis._register(editor.onDidChangeModelLanguageConfiguration((e) => {\r\n\t\t\tthis._lastBracketsData = [];\r\n\t\t\tthis._updateBracketsSoon.schedule();\r\n\t\t}));\r\n\t\tthis._register(editor.onDidChangeConfiguration((e) => {\r\n\t\t\tif (e.hasChanged(EditorOption.matchBrackets)) {\r\n\t\t\t\tthis._matchBrackets = this._editor.getOption(EditorOption.matchBrackets);\r\n\t\t\t\tthis._decorations = this._editor.deltaDecorations(this._decorations, []);\r\n\t\t\t\tthis._lastBracketsData = [];\r\n\t\t\t\tthis._lastVersionId = 0;\r\n\t\t\t\tthis._updateBracketsSoon.schedule();\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\tpublic jumpToBracket(): void {\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst model = this._editor.getModel();\r\n\t\tconst newSelections = this._editor.getSelections().map(selection => {\r\n\t\t\tconst position = selection.getStartPosition();\r\n\r\n\t\t\t// find matching brackets if position is on a bracket\r\n\t\t\tconst brackets = model.matchBracket(position);\r\n\t\t\tlet newCursorPosition: Position | null = null;\r\n\t\t\tif (brackets) {\r\n\t\t\t\tif (brackets[0].containsPosition(position)) {\r\n\t\t\t\t\tnewCursorPosition = brackets[1].getStartPosition();\r\n\t\t\t\t} else if (brackets[1].containsPosition(position)) {\r\n\t\t\t\t\tnewCursorPosition = brackets[0].getStartPosition();\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\t// find the enclosing brackets if the position isn't on a matching bracket\r\n\t\t\t\tconst enclosingBrackets = model.findEnclosingBrackets(position);\r\n\t\t\t\tif (enclosingBrackets) {\r\n\t\t\t\t\tnewCursorPosition = enclosingBrackets[0].getStartPosition();\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// no enclosing brackets, try the very first next bracket\r\n\t\t\t\t\tconst nextBracket = model.findNextBracket(position);\r\n\t\t\t\t\tif (nextBracket && nextBracket.range) {\r\n\t\t\t\t\t\tnewCursorPosition = nextBracket.range.getStartPosition();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (newCursorPosition) {\r\n\t\t\t\treturn new Selection(newCursorPosition.lineNumber, newCursorPosition.column, newCursorPosition.lineNumber, newCursorPosition.column);\r\n\t\t\t}\r\n\t\t\treturn new Selection(position.lineNumber, position.column, position.lineNumber, position.column);\r\n\t\t});\r\n\r\n\t\tthis._editor.setSelections(newSelections);\r\n\t\tthis._editor.revealRange(newSelections[0]);\r\n\t}\r\n\r\n\tpublic selectToBracket(selectBrackets: boolean): void {\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst model = this._editor.getModel();\r\n\t\tconst newSelections: Selection[] = [];\r\n\r\n\t\tthis._editor.getSelections().forEach(selection => {\r\n\t\t\tconst position = selection.getStartPosition();\r\n\t\t\tlet brackets = model.matchBracket(position);\r\n\r\n\t\t\tif (!brackets) {\r\n\t\t\t\tbrackets = model.findEnclosingBrackets(position);\r\n\t\t\t\tif (!brackets) {\r\n\t\t\t\t\tconst nextBracket = model.findNextBracket(position);\r\n\t\t\t\t\tif (nextBracket && nextBracket.range) {\r\n\t\t\t\t\t\tbrackets = model.matchBracket(nextBracket.range.getStartPosition());\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tlet selectFrom: Position | null = null;\r\n\t\t\tlet selectTo: Position | null = null;\r\n\r\n\t\t\tif (brackets) {\r\n\t\t\t\tbrackets.sort(Range.compareRangesUsingStarts);\r\n\t\t\t\tconst [open, close] = brackets;\r\n\t\t\t\tselectFrom = selectBrackets ? open.getStartPosition() : open.getEndPosition();\r\n\t\t\t\tselectTo = selectBrackets ? close.getEndPosition() : close.getStartPosition();\r\n\t\t\t}\r\n\r\n\t\t\tif (selectFrom && selectTo) {\r\n\t\t\t\tnewSelections.push(new Selection(selectFrom.lineNumber, selectFrom.column, selectTo.lineNumber, selectTo.column));\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tif (newSelections.length > 0) {\r\n\t\t\tthis._editor.setSelections(newSelections);\r\n\t\t\tthis._editor.revealRange(newSelections[0]);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static readonly _DECORATION_OPTIONS_WITH_OVERVIEW_RULER = ModelDecorationOptions.register({\r\n\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,\r\n\t\tclassName: 'bracket-match',\r\n\t\toverviewRuler: {\r\n\t\t\tcolor: themeColorFromId(overviewRulerBracketMatchForeground),\r\n\t\t\tposition: OverviewRulerLane.Center\r\n\t\t}\r\n\t});\r\n\r\n\tprivate static readonly _DECORATION_OPTIONS_WITHOUT_OVERVIEW_RULER = ModelDecorationOptions.register({\r\n\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,\r\n\t\tclassName: 'bracket-match'\r\n\t});\r\n\r\n\tprivate _updateBrackets(): void {\r\n\t\tif (this._matchBrackets === 'never') {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._recomputeBrackets();\r\n\r\n\t\tlet newDecorations: IModelDeltaDecoration[] = [], newDecorationsLen = 0;\r\n\t\tfor (const bracketData of this._lastBracketsData) {\r\n\t\t\tlet brackets = bracketData.brackets;\r\n\t\t\tif (brackets) {\r\n\t\t\t\tnewDecorations[newDecorationsLen++] = { range: brackets[0], options: bracketData.options };\r\n\t\t\t\tnewDecorations[newDecorationsLen++] = { range: brackets[1], options: bracketData.options };\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._decorations = this._editor.deltaDecorations(this._decorations, newDecorations);\r\n\t}\r\n\r\n\tprivate _recomputeBrackets(): void {\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\t// no model => no brackets!\r\n\t\t\tthis._lastBracketsData = [];\r\n\t\t\tthis._lastVersionId = 0;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst selections = this._editor.getSelections();\r\n\t\tif (selections.length > 100) {\r\n\t\t\t// no bracket matching for high numbers of selections\r\n\t\t\tthis._lastBracketsData = [];\r\n\t\t\tthis._lastVersionId = 0;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst model = this._editor.getModel();\r\n\t\tconst versionId = model.getVersionId();\r\n\t\tlet previousData: BracketsData[] = [];\r\n\t\tif (this._lastVersionId === versionId) {\r\n\t\t\t// use the previous data only if the model is at the same version id\r\n\t\t\tpreviousData = this._lastBracketsData;\r\n\t\t}\r\n\r\n\t\tlet positions: Position[] = [], positionsLen = 0;\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tlet selection = selections[i];\r\n\r\n\t\t\tif (selection.isEmpty()) {\r\n\t\t\t\t// will bracket match a cursor only if the selection is collapsed\r\n\t\t\t\tpositions[positionsLen++] = selection.getStartPosition();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// sort positions for `previousData` cache hits\r\n\t\tif (positions.length > 1) {\r\n\t\t\tpositions.sort(Position.compare);\r\n\t\t}\r\n\r\n\t\tlet newData: BracketsData[] = [], newDataLen = 0;\r\n\t\tlet previousIndex = 0, previousLen = previousData.length;\r\n\t\tfor (let i = 0, len = positions.length; i < len; i++) {\r\n\t\t\tlet position = positions[i];\r\n\r\n\t\t\twhile (previousIndex < previousLen && previousData[previousIndex].position.isBefore(position)) {\r\n\t\t\t\tpreviousIndex++;\r\n\t\t\t}\r\n\r\n\t\t\tif (previousIndex < previousLen && previousData[previousIndex].position.equals(position)) {\r\n\t\t\t\tnewData[newDataLen++] = previousData[previousIndex];\r\n\t\t\t} else {\r\n\t\t\t\tlet brackets = model.matchBracket(position);\r\n\t\t\t\tlet options = BracketMatchingController._DECORATION_OPTIONS_WITH_OVERVIEW_RULER;\r\n\t\t\t\tif (!brackets && this._matchBrackets === 'always') {\r\n\t\t\t\t\tbrackets = model.findEnclosingBrackets(position, 20 /* give at most 20ms to compute */);\r\n\t\t\t\t\toptions = BracketMatchingController._DECORATION_OPTIONS_WITHOUT_OVERVIEW_RULER;\r\n\t\t\t\t}\r\n\t\t\t\tnewData[newDataLen++] = new BracketsData(position, brackets, options);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._lastBracketsData = newData;\r\n\t\tthis._lastVersionId = versionId;\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(BracketMatchingController.ID, BracketMatchingController);\r\nregisterEditorAction(SelectToBracketAction);\r\nregisterEditorAction(JumpToBracketAction);\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst bracketMatchBackground = theme.getColor(editorBracketMatchBackground);\r\n\tif (bracketMatchBackground) {\r\n\t\tcollector.addRule(`.monaco-editor .bracket-match { background-color: ${bracketMatchBackground}; }`);\r\n\t}\r\n\tconst bracketMatchBorder = theme.getColor(editorBracketMatchBorder);\r\n\tif (bracketMatchBorder) {\r\n\t\tcollector.addRule(`.monaco-editor .bracket-match { border: 1px solid ${bracketMatchBorder}; }`);\r\n\t}\r\n});\r\n\r\n// Go to menu\r\nMenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {\r\n\tgroup: '5_infile_nav',\r\n\tcommand: {\r\n\t\tid: 'editor.action.jumpToBracket',\r\n\t\ttitle: nls.localize({ key: 'miGoToBracket', comment: ['&& denotes a mnemonic'] }, \"Go to &&Bracket\")\r\n\t},\r\n\torder: 2\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction, IActionOptions, ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions';\r\nimport { ICommand } from 'vs/editor/common/editorCommon';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { MoveCaretCommand } from 'vs/editor/contrib/caretOperations/moveCaretCommand';\r\n\r\nclass MoveCaretAction extends EditorAction {\r\n\r\n\tprivate readonly left: boolean;\r\n\r\n\tconstructor(left: boolean, opts: IActionOptions) {\r\n\t\tsuper(opts);\r\n\r\n\t\tthis.left = left;\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet commands: ICommand[] = [];\r\n\t\tlet selections = editor.getSelections();\r\n\r\n\t\tfor (const selection of selections) {\r\n\t\t\tcommands.push(new MoveCaretCommand(selection, this.left));\r\n\t\t}\r\n\r\n\t\teditor.pushUndoStop();\r\n\t\teditor.executeCommands(this.id, commands);\r\n\t\teditor.pushUndoStop();\r\n\t}\r\n}\r\n\r\nclass MoveCaretLeftAction extends MoveCaretAction {\r\n\tconstructor() {\r\n\t\tsuper(true, {\r\n\t\t\tid: 'editor.action.moveCarretLeftAction',\r\n\t\t\tlabel: nls.localize('caret.moveLeft', \"Move Selected Text Left\"),\r\n\t\t\talias: 'Move Selected Text Left',\r\n\t\t\tprecondition: EditorContextKeys.writable\r\n\t\t});\r\n\t}\r\n}\r\n\r\nclass MoveCaretRightAction extends MoveCaretAction {\r\n\tconstructor() {\r\n\t\tsuper(false, {\r\n\t\t\tid: 'editor.action.moveCarretRightAction',\r\n\t\t\tlabel: nls.localize('caret.moveRight', \"Move Selected Text Right\"),\r\n\t\t\talias: 'Move Selected Text Right',\r\n\t\t\tprecondition: EditorContextKeys.writable\r\n\t\t});\r\n\t}\r\n}\r\n\r\nregisterEditorAction(MoveCaretLeftAction);\r\nregisterEditorAction(MoveCaretRightAction);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction, ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions';\r\nimport { ReplaceCommand } from 'vs/editor/common/commands/replaceCommand';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { ICommand } from 'vs/editor/common/editorCommon';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { MoveOperations } from 'vs/editor/common/controller/cursorMoveOperations';\r\n\r\nclass TransposeLettersAction extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.transposeLetters',\r\n\t\t\tlabel: nls.localize('transposeLetters.label', \"Transpose Letters\"),\r\n\t\t\talias: 'Transpose Letters',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\tprimary: 0,\r\n\t\t\t\tmac: {\r\n\t\t\t\t\tprimary: KeyMod.WinCtrl | KeyCode.KEY_T\r\n\t\t\t\t},\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet model = editor.getModel();\r\n\t\tlet commands: ICommand[] = [];\r\n\t\tlet selections = editor.getSelections();\r\n\r\n\t\tfor (let selection of selections) {\r\n\t\t\tif (!selection.isEmpty()) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tlet lineNumber = selection.startLineNumber;\r\n\t\t\tlet column = selection.startColumn;\r\n\r\n\t\t\tlet lastColumn = model.getLineMaxColumn(lineNumber);\r\n\r\n\t\t\tif (lineNumber === 1 && (column === 1 || (column === 2 && lastColumn === 2))) {\r\n\t\t\t\t// at beginning of file, nothing to do\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\t// handle special case: when at end of line, transpose left two chars\r\n\t\t\t// otherwise, transpose left and right chars\r\n\t\t\tlet endPosition = (column === lastColumn) ?\r\n\t\t\t\tselection.getPosition() :\r\n\t\t\t\tMoveOperations.rightPosition(model, selection.getPosition().lineNumber, selection.getPosition().column);\r\n\r\n\t\t\tlet middlePosition = MoveOperations.leftPosition(model, endPosition.lineNumber, endPosition.column);\r\n\t\t\tlet beginPosition = MoveOperations.leftPosition(model, middlePosition.lineNumber, middlePosition.column);\r\n\r\n\t\t\tlet leftChar = model.getValueInRange(Range.fromPositions(beginPosition, middlePosition));\r\n\t\t\tlet rightChar = model.getValueInRange(Range.fromPositions(middlePosition, endPosition));\r\n\r\n\t\t\tlet replaceRange = Range.fromPositions(beginPosition, endPosition);\r\n\t\t\tcommands.push(new ReplaceCommand(replaceRange, rightChar + leftChar));\r\n\t\t}\r\n\r\n\t\tif (commands.length > 0) {\r\n\t\t\teditor.pushUndoStop();\r\n\t\t\teditor.executeCommands(this.id, commands);\r\n\t\t\teditor.pushUndoStop();\r\n\t\t}\r\n\t}\r\n}\r\n\r\nregisterEditorAction(TransposeLettersAction);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport * as browser from 'vs/base/browser/browser';\r\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport { CopyOptions, InMemoryClipboardMetadataManager } from 'vs/editor/browser/controller/textAreaInput';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction, registerEditorAction, Command, MultiCommand } from 'vs/editor/browser/editorExtensions';\r\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { MenuId } from 'vs/platform/actions/common/actions';\r\nimport { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';\r\nimport { Handler } from 'vs/editor/common/editorCommon';\r\n\r\nconst CLIPBOARD_CONTEXT_MENU_GROUP = '9_cutcopypaste';\r\n\r\nconst supportsCut = (platform.isNative || document.queryCommandSupported('cut'));\r\nconst supportsCopy = (platform.isNative || document.queryCommandSupported('copy'));\r\n// IE and Edge have trouble with setting html content in clipboard\r\nconst supportsCopyWithSyntaxHighlighting = (supportsCopy && !browser.isEdgeLegacy);\r\n// Firefox only supports navigator.clipboard.readText() in browser extensions.\r\n// See https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/readText#Browser_compatibility\r\n// When loading over http, navigator.clipboard can be undefined. See https://github.com/microsoft/monaco-editor/issues/2313\r\nconst supportsPaste = (typeof navigator.clipboard === 'undefined' || browser.isFirefox) ? document.queryCommandSupported('paste') : true;\r\n\r\nfunction registerCommand(command: T): T {\r\n\tcommand.register();\r\n\treturn command;\r\n}\r\n\r\nexport const CutAction = supportsCut ? registerCommand(new MultiCommand({\r\n\tid: 'editor.action.clipboardCutAction',\r\n\tprecondition: undefined,\r\n\tkbOpts: (\r\n\t\t// Do not bind cut keybindings in the browser,\r\n\t\t// since browsers do that for us and it avoids security prompts\r\n\t\tplatform.isNative ? {\r\n\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.KEY_X,\r\n\t\t\twin: { primary: KeyMod.CtrlCmd | KeyCode.KEY_X, secondary: [KeyMod.Shift | KeyCode.Delete] },\r\n\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t} : undefined\r\n\t),\r\n\tmenuOpts: [{\r\n\t\tmenuId: MenuId.MenubarEditMenu,\r\n\t\tgroup: '2_ccp',\r\n\t\ttitle: nls.localize({ key: 'miCut', comment: ['&& denotes a mnemonic'] }, \"Cu&&t\"),\r\n\t\torder: 1\r\n\t}, {\r\n\t\tmenuId: MenuId.EditorContext,\r\n\t\tgroup: CLIPBOARD_CONTEXT_MENU_GROUP,\r\n\t\ttitle: nls.localize('actions.clipboard.cutLabel', \"Cut\"),\r\n\t\twhen: EditorContextKeys.writable,\r\n\t\torder: 1,\r\n\t}, {\r\n\t\tmenuId: MenuId.CommandPalette,\r\n\t\tgroup: '',\r\n\t\ttitle: nls.localize('actions.clipboard.cutLabel', \"Cut\"),\r\n\t\torder: 1\r\n\t}]\r\n})) : undefined;\r\n\r\nexport const CopyAction = supportsCopy ? registerCommand(new MultiCommand({\r\n\tid: 'editor.action.clipboardCopyAction',\r\n\tprecondition: undefined,\r\n\tkbOpts: (\r\n\t\t// Do not bind copy keybindings in the browser,\r\n\t\t// since browsers do that for us and it avoids security prompts\r\n\t\tplatform.isNative ? {\r\n\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.KEY_C,\r\n\t\t\twin: { primary: KeyMod.CtrlCmd | KeyCode.KEY_C, secondary: [KeyMod.CtrlCmd | KeyCode.Insert] },\r\n\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t} : undefined\r\n\t),\r\n\tmenuOpts: [{\r\n\t\tmenuId: MenuId.MenubarEditMenu,\r\n\t\tgroup: '2_ccp',\r\n\t\ttitle: nls.localize({ key: 'miCopy', comment: ['&& denotes a mnemonic'] }, \"&&Copy\"),\r\n\t\torder: 2\r\n\t}, {\r\n\t\tmenuId: MenuId.EditorContext,\r\n\t\tgroup: CLIPBOARD_CONTEXT_MENU_GROUP,\r\n\t\ttitle: nls.localize('actions.clipboard.copyLabel', \"Copy\"),\r\n\t\torder: 2,\r\n\t}, {\r\n\t\tmenuId: MenuId.CommandPalette,\r\n\t\tgroup: '',\r\n\t\ttitle: nls.localize('actions.clipboard.copyLabel', \"Copy\"),\r\n\t\torder: 1\r\n\t}]\r\n})) : undefined;\r\n\r\nexport const PasteAction = supportsPaste ? registerCommand(new MultiCommand({\r\n\tid: 'editor.action.clipboardPasteAction',\r\n\tprecondition: undefined,\r\n\tkbOpts: (\r\n\t\t// Do not bind paste keybindings in the browser,\r\n\t\t// since browsers do that for us and it avoids security prompts\r\n\t\tplatform.isNative ? {\r\n\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.KEY_V,\r\n\t\t\twin: { primary: KeyMod.CtrlCmd | KeyCode.KEY_V, secondary: [KeyMod.Shift | KeyCode.Insert] },\r\n\t\t\tlinux: { primary: KeyMod.CtrlCmd | KeyCode.KEY_V, secondary: [KeyMod.Shift | KeyCode.Insert] },\r\n\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t} : undefined\r\n\t),\r\n\tmenuOpts: [{\r\n\t\tmenuId: MenuId.MenubarEditMenu,\r\n\t\tgroup: '2_ccp',\r\n\t\ttitle: nls.localize({ key: 'miPaste', comment: ['&& denotes a mnemonic'] }, \"&&Paste\"),\r\n\t\torder: 3\r\n\t}, {\r\n\t\tmenuId: MenuId.EditorContext,\r\n\t\tgroup: CLIPBOARD_CONTEXT_MENU_GROUP,\r\n\t\ttitle: nls.localize('actions.clipboard.pasteLabel', \"Paste\"),\r\n\t\twhen: EditorContextKeys.writable,\r\n\t\torder: 3,\r\n\t}, {\r\n\t\tmenuId: MenuId.CommandPalette,\r\n\t\tgroup: '',\r\n\t\ttitle: nls.localize('actions.clipboard.pasteLabel', \"Paste\"),\r\n\t\torder: 1\r\n\t}]\r\n})) : undefined;\r\n\r\nclass ExecCommandCopyWithSyntaxHighlightingAction extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.clipboardCopyWithSyntaxHighlightingAction',\r\n\t\t\tlabel: nls.localize('actions.clipboard.copyWithSyntaxHighlightingLabel', \"Copy With Syntax Highlighting\"),\r\n\t\t\talias: 'Copy With Syntax Highlighting',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\tprimary: 0,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst emptySelectionClipboard = editor.getOption(EditorOption.emptySelectionClipboard);\r\n\r\n\t\tif (!emptySelectionClipboard && editor.getSelection().isEmpty()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tCopyOptions.forceCopyWithSyntaxHighlighting = true;\r\n\t\teditor.focus();\r\n\t\tdocument.execCommand('copy');\r\n\t\tCopyOptions.forceCopyWithSyntaxHighlighting = false;\r\n\t}\r\n}\r\n\r\nfunction registerExecCommandImpl(target: MultiCommand | undefined, browserCommand: 'cut' | 'copy'): void {\r\n\tif (!target) {\r\n\t\treturn;\r\n\t}\r\n\r\n\t// 1. handle case when focus is in editor.\r\n\ttarget.addImplementation(10000, (accessor: ServicesAccessor, args: any) => {\r\n\t\t// Only if editor text focus (i.e. not if editor has widget focus).\r\n\t\tconst focusedEditor = accessor.get(ICodeEditorService).getFocusedCodeEditor();\r\n\t\tif (focusedEditor && focusedEditor.hasTextFocus()) {\r\n\t\t\t// Do not execute if there is no selection and empty selection clipboard is off\r\n\t\t\tconst emptySelectionClipboard = focusedEditor.getOption(EditorOption.emptySelectionClipboard);\r\n\t\t\tconst selection = focusedEditor.getSelection();\r\n\t\t\tif (selection && selection.isEmpty() && !emptySelectionClipboard) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t\tdocument.execCommand(browserCommand);\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t});\r\n\r\n\t// 2. (default) handle case when focus is somewhere else.\r\n\ttarget.addImplementation(0, (accessor: ServicesAccessor, args: any) => {\r\n\t\tdocument.execCommand(browserCommand);\r\n\t\treturn true;\r\n\t});\r\n}\r\n\r\nregisterExecCommandImpl(CutAction, 'cut');\r\nregisterExecCommandImpl(CopyAction, 'copy');\r\n\r\nif (PasteAction) {\r\n\t// 1. Paste: handle case when focus is in editor.\r\n\tPasteAction.addImplementation(10000, (accessor: ServicesAccessor, args: any) => {\r\n\t\tconst codeEditorService = accessor.get(ICodeEditorService);\r\n\t\tconst clipboardService = accessor.get(IClipboardService);\r\n\r\n\t\t// Only if editor text focus (i.e. not if editor has widget focus).\r\n\t\tconst focusedEditor = codeEditorService.getFocusedCodeEditor();\r\n\t\tif (focusedEditor && focusedEditor.hasTextFocus()) {\r\n\t\t\tconst result = document.execCommand('paste');\r\n\t\t\t// Use the clipboard service if document.execCommand('paste') was not successful\r\n\t\t\tif (!result && platform.isWeb) {\r\n\t\t\t\t(async () => {\r\n\t\t\t\t\tconst clipboardText = await clipboardService.readText();\r\n\t\t\t\t\tif (clipboardText !== '') {\r\n\t\t\t\t\t\tconst metadata = InMemoryClipboardMetadataManager.INSTANCE.get(clipboardText);\r\n\t\t\t\t\t\tlet pasteOnNewLine = false;\r\n\t\t\t\t\t\tlet multicursorText: string[] | null = null;\r\n\t\t\t\t\t\tlet mode: string | null = null;\r\n\t\t\t\t\t\tif (metadata) {\r\n\t\t\t\t\t\t\tpasteOnNewLine = (focusedEditor.getOption(EditorOption.emptySelectionClipboard) && !!metadata.isFromEmptySelection);\r\n\t\t\t\t\t\t\tmulticursorText = (typeof metadata.multicursorText !== 'undefined' ? metadata.multicursorText : null);\r\n\t\t\t\t\t\t\tmode = metadata.mode;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tfocusedEditor.trigger('keyboard', Handler.Paste, {\r\n\t\t\t\t\t\t\ttext: clipboardText,\r\n\t\t\t\t\t\t\tpasteOnNewLine,\r\n\t\t\t\t\t\t\tmulticursorText,\r\n\t\t\t\t\t\t\tmode\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t}\r\n\t\t\t\t})();\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t});\r\n\r\n\t// 2. Paste: (default) handle case when focus is somewhere else.\r\n\tPasteAction.addImplementation(0, (accessor: ServicesAccessor, args: any) => {\r\n\t\tdocument.execCommand('paste');\r\n\t\treturn true;\r\n\t});\r\n}\r\n\r\nif (supportsCopyWithSyntaxHighlighting) {\r\n\tregisterEditorAction(ExecCommandCopyWithSyntaxHighlightingAction);\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { equals, flatten, isNonEmptyArray, mergeSort, coalesce } from 'vs/base/common/arrays';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { illegalArgument, isPromiseCanceledError, onUnexpectedExternalError } from 'vs/base/common/errors';\r\nimport { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { TextModelCancellationTokenSource } from 'vs/editor/browser/core/editorState';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport * as modes from 'vs/editor/common/modes';\r\nimport { IModelService } from 'vs/editor/common/services/modelService';\r\nimport { CodeActionFilter, CodeActionKind, CodeActionTrigger, filtersAction, mayIncludeActionsOfKind } from './types';\r\nimport { IProgress, Progress } from 'vs/platform/progress/common/progress';\r\nimport { CommandsRegistry } from 'vs/platform/commands/common/commands';\r\n\r\nexport const codeActionCommandId = 'editor.action.codeAction';\r\nexport const refactorCommandId = 'editor.action.refactor';\r\nexport const sourceActionCommandId = 'editor.action.sourceAction';\r\nexport const organizeImportsCommandId = 'editor.action.organizeImports';\r\nexport const fixAllCommandId = 'editor.action.fixAll';\r\n\r\nexport class CodeActionItem {\r\n\r\n\tconstructor(\r\n\t\treadonly action: modes.CodeAction,\r\n\t\treadonly provider: modes.CodeActionProvider | undefined,\r\n\t) { }\r\n\r\n\tasync resolve(token: CancellationToken): Promise {\r\n\t\tif (this.provider?.resolveCodeAction && !this.action.edit) {\r\n\t\t\tlet action: modes.CodeAction | undefined | null;\r\n\t\t\ttry {\r\n\t\t\t\taction = await this.provider.resolveCodeAction(this.action, token);\r\n\t\t\t} catch (err) {\r\n\t\t\t\tonUnexpectedExternalError(err);\r\n\t\t\t}\r\n\t\t\tif (action) {\r\n\t\t\t\tthis.action.edit = action.edit;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this;\r\n\t}\r\n}\r\n\r\nexport interface CodeActionSet extends IDisposable {\r\n\treadonly validActions: readonly CodeActionItem[];\r\n\treadonly allActions: readonly CodeActionItem[];\r\n\treadonly hasAutoFix: boolean;\r\n\r\n\treadonly documentation: readonly modes.Command[];\r\n}\r\n\r\nclass ManagedCodeActionSet extends Disposable implements CodeActionSet {\r\n\r\n\tprivate static codeActionsComparator({ action: a }: CodeActionItem, { action: b }: CodeActionItem): number {\r\n\t\tif (a.isPreferred && !b.isPreferred) {\r\n\t\t\treturn -1;\r\n\t\t} else if (!a.isPreferred && b.isPreferred) {\r\n\t\t\treturn 1;\r\n\t\t}\r\n\r\n\t\tif (isNonEmptyArray(a.diagnostics)) {\r\n\t\t\tif (isNonEmptyArray(b.diagnostics)) {\r\n\t\t\t\treturn a.diagnostics[0].message.localeCompare(b.diagnostics[0].message);\r\n\t\t\t} else {\r\n\t\t\t\treturn -1;\r\n\t\t\t}\r\n\t\t} else if (isNonEmptyArray(b.diagnostics)) {\r\n\t\t\treturn 1;\r\n\t\t} else {\r\n\t\t\treturn 0;\t// both have no diagnostics\r\n\t\t}\r\n\t}\r\n\r\n\tpublic readonly validActions: readonly CodeActionItem[];\r\n\tpublic readonly allActions: readonly CodeActionItem[];\r\n\r\n\tpublic constructor(\r\n\t\tactions: readonly CodeActionItem[],\r\n\t\tpublic readonly documentation: readonly modes.Command[],\r\n\t\tdisposables: DisposableStore,\r\n\t) {\r\n\t\tsuper();\r\n\t\tthis._register(disposables);\r\n\t\tthis.allActions = mergeSort([...actions], ManagedCodeActionSet.codeActionsComparator);\r\n\t\tthis.validActions = this.allActions.filter(({ action }) => !action.disabled);\r\n\t}\r\n\r\n\tpublic get hasAutoFix() {\r\n\t\treturn this.validActions.some(({ action: fix }) => !!fix.kind && CodeActionKind.QuickFix.contains(new CodeActionKind(fix.kind)) && !!fix.isPreferred);\r\n\t}\r\n}\r\n\r\n\r\nconst emptyCodeActionsResponse = { actions: [] as CodeActionItem[], documentation: undefined };\r\n\r\nexport function getCodeActions(\r\n\tmodel: ITextModel,\r\n\trangeOrSelection: Range | Selection,\r\n\ttrigger: CodeActionTrigger,\r\n\tprogress: IProgress,\r\n\ttoken: CancellationToken,\r\n): Promise {\r\n\tconst filter = trigger.filter || {};\r\n\r\n\tconst codeActionContext: modes.CodeActionContext = {\r\n\t\tonly: filter.include?.value,\r\n\t\ttrigger: trigger.type,\r\n\t};\r\n\r\n\tconst cts = new TextModelCancellationTokenSource(model, token);\r\n\tconst providers = getCodeActionProviders(model, filter);\r\n\r\n\tconst disposables = new DisposableStore();\r\n\tconst promises = providers.map(async provider => {\r\n\t\ttry {\r\n\t\t\tprogress.report(provider);\r\n\t\t\tconst providedCodeActions = await provider.provideCodeActions(model, rangeOrSelection, codeActionContext, cts.token);\r\n\t\t\tif (providedCodeActions) {\r\n\t\t\t\tdisposables.add(providedCodeActions);\r\n\t\t\t}\r\n\r\n\t\t\tif (cts.token.isCancellationRequested) {\r\n\t\t\t\treturn emptyCodeActionsResponse;\r\n\t\t\t}\r\n\r\n\t\t\tconst filteredActions = (providedCodeActions?.actions || []).filter(action => action && filtersAction(filter, action));\r\n\t\t\tconst documentation = getDocumentation(provider, filteredActions, filter.include);\r\n\t\t\treturn {\r\n\t\t\t\tactions: filteredActions.map(action => new CodeActionItem(action, provider)),\r\n\t\t\t\tdocumentation\r\n\t\t\t};\r\n\t\t} catch (err) {\r\n\t\t\tif (isPromiseCanceledError(err)) {\r\n\t\t\t\tthrow err;\r\n\t\t\t}\r\n\t\t\tonUnexpectedExternalError(err);\r\n\t\t\treturn emptyCodeActionsResponse;\r\n\t\t}\r\n\t});\r\n\r\n\tconst listener = modes.CodeActionProviderRegistry.onDidChange(() => {\r\n\t\tconst newProviders = modes.CodeActionProviderRegistry.all(model);\r\n\t\tif (!equals(newProviders, providers)) {\r\n\t\t\tcts.cancel();\r\n\t\t}\r\n\t});\r\n\r\n\treturn Promise.all(promises).then(actions => {\r\n\t\tconst allActions = flatten(actions.map(x => x.actions));\r\n\t\tconst allDocumentation = coalesce(actions.map(x => x.documentation));\r\n\t\treturn new ManagedCodeActionSet(allActions, allDocumentation, disposables);\r\n\t})\r\n\t\t.finally(() => {\r\n\t\t\tlistener.dispose();\r\n\t\t\tcts.dispose();\r\n\t\t});\r\n}\r\n\r\nfunction getCodeActionProviders(\r\n\tmodel: ITextModel,\r\n\tfilter: CodeActionFilter\r\n) {\r\n\treturn modes.CodeActionProviderRegistry.all(model)\r\n\t\t// Don't include providers that we know will not return code actions of interest\r\n\t\t.filter(provider => {\r\n\t\t\tif (!provider.providedCodeActionKinds) {\r\n\t\t\t\t// We don't know what type of actions this provider will return.\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t\treturn provider.providedCodeActionKinds.some(kind => mayIncludeActionsOfKind(filter, new CodeActionKind(kind)));\r\n\t\t});\r\n}\r\n\r\nfunction getDocumentation(\r\n\tprovider: modes.CodeActionProvider,\r\n\tprovidedCodeActions: readonly modes.CodeAction[],\r\n\tonly?: CodeActionKind\r\n): modes.Command | undefined {\r\n\tif (!provider.documentation) {\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tconst documentation = provider.documentation.map(entry => ({ kind: new CodeActionKind(entry.kind), command: entry.command }));\r\n\r\n\tif (only) {\r\n\t\tlet currentBest: { readonly kind: CodeActionKind, readonly command: modes.Command } | undefined;\r\n\t\tfor (const entry of documentation) {\r\n\t\t\tif (entry.kind.contains(only)) {\r\n\t\t\t\tif (!currentBest) {\r\n\t\t\t\t\tcurrentBest = entry;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// Take best match\r\n\t\t\t\t\tif (currentBest.kind.contains(entry.kind)) {\r\n\t\t\t\t\t\tcurrentBest = entry;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (currentBest) {\r\n\t\t\treturn currentBest?.command;\r\n\t\t}\r\n\t}\r\n\r\n\t// Otherwise, check to see if any of the provided actions match.\r\n\tfor (const action of providedCodeActions) {\r\n\t\tif (!action.kind) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tfor (const entry of documentation) {\r\n\t\t\tif (entry.kind.contains(new CodeActionKind(action.kind))) {\r\n\t\t\t\treturn entry.command;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\treturn undefined;\r\n}\r\n\r\nCommandsRegistry.registerCommand('_executeCodeActionProvider', async function (accessor, ...args): Promise> {\r\n\tconst [resource, rangeOrSelection, kind, itemResolveCount] = args;\r\n\tif (!(resource instanceof URI)) {\r\n\t\tthrow illegalArgument();\r\n\t}\r\n\r\n\tconst model = accessor.get(IModelService).getModel(resource);\r\n\tif (!model) {\r\n\t\tthrow illegalArgument();\r\n\t}\r\n\r\n\tconst validatedRangeOrSelection = Selection.isISelection(rangeOrSelection)\r\n\t\t? Selection.liftSelection(rangeOrSelection)\r\n\t\t: Range.isIRange(rangeOrSelection)\r\n\t\t\t? model.validateRange(rangeOrSelection)\r\n\t\t\t: undefined;\r\n\r\n\tif (!validatedRangeOrSelection) {\r\n\t\tthrow illegalArgument();\r\n\t}\r\n\r\n\tconst codeActionSet = await getCodeActions(\r\n\t\tmodel,\r\n\t\tvalidatedRangeOrSelection,\r\n\t\t{ type: modes.CodeActionTriggerType.Manual, filter: { includeSourceActions: true, include: kind && kind.value ? new CodeActionKind(kind.value) : undefined } },\r\n\t\tProgress.None,\r\n\t\tCancellationToken.None);\r\n\r\n\r\n\tconst resolving: Promise[] = [];\r\n\tconst resolveCount = Math.min(codeActionSet.validActions.length, typeof itemResolveCount === 'number' ? itemResolveCount : 0);\r\n\tfor (let i = 0; i < resolveCount; i++) {\r\n\t\tresolving.push(codeActionSet.validActions[i].resolve(CancellationToken.None));\r\n\t}\r\n\r\n\ttry {\r\n\t\tawait Promise.all(resolving);\r\n\t\treturn codeActionSet.validActions.map(item => item.action);\r\n\t} finally {\r\n\t\tsetTimeout(() => codeActionSet.dispose(), 100);\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { getDomNodePagePosition } from 'vs/base/browser/dom';\r\nimport { IAnchor } from 'vs/base/browser/ui/contextview/contextview';\r\nimport { Action, IAction, Separator } from 'vs/base/common/actions';\r\nimport { canceled } from 'vs/base/common/errors';\r\nimport { ResolvedKeybinding } from 'vs/base/common/keyCodes';\r\nimport { Lazy } from 'vs/base/common/lazy';\r\nimport { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { IPosition, Position } from 'vs/editor/common/core/position';\r\nimport { ScrollType } from 'vs/editor/common/editorCommon';\r\nimport { CodeAction, CodeActionProviderRegistry, Command } from 'vs/editor/common/modes';\r\nimport { codeActionCommandId, CodeActionItem, CodeActionSet, fixAllCommandId, organizeImportsCommandId, refactorCommandId, sourceActionCommandId } from 'vs/editor/contrib/codeAction/codeAction';\r\nimport { CodeActionAutoApply, CodeActionCommandArgs, CodeActionTrigger, CodeActionKind } from 'vs/editor/contrib/codeAction/types';\r\nimport { IContextMenuService } from 'vs/platform/contextview/browser/contextView';\r\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\r\nimport { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';\r\n\r\ninterface CodeActionWidgetDelegate {\r\n\tonSelectCodeAction: (action: CodeActionItem) => Promise;\r\n}\r\n\r\ninterface ResolveCodeActionKeybinding {\r\n\treadonly kind: CodeActionKind;\r\n\treadonly preferred: boolean;\r\n\treadonly resolvedKeybinding: ResolvedKeybinding;\r\n}\r\n\r\nclass CodeActionAction extends Action {\r\n\tconstructor(\r\n\t\tpublic readonly action: CodeAction,\r\n\t\tcallback: () => Promise,\r\n\t) {\r\n\t\tsuper(action.command ? action.command.id : action.title, stripNewlines(action.title), undefined, !action.disabled, callback);\r\n\t}\r\n}\r\n\r\nfunction stripNewlines(str: string): string {\r\n\treturn str.replace(/\\r\\n|\\r|\\n/g, ' ');\r\n}\r\n\r\nexport interface CodeActionShowOptions {\r\n\treadonly includeDisabledActions: boolean;\r\n}\r\n\r\nexport class CodeActionMenu extends Disposable {\r\n\r\n\tprivate _visible: boolean = false;\r\n\tprivate readonly _showingActions = this._register(new MutableDisposable());\r\n\r\n\tprivate readonly _keybindingResolver: CodeActionKeybindingResolver;\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _editor: ICodeEditor,\r\n\t\tprivate readonly _delegate: CodeActionWidgetDelegate,\r\n\t\t@IContextMenuService private readonly _contextMenuService: IContextMenuService,\r\n\t\t@IKeybindingService keybindingService: IKeybindingService,\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\tthis._keybindingResolver = new CodeActionKeybindingResolver({\r\n\t\t\tgetKeybindings: () => keybindingService.getKeybindings()\r\n\t\t});\r\n\t}\r\n\r\n\tget isVisible(): boolean {\r\n\t\treturn this._visible;\r\n\t}\r\n\r\n\tpublic async show(trigger: CodeActionTrigger, codeActions: CodeActionSet, at: IAnchor | IPosition, options: CodeActionShowOptions): Promise {\r\n\t\tconst actionsToShow = options.includeDisabledActions ? codeActions.allActions : codeActions.validActions;\r\n\t\tif (!actionsToShow.length) {\r\n\t\t\tthis._visible = false;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!this._editor.getDomNode()) {\r\n\t\t\t// cancel when editor went off-dom\r\n\t\t\tthis._visible = false;\r\n\t\t\tthrow canceled();\r\n\t\t}\r\n\r\n\t\tthis._visible = true;\r\n\t\tthis._showingActions.value = codeActions;\r\n\r\n\t\tconst menuActions = this.getMenuActions(trigger, actionsToShow, codeActions.documentation);\r\n\r\n\t\tconst anchor = Position.isIPosition(at) ? this._toCoords(at) : at || { x: 0, y: 0 };\r\n\t\tconst resolver = this._keybindingResolver.getResolver();\r\n\r\n\t\tthis._contextMenuService.showContextMenu({\r\n\t\t\tdomForShadowRoot: this._editor.getDomNode()!,\r\n\t\t\tgetAnchor: () => anchor,\r\n\t\t\tgetActions: () => menuActions,\r\n\t\t\tonHide: () => {\r\n\t\t\t\tthis._visible = false;\r\n\t\t\t\tthis._editor.focus();\r\n\t\t\t},\r\n\t\t\tautoSelectFirstItem: true,\r\n\t\t\tgetKeyBinding: action => action instanceof CodeActionAction ? resolver(action.action) : undefined,\r\n\t\t});\r\n\t}\r\n\r\n\tprivate getMenuActions(\r\n\t\ttrigger: CodeActionTrigger,\r\n\t\tactionsToShow: readonly CodeActionItem[],\r\n\t\tdocumentation: readonly Command[]\r\n\t): IAction[] {\r\n\t\tconst toCodeActionAction = (item: CodeActionItem): CodeActionAction => new CodeActionAction(item.action, () => this._delegate.onSelectCodeAction(item));\r\n\r\n\t\tconst result: IAction[] = actionsToShow\r\n\t\t\t.map(toCodeActionAction);\r\n\r\n\t\tconst allDocumentation: Command[] = [...documentation];\r\n\r\n\t\tconst model = this._editor.getModel();\r\n\t\tif (model && result.length) {\r\n\t\t\tfor (const provider of CodeActionProviderRegistry.all(model)) {\r\n\t\t\t\tif (provider._getAdditionalMenuItems) {\r\n\t\t\t\t\tallDocumentation.push(...provider._getAdditionalMenuItems({ trigger: trigger.type, only: trigger.filter?.include?.value }, actionsToShow.map(item => item.action)));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (allDocumentation.length) {\r\n\t\t\tresult.push(new Separator(), ...allDocumentation.map(command => toCodeActionAction(new CodeActionItem({\r\n\t\t\t\ttitle: command.title,\r\n\t\t\t\tcommand: command,\r\n\t\t\t}, undefined))));\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate _toCoords(position: IPosition): { x: number, y: number } {\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn { x: 0, y: 0 };\r\n\t\t}\r\n\t\tthis._editor.revealPosition(position, ScrollType.Immediate);\r\n\t\tthis._editor.render();\r\n\r\n\t\t// Translate to absolute editor position\r\n\t\tconst cursorCoords = this._editor.getScrolledVisiblePosition(position);\r\n\t\tconst editorCoords = getDomNodePagePosition(this._editor.getDomNode());\r\n\t\tconst x = editorCoords.left + cursorCoords.left;\r\n\t\tconst y = editorCoords.top + cursorCoords.top + cursorCoords.height;\r\n\r\n\t\treturn { x, y };\r\n\t}\r\n}\r\n\r\nexport class CodeActionKeybindingResolver {\r\n\tprivate static readonly codeActionCommands: readonly string[] = [\r\n\t\trefactorCommandId,\r\n\t\tcodeActionCommandId,\r\n\t\tsourceActionCommandId,\r\n\t\torganizeImportsCommandId,\r\n\t\tfixAllCommandId\r\n\t];\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _keybindingProvider: {\r\n\t\t\tgetKeybindings(): readonly ResolvedKeybindingItem[],\r\n\t\t},\r\n\t) { }\r\n\r\n\tpublic getResolver(): (action: CodeAction) => ResolvedKeybinding | undefined {\r\n\t\t// Lazy since we may not actually ever read the value\r\n\t\tconst allCodeActionBindings = new Lazy(() =>\r\n\t\t\tthis._keybindingProvider.getKeybindings()\r\n\t\t\t\t.filter(item => CodeActionKeybindingResolver.codeActionCommands.indexOf(item.command!) >= 0)\r\n\t\t\t\t.filter(item => item.resolvedKeybinding)\r\n\t\t\t\t.map((item): ResolveCodeActionKeybinding => {\r\n\t\t\t\t\t// Special case these commands since they come built-in with VS Code and don't use 'commandArgs'\r\n\t\t\t\t\tlet commandArgs = item.commandArgs;\r\n\t\t\t\t\tif (item.command === organizeImportsCommandId) {\r\n\t\t\t\t\t\tcommandArgs = { kind: CodeActionKind.SourceOrganizeImports.value };\r\n\t\t\t\t\t} else if (item.command === fixAllCommandId) {\r\n\t\t\t\t\t\tcommandArgs = { kind: CodeActionKind.SourceFixAll.value };\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\treturn {\r\n\t\t\t\t\t\tresolvedKeybinding: item.resolvedKeybinding!,\r\n\t\t\t\t\t\t...CodeActionCommandArgs.fromUser(commandArgs, {\r\n\t\t\t\t\t\t\tkind: CodeActionKind.None,\r\n\t\t\t\t\t\t\tapply: CodeActionAutoApply.Never\r\n\t\t\t\t\t\t})\r\n\t\t\t\t\t};\r\n\t\t\t\t}));\r\n\r\n\t\treturn (action) => {\r\n\t\t\tif (action.kind) {\r\n\t\t\t\tconst binding = this.bestKeybindingForCodeAction(action, allCodeActionBindings.getValue());\r\n\t\t\t\treturn binding?.resolvedKeybinding;\r\n\t\t\t}\r\n\t\t\treturn undefined;\r\n\t\t};\r\n\t}\r\n\r\n\tprivate bestKeybindingForCodeAction(\r\n\t\taction: CodeAction,\r\n\t\tcandidates: readonly ResolveCodeActionKeybinding[],\r\n\t): ResolveCodeActionKeybinding | undefined {\r\n\t\tif (!action.kind) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\t\tconst kind = new CodeActionKind(action.kind);\r\n\r\n\t\treturn candidates\r\n\t\t\t.filter(candidate => candidate.kind.contains(kind))\r\n\t\t\t.filter(candidate => {\r\n\t\t\t\tif (candidate.preferred) {\r\n\t\t\t\t\t// If the candidate keybinding only applies to preferred actions, the this action must also be preferred\r\n\t\t\t\t\treturn action.isPreferred;\r\n\t\t\t\t}\r\n\t\t\t\treturn true;\r\n\t\t\t})\r\n\t\t\t.reduceRight((currentBest, candidate) => {\r\n\t\t\t\tif (!currentBest) {\r\n\t\t\t\t\treturn candidate;\r\n\t\t\t\t}\r\n\t\t\t\t// Select the more specific binding\r\n\t\t\t\treturn currentBest.kind.contains(candidate.kind) ? candidate : currentBest;\r\n\t\t\t}, undefined as ResolveCodeActionKeybinding | undefined);\r\n\t}\r\n}\r\n\r\n\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CancelablePromise, createCancelablePromise, TimeoutTimer } from 'vs/base/common/async';\r\nimport { Emitter } from 'vs/base/common/event';\r\nimport { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { CodeActionProviderRegistry, CodeActionTriggerType } from 'vs/editor/common/modes';\r\nimport { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IMarkerService } from 'vs/platform/markers/common/markers';\r\nimport { IEditorProgressService, Progress } from 'vs/platform/progress/common/progress';\r\nimport { getCodeActions, CodeActionSet } from './codeAction';\r\nimport { CodeActionTrigger } from './types';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { isEqual } from 'vs/base/common/resources';\r\n\r\nexport const SUPPORTED_CODE_ACTIONS = new RawContextKey('supportedCodeAction', '');\r\n\r\nexport type TriggeredCodeAction = undefined | {\r\n\treadonly selection: Selection;\r\n\treadonly trigger: CodeActionTrigger;\r\n\treadonly position: Position;\r\n};\r\n\r\nclass CodeActionOracle extends Disposable {\r\n\r\n\tprivate readonly _autoTriggerTimer = this._register(new TimeoutTimer());\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _editor: ICodeEditor,\r\n\t\tprivate readonly _markerService: IMarkerService,\r\n\t\tprivate readonly _signalChange: (triggered: TriggeredCodeAction) => void,\r\n\t\tprivate readonly _delay: number = 250,\r\n\t) {\r\n\t\tsuper();\r\n\t\tthis._register(this._markerService.onMarkerChanged(e => this._onMarkerChanges(e)));\r\n\t\tthis._register(this._editor.onDidChangeCursorPosition(() => this._onCursorChange()));\r\n\t}\r\n\r\n\tpublic trigger(trigger: CodeActionTrigger): TriggeredCodeAction {\r\n\t\tconst selection = this._getRangeOfSelectionUnlessWhitespaceEnclosed(trigger);\r\n\t\treturn this._createEventAndSignalChange(trigger, selection);\r\n\t}\r\n\r\n\tprivate _onMarkerChanges(resources: readonly URI[]): void {\r\n\t\tconst model = this._editor.getModel();\r\n\t\tif (!model) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (resources.some(resource => isEqual(resource, model.uri))) {\r\n\t\t\tthis._autoTriggerTimer.cancelAndSet(() => {\r\n\t\t\t\tthis.trigger({ type: CodeActionTriggerType.Auto });\r\n\t\t\t}, this._delay);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _onCursorChange(): void {\r\n\t\tthis._autoTriggerTimer.cancelAndSet(() => {\r\n\t\t\tthis.trigger({ type: CodeActionTriggerType.Auto });\r\n\t\t}, this._delay);\r\n\t}\r\n\r\n\tprivate _getRangeOfMarker(selection: Selection): Range | undefined {\r\n\t\tconst model = this._editor.getModel();\r\n\t\tif (!model) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\t\tfor (const marker of this._markerService.read({ resource: model.uri })) {\r\n\t\t\tconst markerRange = model.validateRange(marker);\r\n\t\t\tif (Range.intersectRanges(markerRange, selection)) {\r\n\t\t\t\treturn Range.lift(markerRange);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tprivate _getRangeOfSelectionUnlessWhitespaceEnclosed(trigger: CodeActionTrigger): Selection | undefined {\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\t\tconst model = this._editor.getModel();\r\n\t\tconst selection = this._editor.getSelection();\r\n\t\tif (selection.isEmpty() && trigger.type === CodeActionTriggerType.Auto) {\r\n\t\t\tconst { lineNumber, column } = selection.getPosition();\r\n\t\t\tconst line = model.getLineContent(lineNumber);\r\n\t\t\tif (line.length === 0) {\r\n\t\t\t\t// empty line\r\n\t\t\t\treturn undefined;\r\n\t\t\t} else if (column === 1) {\r\n\t\t\t\t// look only right\r\n\t\t\t\tif (/\\s/.test(line[0])) {\r\n\t\t\t\t\treturn undefined;\r\n\t\t\t\t}\r\n\t\t\t} else if (column === model.getLineMaxColumn(lineNumber)) {\r\n\t\t\t\t// look only left\r\n\t\t\t\tif (/\\s/.test(line[line.length - 1])) {\r\n\t\t\t\t\treturn undefined;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\t// look left and right\r\n\t\t\t\tif (/\\s/.test(line[column - 2]) && /\\s/.test(line[column - 1])) {\r\n\t\t\t\t\treturn undefined;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn selection;\r\n\t}\r\n\r\n\tprivate _createEventAndSignalChange(trigger: CodeActionTrigger, selection: Selection | undefined): TriggeredCodeAction {\r\n\t\tconst model = this._editor.getModel();\r\n\t\tif (!selection || !model) {\r\n\t\t\t// cancel\r\n\t\t\tthis._signalChange(undefined);\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\r\n\t\tconst markerRange = this._getRangeOfMarker(selection);\r\n\t\tconst position = markerRange ? markerRange.getStartPosition() : selection.getStartPosition();\r\n\r\n\t\tconst e: TriggeredCodeAction = {\r\n\t\t\ttrigger,\r\n\t\t\tselection,\r\n\t\t\tposition\r\n\t\t};\r\n\t\tthis._signalChange(e);\r\n\t\treturn e;\r\n\t}\r\n}\r\n\r\nexport namespace CodeActionsState {\r\n\r\n\texport const enum Type {\r\n\t\tEmpty,\r\n\t\tTriggered,\r\n\t}\r\n\r\n\texport const Empty = { type: Type.Empty } as const;\r\n\r\n\texport class Triggered {\r\n\t\treadonly type = Type.Triggered;\r\n\r\n\t\tconstructor(\r\n\t\t\tpublic readonly trigger: CodeActionTrigger,\r\n\t\t\tpublic readonly rangeOrSelection: Range | Selection,\r\n\t\t\tpublic readonly position: Position,\r\n\t\t\tpublic readonly actions: CancelablePromise,\r\n\t\t) { }\r\n\t}\r\n\r\n\texport type State = typeof Empty | Triggered;\r\n}\r\n\r\nexport class CodeActionModel extends Disposable {\r\n\r\n\tprivate readonly _codeActionOracle = this._register(new MutableDisposable());\r\n\tprivate _state: CodeActionsState.State = CodeActionsState.Empty;\r\n\tprivate readonly _supportedCodeActions: IContextKey;\r\n\r\n\tprivate readonly _onDidChangeState = this._register(new Emitter());\r\n\tpublic readonly onDidChangeState = this._onDidChangeState.event;\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _editor: ICodeEditor,\r\n\t\tprivate readonly _markerService: IMarkerService,\r\n\t\tcontextKeyService: IContextKeyService,\r\n\t\tprivate readonly _progressService?: IEditorProgressService\r\n\t) {\r\n\t\tsuper();\r\n\t\tthis._supportedCodeActions = SUPPORTED_CODE_ACTIONS.bindTo(contextKeyService);\r\n\r\n\t\tthis._register(this._editor.onDidChangeModel(() => this._update()));\r\n\t\tthis._register(this._editor.onDidChangeModelLanguage(() => this._update()));\r\n\t\tthis._register(CodeActionProviderRegistry.onDidChange(() => this._update()));\r\n\r\n\t\tthis._update();\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tsuper.dispose();\r\n\t\tthis.setState(CodeActionsState.Empty, true);\r\n\t}\r\n\r\n\tprivate _update(): void {\r\n\t\tthis._codeActionOracle.value = undefined;\r\n\r\n\t\tthis.setState(CodeActionsState.Empty);\r\n\r\n\t\tconst model = this._editor.getModel();\r\n\t\tif (model\r\n\t\t\t&& CodeActionProviderRegistry.has(model)\r\n\t\t\t&& !this._editor.getOption(EditorOption.readOnly)\r\n\t\t) {\r\n\t\t\tconst supportedActions: string[] = [];\r\n\t\t\tfor (const provider of CodeActionProviderRegistry.all(model)) {\r\n\t\t\t\tif (Array.isArray(provider.providedCodeActionKinds)) {\r\n\t\t\t\t\tsupportedActions.push(...provider.providedCodeActionKinds);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tthis._supportedCodeActions.set(supportedActions.join(' '));\r\n\r\n\t\t\tthis._codeActionOracle.value = new CodeActionOracle(this._editor, this._markerService, trigger => {\r\n\t\t\t\tif (!trigger) {\r\n\t\t\t\t\tthis.setState(CodeActionsState.Empty);\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst actions = createCancelablePromise(token => getCodeActions(model, trigger.selection, trigger.trigger, Progress.None, token));\r\n\t\t\t\tif (trigger.trigger.type === CodeActionTriggerType.Manual) {\r\n\t\t\t\t\tthis._progressService?.showWhile(actions, 250);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis.setState(new CodeActionsState.Triggered(trigger.trigger, trigger.selection, trigger.position, actions));\r\n\r\n\t\t\t}, undefined);\r\n\t\t\tthis._codeActionOracle.value.trigger({ type: CodeActionTriggerType.Auto });\r\n\t\t} else {\r\n\t\t\tthis._supportedCodeActions.reset();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic trigger(trigger: CodeActionTrigger) {\r\n\t\tif (this._codeActionOracle.value) {\r\n\t\t\tthis._codeActionOracle.value.trigger(trigger);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate setState(newState: CodeActionsState.State, skipNotify?: boolean) {\r\n\t\tif (newState === this._state) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// Cancel old request\r\n\t\tif (this._state.type === CodeActionsState.Type.Triggered) {\r\n\t\t\tthis._state.actions.cancel();\r\n\t\t}\r\n\r\n\t\tthis._state = newState;\r\n\r\n\t\tif (!skipNotify) {\r\n\t\t\tthis._onDidChangeState.fire(newState);\r\n\t\t}\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CancelablePromise, RunOnceScheduler, createCancelablePromise, disposableTimeout } from 'vs/base/common/async';\r\nimport { onUnexpectedError, onUnexpectedExternalError } from 'vs/base/common/errors';\r\nimport { toDisposable, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { StableEditorScrollState } from 'vs/editor/browser/core/editorState';\r\nimport { ICodeEditor, MouseTargetType, IViewZoneChangeAccessor, IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { registerEditorContribution, ServicesAccessor, registerEditorAction, EditorAction } from 'vs/editor/browser/editorExtensions';\r\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { IModelDecorationsChangeAccessor } from 'vs/editor/common/model';\r\nimport { CodeLensProviderRegistry, CodeLens, Command } from 'vs/editor/common/modes';\r\nimport { CodeLensModel, getCodeLensModel, CodeLensItem } from 'vs/editor/contrib/codelens/codelens';\r\nimport { CodeLensWidget, CodeLensHelper } from 'vs/editor/contrib/codelens/codelensWidget';\r\nimport { ICommandService } from 'vs/platform/commands/common/commands';\r\nimport { INotificationService } from 'vs/platform/notification/common/notification';\r\nimport { ICodeLensCache } from 'vs/editor/contrib/codelens/codeLensCache';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { hash } from 'vs/base/common/hash';\r\nimport { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';\r\nimport { localize } from 'vs/nls';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { LanguageFeatureRequestDelays } from 'vs/editor/common/modes/languageFeatureRegistry';\r\n\r\nexport class CodeLensContribution implements IEditorContribution {\r\n\r\n\tstatic readonly ID: string = 'css.editor.codeLens';\r\n\r\n\tprivate readonly _disposables = new DisposableStore();\r\n\tprivate readonly _localToDispose = new DisposableStore();\r\n\tprivate readonly _styleElement: HTMLStyleElement;\r\n\tprivate readonly _styleClassName: string;\r\n\tprivate readonly _lenses: CodeLensWidget[] = [];\r\n\r\n\tprivate readonly _getCodeLensModelDelays = new LanguageFeatureRequestDelays(CodeLensProviderRegistry, 250, 2500);\r\n\tprivate _getCodeLensModelPromise: CancelablePromise | undefined;\r\n\tprivate _oldCodeLensModels = new DisposableStore();\r\n\tprivate _currentCodeLensModel: CodeLensModel | undefined;\r\n\tprivate readonly _resolveCodeLensesDelays = new LanguageFeatureRequestDelays(CodeLensProviderRegistry, 250, 2500);\r\n\tprivate readonly _resolveCodeLensesScheduler = new RunOnceScheduler(() => this._resolveCodeLensesInViewport(), this._resolveCodeLensesDelays.min);\r\n\tprivate _resolveCodeLensesPromise: CancelablePromise | undefined;\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _editor: ICodeEditor,\r\n\t\t@ICommandService private readonly _commandService: ICommandService,\r\n\t\t@INotificationService private readonly _notificationService: INotificationService,\r\n\t\t@ICodeLensCache private readonly _codeLensCache: ICodeLensCache\r\n\t) {\r\n\r\n\t\tthis._disposables.add(this._editor.onDidChangeModel(() => this._onModelChange()));\r\n\t\tthis._disposables.add(this._editor.onDidChangeModelLanguage(() => this._onModelChange()));\r\n\t\tthis._disposables.add(this._editor.onDidChangeConfiguration((e) => {\r\n\t\t\tif (e.hasChanged(EditorOption.fontInfo) || e.hasChanged(EditorOption.codeLensFontSize) || e.hasChanged(EditorOption.codeLensFontFamily)) {\r\n\t\t\t\tthis._updateLensStyle();\r\n\t\t\t}\r\n\t\t\tif (e.hasChanged(EditorOption.codeLens)) {\r\n\t\t\t\tthis._onModelChange();\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._disposables.add(CodeLensProviderRegistry.onDidChange(this._onModelChange, this));\r\n\t\tthis._onModelChange();\r\n\r\n\t\tthis._styleClassName = '_' + hash(this._editor.getId()).toString(16);\r\n\t\tthis._styleElement = dom.createStyleSheet(\r\n\t\t\tdom.isInShadowDOM(this._editor.getContainerDomNode())\r\n\t\t\t\t? this._editor.getContainerDomNode()\r\n\t\t\t\t: undefined\r\n\t\t);\r\n\t\tthis._updateLensStyle();\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._localDispose();\r\n\t\tthis._disposables.dispose();\r\n\t\tthis._oldCodeLensModels.dispose();\r\n\t\tthis._currentCodeLensModel?.dispose();\r\n\t\tthis._styleElement.remove();\r\n\t}\r\n\r\n\tprivate _getLayoutInfo() {\r\n\t\tlet fontSize = this._editor.getOption(EditorOption.codeLensFontSize);\r\n\t\tlet codeLensHeight: number;\r\n\t\tif (!fontSize || fontSize < 5) {\r\n\t\t\tfontSize = (this._editor.getOption(EditorOption.fontSize) * .9) | 0;\r\n\t\t\tcodeLensHeight = this._editor.getOption(EditorOption.lineHeight);\r\n\t\t} else {\r\n\t\t\tcodeLensHeight = (fontSize * Math.max(1.3, this._editor.getOption(EditorOption.lineHeight) / this._editor.getOption(EditorOption.fontSize))) | 0;\r\n\t\t}\r\n\t\treturn { codeLensHeight, fontSize };\r\n\t}\r\n\r\n\tprivate _updateLensStyle(): void {\r\n\r\n\t\tconst { codeLensHeight, fontSize } = this._getLayoutInfo();\r\n\t\tconst fontFamily = this._editor.getOption(EditorOption.codeLensFontFamily);\r\n\t\tconst editorFontInfo = this._editor.getOption(EditorOption.fontInfo);\r\n\r\n\t\tconst fontFamilyVar = `--codelens-font-family${this._styleClassName}`;\r\n\r\n\t\tlet newStyle = `\r\n\t\t.monaco-editor .codelens-decoration.${this._styleClassName} { line-height: ${codeLensHeight}px; font-size: ${fontSize}px; padding-right: ${Math.round(fontSize * 0.5)}px; font-feature-settings: ${editorFontInfo.fontFeatureSettings} }\r\n\t\t.monaco-editor .codelens-decoration.${this._styleClassName} span.codicon { line-height: ${codeLensHeight}px; font-size: ${fontSize}px; }\r\n\t\t`;\r\n\t\tif (fontFamily) {\r\n\t\t\tnewStyle += `.monaco-editor .codelens-decoration.${this._styleClassName} { font-family: var(${fontFamilyVar})}`;\r\n\t\t}\r\n\t\tthis._styleElement.textContent = newStyle;\r\n\t\tthis._editor.getDomNode()?.style.setProperty(fontFamilyVar, fontFamily ?? 'inherit');\r\n\r\n\t\t//\r\n\t\tthis._editor.changeViewZones(accessor => {\r\n\t\t\tfor (let lens of this._lenses) {\r\n\t\t\t\tlens.updateHeight(codeLensHeight, accessor);\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _localDispose(): void {\r\n\t\tthis._getCodeLensModelPromise?.cancel();\r\n\t\tthis._getCodeLensModelPromise = undefined;\r\n\t\tthis._resolveCodeLensesPromise?.cancel();\r\n\t\tthis._resolveCodeLensesPromise = undefined;\r\n\t\tthis._localToDispose.clear();\r\n\t\tthis._oldCodeLensModels.clear();\r\n\t\tthis._currentCodeLensModel?.dispose();\r\n\t}\r\n\r\n\tprivate _onModelChange(): void {\r\n\r\n\t\tthis._localDispose();\r\n\r\n\t\tconst model = this._editor.getModel();\r\n\t\tif (!model) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!this._editor.getOption(EditorOption.codeLens)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst cachedLenses = this._codeLensCache.get(model);\r\n\t\tif (cachedLenses) {\r\n\t\t\tthis._renderCodeLensSymbols(cachedLenses);\r\n\t\t}\r\n\r\n\t\tif (!CodeLensProviderRegistry.has(model)) {\r\n\t\t\t// no provider -> return but check with\r\n\t\t\t// cached lenses. they expire after 30 seconds\r\n\t\t\tif (cachedLenses) {\r\n\t\t\t\tthis._localToDispose.add(disposableTimeout(() => {\r\n\t\t\t\t\tconst cachedLensesNow = this._codeLensCache.get(model);\r\n\t\t\t\t\tif (cachedLenses === cachedLensesNow) {\r\n\t\t\t\t\t\tthis._codeLensCache.delete(model);\r\n\t\t\t\t\t\tthis._onModelChange();\r\n\t\t\t\t\t}\r\n\t\t\t\t}, 30 * 1000));\r\n\t\t\t}\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tfor (const provider of CodeLensProviderRegistry.all(model)) {\r\n\t\t\tif (typeof provider.onDidChange === 'function') {\r\n\t\t\t\tlet registration = provider.onDidChange(() => scheduler.schedule());\r\n\t\t\t\tthis._localToDispose.add(registration);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst scheduler = new RunOnceScheduler(() => {\r\n\t\t\tconst t1 = Date.now();\r\n\r\n\t\t\tthis._getCodeLensModelPromise?.cancel();\r\n\t\t\tthis._getCodeLensModelPromise = createCancelablePromise(token => getCodeLensModel(model, token));\r\n\r\n\t\t\tthis._getCodeLensModelPromise.then(result => {\r\n\t\t\t\tif (this._currentCodeLensModel) {\r\n\t\t\t\t\tthis._oldCodeLensModels.add(this._currentCodeLensModel);\r\n\t\t\t\t}\r\n\t\t\t\tthis._currentCodeLensModel = result;\r\n\r\n\t\t\t\t// cache model to reduce flicker\r\n\t\t\t\tthis._codeLensCache.put(model, result);\r\n\r\n\t\t\t\t// update moving average\r\n\t\t\t\tconst newDelay = this._getCodeLensModelDelays.update(model, Date.now() - t1);\r\n\t\t\t\tscheduler.delay = newDelay;\r\n\r\n\t\t\t\t// render lenses\r\n\t\t\t\tthis._renderCodeLensSymbols(result);\r\n\t\t\t\tthis._resolveCodeLensesInViewport();\r\n\t\t\t}, onUnexpectedError);\r\n\r\n\t\t}, this._getCodeLensModelDelays.get(model));\r\n\r\n\t\tthis._localToDispose.add(scheduler);\r\n\t\tthis._localToDispose.add(toDisposable(() => this._resolveCodeLensesScheduler.cancel()));\r\n\t\tthis._localToDispose.add(this._editor.onDidChangeModelContent(() => {\r\n\t\t\tthis._editor.changeDecorations(decorationsAccessor => {\r\n\t\t\t\tthis._editor.changeViewZones(viewZonesAccessor => {\r\n\t\t\t\t\tlet toDispose: CodeLensWidget[] = [];\r\n\t\t\t\t\tlet lastLensLineNumber: number = -1;\r\n\r\n\t\t\t\t\tthis._lenses.forEach((lens) => {\r\n\t\t\t\t\t\tif (!lens.isValid() || lastLensLineNumber === lens.getLineNumber()) {\r\n\t\t\t\t\t\t\t// invalid -> lens collapsed, attach range doesn't exist anymore\r\n\t\t\t\t\t\t\t// line_number -> lenses should never be on the same line\r\n\t\t\t\t\t\t\ttoDispose.push(lens);\r\n\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tlens.update(viewZonesAccessor);\r\n\t\t\t\t\t\t\tlastLensLineNumber = lens.getLineNumber();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t});\r\n\r\n\t\t\t\t\tlet helper = new CodeLensHelper();\r\n\t\t\t\t\ttoDispose.forEach((l) => {\r\n\t\t\t\t\t\tl.dispose(helper, viewZonesAccessor);\r\n\t\t\t\t\t\tthis._lenses.splice(this._lenses.indexOf(l), 1);\r\n\t\t\t\t\t});\r\n\t\t\t\t\thelper.commit(decorationsAccessor);\r\n\t\t\t\t});\r\n\t\t\t});\r\n\r\n\t\t\t// Ask for all references again\r\n\t\t\tscheduler.schedule();\r\n\t\t}));\r\n\t\tthis._localToDispose.add(this._editor.onDidFocusEditorWidget(() => {\r\n\t\t\tscheduler.schedule();\r\n\t\t}));\r\n\t\tthis._localToDispose.add(this._editor.onDidScrollChange(e => {\r\n\t\t\tif (e.scrollTopChanged && this._lenses.length > 0) {\r\n\t\t\t\tthis._resolveCodeLensesInViewportSoon();\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._localToDispose.add(this._editor.onDidLayoutChange(() => {\r\n\t\t\tthis._resolveCodeLensesInViewportSoon();\r\n\t\t}));\r\n\t\tthis._localToDispose.add(toDisposable(() => {\r\n\t\t\tif (this._editor.getModel()) {\r\n\t\t\t\tconst scrollState = StableEditorScrollState.capture(this._editor);\r\n\t\t\t\tthis._editor.changeDecorations(decorationsAccessor => {\r\n\t\t\t\t\tthis._editor.changeViewZones(viewZonesAccessor => {\r\n\t\t\t\t\t\tthis._disposeAllLenses(decorationsAccessor, viewZonesAccessor);\r\n\t\t\t\t\t});\r\n\t\t\t\t});\r\n\t\t\t\tscrollState.restore(this._editor);\r\n\t\t\t} else {\r\n\t\t\t\t// No accessors available\r\n\t\t\t\tthis._disposeAllLenses(undefined, undefined);\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._localToDispose.add(this._editor.onMouseDown(e => {\r\n\t\t\tif (e.target.type !== MouseTargetType.CONTENT_WIDGET) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tlet target = e.target.element;\r\n\t\t\tif (target?.tagName === 'SPAN') {\r\n\t\t\t\ttarget = target.parentElement;\r\n\t\t\t}\r\n\t\t\tif (target?.tagName === 'A') {\r\n\t\t\t\tfor (const lens of this._lenses) {\r\n\t\t\t\t\tlet command = lens.getCommand(target as HTMLLinkElement);\r\n\t\t\t\t\tif (command) {\r\n\t\t\t\t\t\tthis._commandService.executeCommand(command.id, ...(command.arguments || [])).catch(err => this._notificationService.error(err));\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}));\r\n\t\tscheduler.schedule();\r\n\t}\r\n\r\n\tprivate _disposeAllLenses(decChangeAccessor: IModelDecorationsChangeAccessor | undefined, viewZoneChangeAccessor: IViewZoneChangeAccessor | undefined): void {\r\n\t\tconst helper = new CodeLensHelper();\r\n\t\tfor (const lens of this._lenses) {\r\n\t\t\tlens.dispose(helper, viewZoneChangeAccessor);\r\n\t\t}\r\n\t\tif (decChangeAccessor) {\r\n\t\t\thelper.commit(decChangeAccessor);\r\n\t\t}\r\n\t\tthis._lenses.length = 0;\r\n\t}\r\n\r\n\tprivate _renderCodeLensSymbols(symbols: CodeLensModel): void {\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet maxLineNumber = this._editor.getModel().getLineCount();\r\n\t\tlet groups: CodeLensItem[][] = [];\r\n\t\tlet lastGroup: CodeLensItem[] | undefined;\r\n\r\n\t\tfor (let symbol of symbols.lenses) {\r\n\t\t\tlet line = symbol.symbol.range.startLineNumber;\r\n\t\t\tif (line < 1 || line > maxLineNumber) {\r\n\t\t\t\t// invalid code lens\r\n\t\t\t\tcontinue;\r\n\t\t\t} else if (lastGroup && lastGroup[lastGroup.length - 1].symbol.range.startLineNumber === line) {\r\n\t\t\t\t// on same line as previous\r\n\t\t\t\tlastGroup.push(symbol);\r\n\t\t\t} else {\r\n\t\t\t\t// on later line as previous\r\n\t\t\t\tlastGroup = [symbol];\r\n\t\t\t\tgroups.push(lastGroup);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst scrollState = StableEditorScrollState.capture(this._editor);\r\n\t\tconst layoutInfo = this._getLayoutInfo();\r\n\r\n\t\tthis._editor.changeDecorations(decorationsAccessor => {\r\n\t\t\tthis._editor.changeViewZones(viewZoneAccessor => {\r\n\r\n\t\t\t\tconst helper = new CodeLensHelper();\r\n\t\t\t\tlet codeLensIndex = 0;\r\n\t\t\t\tlet groupsIndex = 0;\r\n\r\n\t\t\t\twhile (groupsIndex < groups.length && codeLensIndex < this._lenses.length) {\r\n\r\n\t\t\t\t\tlet symbolsLineNumber = groups[groupsIndex][0].symbol.range.startLineNumber;\r\n\t\t\t\t\tlet codeLensLineNumber = this._lenses[codeLensIndex].getLineNumber();\r\n\r\n\t\t\t\t\tif (codeLensLineNumber < symbolsLineNumber) {\r\n\t\t\t\t\t\tthis._lenses[codeLensIndex].dispose(helper, viewZoneAccessor);\r\n\t\t\t\t\t\tthis._lenses.splice(codeLensIndex, 1);\r\n\t\t\t\t\t} else if (codeLensLineNumber === symbolsLineNumber) {\r\n\t\t\t\t\t\tthis._lenses[codeLensIndex].updateCodeLensSymbols(groups[groupsIndex], helper);\r\n\t\t\t\t\t\tgroupsIndex++;\r\n\t\t\t\t\t\tcodeLensIndex++;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tthis._lenses.splice(codeLensIndex, 0, new CodeLensWidget(groups[groupsIndex], this._editor, this._styleClassName, helper, viewZoneAccessor, layoutInfo.codeLensHeight, () => this._resolveCodeLensesInViewportSoon()));\r\n\t\t\t\t\t\tcodeLensIndex++;\r\n\t\t\t\t\t\tgroupsIndex++;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Delete extra code lenses\r\n\t\t\t\twhile (codeLensIndex < this._lenses.length) {\r\n\t\t\t\t\tthis._lenses[codeLensIndex].dispose(helper, viewZoneAccessor);\r\n\t\t\t\t\tthis._lenses.splice(codeLensIndex, 1);\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Create extra symbols\r\n\t\t\t\twhile (groupsIndex < groups.length) {\r\n\t\t\t\t\tthis._lenses.push(new CodeLensWidget(groups[groupsIndex], this._editor, this._styleClassName, helper, viewZoneAccessor, layoutInfo.codeLensHeight, () => this._resolveCodeLensesInViewportSoon()));\r\n\t\t\t\t\tgroupsIndex++;\r\n\t\t\t\t}\r\n\r\n\t\t\t\thelper.commit(decorationsAccessor);\r\n\t\t\t});\r\n\t\t});\r\n\r\n\t\tscrollState.restore(this._editor);\r\n\t}\r\n\r\n\tprivate _resolveCodeLensesInViewportSoon(): void {\r\n\t\tconst model = this._editor.getModel();\r\n\t\tif (model) {\r\n\t\t\tthis._resolveCodeLensesScheduler.schedule();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _resolveCodeLensesInViewport(): void {\r\n\r\n\t\tthis._resolveCodeLensesPromise?.cancel();\r\n\t\tthis._resolveCodeLensesPromise = undefined;\r\n\r\n\t\tconst model = this._editor.getModel();\r\n\t\tif (!model) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst toResolve: CodeLensItem[][] = [];\r\n\t\tconst lenses: CodeLensWidget[] = [];\r\n\t\tthis._lenses.forEach((lens) => {\r\n\t\t\tconst request = lens.computeIfNecessary(model);\r\n\t\t\tif (request) {\r\n\t\t\t\ttoResolve.push(request);\r\n\t\t\t\tlenses.push(lens);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tif (toResolve.length === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst t1 = Date.now();\r\n\r\n\t\tconst resolvePromise = createCancelablePromise(token => {\r\n\r\n\t\t\tconst promises = toResolve.map((request, i) => {\r\n\r\n\t\t\t\tconst resolvedSymbols = new Array(request.length);\r\n\t\t\t\tconst promises = request.map((request, i) => {\r\n\t\t\t\t\tif (!request.symbol.command && typeof request.provider.resolveCodeLens === 'function') {\r\n\t\t\t\t\t\treturn Promise.resolve(request.provider.resolveCodeLens(model, request.symbol, token)).then(symbol => {\r\n\t\t\t\t\t\t\tresolvedSymbols[i] = symbol;\r\n\t\t\t\t\t\t}, onUnexpectedExternalError);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tresolvedSymbols[i] = request.symbol;\r\n\t\t\t\t\t\treturn Promise.resolve(undefined);\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\r\n\t\t\t\treturn Promise.all(promises).then(() => {\r\n\t\t\t\t\tif (!token.isCancellationRequested && !lenses[i].isDisposed()) {\r\n\t\t\t\t\t\tlenses[i].updateCommands(resolvedSymbols);\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t});\r\n\r\n\t\t\treturn Promise.all(promises);\r\n\t\t});\r\n\t\tthis._resolveCodeLensesPromise = resolvePromise;\r\n\r\n\t\tthis._resolveCodeLensesPromise.then(() => {\r\n\r\n\t\t\t// update moving average\r\n\t\t\tconst newDelay = this._resolveCodeLensesDelays.update(model, Date.now() - t1);\r\n\t\t\tthis._resolveCodeLensesScheduler.delay = newDelay;\r\n\r\n\t\t\tif (this._currentCodeLensModel) { // update the cached state with new resolved items\r\n\t\t\t\tthis._codeLensCache.put(model, this._currentCodeLensModel);\r\n\t\t\t}\r\n\t\t\tthis._oldCodeLensModels.clear(); // dispose old models once we have updated the UI with the current model\r\n\t\t\tif (resolvePromise === this._resolveCodeLensesPromise) {\r\n\t\t\t\tthis._resolveCodeLensesPromise = undefined;\r\n\t\t\t}\r\n\t\t}, err => {\r\n\t\t\tonUnexpectedError(err); // can also be cancellation!\r\n\t\t\tif (resolvePromise === this._resolveCodeLensesPromise) {\r\n\t\t\t\tthis._resolveCodeLensesPromise = undefined;\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tgetLenses(): readonly CodeLensWidget[] {\r\n\t\treturn this._lenses;\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(CodeLensContribution.ID, CodeLensContribution);\r\n\r\nregisterEditorAction(class ShowLensesInCurrentLine extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'codelens.showLensesInCurrentLine',\r\n\t\t\tprecondition: EditorContextKeys.hasCodeLensProvider,\r\n\t\t\tlabel: localize('showLensOnLine', \"Show CodeLens Commands For Current Line\"),\r\n\t\t\talias: 'Show CodeLens Commands For Current Line',\r\n\t\t});\r\n\t}\r\n\r\n\tasync run(accessor: ServicesAccessor, editor: ICodeEditor): Promise {\r\n\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst quickInputService = accessor.get(IQuickInputService);\r\n\t\tconst commandService = accessor.get(ICommandService);\r\n\t\tconst notificationService = accessor.get(INotificationService);\r\n\r\n\t\tconst lineNumber = editor.getSelection().positionLineNumber;\r\n\t\tconst codelensController = editor.getContribution(CodeLensContribution.ID);\r\n\t\tconst items: { label: string, command: Command }[] = [];\r\n\r\n\t\tfor (let lens of codelensController.getLenses()) {\r\n\t\t\tif (lens.getLineNumber() === lineNumber) {\r\n\t\t\t\tfor (let item of lens.getItems()) {\r\n\t\t\t\t\tconst { command } = item.symbol;\r\n\t\t\t\t\tif (command) {\r\n\t\t\t\t\t\titems.push({\r\n\t\t\t\t\t\t\tlabel: command.title,\r\n\t\t\t\t\t\t\tcommand: command\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (items.length === 0) {\r\n\t\t\t// We dont want an empty picker\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst item = await quickInputService.pick(items, { canPickMany: false });\r\n\t\tif (!item) {\r\n\t\t\t// Nothing picked\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\tawait commandService.executeCommand(item.command.id, ...(item.command.arguments || []));\r\n\t\t} catch (err) {\r\n\t\t\tnotificationService.error(err);\r\n\t\t}\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CancelablePromise, TimeoutTimer, createCancelablePromise } from 'vs/base/common/async';\r\nimport { RGBA } from 'vs/base/common/color';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport { hash } from 'vs/base/common/hash';\r\nimport { Disposable, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { registerEditorContribution } from 'vs/editor/browser/editorExtensions';\r\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { IModelDeltaDecoration } from 'vs/editor/common/model';\r\nimport { ModelDecorationOptions } from 'vs/editor/common/model/textModel';\r\nimport { ColorProviderRegistry } from 'vs/editor/common/modes';\r\nimport { IColorData, getColors } from 'vs/editor/contrib/colorPicker/color';\r\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\nconst MAX_DECORATORS = 500;\r\n\r\nexport class ColorDetector extends Disposable implements IEditorContribution {\r\n\r\n\tpublic static readonly ID: string = 'editor.contrib.colorDetector';\r\n\r\n\tstatic readonly RECOMPUTE_TIME = 1000; // ms\r\n\r\n\tprivate readonly _localToDispose = this._register(new DisposableStore());\r\n\tprivate _computePromise: CancelablePromise | null;\r\n\tprivate _timeoutTimer: TimeoutTimer | null;\r\n\r\n\tprivate _decorationsIds: string[] = [];\r\n\tprivate _colorDatas = new Map();\r\n\r\n\tprivate _colorDecoratorIds: string[] = [];\r\n\tprivate readonly _decorationsTypes = new Set();\r\n\r\n\tprivate _isEnabled: boolean;\r\n\r\n\tconstructor(private readonly _editor: ICodeEditor,\r\n\t\t@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,\r\n\t\t@IConfigurationService private readonly _configurationService: IConfigurationService\r\n\t) {\r\n\t\tsuper();\r\n\t\tthis._register(_editor.onDidChangeModel(() => {\r\n\t\t\tthis._isEnabled = this.isEnabled();\r\n\t\t\tthis.onModelChanged();\r\n\t\t}));\r\n\t\tthis._register(_editor.onDidChangeModelLanguage(() => this.onModelChanged()));\r\n\t\tthis._register(ColorProviderRegistry.onDidChange(() => this.onModelChanged()));\r\n\t\tthis._register(_editor.onDidChangeConfiguration(() => {\r\n\t\t\tlet prevIsEnabled = this._isEnabled;\r\n\t\t\tthis._isEnabled = this.isEnabled();\r\n\t\t\tif (prevIsEnabled !== this._isEnabled) {\r\n\t\t\t\tif (this._isEnabled) {\r\n\t\t\t\t\tthis.onModelChanged();\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis.removeAllDecorations();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._timeoutTimer = null;\r\n\t\tthis._computePromise = null;\r\n\t\tthis._isEnabled = this.isEnabled();\r\n\t\tthis.onModelChanged();\r\n\t}\r\n\r\n\tisEnabled(): boolean {\r\n\t\tconst model = this._editor.getModel();\r\n\t\tif (!model) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tconst languageId = model.getLanguageIdentifier();\r\n\t\t// handle deprecated settings. [languageId].colorDecorators.enable\r\n\t\tconst deprecatedConfig = this._configurationService.getValue<{}>(languageId.language);\r\n\t\tif (deprecatedConfig) {\r\n\t\t\tconst colorDecorators = (deprecatedConfig as any)['colorDecorators']; // deprecatedConfig.valueOf('.colorDecorators.enable');\r\n\t\t\tif (colorDecorators && colorDecorators['enable'] !== undefined && !colorDecorators['enable']) {\r\n\t\t\t\treturn colorDecorators['enable'];\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this._editor.getOption(EditorOption.colorDecorators);\r\n\t}\r\n\r\n\tstatic get(editor: ICodeEditor): ColorDetector {\r\n\t\treturn editor.getContribution(this.ID);\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis.stop();\r\n\t\tthis.removeAllDecorations();\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tprivate onModelChanged(): void {\r\n\t\tthis.stop();\r\n\r\n\t\tif (!this._isEnabled) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst model = this._editor.getModel();\r\n\r\n\t\tif (!model || !ColorProviderRegistry.has(model)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._localToDispose.add(this._editor.onDidChangeModelContent(() => {\r\n\t\t\tif (!this._timeoutTimer) {\r\n\t\t\t\tthis._timeoutTimer = new TimeoutTimer();\r\n\t\t\t\tthis._timeoutTimer.cancelAndSet(() => {\r\n\t\t\t\t\tthis._timeoutTimer = null;\r\n\t\t\t\t\tthis.beginCompute();\r\n\t\t\t\t}, ColorDetector.RECOMPUTE_TIME);\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis.beginCompute();\r\n\t}\r\n\r\n\tprivate beginCompute(): void {\r\n\t\tthis._computePromise = createCancelablePromise(token => {\r\n\t\t\tconst model = this._editor.getModel();\r\n\t\t\tif (!model) {\r\n\t\t\t\treturn Promise.resolve([]);\r\n\t\t\t}\r\n\t\t\treturn getColors(model, token);\r\n\t\t});\r\n\t\tthis._computePromise.then((colorInfos) => {\r\n\t\t\tthis.updateDecorations(colorInfos);\r\n\t\t\tthis.updateColorDecorators(colorInfos);\r\n\t\t\tthis._computePromise = null;\r\n\t\t}, onUnexpectedError);\r\n\t}\r\n\r\n\tprivate stop(): void {\r\n\t\tif (this._timeoutTimer) {\r\n\t\t\tthis._timeoutTimer.cancel();\r\n\t\t\tthis._timeoutTimer = null;\r\n\t\t}\r\n\t\tif (this._computePromise) {\r\n\t\t\tthis._computePromise.cancel();\r\n\t\t\tthis._computePromise = null;\r\n\t\t}\r\n\t\tthis._localToDispose.clear();\r\n\t}\r\n\r\n\tprivate updateDecorations(colorDatas: IColorData[]): void {\r\n\t\tconst decorations = colorDatas.map(c => ({\r\n\t\t\trange: {\r\n\t\t\t\tstartLineNumber: c.colorInfo.range.startLineNumber,\r\n\t\t\t\tstartColumn: c.colorInfo.range.startColumn,\r\n\t\t\t\tendLineNumber: c.colorInfo.range.endLineNumber,\r\n\t\t\t\tendColumn: c.colorInfo.range.endColumn\r\n\t\t\t},\r\n\t\t\toptions: ModelDecorationOptions.EMPTY\r\n\t\t}));\r\n\r\n\t\tthis._decorationsIds = this._editor.deltaDecorations(this._decorationsIds, decorations);\r\n\r\n\t\tthis._colorDatas = new Map();\r\n\t\tthis._decorationsIds.forEach((id, i) => this._colorDatas.set(id, colorDatas[i]));\r\n\t}\r\n\r\n\tprivate updateColorDecorators(colorData: IColorData[]): void {\r\n\t\tlet decorations: IModelDeltaDecoration[] = [];\r\n\t\tlet newDecorationsTypes: { [key: string]: boolean } = {};\r\n\r\n\t\tfor (let i = 0; i < colorData.length && decorations.length < MAX_DECORATORS; i++) {\r\n\t\t\tconst { red, green, blue, alpha } = colorData[i].colorInfo.color;\r\n\t\t\tconst rgba = new RGBA(Math.round(red * 255), Math.round(green * 255), Math.round(blue * 255), alpha);\r\n\t\t\tlet subKey = hash(`rgba(${rgba.r},${rgba.g},${rgba.b},${rgba.a})`).toString(16);\r\n\t\t\tlet color = `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})`;\r\n\t\t\tlet key = 'colorBox-' + subKey;\r\n\r\n\t\t\tif (!this._decorationsTypes.has(key) && !newDecorationsTypes[key]) {\r\n\t\t\t\tthis._codeEditorService.registerDecorationType(key, {\r\n\t\t\t\t\tbefore: {\r\n\t\t\t\t\t\tcontentText: ' ',\r\n\t\t\t\t\t\tborder: 'solid 0.1em #000',\r\n\t\t\t\t\t\tmargin: '0.1em 0.2em 0 0.2em',\r\n\t\t\t\t\t\twidth: '0.8em',\r\n\t\t\t\t\t\theight: '0.8em',\r\n\t\t\t\t\t\tbackgroundColor: color\r\n\t\t\t\t\t},\r\n\t\t\t\t\tdark: {\r\n\t\t\t\t\t\tbefore: {\r\n\t\t\t\t\t\t\tborder: 'solid 0.1em #eee'\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}, undefined, this._editor);\r\n\t\t\t}\r\n\r\n\t\t\tnewDecorationsTypes[key] = true;\r\n\t\t\tdecorations.push({\r\n\t\t\t\trange: {\r\n\t\t\t\t\tstartLineNumber: colorData[i].colorInfo.range.startLineNumber,\r\n\t\t\t\t\tstartColumn: colorData[i].colorInfo.range.startColumn,\r\n\t\t\t\t\tendLineNumber: colorData[i].colorInfo.range.endLineNumber,\r\n\t\t\t\t\tendColumn: colorData[i].colorInfo.range.endColumn\r\n\t\t\t\t},\r\n\t\t\t\toptions: this._codeEditorService.resolveDecorationOptions(key, true)\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tthis._decorationsTypes.forEach(subType => {\r\n\t\t\tif (!newDecorationsTypes[subType]) {\r\n\t\t\t\tthis._codeEditorService.removeDecorationType(subType);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tthis._colorDecoratorIds = this._editor.deltaDecorations(this._colorDecoratorIds, decorations);\r\n\t}\r\n\r\n\tprivate removeAllDecorations(): void {\r\n\t\tthis._decorationsIds = this._editor.deltaDecorations(this._decorationsIds, []);\r\n\t\tthis._colorDecoratorIds = this._editor.deltaDecorations(this._colorDecoratorIds, []);\r\n\r\n\t\tthis._decorationsTypes.forEach(subType => {\r\n\t\t\tthis._codeEditorService.removeDecorationType(subType);\r\n\t\t});\r\n\t}\r\n\r\n\tgetColorData(position: Position): IColorData | null {\r\n\t\tconst model = this._editor.getModel();\r\n\t\tif (!model) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst decorations = model\r\n\t\t\t.getDecorationsInRange(Range.fromPositions(position, position))\r\n\t\t\t.filter(d => this._colorDatas.has(d.id));\r\n\r\n\t\tif (decorations.length === 0) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\treturn this._colorDatas.get(decorations[0].id)!;\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(ColorDetector.ID, ColorDetector);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction, IActionOptions, ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { ICommand } from 'vs/editor/common/editorCommon';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { BlockCommentCommand } from 'vs/editor/contrib/comment/blockCommentCommand';\r\nimport { LineCommentCommand, Type } from 'vs/editor/contrib/comment/lineCommentCommand';\r\nimport { MenuId } from 'vs/platform/actions/common/actions';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\n\r\nabstract class CommentLineAction extends EditorAction {\r\n\r\n\tprivate readonly _type: Type;\r\n\r\n\tconstructor(type: Type, opts: IActionOptions) {\r\n\t\tsuper(opts);\r\n\t\tthis._type = type;\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst model = editor.getModel();\r\n\t\tconst commands: ICommand[] = [];\r\n\t\tconst modelOptions = model.getOptions();\r\n\t\tconst commentsOptions = editor.getOption(EditorOption.comments);\r\n\r\n\t\tconst selections = editor.getSelections().map((selection, index) => ({ selection, index, ignoreFirstLine: false }));\r\n\t\tselections.sort((a, b) => Range.compareRangesUsingStarts(a.selection, b.selection));\r\n\r\n\t\t// Remove selections that would result in copying the same line\r\n\t\tlet prev = selections[0];\r\n\t\tfor (let i = 1; i < selections.length; i++) {\r\n\t\t\tconst curr = selections[i];\r\n\t\t\tif (prev.selection.endLineNumber === curr.selection.startLineNumber) {\r\n\t\t\t\t// these two selections would copy the same line\r\n\t\t\t\tif (prev.index < curr.index) {\r\n\t\t\t\t\t// prev wins\r\n\t\t\t\t\tcurr.ignoreFirstLine = true;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// curr wins\r\n\t\t\t\t\tprev.ignoreFirstLine = true;\r\n\t\t\t\t\tprev = curr;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\r\n\t\tfor (const selection of selections) {\r\n\t\t\tcommands.push(new LineCommentCommand(\r\n\t\t\t\tselection.selection,\r\n\t\t\t\tmodelOptions.tabSize,\r\n\t\t\t\tthis._type,\r\n\t\t\t\tcommentsOptions.insertSpace,\r\n\t\t\t\tcommentsOptions.ignoreEmptyLines,\r\n\t\t\t\tselection.ignoreFirstLine\r\n\t\t\t));\r\n\t\t}\r\n\r\n\t\teditor.pushUndoStop();\r\n\t\teditor.executeCommands(this.id, commands);\r\n\t\teditor.pushUndoStop();\r\n\t}\r\n\r\n}\r\n\r\nclass ToggleCommentLineAction extends CommentLineAction {\r\n\tconstructor() {\r\n\t\tsuper(Type.Toggle, {\r\n\t\t\tid: 'editor.action.commentLine',\r\n\t\t\tlabel: nls.localize('comment.line', \"Toggle Line Comment\"),\r\n\t\t\talias: 'Toggle Line Comment',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.US_SLASH,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tmenuOpts: {\r\n\t\t\t\tmenuId: MenuId.MenubarEditMenu,\r\n\t\t\t\tgroup: '5_insert',\r\n\t\t\t\ttitle: nls.localize({ key: 'miToggleLineComment', comment: ['&& denotes a mnemonic'] }, \"&&Toggle Line Comment\"),\r\n\t\t\t\torder: 1\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n\r\nclass AddLineCommentAction extends CommentLineAction {\r\n\tconstructor() {\r\n\t\tsuper(Type.ForceAdd, {\r\n\t\t\tid: 'editor.action.addCommentLine',\r\n\t\t\tlabel: nls.localize('comment.line.add', \"Add Line Comment\"),\r\n\t\t\talias: 'Add Line Comment',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_C),\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n\r\nclass RemoveLineCommentAction extends CommentLineAction {\r\n\tconstructor() {\r\n\t\tsuper(Type.ForceRemove, {\r\n\t\t\tid: 'editor.action.removeCommentLine',\r\n\t\t\tlabel: nls.localize('comment.line.remove', \"Remove Line Comment\"),\r\n\t\t\talias: 'Remove Line Comment',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_U),\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n\r\nclass BlockCommentAction extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.blockComment',\r\n\t\t\tlabel: nls.localize('comment.block', \"Toggle Block Comment\"),\r\n\t\t\talias: 'Toggle Block Comment',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_A,\r\n\t\t\t\tlinux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_A },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tmenuOpts: {\r\n\t\t\t\tmenuId: MenuId.MenubarEditMenu,\r\n\t\t\t\tgroup: '5_insert',\r\n\t\t\t\ttitle: nls.localize({ key: 'miToggleBlockComment', comment: ['&& denotes a mnemonic'] }, \"Toggle &&Block Comment\"),\r\n\t\t\t\torder: 2\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst commentsOptions = editor.getOption(EditorOption.comments);\r\n\t\tconst commands: ICommand[] = [];\r\n\t\tconst selections = editor.getSelections();\r\n\t\tfor (const selection of selections) {\r\n\t\t\tcommands.push(new BlockCommentCommand(selection, commentsOptions.insertSpace));\r\n\t\t}\r\n\r\n\t\teditor.pushUndoStop();\r\n\t\teditor.executeCommands(this.id, commands);\r\n\t\teditor.pushUndoStop();\r\n\t}\r\n}\r\n\r\nregisterEditorAction(ToggleCommentLineAction);\r\nregisterEditorAction(AddLineCommentAction);\r\nregisterEditorAction(RemoveLineCommentAction);\r\nregisterEditorAction(BlockCommentAction);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { IAnchor } from 'vs/base/browser/ui/contextview/contextview';\r\nimport { IAction, Separator, SubmenuAction } from 'vs/base/common/actions';\r\nimport { KeyCode, KeyMod, ResolvedKeybinding } from 'vs/base/common/keyCodes';\r\nimport { DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions';\r\nimport { IEditorContribution, ScrollType } from 'vs/editor/common/editorCommon';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { IMenuService, MenuId, SubmenuItemAction } from 'vs/platform/actions/common/actions';\r\nimport { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';\r\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';\r\n\r\nexport class ContextMenuController implements IEditorContribution {\r\n\r\n\tpublic static readonly ID = 'editor.contrib.contextmenu';\r\n\r\n\tpublic static get(editor: ICodeEditor): ContextMenuController {\r\n\t\treturn editor.getContribution(ContextMenuController.ID);\r\n\t}\r\n\r\n\tprivate readonly _toDispose = new DisposableStore();\r\n\tprivate _contextMenuIsBeingShownCount: number = 0;\r\n\tprivate readonly _editor: ICodeEditor;\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor,\r\n\t\t@IContextMenuService private readonly _contextMenuService: IContextMenuService,\r\n\t\t@IContextViewService private readonly _contextViewService: IContextViewService,\r\n\t\t@IContextKeyService private readonly _contextKeyService: IContextKeyService,\r\n\t\t@IKeybindingService private readonly _keybindingService: IKeybindingService,\r\n\t\t@IMenuService private readonly _menuService: IMenuService\r\n\t) {\r\n\t\tthis._editor = editor;\r\n\r\n\t\tthis._toDispose.add(this._editor.onContextMenu((e: IEditorMouseEvent) => this._onContextMenu(e)));\r\n\t\tthis._toDispose.add(this._editor.onMouseWheel((e: IMouseWheelEvent) => {\r\n\t\t\tif (this._contextMenuIsBeingShownCount > 0) {\r\n\t\t\t\tconst view = this._contextViewService.getContextViewElement();\r\n\t\t\t\tconst target = e.srcElement as HTMLElement;\r\n\r\n\t\t\t\t// Event triggers on shadow root host first\r\n\t\t\t\t// Check if the context view is under this host before hiding it #103169\r\n\t\t\t\tif (!(target.shadowRoot && dom.getShadowRoot(view) === target.shadowRoot)) {\r\n\t\t\t\t\tthis._contextViewService.hideContextView();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._toDispose.add(this._editor.onKeyDown((e: IKeyboardEvent) => {\r\n\t\t\tif (e.keyCode === KeyCode.ContextMenu) {\r\n\t\t\t\t// Chrome is funny like that\r\n\t\t\t\te.preventDefault();\r\n\t\t\t\te.stopPropagation();\r\n\t\t\t\tthis.showContextMenu();\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\tprivate _onContextMenu(e: IEditorMouseEvent): void {\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!this._editor.getOption(EditorOption.contextmenu)) {\r\n\t\t\tthis._editor.focus();\r\n\t\t\t// Ensure the cursor is at the position of the mouse click\r\n\t\t\tif (e.target.position && !this._editor.getSelection().containsPosition(e.target.position)) {\r\n\t\t\t\tthis._editor.setPosition(e.target.position);\r\n\t\t\t}\r\n\t\t\treturn; // Context menu is turned off through configuration\r\n\t\t}\r\n\r\n\t\tif (e.target.type === MouseTargetType.OVERLAY_WIDGET) {\r\n\t\t\treturn; // allow native menu on widgets to support right click on input field for example in find\r\n\t\t}\r\n\r\n\t\te.event.preventDefault();\r\n\r\n\t\tif (e.target.type !== MouseTargetType.CONTENT_TEXT && e.target.type !== MouseTargetType.CONTENT_EMPTY && e.target.type !== MouseTargetType.TEXTAREA) {\r\n\t\t\treturn; // only support mouse click into text or native context menu key for now\r\n\t\t}\r\n\r\n\t\t// Ensure the editor gets focus if it hasn't, so the right events are being sent to other contributions\r\n\t\tthis._editor.focus();\r\n\r\n\t\t// Ensure the cursor is at the position of the mouse click\r\n\t\tif (e.target.position) {\r\n\t\t\tlet hasSelectionAtPosition = false;\r\n\t\t\tfor (const selection of this._editor.getSelections()) {\r\n\t\t\t\tif (selection.containsPosition(e.target.position)) {\r\n\t\t\t\t\thasSelectionAtPosition = true;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (!hasSelectionAtPosition) {\r\n\t\t\t\tthis._editor.setPosition(e.target.position);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Unless the user triggerd the context menu through Shift+F10, use the mouse position as menu position\r\n\t\tlet anchor: IAnchor | null = null;\r\n\t\tif (e.target.type !== MouseTargetType.TEXTAREA) {\r\n\t\t\tanchor = { x: e.event.posx - 1, width: 2, y: e.event.posy - 1, height: 2 };\r\n\t\t}\r\n\r\n\t\t// Show the context menu\r\n\t\tthis.showContextMenu(anchor);\r\n\t}\r\n\r\n\tpublic showContextMenu(anchor?: IAnchor | null): void {\r\n\t\tif (!this._editor.getOption(EditorOption.contextmenu)) {\r\n\t\t\treturn; // Context menu is turned off through configuration\r\n\t\t}\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!this._contextMenuService) {\r\n\t\t\tthis._editor.focus();\r\n\t\t\treturn;\t// We need the context menu service to function\r\n\t\t}\r\n\r\n\t\t// Find actions available for menu\r\n\t\tconst menuActions = this._getMenuActions(this._editor.getModel(), MenuId.EditorContext);\r\n\r\n\t\t// Show menu if we have actions to show\r\n\t\tif (menuActions.length > 0) {\r\n\t\t\tthis._doShowContextMenu(menuActions, anchor);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _getMenuActions(model: ITextModel, menuId: MenuId): IAction[] {\r\n\t\tconst result: IAction[] = [];\r\n\r\n\t\t// get menu groups\r\n\t\tconst menu = this._menuService.createMenu(menuId, this._contextKeyService);\r\n\t\tconst groups = menu.getActions({ arg: model.uri });\r\n\t\tmenu.dispose();\r\n\r\n\t\t// translate them into other actions\r\n\t\tfor (let group of groups) {\r\n\t\t\tconst [, actions] = group;\r\n\t\t\tlet addedItems = 0;\r\n\t\t\tfor (const action of actions) {\r\n\t\t\t\tif (action instanceof SubmenuItemAction) {\r\n\t\t\t\t\tconst subActions = this._getMenuActions(model, action.item.submenu);\r\n\t\t\t\t\tif (subActions.length > 0) {\r\n\t\t\t\t\t\tresult.push(new SubmenuAction(action.id, action.label, subActions));\r\n\t\t\t\t\t\taddedItems++;\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tresult.push(action);\r\n\t\t\t\t\taddedItems++;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (addedItems) {\r\n\t\t\t\tresult.push(new Separator());\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (result.length) {\r\n\t\t\tresult.pop(); // remove last separator\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate _doShowContextMenu(actions: IAction[], anchor: IAnchor | null = null): void {\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// Disable hover\r\n\t\tconst oldHoverSetting = this._editor.getOption(EditorOption.hover);\r\n\t\tthis._editor.updateOptions({\r\n\t\t\thover: {\r\n\t\t\t\tenabled: false\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tif (!anchor) {\r\n\t\t\t// Ensure selection is visible\r\n\t\t\tthis._editor.revealPosition(this._editor.getPosition(), ScrollType.Immediate);\r\n\r\n\t\t\tthis._editor.render();\r\n\t\t\tconst cursorCoords = this._editor.getScrolledVisiblePosition(this._editor.getPosition());\r\n\r\n\t\t\t// Translate to absolute editor position\r\n\t\t\tconst editorCoords = dom.getDomNodePagePosition(this._editor.getDomNode());\r\n\t\t\tconst posx = editorCoords.left + cursorCoords.left;\r\n\t\t\tconst posy = editorCoords.top + cursorCoords.top + cursorCoords.height;\r\n\r\n\t\t\tanchor = { x: posx, y: posy };\r\n\t\t}\r\n\r\n\t\t// Show menu\r\n\t\tthis._contextMenuIsBeingShownCount++;\r\n\t\tthis._contextMenuService.showContextMenu({\r\n\t\t\tdomForShadowRoot: this._editor.getDomNode(),\r\n\r\n\t\t\tgetAnchor: () => anchor!,\r\n\r\n\t\t\tgetActions: () => actions,\r\n\r\n\t\t\tgetActionViewItem: (action) => {\r\n\t\t\t\tconst keybinding = this._keybindingFor(action);\r\n\t\t\t\tif (keybinding) {\r\n\t\t\t\t\treturn new ActionViewItem(action, action, { label: true, keybinding: keybinding.getLabel(), isMenu: true });\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst customActionViewItem = action;\r\n\t\t\t\tif (typeof customActionViewItem.getActionViewItem === 'function') {\r\n\t\t\t\t\treturn customActionViewItem.getActionViewItem();\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn new ActionViewItem(action, action, { icon: true, label: true, isMenu: true });\r\n\t\t\t},\r\n\r\n\t\t\tgetKeyBinding: (action): ResolvedKeybinding | undefined => {\r\n\t\t\t\treturn this._keybindingFor(action);\r\n\t\t\t},\r\n\r\n\t\t\tonHide: (wasCancelled: boolean) => {\r\n\t\t\t\tthis._contextMenuIsBeingShownCount--;\r\n\t\t\t\tthis._editor.focus();\r\n\t\t\t\tthis._editor.updateOptions({\r\n\t\t\t\t\thover: oldHoverSetting\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _keybindingFor(action: IAction): ResolvedKeybinding | undefined {\r\n\t\treturn this._keybindingService.lookupKeybinding(action.id);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tif (this._contextMenuIsBeingShownCount > 0) {\r\n\t\t\tthis._contextViewService.hideContextView();\r\n\t\t}\r\n\r\n\t\tthis._toDispose.dispose();\r\n\t}\r\n}\r\n\r\nclass ShowContextMenu extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.showContextMenu',\r\n\t\t\tlabel: nls.localize('action.showContextMenu.label', \"Show Editor Context Menu\"),\r\n\t\t\talias: 'Show Editor Context Menu',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\tprimary: KeyMod.Shift | KeyCode.F10,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tlet contribution = ContextMenuController.get(editor);\r\n\t\tcontribution.showContextMenu();\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(ContextMenuController.ID, ContextMenuController);\r\nregisterEditorAction(ShowContextMenu);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\n\r\nclass CursorState {\r\n\treadonly selections: readonly Selection[];\r\n\r\n\tconstructor(selections: readonly Selection[]) {\r\n\t\tthis.selections = selections;\r\n\t}\r\n\r\n\tpublic equals(other: CursorState): boolean {\r\n\t\tconst thisLen = this.selections.length;\r\n\t\tconst otherLen = other.selections.length;\r\n\t\tif (thisLen !== otherLen) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tfor (let i = 0; i < thisLen; i++) {\r\n\t\t\tif (!this.selections[i].equalsSelection(other.selections[i])) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n}\r\n\r\nclass StackElement {\r\n\tconstructor(\r\n\t\tpublic readonly cursorState: CursorState,\r\n\t\tpublic readonly scrollTop: number,\r\n\t\tpublic readonly scrollLeft: number\r\n\t) { }\r\n}\r\n\r\nexport class CursorUndoRedoController extends Disposable implements IEditorContribution {\r\n\r\n\tpublic static readonly ID = 'editor.contrib.cursorUndoRedoController';\r\n\r\n\tpublic static get(editor: ICodeEditor): CursorUndoRedoController {\r\n\t\treturn editor.getContribution(CursorUndoRedoController.ID);\r\n\t}\r\n\r\n\tprivate readonly _editor: ICodeEditor;\r\n\tprivate _isCursorUndoRedo: boolean;\r\n\r\n\tprivate _undoStack: StackElement[];\r\n\tprivate _redoStack: StackElement[];\r\n\r\n\tconstructor(editor: ICodeEditor) {\r\n\t\tsuper();\r\n\t\tthis._editor = editor;\r\n\t\tthis._isCursorUndoRedo = false;\r\n\r\n\t\tthis._undoStack = [];\r\n\t\tthis._redoStack = [];\r\n\r\n\t\tthis._register(editor.onDidChangeModel((e) => {\r\n\t\t\tthis._undoStack = [];\r\n\t\t\tthis._redoStack = [];\r\n\t\t}));\r\n\t\tthis._register(editor.onDidChangeModelContent((e) => {\r\n\t\t\tthis._undoStack = [];\r\n\t\t\tthis._redoStack = [];\r\n\t\t}));\r\n\t\tthis._register(editor.onDidChangeCursorSelection((e) => {\r\n\t\t\tif (this._isCursorUndoRedo) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (!e.oldSelections) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (e.oldModelVersionId !== e.modelVersionId) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tconst prevState = new CursorState(e.oldSelections);\r\n\t\t\tconst isEqualToLastUndoStack = (this._undoStack.length > 0 && this._undoStack[this._undoStack.length - 1].cursorState.equals(prevState));\r\n\t\t\tif (!isEqualToLastUndoStack) {\r\n\t\t\t\tthis._undoStack.push(new StackElement(prevState, editor.getScrollTop(), editor.getScrollLeft()));\r\n\t\t\t\tthis._redoStack = [];\r\n\t\t\t\tif (this._undoStack.length > 50) {\r\n\t\t\t\t\t// keep the cursor undo stack bounded\r\n\t\t\t\t\tthis._undoStack.shift();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\tpublic cursorUndo(): void {\r\n\t\tif (!this._editor.hasModel() || this._undoStack.length === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._redoStack.push(new StackElement(new CursorState(this._editor.getSelections()), this._editor.getScrollTop(), this._editor.getScrollLeft()));\r\n\t\tthis._applyState(this._undoStack.pop()!);\r\n\t}\r\n\r\n\tpublic cursorRedo(): void {\r\n\t\tif (!this._editor.hasModel() || this._redoStack.length === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._undoStack.push(new StackElement(new CursorState(this._editor.getSelections()), this._editor.getScrollTop(), this._editor.getScrollLeft()));\r\n\t\tthis._applyState(this._redoStack.pop()!);\r\n\t}\r\n\r\n\tprivate _applyState(stackElement: StackElement): void {\r\n\t\tthis._isCursorUndoRedo = true;\r\n\t\tthis._editor.setSelections(stackElement.cursorState.selections);\r\n\t\tthis._editor.setScrollPosition({\r\n\t\t\tscrollTop: stackElement.scrollTop,\r\n\t\t\tscrollLeft: stackElement.scrollLeft\r\n\t\t});\r\n\t\tthis._isCursorUndoRedo = false;\r\n\t}\r\n}\r\n\r\nexport class CursorUndo extends EditorAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'cursorUndo',\r\n\t\t\tlabel: nls.localize('cursor.undo', \"Cursor Undo\"),\r\n\t\t\talias: 'Cursor Undo',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.KEY_U,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {\r\n\t\tCursorUndoRedoController.get(editor).cursorUndo();\r\n\t}\r\n}\r\n\r\nexport class CursorRedo extends EditorAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'cursorRedo',\r\n\t\t\tlabel: nls.localize('cursor.redo', \"Cursor Redo\"),\r\n\t\t\talias: 'Cursor Redo',\r\n\t\t\tprecondition: undefined\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {\r\n\t\tCursorUndoRedoController.get(editor).cursorRedo();\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(CursorUndoRedoController.ID, CursorUndoRedoController);\r\nregisterEditorAction(CursorUndo);\r\nregisterEditorAction(CursorRedo);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./dnd';\r\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { isMacintosh } from 'vs/base/common/platform';\r\nimport { KeyCode } from 'vs/base/common/keyCodes';\r\nimport { ICodeEditor, IEditorMouseEvent, IMouseTarget, MouseTargetType, IPartialEditorMouseEvent } from 'vs/editor/browser/editorBrowser';\r\nimport { registerEditorContribution } from 'vs/editor/browser/editorExtensions';\r\nimport { IEditorContribution, ScrollType } from 'vs/editor/common/editorCommon';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { DragAndDropCommand } from 'vs/editor/contrib/dnd/dragAndDropCommand';\r\nimport { ModelDecorationOptions } from 'vs/editor/common/model/textModel';\r\nimport { IModelDeltaDecoration } from 'vs/editor/common/model';\r\nimport { IMouseEvent } from 'vs/base/browser/mouseEvent';\r\nimport { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents';\r\n\r\nfunction hasTriggerModifier(e: IKeyboardEvent | IMouseEvent): boolean {\r\n\tif (isMacintosh) {\r\n\t\treturn e.altKey;\r\n\t} else {\r\n\t\treturn e.ctrlKey;\r\n\t}\r\n}\r\n\r\nexport class DragAndDropController extends Disposable implements IEditorContribution {\r\n\r\n\tpublic static readonly ID = 'editor.contrib.dragAndDrop';\r\n\r\n\tprivate readonly _editor: ICodeEditor;\r\n\tprivate _dragSelection: Selection | null;\r\n\tprivate _dndDecorationIds: string[];\r\n\tprivate _mouseDown: boolean;\r\n\tprivate _modifierPressed: boolean;\r\n\tstatic readonly TRIGGER_KEY_VALUE = isMacintosh ? KeyCode.Alt : KeyCode.Ctrl;\r\n\r\n\tconstructor(editor: ICodeEditor) {\r\n\t\tsuper();\r\n\t\tthis._editor = editor;\r\n\t\tthis._register(this._editor.onMouseDown((e: IEditorMouseEvent) => this._onEditorMouseDown(e)));\r\n\t\tthis._register(this._editor.onMouseUp((e: IEditorMouseEvent) => this._onEditorMouseUp(e)));\r\n\t\tthis._register(this._editor.onMouseDrag((e: IEditorMouseEvent) => this._onEditorMouseDrag(e)));\r\n\t\tthis._register(this._editor.onMouseDrop((e: IPartialEditorMouseEvent) => this._onEditorMouseDrop(e)));\r\n\t\tthis._register(this._editor.onMouseDropCanceled(() => this._onEditorMouseDropCanceled()));\r\n\t\tthis._register(this._editor.onKeyDown((e: IKeyboardEvent) => this.onEditorKeyDown(e)));\r\n\t\tthis._register(this._editor.onKeyUp((e: IKeyboardEvent) => this.onEditorKeyUp(e)));\r\n\t\tthis._register(this._editor.onDidBlurEditorWidget(() => this.onEditorBlur()));\r\n\t\tthis._register(this._editor.onDidBlurEditorText(() => this.onEditorBlur()));\r\n\t\tthis._dndDecorationIds = [];\r\n\t\tthis._mouseDown = false;\r\n\t\tthis._modifierPressed = false;\r\n\t\tthis._dragSelection = null;\r\n\t}\r\n\r\n\tprivate onEditorBlur() {\r\n\t\tthis._removeDecoration();\r\n\t\tthis._dragSelection = null;\r\n\t\tthis._mouseDown = false;\r\n\t\tthis._modifierPressed = false;\r\n\t}\r\n\r\n\tprivate onEditorKeyDown(e: IKeyboardEvent): void {\r\n\t\tif (!this._editor.getOption(EditorOption.dragAndDrop) || this._editor.getOption(EditorOption.columnSelection)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (hasTriggerModifier(e)) {\r\n\t\t\tthis._modifierPressed = true;\r\n\t\t}\r\n\r\n\t\tif (this._mouseDown && hasTriggerModifier(e)) {\r\n\t\t\tthis._editor.updateOptions({\r\n\t\t\t\tmouseStyle: 'copy'\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tprivate onEditorKeyUp(e: IKeyboardEvent): void {\r\n\t\tif (!this._editor.getOption(EditorOption.dragAndDrop) || this._editor.getOption(EditorOption.columnSelection)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (hasTriggerModifier(e)) {\r\n\t\t\tthis._modifierPressed = false;\r\n\t\t}\r\n\r\n\t\tif (this._mouseDown && e.keyCode === DragAndDropController.TRIGGER_KEY_VALUE) {\r\n\t\t\tthis._editor.updateOptions({\r\n\t\t\t\tmouseStyle: 'default'\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _onEditorMouseDown(mouseEvent: IEditorMouseEvent): void {\r\n\t\tthis._mouseDown = true;\r\n\t}\r\n\r\n\tprivate _onEditorMouseUp(mouseEvent: IEditorMouseEvent): void {\r\n\t\tthis._mouseDown = false;\r\n\t\t// Whenever users release the mouse, the drag and drop operation should finish and the cursor should revert to text.\r\n\t\tthis._editor.updateOptions({\r\n\t\t\tmouseStyle: 'text'\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _onEditorMouseDrag(mouseEvent: IEditorMouseEvent): void {\r\n\t\tlet target = mouseEvent.target;\r\n\r\n\t\tif (this._dragSelection === null) {\r\n\t\t\tconst selections = this._editor.getSelections() || [];\r\n\t\t\tlet possibleSelections = selections.filter(selection => target.position && selection.containsPosition(target.position));\r\n\t\t\tif (possibleSelections.length === 1) {\r\n\t\t\t\tthis._dragSelection = possibleSelections[0];\r\n\t\t\t} else {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (hasTriggerModifier(mouseEvent.event)) {\r\n\t\t\tthis._editor.updateOptions({\r\n\t\t\t\tmouseStyle: 'copy'\r\n\t\t\t});\r\n\t\t} else {\r\n\t\t\tthis._editor.updateOptions({\r\n\t\t\t\tmouseStyle: 'default'\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tif (target.position) {\r\n\t\t\tif (this._dragSelection.containsPosition(target.position)) {\r\n\t\t\t\tthis._removeDecoration();\r\n\t\t\t} else {\r\n\t\t\t\tthis.showAt(target.position);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _onEditorMouseDropCanceled() {\r\n\t\tthis._editor.updateOptions({\r\n\t\t\tmouseStyle: 'text'\r\n\t\t});\r\n\r\n\t\tthis._removeDecoration();\r\n\t\tthis._dragSelection = null;\r\n\t\tthis._mouseDown = false;\r\n\t}\r\n\r\n\tprivate _onEditorMouseDrop(mouseEvent: IPartialEditorMouseEvent): void {\r\n\t\tif (mouseEvent.target && (this._hitContent(mouseEvent.target) || this._hitMargin(mouseEvent.target)) && mouseEvent.target.position) {\r\n\t\t\tlet newCursorPosition = new Position(mouseEvent.target.position.lineNumber, mouseEvent.target.position.column);\r\n\r\n\t\t\tif (this._dragSelection === null) {\r\n\t\t\t\tlet newSelections: Selection[] | null = null;\r\n\t\t\t\tif (mouseEvent.event.shiftKey) {\r\n\t\t\t\t\tlet primarySelection = this._editor.getSelection();\r\n\t\t\t\t\tif (primarySelection) {\r\n\t\t\t\t\t\tconst { selectionStartLineNumber, selectionStartColumn } = primarySelection;\r\n\t\t\t\t\t\tnewSelections = [new Selection(selectionStartLineNumber, selectionStartColumn, newCursorPosition.lineNumber, newCursorPosition.column)];\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tnewSelections = (this._editor.getSelections() || []).map(selection => {\r\n\t\t\t\t\t\tif (selection.containsPosition(newCursorPosition)) {\r\n\t\t\t\t\t\t\treturn new Selection(newCursorPosition.lineNumber, newCursorPosition.column, newCursorPosition.lineNumber, newCursorPosition.column);\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\treturn selection;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t\t// Use `mouse` as the source instead of `api` and setting the reason to explicit (to behave like any other mouse operation).\r\n\t\t\t\t(this._editor).setSelections(newSelections || [], 'mouse', CursorChangeReason.Explicit);\r\n\t\t\t} else if (!this._dragSelection.containsPosition(newCursorPosition) ||\r\n\t\t\t\t(\r\n\t\t\t\t\t(\r\n\t\t\t\t\t\thasTriggerModifier(mouseEvent.event) ||\r\n\t\t\t\t\t\tthis._modifierPressed\r\n\t\t\t\t\t) && (\r\n\t\t\t\t\t\tthis._dragSelection.getEndPosition().equals(newCursorPosition) || this._dragSelection.getStartPosition().equals(newCursorPosition)\r\n\t\t\t\t\t) // we allow users to paste content beside the selection\r\n\t\t\t\t)) {\r\n\t\t\t\tthis._editor.pushUndoStop();\r\n\t\t\t\tthis._editor.executeCommand(DragAndDropController.ID, new DragAndDropCommand(this._dragSelection, newCursorPosition, hasTriggerModifier(mouseEvent.event) || this._modifierPressed));\r\n\t\t\t\tthis._editor.pushUndoStop();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._editor.updateOptions({\r\n\t\t\tmouseStyle: 'text'\r\n\t\t});\r\n\r\n\t\tthis._removeDecoration();\r\n\t\tthis._dragSelection = null;\r\n\t\tthis._mouseDown = false;\r\n\t}\r\n\r\n\tprivate static readonly _DECORATION_OPTIONS = ModelDecorationOptions.register({\r\n\t\tclassName: 'dnd-target'\r\n\t});\r\n\r\n\tpublic showAt(position: Position): void {\r\n\t\tlet newDecorations: IModelDeltaDecoration[] = [{\r\n\t\t\trange: new Range(position.lineNumber, position.column, position.lineNumber, position.column),\r\n\t\t\toptions: DragAndDropController._DECORATION_OPTIONS\r\n\t\t}];\r\n\r\n\t\tthis._dndDecorationIds = this._editor.deltaDecorations(this._dndDecorationIds, newDecorations);\r\n\t\tthis._editor.revealPosition(position, ScrollType.Immediate);\r\n\t}\r\n\r\n\tprivate _removeDecoration(): void {\r\n\t\tthis._dndDecorationIds = this._editor.deltaDecorations(this._dndDecorationIds, []);\r\n\t}\r\n\r\n\tprivate _hitContent(target: IMouseTarget): boolean {\r\n\t\treturn target.type === MouseTargetType.CONTENT_TEXT ||\r\n\t\t\ttarget.type === MouseTargetType.CONTENT_EMPTY;\r\n\t}\r\n\r\n\tprivate _hitMargin(target: IMouseTarget): boolean {\r\n\t\treturn target.type === MouseTargetType.GUTTER_GLYPH_MARGIN ||\r\n\t\t\ttarget.type === MouseTargetType.GUTTER_LINE_NUMBERS ||\r\n\t\t\ttarget.type === MouseTargetType.GUTTER_LINE_DECORATIONS;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._removeDecoration();\r\n\t\tthis._dragSelection = null;\r\n\t\tthis._mouseDown = false;\r\n\t\tthis._modifierPressed = false;\r\n\t\tsuper.dispose();\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(DragAndDropController.ID, DragAndDropController);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction, ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions';\r\nimport { EditorZoom } from 'vs/editor/common/config/editorZoom';\r\n\r\nclass EditorFontZoomIn extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.fontZoomIn',\r\n\t\t\tlabel: nls.localize('EditorFontZoomIn.label', \"Editor Font Zoom In\"),\r\n\t\t\talias: 'Editor Font Zoom In',\r\n\t\t\tprecondition: undefined\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tEditorZoom.setZoomLevel(EditorZoom.getZoomLevel() + 1);\r\n\t}\r\n}\r\n\r\nclass EditorFontZoomOut extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.fontZoomOut',\r\n\t\t\tlabel: nls.localize('EditorFontZoomOut.label', \"Editor Font Zoom Out\"),\r\n\t\t\talias: 'Editor Font Zoom Out',\r\n\t\t\tprecondition: undefined\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tEditorZoom.setZoomLevel(EditorZoom.getZoomLevel() - 1);\r\n\t}\r\n}\r\n\r\nclass EditorFontZoomReset extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.fontZoomReset',\r\n\t\t\tlabel: nls.localize('EditorFontZoomReset.label', \"Editor Font Zoom Reset\"),\r\n\t\t\talias: 'Editor Font Zoom Reset',\r\n\t\t\tprecondition: undefined\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tEditorZoom.setZoomLevel(0);\r\n\t}\r\n}\r\n\r\nregisterEditorAction(EditorFontZoomIn);\r\nregisterEditorAction(EditorFontZoomOut);\r\nregisterEditorAction(EditorFontZoomReset);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { alert } from 'vs/base/browser/ui/aria/aria';\r\nimport { asArray, isNonEmptyArray } from 'vs/base/common/arrays';\r\nimport { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\r\nimport { illegalArgument, onUnexpectedExternalError } from 'vs/base/common/errors';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { CodeEditorStateFlag, EditorStateCancellationTokenSource, TextModelCancellationTokenSource } from 'vs/editor/browser/core/editorState';\r\nimport { IActiveCodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { ServicesAccessor } from 'vs/editor/browser/editorExtensions';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { ScrollType } from 'vs/editor/common/editorCommon';\r\nimport { ISingleEditOperation, ITextModel } from 'vs/editor/common/model';\r\nimport { DocumentFormattingEditProvider, DocumentFormattingEditProviderRegistry, DocumentRangeFormattingEditProvider, DocumentRangeFormattingEditProviderRegistry, FormattingOptions, OnTypeFormattingEditProviderRegistry, TextEdit } from 'vs/editor/common/modes';\r\nimport { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';\r\nimport { IModelService } from 'vs/editor/common/services/modelService';\r\nimport { FormattingEdit } from 'vs/editor/contrib/format/formattingEdit';\r\nimport * as nls from 'vs/nls';\r\nimport { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';\r\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { LinkedList } from 'vs/base/common/linkedList';\r\nimport { CommandsRegistry } from 'vs/platform/commands/common/commands';\r\nimport { assertType } from 'vs/base/common/types';\r\nimport { IProgress } from 'vs/platform/progress/common/progress';\r\nimport { Iterable } from 'vs/base/common/iterator';\r\n\r\nexport function alertFormattingEdits(edits: ISingleEditOperation[]): void {\r\n\r\n\tedits = edits.filter(edit => edit.range);\r\n\tif (!edits.length) {\r\n\t\treturn;\r\n\t}\r\n\r\n\tlet { range } = edits[0];\r\n\tfor (let i = 1; i < edits.length; i++) {\r\n\t\trange = Range.plusRange(range, edits[i].range);\r\n\t}\r\n\tconst { startLineNumber, endLineNumber } = range;\r\n\tif (startLineNumber === endLineNumber) {\r\n\t\tif (edits.length === 1) {\r\n\t\t\talert(nls.localize('hint11', \"Made 1 formatting edit on line {0}\", startLineNumber));\r\n\t\t} else {\r\n\t\t\talert(nls.localize('hintn1', \"Made {0} formatting edits on line {1}\", edits.length, startLineNumber));\r\n\t\t}\r\n\t} else {\r\n\t\tif (edits.length === 1) {\r\n\t\t\talert(nls.localize('hint1n', \"Made 1 formatting edit between lines {0} and {1}\", startLineNumber, endLineNumber));\r\n\t\t} else {\r\n\t\t\talert(nls.localize('hintnn', \"Made {0} formatting edits between lines {1} and {2}\", edits.length, startLineNumber, endLineNumber));\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport function getRealAndSyntheticDocumentFormattersOrdered(model: ITextModel): DocumentFormattingEditProvider[] {\r\n\tconst result: DocumentFormattingEditProvider[] = [];\r\n\tconst seen = new Set();\r\n\r\n\t// (1) add all document formatter\r\n\tconst docFormatter = DocumentFormattingEditProviderRegistry.ordered(model);\r\n\tfor (const formatter of docFormatter) {\r\n\t\tresult.push(formatter);\r\n\t\tif (formatter.extensionId) {\r\n\t\t\tseen.add(ExtensionIdentifier.toKey(formatter.extensionId));\r\n\t\t}\r\n\t}\r\n\r\n\t// (2) add all range formatter as document formatter (unless the same extension already did that)\r\n\tconst rangeFormatter = DocumentRangeFormattingEditProviderRegistry.ordered(model);\r\n\tfor (const formatter of rangeFormatter) {\r\n\t\tif (formatter.extensionId) {\r\n\t\t\tif (seen.has(ExtensionIdentifier.toKey(formatter.extensionId))) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tseen.add(ExtensionIdentifier.toKey(formatter.extensionId));\r\n\t\t}\r\n\t\tresult.push({\r\n\t\t\tdisplayName: formatter.displayName,\r\n\t\t\textensionId: formatter.extensionId,\r\n\t\t\tprovideDocumentFormattingEdits(model, options, token) {\r\n\t\t\t\treturn formatter.provideDocumentRangeFormattingEdits(model, model.getFullModelRange(), options, token);\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\treturn result;\r\n}\r\n\r\nexport const enum FormattingMode {\r\n\tExplicit = 1,\r\n\tSilent = 2\r\n}\r\n\r\nexport interface IFormattingEditProviderSelector {\r\n\t(formatter: T[], document: ITextModel, mode: FormattingMode): Promise;\r\n}\r\n\r\nexport abstract class FormattingConflicts {\r\n\r\n\tprivate static readonly _selectors = new LinkedList();\r\n\r\n\tstatic setFormatterSelector(selector: IFormattingEditProviderSelector): IDisposable {\r\n\t\tconst remove = FormattingConflicts._selectors.unshift(selector);\r\n\t\treturn { dispose: remove };\r\n\t}\r\n\r\n\tstatic async select(formatter: T[], document: ITextModel, mode: FormattingMode): Promise {\r\n\t\tif (formatter.length === 0) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\t\tconst selector = Iterable.first(FormattingConflicts._selectors);\r\n\t\tif (selector) {\r\n\t\t\treturn await selector(formatter, document, mode);\r\n\t\t}\r\n\t\treturn undefined;\r\n\t}\r\n}\r\n\r\nexport async function formatDocumentRangesWithSelectedProvider(\r\n\taccessor: ServicesAccessor,\r\n\teditorOrModel: ITextModel | IActiveCodeEditor,\r\n\trangeOrRanges: Range | Range[],\r\n\tmode: FormattingMode,\r\n\tprogress: IProgress,\r\n\ttoken: CancellationToken\r\n): Promise {\r\n\r\n\tconst instaService = accessor.get(IInstantiationService);\r\n\tconst model = isCodeEditor(editorOrModel) ? editorOrModel.getModel() : editorOrModel;\r\n\tconst provider = DocumentRangeFormattingEditProviderRegistry.ordered(model);\r\n\tconst selected = await FormattingConflicts.select(provider, model, mode);\r\n\tif (selected) {\r\n\t\tprogress.report(selected);\r\n\t\tawait instaService.invokeFunction(formatDocumentRangesWithProvider, selected, editorOrModel, rangeOrRanges, token);\r\n\t}\r\n}\r\n\r\nexport async function formatDocumentRangesWithProvider(\r\n\taccessor: ServicesAccessor,\r\n\tprovider: DocumentRangeFormattingEditProvider,\r\n\teditorOrModel: ITextModel | IActiveCodeEditor,\r\n\trangeOrRanges: Range | Range[],\r\n\ttoken: CancellationToken\r\n): Promise {\r\n\tconst workerService = accessor.get(IEditorWorkerService);\r\n\r\n\tlet model: ITextModel;\r\n\tlet cts: CancellationTokenSource;\r\n\tif (isCodeEditor(editorOrModel)) {\r\n\t\tmodel = editorOrModel.getModel();\r\n\t\tcts = new EditorStateCancellationTokenSource(editorOrModel, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position, undefined, token);\r\n\t} else {\r\n\t\tmodel = editorOrModel;\r\n\t\tcts = new TextModelCancellationTokenSource(editorOrModel, token);\r\n\t}\r\n\r\n\t// make sure that ranges don't overlap nor touch each other\r\n\tlet ranges: Range[] = [];\r\n\tlet len = 0;\r\n\tfor (let range of asArray(rangeOrRanges).sort(Range.compareRangesUsingStarts)) {\r\n\t\tif (len > 0 && Range.areIntersectingOrTouching(ranges[len - 1], range)) {\r\n\t\t\tranges[len - 1] = Range.fromPositions(ranges[len - 1].getStartPosition(), range.getEndPosition());\r\n\t\t} else {\r\n\t\t\tlen = ranges.push(range);\r\n\t\t}\r\n\t}\r\n\r\n\tconst allEdits: TextEdit[] = [];\r\n\tfor (let range of ranges) {\r\n\t\ttry {\r\n\t\t\tconst rawEdits = await provider.provideDocumentRangeFormattingEdits(\r\n\t\t\t\tmodel,\r\n\t\t\t\trange,\r\n\t\t\t\tmodel.getFormattingOptions(),\r\n\t\t\t\tcts.token\r\n\t\t\t);\r\n\t\t\tconst minEdits = await workerService.computeMoreMinimalEdits(model.uri, rawEdits);\r\n\t\t\tif (minEdits) {\r\n\t\t\t\tallEdits.push(...minEdits);\r\n\t\t\t}\r\n\t\t\tif (cts.token.isCancellationRequested) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t} finally {\r\n\t\t\tcts.dispose();\r\n\t\t}\r\n\t}\r\n\r\n\tif (allEdits.length === 0) {\r\n\t\treturn false;\r\n\t}\r\n\r\n\tif (isCodeEditor(editorOrModel)) {\r\n\t\t// use editor to apply edits\r\n\t\tFormattingEdit.execute(editorOrModel, allEdits, true);\r\n\t\talertFormattingEdits(allEdits);\r\n\t\teditorOrModel.revealPositionInCenterIfOutsideViewport(editorOrModel.getPosition(), ScrollType.Immediate);\r\n\r\n\t} else {\r\n\t\t// use model to apply edits\r\n\t\tconst [{ range }] = allEdits;\r\n\t\tconst initialSelection = new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);\r\n\t\tmodel.pushEditOperations([initialSelection], allEdits.map(edit => {\r\n\t\t\treturn {\r\n\t\t\t\ttext: edit.text,\r\n\t\t\t\trange: Range.lift(edit.range),\r\n\t\t\t\tforceMoveMarkers: true\r\n\t\t\t};\r\n\t\t}), undoEdits => {\r\n\t\t\tfor (const { range } of undoEdits) {\r\n\t\t\t\tif (Range.areIntersectingOrTouching(range, initialSelection)) {\r\n\t\t\t\t\treturn [new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn)];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t});\r\n\t}\r\n\r\n\treturn true;\r\n}\r\n\r\nexport async function formatDocumentWithSelectedProvider(\r\n\taccessor: ServicesAccessor,\r\n\teditorOrModel: ITextModel | IActiveCodeEditor,\r\n\tmode: FormattingMode,\r\n\tprogress: IProgress,\r\n\ttoken: CancellationToken\r\n): Promise {\r\n\r\n\tconst instaService = accessor.get(IInstantiationService);\r\n\tconst model = isCodeEditor(editorOrModel) ? editorOrModel.getModel() : editorOrModel;\r\n\tconst provider = getRealAndSyntheticDocumentFormattersOrdered(model);\r\n\tconst selected = await FormattingConflicts.select(provider, model, mode);\r\n\tif (selected) {\r\n\t\tprogress.report(selected);\r\n\t\tawait instaService.invokeFunction(formatDocumentWithProvider, selected, editorOrModel, mode, token);\r\n\t}\r\n}\r\n\r\nexport async function formatDocumentWithProvider(\r\n\taccessor: ServicesAccessor,\r\n\tprovider: DocumentFormattingEditProvider,\r\n\teditorOrModel: ITextModel | IActiveCodeEditor,\r\n\tmode: FormattingMode,\r\n\ttoken: CancellationToken\r\n): Promise {\r\n\tconst workerService = accessor.get(IEditorWorkerService);\r\n\r\n\tlet model: ITextModel;\r\n\tlet cts: CancellationTokenSource;\r\n\tif (isCodeEditor(editorOrModel)) {\r\n\t\tmodel = editorOrModel.getModel();\r\n\t\tcts = new EditorStateCancellationTokenSource(editorOrModel, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position, undefined, token);\r\n\t} else {\r\n\t\tmodel = editorOrModel;\r\n\t\tcts = new TextModelCancellationTokenSource(editorOrModel, token);\r\n\t}\r\n\r\n\tlet edits: TextEdit[] | undefined;\r\n\ttry {\r\n\t\tconst rawEdits = await provider.provideDocumentFormattingEdits(\r\n\t\t\tmodel,\r\n\t\t\tmodel.getFormattingOptions(),\r\n\t\t\tcts.token\r\n\t\t);\r\n\r\n\t\tedits = await workerService.computeMoreMinimalEdits(model.uri, rawEdits);\r\n\r\n\t\tif (cts.token.isCancellationRequested) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t} finally {\r\n\t\tcts.dispose();\r\n\t}\r\n\r\n\tif (!edits || edits.length === 0) {\r\n\t\treturn false;\r\n\t}\r\n\r\n\tif (isCodeEditor(editorOrModel)) {\r\n\t\t// use editor to apply edits\r\n\t\tFormattingEdit.execute(editorOrModel, edits, mode !== FormattingMode.Silent);\r\n\r\n\t\tif (mode !== FormattingMode.Silent) {\r\n\t\t\talertFormattingEdits(edits);\r\n\t\t\teditorOrModel.revealPositionInCenterIfOutsideViewport(editorOrModel.getPosition(), ScrollType.Immediate);\r\n\t\t}\r\n\r\n\t} else {\r\n\t\t// use model to apply edits\r\n\t\tconst [{ range }] = edits;\r\n\t\tconst initialSelection = new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);\r\n\t\tmodel.pushEditOperations([initialSelection], edits.map(edit => {\r\n\t\t\treturn {\r\n\t\t\t\ttext: edit.text,\r\n\t\t\t\trange: Range.lift(edit.range),\r\n\t\t\t\tforceMoveMarkers: true\r\n\t\t\t};\r\n\t\t}), undoEdits => {\r\n\t\t\tfor (const { range } of undoEdits) {\r\n\t\t\t\tif (Range.areIntersectingOrTouching(range, initialSelection)) {\r\n\t\t\t\t\treturn [new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn)];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t});\r\n\t}\r\n\r\n\treturn true;\r\n}\r\n\r\nexport async function getDocumentRangeFormattingEditsUntilResult(\r\n\tworkerService: IEditorWorkerService,\r\n\tmodel: ITextModel,\r\n\trange: Range,\r\n\toptions: FormattingOptions,\r\n\ttoken: CancellationToken\r\n): Promise {\r\n\r\n\tconst providers = DocumentRangeFormattingEditProviderRegistry.ordered(model);\r\n\tfor (const provider of providers) {\r\n\t\tlet rawEdits = await Promise.resolve(provider.provideDocumentRangeFormattingEdits(model, range, options, token)).catch(onUnexpectedExternalError);\r\n\t\tif (isNonEmptyArray(rawEdits)) {\r\n\t\t\treturn await workerService.computeMoreMinimalEdits(model.uri, rawEdits);\r\n\t\t}\r\n\t}\r\n\treturn undefined;\r\n}\r\n\r\nexport async function getDocumentFormattingEditsUntilResult(\r\n\tworkerService: IEditorWorkerService,\r\n\tmodel: ITextModel,\r\n\toptions: FormattingOptions,\r\n\ttoken: CancellationToken\r\n): Promise {\r\n\r\n\tconst providers = getRealAndSyntheticDocumentFormattersOrdered(model);\r\n\tfor (const provider of providers) {\r\n\t\tlet rawEdits = await Promise.resolve(provider.provideDocumentFormattingEdits(model, options, token)).catch(onUnexpectedExternalError);\r\n\t\tif (isNonEmptyArray(rawEdits)) {\r\n\t\t\treturn await workerService.computeMoreMinimalEdits(model.uri, rawEdits);\r\n\t\t}\r\n\t}\r\n\treturn undefined;\r\n}\r\n\r\nexport function getOnTypeFormattingEdits(\r\n\tworkerService: IEditorWorkerService,\r\n\tmodel: ITextModel,\r\n\tposition: Position,\r\n\tch: string,\r\n\toptions: FormattingOptions\r\n): Promise {\r\n\r\n\tconst providers = OnTypeFormattingEditProviderRegistry.ordered(model);\r\n\r\n\tif (providers.length === 0) {\r\n\t\treturn Promise.resolve(undefined);\r\n\t}\r\n\r\n\tif (providers[0].autoFormatTriggerCharacters.indexOf(ch) < 0) {\r\n\t\treturn Promise.resolve(undefined);\r\n\t}\r\n\r\n\treturn Promise.resolve(providers[0].provideOnTypeFormattingEdits(model, position, ch, options, CancellationToken.None)).catch(onUnexpectedExternalError).then(edits => {\r\n\t\treturn workerService.computeMoreMinimalEdits(model.uri, edits);\r\n\t});\r\n}\r\n\r\nCommandsRegistry.registerCommand('_executeFormatRangeProvider', function (accessor, ...args) {\r\n\tconst [resource, range, options] = args;\r\n\tassertType(URI.isUri(resource));\r\n\tassertType(Range.isIRange(range));\r\n\r\n\tconst model = accessor.get(IModelService).getModel(resource);\r\n\tif (!model) {\r\n\t\tthrow illegalArgument('resource');\r\n\t}\r\n\treturn getDocumentRangeFormattingEditsUntilResult(accessor.get(IEditorWorkerService), model, Range.lift(range), options, CancellationToken.None);\r\n});\r\n\r\nCommandsRegistry.registerCommand('_executeFormatDocumentProvider', function (accessor, ...args) {\r\n\tconst [resource, options] = args;\r\n\tassertType(URI.isUri(resource));\r\n\r\n\tconst model = accessor.get(IModelService).getModel(resource);\r\n\tif (!model) {\r\n\t\tthrow illegalArgument('resource');\r\n\t}\r\n\r\n\treturn getDocumentFormattingEditsUntilResult(accessor.get(IEditorWorkerService), model, options, CancellationToken.None);\r\n});\r\n\r\nCommandsRegistry.registerCommand('_executeFormatOnTypeProvider', function (accessor, ...args) {\r\n\tconst [resource, position, ch, options] = args;\r\n\tassertType(URI.isUri(resource));\r\n\tassertType(Position.isIPosition(position));\r\n\tassertType(typeof ch === 'string');\r\n\r\n\tconst model = accessor.get(IModelService).getModel(resource);\r\n\tif (!model) {\r\n\t\tthrow illegalArgument('resource');\r\n\t}\r\n\r\n\treturn getOnTypeFormattingEdits(accessor.get(IEditorWorkerService), model, Position.lift(position), ch, options);\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { isNonEmptyArray } from 'vs/base/common/arrays';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction, registerEditorAction, registerEditorContribution, ServicesAccessor } from 'vs/editor/browser/editorExtensions';\r\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\r\nimport { CharacterSet } from 'vs/editor/common/core/characterClassifier';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { DocumentRangeFormattingEditProviderRegistry, OnTypeFormattingEditProviderRegistry } from 'vs/editor/common/modes';\r\nimport { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';\r\nimport { getOnTypeFormattingEdits, alertFormattingEdits, formatDocumentRangesWithSelectedProvider, formatDocumentWithSelectedProvider, FormattingMode } from 'vs/editor/contrib/format/format';\r\nimport { FormattingEdit } from 'vs/editor/contrib/format/formattingEdit';\r\nimport * as nls from 'vs/nls';\r\nimport { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';\r\nimport { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { Progress, IEditorProgressService } from 'vs/platform/progress/common/progress';\r\n\r\nclass FormatOnType implements IEditorContribution {\r\n\r\n\tpublic static readonly ID = 'editor.contrib.autoFormat';\r\n\r\n\tprivate readonly _editor: ICodeEditor;\r\n\tprivate readonly _callOnDispose = new DisposableStore();\r\n\tprivate readonly _callOnModel = new DisposableStore();\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor,\r\n\t\t@IEditorWorkerService private readonly _workerService: IEditorWorkerService\r\n\t) {\r\n\t\tthis._editor = editor;\r\n\t\tthis._callOnDispose.add(editor.onDidChangeConfiguration(() => this._update()));\r\n\t\tthis._callOnDispose.add(editor.onDidChangeModel(() => this._update()));\r\n\t\tthis._callOnDispose.add(editor.onDidChangeModelLanguage(() => this._update()));\r\n\t\tthis._callOnDispose.add(OnTypeFormattingEditProviderRegistry.onDidChange(this._update, this));\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._callOnDispose.dispose();\r\n\t\tthis._callOnModel.dispose();\r\n\t}\r\n\r\n\tprivate _update(): void {\r\n\r\n\t\t// clean up\r\n\t\tthis._callOnModel.clear();\r\n\r\n\t\t// we are disabled\r\n\t\tif (!this._editor.getOption(EditorOption.formatOnType)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// no model\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst model = this._editor.getModel();\r\n\r\n\t\t// no support\r\n\t\tconst [support] = OnTypeFormattingEditProviderRegistry.ordered(model);\r\n\t\tif (!support || !support.autoFormatTriggerCharacters) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// register typing listeners that will trigger the format\r\n\t\tlet triggerChars = new CharacterSet();\r\n\t\tfor (let ch of support.autoFormatTriggerCharacters) {\r\n\t\t\ttriggerChars.add(ch.charCodeAt(0));\r\n\t\t}\r\n\t\tthis._callOnModel.add(this._editor.onDidType((text: string) => {\r\n\t\t\tlet lastCharCode = text.charCodeAt(text.length - 1);\r\n\t\t\tif (triggerChars.has(lastCharCode)) {\r\n\t\t\t\tthis._trigger(String.fromCharCode(lastCharCode));\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\tprivate _trigger(ch: string): void {\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this._editor.getSelections().length > 1) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst model = this._editor.getModel();\r\n\t\tconst position = this._editor.getPosition();\r\n\t\tlet canceled = false;\r\n\r\n\t\t// install a listener that checks if edits happens before the\r\n\t\t// position on which we format right now. If so, we won't\r\n\t\t// apply the format edits\r\n\t\tconst unbind = this._editor.onDidChangeModelContent((e) => {\r\n\t\t\tif (e.isFlush) {\r\n\t\t\t\t// a model.setValue() was called\r\n\t\t\t\t// cancel only once\r\n\t\t\t\tcanceled = true;\r\n\t\t\t\tunbind.dispose();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tfor (let i = 0, len = e.changes.length; i < len; i++) {\r\n\t\t\t\tconst change = e.changes[i];\r\n\t\t\t\tif (change.range.endLineNumber <= position.lineNumber) {\r\n\t\t\t\t\t// cancel only once\r\n\t\t\t\t\tcanceled = true;\r\n\t\t\t\t\tunbind.dispose();\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t});\r\n\r\n\t\tgetOnTypeFormattingEdits(\r\n\t\t\tthis._workerService,\r\n\t\t\tmodel,\r\n\t\t\tposition,\r\n\t\t\tch,\r\n\t\t\tmodel.getFormattingOptions()\r\n\t\t).then(edits => {\r\n\r\n\t\t\tunbind.dispose();\r\n\r\n\t\t\tif (canceled) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (isNonEmptyArray(edits)) {\r\n\t\t\t\tFormattingEdit.execute(this._editor, edits, true);\r\n\t\t\t\talertFormattingEdits(edits);\r\n\t\t\t}\r\n\r\n\t\t}, (err) => {\r\n\t\t\tunbind.dispose();\r\n\t\t\tthrow err;\r\n\t\t});\r\n\t}\r\n}\r\n\r\nclass FormatOnPaste implements IEditorContribution {\r\n\r\n\tpublic static readonly ID = 'editor.contrib.formatOnPaste';\r\n\r\n\tprivate readonly _callOnDispose = new DisposableStore();\r\n\tprivate readonly _callOnModel = new DisposableStore();\r\n\r\n\tconstructor(\r\n\t\tprivate readonly editor: ICodeEditor,\r\n\t\t@IInstantiationService private readonly _instantiationService: IInstantiationService,\r\n\t) {\r\n\t\tthis._callOnDispose.add(editor.onDidChangeConfiguration(() => this._update()));\r\n\t\tthis._callOnDispose.add(editor.onDidChangeModel(() => this._update()));\r\n\t\tthis._callOnDispose.add(editor.onDidChangeModelLanguage(() => this._update()));\r\n\t\tthis._callOnDispose.add(DocumentRangeFormattingEditProviderRegistry.onDidChange(this._update, this));\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._callOnDispose.dispose();\r\n\t\tthis._callOnModel.dispose();\r\n\t}\r\n\r\n\tprivate _update(): void {\r\n\r\n\t\t// clean up\r\n\t\tthis._callOnModel.clear();\r\n\r\n\t\t// we are disabled\r\n\t\tif (!this.editor.getOption(EditorOption.formatOnPaste)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// no model\r\n\t\tif (!this.editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// no formatter\r\n\t\tif (!DocumentRangeFormattingEditProviderRegistry.has(this.editor.getModel())) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._callOnModel.add(this.editor.onDidPaste(({ range }) => this._trigger(range)));\r\n\t}\r\n\r\n\tprivate _trigger(range: Range): void {\r\n\t\tif (!this.editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (this.editor.getSelections().length > 1) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._instantiationService.invokeFunction(formatDocumentRangesWithSelectedProvider, this.editor, range, FormattingMode.Silent, Progress.None, CancellationToken.None).catch(onUnexpectedError);\r\n\t}\r\n}\r\n\r\nclass FormatDocumentAction extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.formatDocument',\r\n\t\t\tlabel: nls.localize('formatDocument.label', \"Format Document\"),\r\n\t\t\talias: 'Format Document',\r\n\t\t\tprecondition: ContextKeyExpr.and(EditorContextKeys.notInCompositeEditor, EditorContextKeys.writable, EditorContextKeys.hasDocumentFormattingProvider),\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_F,\r\n\t\t\t\tlinux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_I },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tcontextMenuOpts: {\r\n\t\t\t\tgroup: '1_modification',\r\n\t\t\t\torder: 1.3\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tasync run(accessor: ServicesAccessor, editor: ICodeEditor): Promise {\r\n\t\tif (editor.hasModel()) {\r\n\t\t\tconst instaService = accessor.get(IInstantiationService);\r\n\t\t\tconst progressService = accessor.get(IEditorProgressService);\r\n\t\t\tawait progressService.showWhile(\r\n\t\t\t\tinstaService.invokeFunction(formatDocumentWithSelectedProvider, editor, FormattingMode.Explicit, Progress.None, CancellationToken.None),\r\n\t\t\t\t250\r\n\t\t\t);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass FormatSelectionAction extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.formatSelection',\r\n\t\t\tlabel: nls.localize('formatSelection.label', \"Format Selection\"),\r\n\t\t\talias: 'Format Selection',\r\n\t\t\tprecondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasDocumentSelectionFormattingProvider),\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_F),\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tcontextMenuOpts: {\r\n\t\t\t\twhen: EditorContextKeys.hasNonEmptySelection,\r\n\t\t\t\tgroup: '1_modification',\r\n\t\t\t\torder: 1.31\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tasync run(accessor: ServicesAccessor, editor: ICodeEditor): Promise {\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst instaService = accessor.get(IInstantiationService);\r\n\t\tconst model = editor.getModel();\r\n\r\n\t\tconst ranges = editor.getSelections().map(range => {\r\n\t\t\treturn range.isEmpty()\r\n\t\t\t\t? new Range(range.startLineNumber, 1, range.startLineNumber, model.getLineMaxColumn(range.startLineNumber))\r\n\t\t\t\t: range;\r\n\t\t});\r\n\r\n\t\tconst progressService = accessor.get(IEditorProgressService);\r\n\t\tawait progressService.showWhile(\r\n\t\t\tinstaService.invokeFunction(formatDocumentRangesWithSelectedProvider, editor, ranges, FormattingMode.Explicit, Progress.None, CancellationToken.None),\r\n\t\t\t250\r\n\t\t);\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(FormatOnType.ID, FormatOnType);\r\nregisterEditorContribution(FormatOnPaste.ID, FormatOnPaste);\r\nregisterEditorAction(FormatDocumentAction);\r\nregisterEditorAction(FormatSelectionAction);\r\n\r\n// this is the old format action that does both (format document OR format selection)\r\n// and we keep it here such that existing keybinding configurations etc will still work\r\nCommandsRegistry.registerCommand('editor.action.format', async accessor => {\r\n\tconst editor = accessor.get(ICodeEditorService).getFocusedCodeEditor();\r\n\tif (!editor || !editor.hasModel()) {\r\n\t\treturn;\r\n\t}\r\n\tconst commandService = accessor.get(ICommandService);\r\n\tif (editor.getSelection().isEmpty()) {\r\n\t\tawait commandService.executeCommand('editor.action.formatDocument');\r\n\t} else {\r\n\t\tawait commandService.executeCommand('editor.action.formatSelection');\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { onUnexpectedExternalError } from 'vs/base/common/errors';\r\nimport { registerModelAndPositionCommand } from 'vs/editor/browser/editorExtensions';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { LocationLink, DefinitionProviderRegistry, ImplementationProviderRegistry, TypeDefinitionProviderRegistry, DeclarationProviderRegistry, ProviderResult, ReferenceProviderRegistry } from 'vs/editor/common/modes';\r\nimport { LanguageFeatureRegistry } from 'vs/editor/common/modes/languageFeatureRegistry';\r\n\r\n\r\nfunction getLocationLinks(\r\n\tmodel: ITextModel,\r\n\tposition: Position,\r\n\tregistry: LanguageFeatureRegistry,\r\n\tprovide: (provider: T, model: ITextModel, position: Position) => ProviderResult\r\n): Promise {\r\n\tconst provider = registry.ordered(model);\r\n\r\n\t// get results\r\n\tconst promises = provider.map((provider): Promise => {\r\n\t\treturn Promise.resolve(provide(provider, model, position)).then(undefined, err => {\r\n\t\t\tonUnexpectedExternalError(err);\r\n\t\t\treturn undefined;\r\n\t\t});\r\n\t});\r\n\r\n\treturn Promise.all(promises).then(values => {\r\n\t\tconst result: LocationLink[] = [];\r\n\t\tfor (let value of values) {\r\n\t\t\tif (Array.isArray(value)) {\r\n\t\t\t\tresult.push(...value);\r\n\t\t\t} else if (value) {\r\n\t\t\t\tresult.push(value);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn result;\r\n\t});\r\n}\r\n\r\n\r\nexport function getDefinitionsAtPosition(model: ITextModel, position: Position, token: CancellationToken): Promise {\r\n\treturn getLocationLinks(model, position, DefinitionProviderRegistry, (provider, model, position) => {\r\n\t\treturn provider.provideDefinition(model, position, token);\r\n\t});\r\n}\r\n\r\nexport function getDeclarationsAtPosition(model: ITextModel, position: Position, token: CancellationToken): Promise {\r\n\treturn getLocationLinks(model, position, DeclarationProviderRegistry, (provider, model, position) => {\r\n\t\treturn provider.provideDeclaration(model, position, token);\r\n\t});\r\n}\r\n\r\nexport function getImplementationsAtPosition(model: ITextModel, position: Position, token: CancellationToken): Promise {\r\n\treturn getLocationLinks(model, position, ImplementationProviderRegistry, (provider, model, position) => {\r\n\t\treturn provider.provideImplementation(model, position, token);\r\n\t});\r\n}\r\n\r\nexport function getTypeDefinitionsAtPosition(model: ITextModel, position: Position, token: CancellationToken): Promise {\r\n\treturn getLocationLinks(model, position, TypeDefinitionProviderRegistry, (provider, model, position) => {\r\n\t\treturn provider.provideTypeDefinition(model, position, token);\r\n\t});\r\n}\r\n\r\nexport function getReferencesAtPosition(model: ITextModel, position: Position, compact: boolean, token: CancellationToken): Promise {\r\n\treturn getLocationLinks(model, position, ReferenceProviderRegistry, async (provider, model, position) => {\r\n\t\tconst result = await provider.provideReferences(model, position, { includeDeclaration: true }, token);\r\n\t\tif (!compact || !result || result.length !== 2) {\r\n\t\t\treturn result;\r\n\t\t}\r\n\t\tconst resultWithoutDeclaration = await provider.provideReferences(model, position, { includeDeclaration: false }, token);\r\n\t\tif (resultWithoutDeclaration && resultWithoutDeclaration.length === 1) {\r\n\t\t\treturn resultWithoutDeclaration;\r\n\t\t}\r\n\t\treturn result;\r\n\t});\r\n}\r\n\r\nregisterModelAndPositionCommand('_executeDefinitionProvider', (model, position) => getDefinitionsAtPosition(model, position, CancellationToken.None));\r\nregisterModelAndPositionCommand('_executeDeclarationProvider', (model, position) => getDeclarationsAtPosition(model, position, CancellationToken.None));\r\nregisterModelAndPositionCommand('_executeImplementationProvider', (model, position) => getImplementationsAtPosition(model, position, CancellationToken.None));\r\nregisterModelAndPositionCommand('_executeTypeDefinitionProvider', (model, position) => getTypeDefinitionsAtPosition(model, position, CancellationToken.None));\r\nregisterModelAndPositionCommand('_executeReferenceProvider', (model, position) => getReferencesAtPosition(model, position, false, CancellationToken.None));\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { ReferencesModel, OneReference } from 'vs/editor/contrib/gotoSymbol/referencesModel';\r\nimport { RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';\r\nimport { createDecorator, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';\r\nimport { registerSingleton } from 'vs/platform/instantiation/common/extensions';\r\nimport { KeybindingWeight, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { KeyCode } from 'vs/base/common/keyCodes';\r\nimport { registerEditorCommand, EditorCommand } from 'vs/editor/browser/editorExtensions';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { dispose, IDisposable, combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { localize } from 'vs/nls';\r\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\r\nimport { INotificationService } from 'vs/platform/notification/common/notification';\r\nimport { isEqual } from 'vs/base/common/resources';\r\nimport { TextEditorSelectionRevealType } from 'vs/platform/editor/common/editor';\r\n\r\nexport const ctxHasSymbols = new RawContextKey('hasSymbols', false);\r\n\r\nexport const ISymbolNavigationService = createDecorator('ISymbolNavigationService');\r\n\r\nexport interface ISymbolNavigationService {\r\n\treadonly _serviceBrand: undefined;\r\n\treset(): void;\r\n\tput(anchor: OneReference): void;\r\n\trevealNext(source: ICodeEditor): Promise;\r\n}\r\n\r\nclass SymbolNavigationService implements ISymbolNavigationService {\r\n\r\n\tdeclare readonly _serviceBrand: undefined;\r\n\r\n\tprivate readonly _ctxHasSymbols: IContextKey;\r\n\r\n\tprivate _currentModel?: ReferencesModel = undefined;\r\n\tprivate _currentIdx: number = -1;\r\n\tprivate _currentState?: IDisposable;\r\n\tprivate _currentMessage?: IDisposable;\r\n\tprivate _ignoreEditorChange: boolean = false;\r\n\r\n\tconstructor(\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\r\n\t\t@ICodeEditorService private readonly _editorService: ICodeEditorService,\r\n\t\t@INotificationService private readonly _notificationService: INotificationService,\r\n\t\t@IKeybindingService private readonly _keybindingService: IKeybindingService,\r\n\t) {\r\n\t\tthis._ctxHasSymbols = ctxHasSymbols.bindTo(contextKeyService);\r\n\t}\r\n\r\n\treset(): void {\r\n\t\tthis._ctxHasSymbols.reset();\r\n\t\tthis._currentState?.dispose();\r\n\t\tthis._currentMessage?.dispose();\r\n\t\tthis._currentModel = undefined;\r\n\t\tthis._currentIdx = -1;\r\n\t}\r\n\r\n\tput(anchor: OneReference): void {\r\n\t\tconst refModel = anchor.parent.parent;\r\n\r\n\t\tif (refModel.references.length <= 1) {\r\n\t\t\tthis.reset();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._currentModel = refModel;\r\n\t\tthis._currentIdx = refModel.references.indexOf(anchor);\r\n\t\tthis._ctxHasSymbols.set(true);\r\n\t\tthis._showMessage();\r\n\r\n\t\tconst editorState = new EditorState(this._editorService);\r\n\t\tconst listener = editorState.onDidChange(_ => {\r\n\r\n\t\t\tif (this._ignoreEditorChange) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst editor = this._editorService.getActiveCodeEditor();\r\n\t\t\tif (!editor) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tconst model = editor.getModel();\r\n\t\t\tconst position = editor.getPosition();\r\n\t\t\tif (!model || !position) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tlet seenUri: boolean = false;\r\n\t\t\tlet seenPosition: boolean = false;\r\n\t\t\tfor (const reference of refModel.references) {\r\n\t\t\t\tif (isEqual(reference.uri, model.uri)) {\r\n\t\t\t\t\tseenUri = true;\r\n\t\t\t\t\tseenPosition = seenPosition || Range.containsPosition(reference.range, position);\r\n\t\t\t\t} else if (seenUri) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (!seenUri || !seenPosition) {\r\n\t\t\t\tthis.reset();\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tthis._currentState = combinedDisposable(editorState, listener);\r\n\t}\r\n\r\n\trevealNext(source: ICodeEditor): Promise {\r\n\t\tif (!this._currentModel) {\r\n\t\t\treturn Promise.resolve();\r\n\t\t}\r\n\r\n\t\t// get next result and advance\r\n\t\tthis._currentIdx += 1;\r\n\t\tthis._currentIdx %= this._currentModel.references.length;\r\n\t\tconst reference = this._currentModel.references[this._currentIdx];\r\n\r\n\t\t// status\r\n\t\tthis._showMessage();\r\n\r\n\t\t// open editor, ignore events while that happens\r\n\t\tthis._ignoreEditorChange = true;\r\n\t\treturn this._editorService.openCodeEditor({\r\n\t\t\tresource: reference.uri,\r\n\t\t\toptions: {\r\n\t\t\t\tselection: Range.collapseToStart(reference.range),\r\n\t\t\t\tselectionRevealType: TextEditorSelectionRevealType.NearTopIfOutsideViewport\r\n\t\t\t}\r\n\t\t}, source).finally(() => {\r\n\t\t\tthis._ignoreEditorChange = false;\r\n\t\t});\r\n\r\n\t}\r\n\r\n\tprivate _showMessage(): void {\r\n\r\n\t\tthis._currentMessage?.dispose();\r\n\r\n\t\tconst kb = this._keybindingService.lookupKeybinding('editor.gotoNextSymbolFromResult');\r\n\t\tconst message = kb\r\n\t\t\t? localize('location.kb', \"Symbol {0} of {1}, {2} for next\", this._currentIdx + 1, this._currentModel!.references.length, kb.getLabel())\r\n\t\t\t: localize('location', \"Symbol {0} of {1}\", this._currentIdx + 1, this._currentModel!.references.length);\r\n\r\n\t\tthis._currentMessage = this._notificationService.status(message);\r\n\t}\r\n}\r\n\r\nregisterSingleton(ISymbolNavigationService, SymbolNavigationService, true);\r\n\r\nregisterEditorCommand(new class extends EditorCommand {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.gotoNextSymbolFromResult',\r\n\t\t\tprecondition: ctxHasSymbols,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib,\r\n\t\t\t\tprimary: KeyCode.F12\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\trunEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor): void | Promise {\r\n\t\treturn accessor.get(ISymbolNavigationService).revealNext(editor);\r\n\t}\r\n});\r\n\r\nKeybindingsRegistry.registerCommandAndKeybindingRule({\r\n\tid: 'editor.gotoNextSymbolFromResult.cancel',\r\n\tweight: KeybindingWeight.EditorContrib,\r\n\twhen: ctxHasSymbols,\r\n\tprimary: KeyCode.Escape,\r\n\thandler(accessor) {\r\n\t\taccessor.get(ISymbolNavigationService).reset();\r\n\t}\r\n});\r\n\r\n//\r\n\r\nclass EditorState {\r\n\r\n\tprivate readonly _listener = new Map();\r\n\tprivate readonly _disposables = new DisposableStore();\r\n\r\n\tprivate readonly _onDidChange = new Emitter<{ editor: ICodeEditor }>();\r\n\treadonly onDidChange: Event<{ editor: ICodeEditor }> = this._onDidChange.event;\r\n\r\n\tconstructor(@ICodeEditorService editorService: ICodeEditorService) {\r\n\t\tthis._disposables.add(editorService.onCodeEditorRemove(this._onDidRemoveEditor, this));\r\n\t\tthis._disposables.add(editorService.onCodeEditorAdd(this._onDidAddEditor, this));\r\n\t\teditorService.listCodeEditors().forEach(this._onDidAddEditor, this);\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._disposables.dispose();\r\n\t\tthis._onDidChange.dispose();\r\n\t\tdispose(this._listener.values());\r\n\t}\r\n\r\n\tprivate _onDidAddEditor(editor: ICodeEditor): void {\r\n\t\tthis._listener.set(editor, combinedDisposable(\r\n\t\t\teditor.onDidChangeCursorPosition(_ => this._onDidChange.fire({ editor })),\r\n\t\t\teditor.onDidChangeModelContent(_ => this._onDidChange.fire({ editor })),\r\n\t\t));\r\n\t}\r\n\r\n\tprivate _onDidRemoveEditor(editor: ICodeEditor): void {\r\n\t\tthis._listener.get(editor)?.dispose();\r\n\t\tthis._listener.delete(editor);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { coalesce } from 'vs/base/common/arrays';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { onUnexpectedExternalError } from 'vs/base/common/errors';\r\nimport { registerModelAndPositionCommand } from 'vs/editor/browser/editorExtensions';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { Hover, HoverProviderRegistry } from 'vs/editor/common/modes';\r\n\r\nexport function getHover(model: ITextModel, position: Position, token: CancellationToken): Promise {\r\n\r\n\tconst supports = HoverProviderRegistry.ordered(model);\r\n\r\n\tconst promises = supports.map(support => {\r\n\t\treturn Promise.resolve(support.provideHover(model, position, token)).then(hover => {\r\n\t\t\treturn hover && isValid(hover) ? hover : undefined;\r\n\t\t}, err => {\r\n\t\t\tonUnexpectedExternalError(err);\r\n\t\t\treturn undefined;\r\n\t\t});\r\n\t});\r\n\r\n\treturn Promise.all(promises).then(coalesce);\r\n}\r\n\r\nregisterModelAndPositionCommand('_executeHoverProvider', (model, position) => getHover(model, position, CancellationToken.None));\r\n\r\nfunction isValid(result: Hover) {\r\n\tconst hasRange = (typeof result.range !== 'undefined');\r\n\tconst hasHtmlContent = typeof result.contents !== 'undefined' && result.contents && result.contents.length > 0;\r\n\treturn hasRange && hasHtmlContent;\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { IMarkdownString, MarkdownString, isEmptyMarkdownString, markedStringsEquals } from 'vs/base/common/htmlContent';\r\nimport { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { MarkdownRenderer } from 'vs/editor/browser/core/markdownRenderer';\r\nimport { asArray } from 'vs/base/common/arrays';\r\nimport { IOpenerService } from 'vs/platform/opener/common/opener';\r\nimport { IModeService } from 'vs/editor/common/services/modeService';\r\nimport { IModelDecoration } from 'vs/editor/common/model';\r\nimport { IEditorHover, IEditorHoverParticipant, IHoverPart } from 'vs/editor/contrib/hover/modesContentHover';\r\nimport { HoverProviderRegistry } from 'vs/editor/common/modes';\r\nimport { getHover } from 'vs/editor/contrib/hover/getHover';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\n\r\nconst $ = dom.$;\r\n\r\nexport class MarkdownHover implements IHoverPart {\r\n\r\n\tconstructor(\r\n\t\tpublic readonly range: Range,\r\n\t\tpublic readonly contents: IMarkdownString[]\r\n\t) { }\r\n\r\n\tpublic equals(other: IHoverPart): boolean {\r\n\t\tif (other instanceof MarkdownHover) {\r\n\t\t\treturn markedStringsEquals(this.contents, other.contents);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\nexport class MarkdownHoverParticipant implements IEditorHoverParticipant {\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _editor: ICodeEditor,\r\n\t\tprivate readonly _hover: IEditorHover,\r\n\t\t@IModeService private readonly _modeService: IModeService,\r\n\t\t@IOpenerService private readonly _openerService: IOpenerService,\r\n\t) { }\r\n\r\n\tpublic createLoadingMessage(range: Range): MarkdownHover {\r\n\t\treturn new MarkdownHover(range, [new MarkdownString().appendText(nls.localize('modesContentHover.loading', \"Loading...\"))]);\r\n\t}\r\n\r\n\tpublic computeSync(hoverRange: Range, lineDecorations: IModelDecoration[]): MarkdownHover[] {\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tconst model = this._editor.getModel();\r\n\t\tconst lineNumber = hoverRange.startLineNumber;\r\n\t\tconst maxColumn = model.getLineMaxColumn(lineNumber);\r\n\t\tconst result: MarkdownHover[] = [];\r\n\t\tfor (const d of lineDecorations) {\r\n\t\t\tconst startColumn = (d.range.startLineNumber === lineNumber) ? d.range.startColumn : 1;\r\n\t\t\tconst endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn;\r\n\r\n\t\t\tconst hoverMessage = d.options.hoverMessage;\r\n\t\t\tif (!hoverMessage || isEmptyMarkdownString(hoverMessage)) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tconst range = new Range(hoverRange.startLineNumber, startColumn, hoverRange.startLineNumber, endColumn);\r\n\t\t\tresult.push(new MarkdownHover(range, asArray(hoverMessage)));\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic async computeAsync(range: Range, token: CancellationToken): Promise {\r\n\t\tif (!this._editor.hasModel() || !range) {\r\n\t\t\treturn Promise.resolve([]);\r\n\t\t}\r\n\r\n\t\tconst model = this._editor.getModel();\r\n\r\n\t\tif (!HoverProviderRegistry.has(model)) {\r\n\t\t\treturn Promise.resolve([]);\r\n\t\t}\r\n\r\n\t\tconst hovers = await getHover(model, new Position(\r\n\t\t\trange.startLineNumber,\r\n\t\t\trange.startColumn\r\n\t\t), token);\r\n\r\n\t\tconst result: MarkdownHover[] = [];\r\n\t\tfor (const hover of hovers) {\r\n\t\t\tif (isEmptyMarkdownString(hover.contents)) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tconst rng = hover.range ? Range.lift(hover.range) : range;\r\n\t\t\tresult.push(new MarkdownHover(rng, hover.contents));\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic renderHoverParts(hoverParts: MarkdownHover[], fragment: DocumentFragment): IDisposable {\r\n\t\tconst disposables = new DisposableStore();\r\n\t\tfor (const hoverPart of hoverParts) {\r\n\t\t\tfor (const contents of hoverPart.contents) {\r\n\t\t\t\tif (isEmptyMarkdownString(contents)) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\tconst markdownHoverElement = $('div.hover-row.markdown-hover');\r\n\t\t\t\tconst hoverContentsElement = dom.append(markdownHoverElement, $('div.hover-contents'));\r\n\t\t\t\tconst renderer = disposables.add(new MarkdownRenderer({ editor: this._editor }, this._modeService, this._openerService));\r\n\t\t\t\tdisposables.add(renderer.onDidRenderAsync(() => {\r\n\t\t\t\t\thoverContentsElement.className = 'hover-contents code-hover-contents';\r\n\t\t\t\t\tthis._hover.onContentsChanged();\r\n\t\t\t\t}));\r\n\t\t\t\tconst renderedContents = disposables.add(renderer.render(contents));\r\n\t\t\t\thoverContentsElement.appendChild(renderedContents.element);\r\n\t\t\t\tfragment.appendChild(markdownHoverElement);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn disposables;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { registerEditorAction, ServicesAccessor, EditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions';\r\nimport { IInplaceReplaceSupportResult } from 'vs/editor/common/modes';\r\nimport { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';\r\nimport { InPlaceReplaceCommand } from './inPlaceReplaceCommand';\r\nimport { EditorState, CodeEditorStateFlag } from 'vs/editor/browser/core/editorState';\r\nimport { registerThemingParticipant } from 'vs/platform/theme/common/themeService';\r\nimport { editorBracketMatchBorder } from 'vs/editor/common/view/editorColorRegistry';\r\nimport { ModelDecorationOptions } from 'vs/editor/common/model/textModel';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { CancelablePromise, createCancelablePromise, timeout } from 'vs/base/common/async';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\n\r\nclass InPlaceReplaceController implements IEditorContribution {\r\n\r\n\tpublic static readonly ID = 'editor.contrib.inPlaceReplaceController';\r\n\r\n\tstatic get(editor: ICodeEditor): InPlaceReplaceController {\r\n\t\treturn editor.getContribution(InPlaceReplaceController.ID);\r\n\t}\r\n\r\n\tprivate static readonly DECORATION = ModelDecorationOptions.register({\r\n\t\tclassName: 'valueSetReplacement'\r\n\t});\r\n\r\n\tprivate readonly editor: ICodeEditor;\r\n\tprivate readonly editorWorkerService: IEditorWorkerService;\r\n\tprivate decorationIds: string[] = [];\r\n\tprivate currentRequest?: CancelablePromise;\r\n\tprivate decorationRemover?: CancelablePromise;\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor,\r\n\t\t@IEditorWorkerService editorWorkerService: IEditorWorkerService\r\n\t) {\r\n\t\tthis.editor = editor;\r\n\t\tthis.editorWorkerService = editorWorkerService;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t}\r\n\r\n\tpublic run(source: string, up: boolean): Promise | undefined {\r\n\r\n\t\t// cancel any pending request\r\n\t\tif (this.currentRequest) {\r\n\t\t\tthis.currentRequest.cancel();\r\n\t\t}\r\n\r\n\t\tconst editorSelection = this.editor.getSelection();\r\n\t\tconst model = this.editor.getModel();\r\n\t\tif (!model || !editorSelection) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\t\tlet selection = editorSelection;\r\n\t\tif (selection.startLineNumber !== selection.endLineNumber) {\r\n\t\t\t// Can't accept multiline selection\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\r\n\t\tconst state = new EditorState(this.editor, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position);\r\n\t\tconst modelURI = model.uri;\r\n\t\tif (!this.editorWorkerService.canNavigateValueSet(modelURI)) {\r\n\t\t\treturn Promise.resolve(undefined);\r\n\t\t}\r\n\r\n\t\tthis.currentRequest = createCancelablePromise(token => this.editorWorkerService.navigateValueSet(modelURI, selection!, up));\r\n\r\n\t\treturn this.currentRequest.then(result => {\r\n\r\n\t\t\tif (!result || !result.range || !result.value) {\r\n\t\t\t\t// No proper result\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (!state.validate(this.editor)) {\r\n\t\t\t\t// state has changed\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\t// Selection\r\n\t\t\tlet editRange = Range.lift(result.range);\r\n\t\t\tlet highlightRange = result.range;\r\n\t\t\tlet diff = result.value.length - (selection!.endColumn - selection!.startColumn);\r\n\r\n\t\t\t// highlight\r\n\t\t\thighlightRange = {\r\n\t\t\t\tstartLineNumber: highlightRange.startLineNumber,\r\n\t\t\t\tstartColumn: highlightRange.startColumn,\r\n\t\t\t\tendLineNumber: highlightRange.endLineNumber,\r\n\t\t\t\tendColumn: highlightRange.startColumn + result.value.length\r\n\t\t\t};\r\n\t\t\tif (diff > 1) {\r\n\t\t\t\tselection = new Selection(selection!.startLineNumber, selection!.startColumn, selection!.endLineNumber, selection!.endColumn + diff - 1);\r\n\t\t\t}\r\n\r\n\t\t\t// Insert new text\r\n\t\t\tconst command = new InPlaceReplaceCommand(editRange, selection!, result.value);\r\n\r\n\t\t\tthis.editor.pushUndoStop();\r\n\t\t\tthis.editor.executeCommand(source, command);\r\n\t\t\tthis.editor.pushUndoStop();\r\n\r\n\t\t\t// add decoration\r\n\t\t\tthis.decorationIds = this.editor.deltaDecorations(this.decorationIds, [{\r\n\t\t\t\trange: highlightRange,\r\n\t\t\t\toptions: InPlaceReplaceController.DECORATION\r\n\t\t\t}]);\r\n\r\n\t\t\t// remove decoration after delay\r\n\t\t\tif (this.decorationRemover) {\r\n\t\t\t\tthis.decorationRemover.cancel();\r\n\t\t\t}\r\n\t\t\tthis.decorationRemover = timeout(350);\r\n\t\t\tthis.decorationRemover.then(() => this.decorationIds = this.editor.deltaDecorations(this.decorationIds, [])).catch(onUnexpectedError);\r\n\r\n\t\t}).catch(onUnexpectedError);\r\n\t}\r\n}\r\n\r\nclass InPlaceReplaceUp extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.inPlaceReplace.up',\r\n\t\t\tlabel: nls.localize('InPlaceReplaceAction.previous.label', \"Replace with Previous Value\"),\r\n\t\t\talias: 'Replace with Previous Value',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_COMMA,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): Promise | undefined {\r\n\t\tconst controller = InPlaceReplaceController.get(editor);\r\n\t\tif (!controller) {\r\n\t\t\treturn Promise.resolve(undefined);\r\n\t\t}\r\n\t\treturn controller.run(this.id, true);\r\n\t}\r\n}\r\n\r\nclass InPlaceReplaceDown extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.inPlaceReplace.down',\r\n\t\t\tlabel: nls.localize('InPlaceReplaceAction.next.label', \"Replace with Next Value\"),\r\n\t\t\talias: 'Replace with Next Value',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_DOT,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): Promise | undefined {\r\n\t\tconst controller = InPlaceReplaceController.get(editor);\r\n\t\tif (!controller) {\r\n\t\t\treturn Promise.resolve(undefined);\r\n\t\t}\r\n\t\treturn controller.run(this.id, false);\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(InPlaceReplaceController.ID, InPlaceReplaceController);\r\nregisterEditorAction(InPlaceReplaceUp);\r\nregisterEditorAction(InPlaceReplaceDown);\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst border = theme.getColor(editorBracketMatchBorder);\r\n\tif (border) {\r\n\t\tcollector.addRule(`.monaco-editor.vs .valueSetReplacement { outline: solid 2px ${border}; }`);\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { DisposableStore } from 'vs/base/common/lifecycle';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction, IActionOptions, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions';\r\nimport { ShiftCommand } from 'vs/editor/common/commands/shiftCommand';\r\nimport { EditOperation } from 'vs/editor/common/core/editOperation';\r\nimport { Range, IRange } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { ICommand, ICursorStateComputerData, IEditOperationBuilder, IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { IIdentifiedSingleEditOperation, ITextModel, EndOfLineSequence } from 'vs/editor/common/model';\r\nimport { TextModel } from 'vs/editor/common/model/textModel';\r\nimport { StandardTokenType, TextEdit } from 'vs/editor/common/modes';\r\nimport { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';\r\nimport { IndentConsts } from 'vs/editor/common/modes/supports/indentRules';\r\nimport { IModelService } from 'vs/editor/common/services/modelService';\r\nimport * as indentUtils from 'vs/editor/contrib/indentation/indentUtils';\r\nimport { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';\r\nimport { EditorOption, EditorAutoIndentStrategy } from 'vs/editor/common/config/editorOptions';\r\n\r\nexport function getReindentEditOperations(model: ITextModel, startLineNumber: number, endLineNumber: number, inheritedIndent?: string): IIdentifiedSingleEditOperation[] {\r\n\tif (model.getLineCount() === 1 && model.getLineMaxColumn(1) === 1) {\r\n\t\t// Model is empty\r\n\t\treturn [];\r\n\t}\r\n\r\n\tlet indentationRules = LanguageConfigurationRegistry.getIndentationRules(model.getLanguageIdentifier().id);\r\n\tif (!indentationRules) {\r\n\t\treturn [];\r\n\t}\r\n\r\n\tendLineNumber = Math.min(endLineNumber, model.getLineCount());\r\n\r\n\t// Skip `unIndentedLinePattern` lines\r\n\twhile (startLineNumber <= endLineNumber) {\r\n\t\tif (!indentationRules.unIndentedLinePattern) {\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tlet text = model.getLineContent(startLineNumber);\r\n\t\tif (!indentationRules.unIndentedLinePattern.test(text)) {\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tstartLineNumber++;\r\n\t}\r\n\r\n\tif (startLineNumber > endLineNumber - 1) {\r\n\t\treturn [];\r\n\t}\r\n\r\n\tconst { tabSize, indentSize, insertSpaces } = model.getOptions();\r\n\tconst shiftIndent = (indentation: string, count?: number) => {\r\n\t\tcount = count || 1;\r\n\t\treturn ShiftCommand.shiftIndent(indentation, indentation.length + count, tabSize, indentSize, insertSpaces);\r\n\t};\r\n\tconst unshiftIndent = (indentation: string, count?: number) => {\r\n\t\tcount = count || 1;\r\n\t\treturn ShiftCommand.unshiftIndent(indentation, indentation.length + count, tabSize, indentSize, insertSpaces);\r\n\t};\r\n\tlet indentEdits: IIdentifiedSingleEditOperation[] = [];\r\n\r\n\t// indentation being passed to lines below\r\n\tlet globalIndent: string;\r\n\r\n\t// Calculate indentation for the first line\r\n\t// If there is no passed-in indentation, we use the indentation of the first line as base.\r\n\tlet currentLineText = model.getLineContent(startLineNumber);\r\n\tlet adjustedLineContent = currentLineText;\r\n\tif (inheritedIndent !== undefined && inheritedIndent !== null) {\r\n\t\tglobalIndent = inheritedIndent;\r\n\t\tlet oldIndentation = strings.getLeadingWhitespace(currentLineText);\r\n\r\n\t\tadjustedLineContent = globalIndent + currentLineText.substring(oldIndentation.length);\r\n\t\tif (indentationRules.decreaseIndentPattern && indentationRules.decreaseIndentPattern.test(adjustedLineContent)) {\r\n\t\t\tglobalIndent = unshiftIndent(globalIndent);\r\n\t\t\tadjustedLineContent = globalIndent + currentLineText.substring(oldIndentation.length);\r\n\r\n\t\t}\r\n\t\tif (currentLineText !== adjustedLineContent) {\r\n\t\t\tindentEdits.push(EditOperation.replaceMove(new Selection(startLineNumber, 1, startLineNumber, oldIndentation.length + 1), TextModel.normalizeIndentation(globalIndent, indentSize, insertSpaces)));\r\n\t\t}\r\n\t} else {\r\n\t\tglobalIndent = strings.getLeadingWhitespace(currentLineText);\r\n\t}\r\n\r\n\t// idealIndentForNextLine doesn't equal globalIndent when there is a line matching `indentNextLinePattern`.\r\n\tlet idealIndentForNextLine: string = globalIndent;\r\n\r\n\tif (indentationRules.increaseIndentPattern && indentationRules.increaseIndentPattern.test(adjustedLineContent)) {\r\n\t\tidealIndentForNextLine = shiftIndent(idealIndentForNextLine);\r\n\t\tglobalIndent = shiftIndent(globalIndent);\r\n\t}\r\n\telse if (indentationRules.indentNextLinePattern && indentationRules.indentNextLinePattern.test(adjustedLineContent)) {\r\n\t\tidealIndentForNextLine = shiftIndent(idealIndentForNextLine);\r\n\t}\r\n\r\n\tstartLineNumber++;\r\n\r\n\t// Calculate indentation adjustment for all following lines\r\n\tfor (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {\r\n\t\tlet text = model.getLineContent(lineNumber);\r\n\t\tlet oldIndentation = strings.getLeadingWhitespace(text);\r\n\t\tlet adjustedLineContent = idealIndentForNextLine + text.substring(oldIndentation.length);\r\n\r\n\t\tif (indentationRules.decreaseIndentPattern && indentationRules.decreaseIndentPattern.test(adjustedLineContent)) {\r\n\t\t\tidealIndentForNextLine = unshiftIndent(idealIndentForNextLine);\r\n\t\t\tglobalIndent = unshiftIndent(globalIndent);\r\n\t\t}\r\n\r\n\t\tif (oldIndentation !== idealIndentForNextLine) {\r\n\t\t\tindentEdits.push(EditOperation.replaceMove(new Selection(lineNumber, 1, lineNumber, oldIndentation.length + 1), TextModel.normalizeIndentation(idealIndentForNextLine, indentSize, insertSpaces)));\r\n\t\t}\r\n\r\n\t\t// calculate idealIndentForNextLine\r\n\t\tif (indentationRules.unIndentedLinePattern && indentationRules.unIndentedLinePattern.test(text)) {\r\n\t\t\t// In reindent phase, if the line matches `unIndentedLinePattern` we inherit indentation from above lines\r\n\t\t\t// but don't change globalIndent and idealIndentForNextLine.\r\n\t\t\tcontinue;\r\n\t\t} else if (indentationRules.increaseIndentPattern && indentationRules.increaseIndentPattern.test(adjustedLineContent)) {\r\n\t\t\tglobalIndent = shiftIndent(globalIndent);\r\n\t\t\tidealIndentForNextLine = globalIndent;\r\n\t\t} else if (indentationRules.indentNextLinePattern && indentationRules.indentNextLinePattern.test(adjustedLineContent)) {\r\n\t\t\tidealIndentForNextLine = shiftIndent(idealIndentForNextLine);\r\n\t\t} else {\r\n\t\t\tidealIndentForNextLine = globalIndent;\r\n\t\t}\r\n\t}\r\n\r\n\treturn indentEdits;\r\n}\r\n\r\nexport class IndentationToSpacesAction extends EditorAction {\r\n\tpublic static readonly ID = 'editor.action.indentationToSpaces';\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: IndentationToSpacesAction.ID,\r\n\t\t\tlabel: nls.localize('indentationToSpaces', \"Convert Indentation to Spaces\"),\r\n\t\t\talias: 'Convert Indentation to Spaces',\r\n\t\t\tprecondition: EditorContextKeys.writable\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tlet model = editor.getModel();\r\n\t\tif (!model) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tlet modelOpts = model.getOptions();\r\n\t\tlet selection = editor.getSelection();\r\n\t\tif (!selection) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst command = new IndentationToSpacesCommand(selection, modelOpts.tabSize);\r\n\r\n\t\teditor.pushUndoStop();\r\n\t\teditor.executeCommands(this.id, [command]);\r\n\t\teditor.pushUndoStop();\r\n\r\n\t\tmodel.updateOptions({\r\n\t\t\tinsertSpaces: true\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class IndentationToTabsAction extends EditorAction {\r\n\tpublic static readonly ID = 'editor.action.indentationToTabs';\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: IndentationToTabsAction.ID,\r\n\t\t\tlabel: nls.localize('indentationToTabs', \"Convert Indentation to Tabs\"),\r\n\t\t\talias: 'Convert Indentation to Tabs',\r\n\t\t\tprecondition: EditorContextKeys.writable\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tlet model = editor.getModel();\r\n\t\tif (!model) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tlet modelOpts = model.getOptions();\r\n\t\tlet selection = editor.getSelection();\r\n\t\tif (!selection) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst command = new IndentationToTabsCommand(selection, modelOpts.tabSize);\r\n\r\n\t\teditor.pushUndoStop();\r\n\t\teditor.executeCommands(this.id, [command]);\r\n\t\teditor.pushUndoStop();\r\n\r\n\t\tmodel.updateOptions({\r\n\t\t\tinsertSpaces: false\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class ChangeIndentationSizeAction extends EditorAction {\r\n\r\n\tconstructor(private readonly insertSpaces: boolean, opts: IActionOptions) {\r\n\t\tsuper(opts);\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tconst quickInputService = accessor.get(IQuickInputService);\r\n\t\tconst modelService = accessor.get(IModelService);\r\n\r\n\t\tlet model = editor.getModel();\r\n\t\tif (!model) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet creationOpts = modelService.getCreationOptions(model.getLanguageIdentifier().language, model.uri, model.isForSimpleWidget);\r\n\t\tconst picks = [1, 2, 3, 4, 5, 6, 7, 8].map(n => ({\r\n\t\t\tid: n.toString(),\r\n\t\t\tlabel: n.toString(),\r\n\t\t\t// add description for tabSize value set in the configuration\r\n\t\t\tdescription: n === creationOpts.tabSize ? nls.localize('configuredTabSize', \"Configured Tab Size\") : undefined\r\n\t\t}));\r\n\r\n\t\t// auto focus the tabSize set for the current editor\r\n\t\tconst autoFocusIndex = Math.min(model.getOptions().tabSize - 1, 7);\r\n\r\n\t\tsetTimeout(() => {\r\n\t\t\tquickInputService.pick(picks, { placeHolder: nls.localize({ key: 'selectTabWidth', comment: ['Tab corresponds to the tab key'] }, \"Select Tab Size for Current File\"), activeItem: picks[autoFocusIndex] }).then(pick => {\r\n\t\t\t\tif (pick) {\r\n\t\t\t\t\tif (model && !model.isDisposed()) {\r\n\t\t\t\t\t\tmodel.updateOptions({\r\n\t\t\t\t\t\t\ttabSize: parseInt(pick.label, 10),\r\n\t\t\t\t\t\t\tinsertSpaces: this.insertSpaces\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}, 50/* quick input is sensitive to being opened so soon after another */);\r\n\t}\r\n}\r\n\r\nexport class IndentUsingTabs extends ChangeIndentationSizeAction {\r\n\r\n\tpublic static readonly ID = 'editor.action.indentUsingTabs';\r\n\r\n\tconstructor() {\r\n\t\tsuper(false, {\r\n\t\t\tid: IndentUsingTabs.ID,\r\n\t\t\tlabel: nls.localize('indentUsingTabs', \"Indent Using Tabs\"),\r\n\t\t\talias: 'Indent Using Tabs',\r\n\t\t\tprecondition: undefined\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class IndentUsingSpaces extends ChangeIndentationSizeAction {\r\n\r\n\tpublic static readonly ID = 'editor.action.indentUsingSpaces';\r\n\r\n\tconstructor() {\r\n\t\tsuper(true, {\r\n\t\t\tid: IndentUsingSpaces.ID,\r\n\t\t\tlabel: nls.localize('indentUsingSpaces', \"Indent Using Spaces\"),\r\n\t\t\talias: 'Indent Using Spaces',\r\n\t\t\tprecondition: undefined\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class DetectIndentation extends EditorAction {\r\n\r\n\tpublic static readonly ID = 'editor.action.detectIndentation';\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: DetectIndentation.ID,\r\n\t\t\tlabel: nls.localize('detectIndentation', \"Detect Indentation from Content\"),\r\n\t\t\talias: 'Detect Indentation from Content',\r\n\t\t\tprecondition: undefined\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tconst modelService = accessor.get(IModelService);\r\n\r\n\t\tlet model = editor.getModel();\r\n\t\tif (!model) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet creationOpts = modelService.getCreationOptions(model.getLanguageIdentifier().language, model.uri, model.isForSimpleWidget);\r\n\t\tmodel.detectIndentation(creationOpts.insertSpaces, creationOpts.tabSize);\r\n\t}\r\n}\r\n\r\nexport class ReindentLinesAction extends EditorAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.reindentlines',\r\n\t\t\tlabel: nls.localize('editor.reindentlines', \"Reindent Lines\"),\r\n\t\t\talias: 'Reindent Lines',\r\n\t\t\tprecondition: EditorContextKeys.writable\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tlet model = editor.getModel();\r\n\t\tif (!model) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tlet edits = getReindentEditOperations(model, 1, model.getLineCount());\r\n\t\tif (edits.length > 0) {\r\n\t\t\teditor.pushUndoStop();\r\n\t\t\teditor.executeEdits(this.id, edits);\r\n\t\t\teditor.pushUndoStop();\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class ReindentSelectedLinesAction extends EditorAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.reindentselectedlines',\r\n\t\t\tlabel: nls.localize('editor.reindentselectedlines', \"Reindent Selected Lines\"),\r\n\t\t\talias: 'Reindent Selected Lines',\r\n\t\t\tprecondition: EditorContextKeys.writable\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tlet model = editor.getModel();\r\n\t\tif (!model) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet selections = editor.getSelections();\r\n\t\tif (selections === null) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet edits: IIdentifiedSingleEditOperation[] = [];\r\n\r\n\t\tfor (let selection of selections) {\r\n\t\t\tlet startLineNumber = selection.startLineNumber;\r\n\t\t\tlet endLineNumber = selection.endLineNumber;\r\n\r\n\t\t\tif (startLineNumber !== endLineNumber && selection.endColumn === 1) {\r\n\t\t\t\tendLineNumber--;\r\n\t\t\t}\r\n\r\n\t\t\tif (startLineNumber === 1) {\r\n\t\t\t\tif (startLineNumber === endLineNumber) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tstartLineNumber--;\r\n\t\t\t}\r\n\r\n\t\t\tlet editOperations = getReindentEditOperations(model, startLineNumber, endLineNumber);\r\n\t\t\tedits.push(...editOperations);\r\n\t\t}\r\n\r\n\t\tif (edits.length > 0) {\r\n\t\t\teditor.pushUndoStop();\r\n\t\t\teditor.executeEdits(this.id, edits);\r\n\t\t\teditor.pushUndoStop();\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class AutoIndentOnPasteCommand implements ICommand {\r\n\r\n\tprivate readonly _edits: { range: IRange; text: string; eol?: EndOfLineSequence; }[];\r\n\r\n\tprivate readonly _initialSelection: Selection;\r\n\tprivate _selectionId: string | null;\r\n\r\n\tconstructor(edits: TextEdit[], initialSelection: Selection) {\r\n\t\tthis._initialSelection = initialSelection;\r\n\t\tthis._edits = [];\r\n\t\tthis._selectionId = null;\r\n\r\n\t\tfor (let edit of edits) {\r\n\t\t\tif (edit.range && typeof edit.text === 'string') {\r\n\t\t\t\tthis._edits.push(edit as { range: IRange; text: string; eol?: EndOfLineSequence; });\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\r\n\t\tfor (let edit of this._edits) {\r\n\t\t\tbuilder.addEditOperation(Range.lift(edit.range), edit.text);\r\n\t\t}\r\n\r\n\t\tlet selectionIsSet = false;\r\n\t\tif (Array.isArray(this._edits) && this._edits.length === 1 && this._initialSelection.isEmpty()) {\r\n\t\t\tif (this._edits[0].range.startColumn === this._initialSelection.endColumn &&\r\n\t\t\t\tthis._edits[0].range.startLineNumber === this._initialSelection.endLineNumber) {\r\n\t\t\t\tselectionIsSet = true;\r\n\t\t\t\tthis._selectionId = builder.trackSelection(this._initialSelection, true);\r\n\t\t\t} else if (this._edits[0].range.endColumn === this._initialSelection.startColumn &&\r\n\t\t\t\tthis._edits[0].range.endLineNumber === this._initialSelection.startLineNumber) {\r\n\t\t\t\tselectionIsSet = true;\r\n\t\t\t\tthis._selectionId = builder.trackSelection(this._initialSelection, false);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!selectionIsSet) {\r\n\t\t\tthis._selectionId = builder.trackSelection(this._initialSelection);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\r\n\t\treturn helper.getTrackedSelection(this._selectionId!);\r\n\t}\r\n}\r\n\r\nexport class AutoIndentOnPaste implements IEditorContribution {\r\n\tpublic static readonly ID = 'editor.contrib.autoIndentOnPaste';\r\n\r\n\tprivate readonly editor: ICodeEditor;\r\n\tprivate readonly callOnDispose = new DisposableStore();\r\n\tprivate readonly callOnModel = new DisposableStore();\r\n\r\n\tconstructor(editor: ICodeEditor) {\r\n\t\tthis.editor = editor;\r\n\r\n\t\tthis.callOnDispose.add(editor.onDidChangeConfiguration(() => this.update()));\r\n\t\tthis.callOnDispose.add(editor.onDidChangeModel(() => this.update()));\r\n\t\tthis.callOnDispose.add(editor.onDidChangeModelLanguage(() => this.update()));\r\n\t}\r\n\r\n\tprivate update(): void {\r\n\r\n\t\t// clean up\r\n\t\tthis.callOnModel.clear();\r\n\r\n\t\t// we are disabled\r\n\t\tif (this.editor.getOption(EditorOption.autoIndent) < EditorAutoIndentStrategy.Full || this.editor.getOption(EditorOption.formatOnPaste)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// no model\r\n\t\tif (!this.editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.callOnModel.add(this.editor.onDidPaste(({ range }) => {\r\n\t\t\tthis.trigger(range);\r\n\t\t}));\r\n\t}\r\n\r\n\tprivate trigger(range: Range): void {\r\n\t\tlet selections = this.editor.getSelections();\r\n\t\tif (selections === null || selections.length > 1) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst model = this.editor.getModel();\r\n\t\tif (!model) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!model.isCheapToTokenize(range.getStartPosition().lineNumber)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst autoIndent = this.editor.getOption(EditorOption.autoIndent);\r\n\t\tconst { tabSize, indentSize, insertSpaces } = model.getOptions();\r\n\t\tlet textEdits: TextEdit[] = [];\r\n\r\n\t\tlet indentConverter = {\r\n\t\t\tshiftIndent: (indentation: string) => {\r\n\t\t\t\treturn ShiftCommand.shiftIndent(indentation, indentation.length + 1, tabSize, indentSize, insertSpaces);\r\n\t\t\t},\r\n\t\t\tunshiftIndent: (indentation: string) => {\r\n\t\t\t\treturn ShiftCommand.unshiftIndent(indentation, indentation.length + 1, tabSize, indentSize, insertSpaces);\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tlet startLineNumber = range.startLineNumber;\r\n\r\n\t\twhile (startLineNumber <= range.endLineNumber) {\r\n\t\t\tif (this.shouldIgnoreLine(model, startLineNumber)) {\r\n\t\t\t\tstartLineNumber++;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tif (startLineNumber > range.endLineNumber) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet firstLineText = model.getLineContent(startLineNumber);\r\n\t\tif (!/\\S/.test(firstLineText.substring(0, range.startColumn - 1))) {\r\n\t\t\tlet indentOfFirstLine = LanguageConfigurationRegistry.getGoodIndentForLine(autoIndent, model, model.getLanguageIdentifier().id, startLineNumber, indentConverter);\r\n\r\n\t\t\tif (indentOfFirstLine !== null) {\r\n\t\t\t\tlet oldIndentation = strings.getLeadingWhitespace(firstLineText);\r\n\t\t\t\tlet newSpaceCnt = indentUtils.getSpaceCnt(indentOfFirstLine, tabSize);\r\n\t\t\t\tlet oldSpaceCnt = indentUtils.getSpaceCnt(oldIndentation, tabSize);\r\n\r\n\t\t\t\tif (newSpaceCnt !== oldSpaceCnt) {\r\n\t\t\t\t\tlet newIndent = indentUtils.generateIndent(newSpaceCnt, tabSize, insertSpaces);\r\n\t\t\t\t\ttextEdits.push({\r\n\t\t\t\t\t\trange: new Range(startLineNumber, 1, startLineNumber, oldIndentation.length + 1),\r\n\t\t\t\t\t\ttext: newIndent\r\n\t\t\t\t\t});\r\n\t\t\t\t\tfirstLineText = newIndent + firstLineText.substr(oldIndentation.length);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tlet indentMetadata = LanguageConfigurationRegistry.getIndentMetadata(model, startLineNumber);\r\n\r\n\t\t\t\t\tif (indentMetadata === 0 || indentMetadata === IndentConsts.UNINDENT_MASK) {\r\n\t\t\t\t\t\t// we paste content into a line where only contains whitespaces\r\n\t\t\t\t\t\t// after pasting, the indentation of the first line is already correct\r\n\t\t\t\t\t\t// the first line doesn't match any indentation rule\r\n\t\t\t\t\t\t// then no-op.\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst firstLineNumber = startLineNumber;\r\n\r\n\t\t// ignore empty or ignored lines\r\n\t\twhile (startLineNumber < range.endLineNumber) {\r\n\t\t\tif (!/\\S/.test(model.getLineContent(startLineNumber + 1))) {\r\n\t\t\t\tstartLineNumber++;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tif (startLineNumber !== range.endLineNumber) {\r\n\t\t\tlet virtualModel = {\r\n\t\t\t\tgetLineTokens: (lineNumber: number) => {\r\n\t\t\t\t\treturn model.getLineTokens(lineNumber);\r\n\t\t\t\t},\r\n\t\t\t\tgetLanguageIdentifier: () => {\r\n\t\t\t\t\treturn model.getLanguageIdentifier();\r\n\t\t\t\t},\r\n\t\t\t\tgetLanguageIdAtPosition: (lineNumber: number, column: number) => {\r\n\t\t\t\t\treturn model.getLanguageIdAtPosition(lineNumber, column);\r\n\t\t\t\t},\r\n\t\t\t\tgetLineContent: (lineNumber: number) => {\r\n\t\t\t\t\tif (lineNumber === firstLineNumber) {\r\n\t\t\t\t\t\treturn firstLineText;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\treturn model.getLineContent(lineNumber);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t};\r\n\t\t\tlet indentOfSecondLine = LanguageConfigurationRegistry.getGoodIndentForLine(autoIndent, virtualModel, model.getLanguageIdentifier().id, startLineNumber + 1, indentConverter);\r\n\t\t\tif (indentOfSecondLine !== null) {\r\n\t\t\t\tlet newSpaceCntOfSecondLine = indentUtils.getSpaceCnt(indentOfSecondLine, tabSize);\r\n\t\t\t\tlet oldSpaceCntOfSecondLine = indentUtils.getSpaceCnt(strings.getLeadingWhitespace(model.getLineContent(startLineNumber + 1)), tabSize);\r\n\r\n\t\t\t\tif (newSpaceCntOfSecondLine !== oldSpaceCntOfSecondLine) {\r\n\t\t\t\t\tlet spaceCntOffset = newSpaceCntOfSecondLine - oldSpaceCntOfSecondLine;\r\n\t\t\t\t\tfor (let i = startLineNumber + 1; i <= range.endLineNumber; i++) {\r\n\t\t\t\t\t\tlet lineContent = model.getLineContent(i);\r\n\t\t\t\t\t\tlet originalIndent = strings.getLeadingWhitespace(lineContent);\r\n\t\t\t\t\t\tlet originalSpacesCnt = indentUtils.getSpaceCnt(originalIndent, tabSize);\r\n\t\t\t\t\t\tlet newSpacesCnt = originalSpacesCnt + spaceCntOffset;\r\n\t\t\t\t\t\tlet newIndent = indentUtils.generateIndent(newSpacesCnt, tabSize, insertSpaces);\r\n\r\n\t\t\t\t\t\tif (newIndent !== originalIndent) {\r\n\t\t\t\t\t\t\ttextEdits.push({\r\n\t\t\t\t\t\t\t\trange: new Range(i, 1, i, originalIndent.length + 1),\r\n\t\t\t\t\t\t\t\ttext: newIndent\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (textEdits.length > 0) {\r\n\t\t\tthis.editor.pushUndoStop();\r\n\t\t\tlet cmd = new AutoIndentOnPasteCommand(textEdits, this.editor.getSelection()!);\r\n\t\t\tthis.editor.executeCommand('autoIndentOnPaste', cmd);\r\n\t\t\tthis.editor.pushUndoStop();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate shouldIgnoreLine(model: ITextModel, lineNumber: number): boolean {\r\n\t\tmodel.forceTokenization(lineNumber);\r\n\t\tlet nonWhitespaceColumn = model.getLineFirstNonWhitespaceColumn(lineNumber);\r\n\t\tif (nonWhitespaceColumn === 0) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tlet tokens = model.getLineTokens(lineNumber);\r\n\t\tif (tokens.getCount() > 0) {\r\n\t\t\tlet firstNonWhitespaceTokenIndex = tokens.findTokenIndexAtOffset(nonWhitespaceColumn);\r\n\t\t\tif (firstNonWhitespaceTokenIndex >= 0 && tokens.getStandardTokenType(firstNonWhitespaceTokenIndex) === StandardTokenType.Comment) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis.callOnDispose.dispose();\r\n\t\tthis.callOnModel.dispose();\r\n\t}\r\n}\r\n\r\nfunction getIndentationEditOperations(model: ITextModel, builder: IEditOperationBuilder, tabSize: number, tabsToSpaces: boolean): void {\r\n\tif (model.getLineCount() === 1 && model.getLineMaxColumn(1) === 1) {\r\n\t\t// Model is empty\r\n\t\treturn;\r\n\t}\r\n\r\n\tlet spaces = '';\r\n\tfor (let i = 0; i < tabSize; i++) {\r\n\t\tspaces += ' ';\r\n\t}\r\n\r\n\tlet spacesRegExp = new RegExp(spaces, 'gi');\r\n\r\n\tfor (let lineNumber = 1, lineCount = model.getLineCount(); lineNumber <= lineCount; lineNumber++) {\r\n\t\tlet lastIndentationColumn = model.getLineFirstNonWhitespaceColumn(lineNumber);\r\n\t\tif (lastIndentationColumn === 0) {\r\n\t\t\tlastIndentationColumn = model.getLineMaxColumn(lineNumber);\r\n\t\t}\r\n\r\n\t\tif (lastIndentationColumn === 1) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tconst originalIndentationRange = new Range(lineNumber, 1, lineNumber, lastIndentationColumn);\r\n\t\tconst originalIndentation = model.getValueInRange(originalIndentationRange);\r\n\t\tconst newIndentation = (\r\n\t\t\ttabsToSpaces\r\n\t\t\t\t? originalIndentation.replace(/\\t/ig, spaces)\r\n\t\t\t\t: originalIndentation.replace(spacesRegExp, '\\t')\r\n\t\t);\r\n\r\n\t\tbuilder.addEditOperation(originalIndentationRange, newIndentation);\r\n\t}\r\n}\r\n\r\nexport class IndentationToSpacesCommand implements ICommand {\r\n\r\n\tprivate selectionId: string | null = null;\r\n\r\n\tconstructor(private readonly selection: Selection, private tabSize: number) { }\r\n\r\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\r\n\t\tthis.selectionId = builder.trackSelection(this.selection);\r\n\t\tgetIndentationEditOperations(model, builder, this.tabSize, true);\r\n\t}\r\n\r\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\r\n\t\treturn helper.getTrackedSelection(this.selectionId!);\r\n\t}\r\n}\r\n\r\nexport class IndentationToTabsCommand implements ICommand {\r\n\r\n\tprivate selectionId: string | null = null;\r\n\r\n\tconstructor(private readonly selection: Selection, private tabSize: number) { }\r\n\r\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\r\n\t\tthis.selectionId = builder.trackSelection(this.selection);\r\n\t\tgetIndentationEditOperations(model, builder, this.tabSize, false);\r\n\t}\r\n\r\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\r\n\t\treturn helper.getTrackedSelection(this.selectionId!);\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(AutoIndentOnPaste.ID, AutoIndentOnPaste);\r\nregisterEditorAction(IndentationToSpacesAction);\r\nregisterEditorAction(IndentationToTabsAction);\r\nregisterEditorAction(IndentUsingTabs);\r\nregisterEditorAction(IndentUsingSpaces);\r\nregisterEditorAction(DetectIndentation);\r\nregisterEditorAction(ReindentLinesAction);\r\nregisterEditorAction(ReindentSelectedLinesAction);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { RunOnceScheduler } from 'vs/base/common/async';\r\nimport { onUnexpectedExternalError } from 'vs/base/common/errors';\r\nimport { hash } from 'vs/base/common/hash';\r\nimport { DisposableStore, toDisposable } from 'vs/base/common/lifecycle';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { registerEditorContribution } from 'vs/editor/browser/editorExtensions';\r\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\r\nimport { IContentDecorationRenderOptions, IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { IModelDeltaDecoration, ITextModel } from 'vs/editor/common/model';\r\nimport { InlineHintsProvider, InlineHintsProviderRegistry, InlineHint } from 'vs/editor/common/modes';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { flatten } from 'vs/base/common/arrays';\r\nimport { editorInlineHintForeground, editorInlineHintBackground } from 'vs/platform/theme/common/colorRegistry';\r\nimport { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\r\nimport { IThemeService } from 'vs/platform/theme/common/themeService';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { LanguageFeatureRequestDelays } from 'vs/editor/common/modes/languageFeatureRegistry';\r\nimport { MarkdownString } from 'vs/base/common/htmlContent';\r\nimport { CommandsRegistry } from 'vs/platform/commands/common/commands';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { IRange } from 'vs/base/common/range';\r\nimport { assertType } from 'vs/base/common/types';\r\nimport { ITextModelService } from 'vs/editor/common/services/resolverService';\r\n\r\nconst MAX_DECORATORS = 500;\r\n\r\nexport interface InlineHintsData {\r\n\tlist: InlineHint[];\r\n\tprovider: InlineHintsProvider;\r\n}\r\n\r\nexport async function getInlineHints(model: ITextModel, ranges: Range[], token: CancellationToken): Promise {\r\n\tconst datas: InlineHintsData[] = [];\r\n\tconst providers = InlineHintsProviderRegistry.ordered(model).reverse();\r\n\tconst promises = flatten(providers.map(provider => ranges.map(range => Promise.resolve(provider.provideInlineHints(model, range, token)).then(result => {\r\n\t\tif (result) {\r\n\t\t\tdatas.push({ list: result, provider });\r\n\t\t}\r\n\t}, err => {\r\n\t\tonUnexpectedExternalError(err);\r\n\t}))));\r\n\r\n\tawait Promise.all(promises);\r\n\r\n\treturn datas;\r\n}\r\n\r\nexport class InlineHintsController implements IEditorContribution {\r\n\r\n\tstatic readonly ID: string = 'editor.contrib.InlineHints';\r\n\r\n\t// static get(editor: ICodeEditor): InlineHintsController {\r\n\t// \treturn editor.getContribution(this.ID);\r\n\t// }\r\n\r\n\tprivate readonly _disposables = new DisposableStore();\r\n\tprivate readonly _sessionDisposables = new DisposableStore();\r\n\tprivate readonly _getInlineHintsDelays = new LanguageFeatureRequestDelays(InlineHintsProviderRegistry, 250, 2500);\r\n\r\n\tprivate _decorationsTypeIds: string[] = [];\r\n\tprivate _decorationIds: string[] = [];\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _editor: ICodeEditor,\r\n\t\t@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,\r\n\t\t@IThemeService private readonly _themeService: IThemeService,\r\n\t) {\r\n\t\tthis._disposables.add(InlineHintsProviderRegistry.onDidChange(() => this._update()));\r\n\t\tthis._disposables.add(_themeService.onDidColorThemeChange(() => this._update()));\r\n\t\tthis._disposables.add(_editor.onDidChangeModel(() => this._update()));\r\n\t\tthis._disposables.add(_editor.onDidChangeModelLanguage(() => this._update()));\r\n\t\tthis._disposables.add(_editor.onDidChangeConfiguration(e => {\r\n\t\t\tif (e.hasChanged(EditorOption.inlineHints)) {\r\n\t\t\t\tthis._update();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._update();\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._sessionDisposables.dispose();\r\n\t\tthis._removeAllDecorations();\r\n\t\tthis._disposables.dispose();\r\n\t}\r\n\r\n\tprivate _update(): void {\r\n\t\tthis._sessionDisposables.clear();\r\n\r\n\t\tif (!this._editor.getOption(EditorOption.inlineHints).enabled) {\r\n\t\t\tthis._removeAllDecorations();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst model = this._editor.getModel();\r\n\t\tif (!model || !InlineHintsProviderRegistry.has(model)) {\r\n\t\t\tthis._removeAllDecorations();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst scheduler = new RunOnceScheduler(async () => {\r\n\t\t\tconst t1 = Date.now();\r\n\r\n\t\t\tconst cts = new CancellationTokenSource();\r\n\t\t\tthis._sessionDisposables.add(toDisposable(() => cts.dispose(true)));\r\n\r\n\t\t\tconst visibleRanges = this._editor.getVisibleRangesPlusViewportAboveBelow();\r\n\t\t\tconst result = await getInlineHints(model, visibleRanges, cts.token);\r\n\r\n\t\t\t// update moving average\r\n\t\t\tconst newDelay = this._getInlineHintsDelays.update(model, Date.now() - t1);\r\n\t\t\tscheduler.delay = newDelay;\r\n\r\n\t\t\t// render hints\r\n\t\t\tthis._updateHintsDecorators(result);\r\n\r\n\t\t}, this._getInlineHintsDelays.get(model));\r\n\r\n\t\tthis._sessionDisposables.add(scheduler);\r\n\r\n\t\t// update inline hints when content or scroll position changes\r\n\t\tthis._sessionDisposables.add(this._editor.onDidChangeModelContent(() => scheduler.schedule()));\r\n\t\tthis._disposables.add(this._editor.onDidScrollChange(() => scheduler.schedule()));\r\n\t\tscheduler.schedule();\r\n\r\n\t\t// update inline hints when any any provider fires an event\r\n\t\tconst providerListener = new DisposableStore();\r\n\t\tthis._sessionDisposables.add(providerListener);\r\n\t\tfor (const provider of InlineHintsProviderRegistry.all(model)) {\r\n\t\t\tif (typeof provider.onDidChangeInlineHints === 'function') {\r\n\t\t\t\tproviderListener.add(provider.onDidChangeInlineHints(() => scheduler.schedule()));\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _updateHintsDecorators(hintsData: InlineHintsData[]): void {\r\n\t\tconst { fontSize, fontFamily } = this._getLayoutInfo();\r\n\t\tconst backgroundColor = this._themeService.getColorTheme().getColor(editorInlineHintBackground);\r\n\t\tconst fontColor = this._themeService.getColorTheme().getColor(editorInlineHintForeground);\r\n\r\n\t\tconst newDecorationsTypeIds: string[] = [];\r\n\t\tconst newDecorationsData: IModelDeltaDecoration[] = [];\r\n\r\n\t\tfor (const { list: hints } of hintsData) {\r\n\r\n\t\t\tfor (let j = 0; j < hints.length && newDecorationsData.length < MAX_DECORATORS; j++) {\r\n\t\t\t\tconst { text, range, description: hoverMessage, whitespaceBefore, whitespaceAfter } = hints[j];\r\n\t\t\t\tconst marginBefore = whitespaceBefore ? (fontSize / 3) | 0 : 0;\r\n\t\t\t\tconst marginAfter = whitespaceAfter ? (fontSize / 3) | 0 : 0;\r\n\r\n\t\t\t\tconst before: IContentDecorationRenderOptions = {\r\n\t\t\t\t\tcontentText: text,\r\n\t\t\t\t\tbackgroundColor: `${backgroundColor}`,\r\n\t\t\t\t\tcolor: `${fontColor}`,\r\n\t\t\t\t\tmargin: `0px ${marginAfter}px 0px ${marginBefore}px`,\r\n\t\t\t\t\tfontSize: `${fontSize}px`,\r\n\t\t\t\t\tfontFamily: fontFamily,\r\n\t\t\t\t\tpadding: `0px ${(fontSize / 4) | 0}px`,\r\n\t\t\t\t\tborderRadius: `${(fontSize / 4) | 0}px`,\r\n\t\t\t\t};\r\n\t\t\t\tconst key = 'inlineHints-' + hash(before).toString(16);\r\n\t\t\t\tthis._codeEditorService.registerDecorationType(key, { before }, undefined, this._editor);\r\n\r\n\t\t\t\t// decoration types are ref-counted which means we only need to\r\n\t\t\t\t// call register und remove equally often\r\n\t\t\t\tnewDecorationsTypeIds.push(key);\r\n\r\n\t\t\t\tconst options = this._codeEditorService.resolveDecorationOptions(key, true);\r\n\t\t\t\tif (typeof hoverMessage === 'string') {\r\n\t\t\t\t\toptions.hoverMessage = new MarkdownString().appendText(hoverMessage);\r\n\t\t\t\t} else if (hoverMessage) {\r\n\t\t\t\t\toptions.hoverMessage = hoverMessage;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tnewDecorationsData.push({\r\n\t\t\t\t\trange,\r\n\t\t\t\t\toptions\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._decorationsTypeIds.forEach(this._codeEditorService.removeDecorationType, this._codeEditorService);\r\n\t\tthis._decorationsTypeIds = newDecorationsTypeIds;\r\n\r\n\t\tthis._decorationIds = this._editor.deltaDecorations(this._decorationIds, newDecorationsData);\r\n\t}\r\n\r\n\tprivate _getLayoutInfo() {\r\n\t\tconst options = this._editor.getOption(EditorOption.inlineHints);\r\n\t\tconst editorFontSize = this._editor.getOption(EditorOption.fontSize);\r\n\t\tlet fontSize = options.fontSize;\r\n\t\tif (!fontSize || fontSize < 5 || fontSize > editorFontSize) {\r\n\t\t\tfontSize = (editorFontSize * .9) | 0;\r\n\t\t}\r\n\t\tconst fontFamily = options.fontFamily;\r\n\t\treturn { fontSize, fontFamily };\r\n\t}\r\n\r\n\tprivate _removeAllDecorations(): void {\r\n\t\tthis._decorationIds = this._editor.deltaDecorations(this._decorationIds, []);\r\n\t\tthis._decorationsTypeIds.forEach(this._codeEditorService.removeDecorationType, this._codeEditorService);\r\n\t\tthis._decorationsTypeIds = [];\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(InlineHintsController.ID, InlineHintsController);\r\n\r\nCommandsRegistry.registerCommand('_executeInlineHintProvider', async (accessor, ...args: [URI, IRange]): Promise => {\r\n\r\n\tconst [uri, range] = args;\r\n\tassertType(URI.isUri(uri));\r\n\tassertType(Range.isIRange(range));\r\n\r\n\tconst ref = await accessor.get(ITextModelService).createModelReference(uri);\r\n\ttry {\r\n\t\tconst data = await getInlineHints(ref.object.textEditorModel, [Range.lift(range)], CancellationToken.None);\r\n\t\treturn flatten(data.map(item => item.list)).sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range));\r\n\r\n\t} finally {\r\n\t\tref.dispose();\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { CoreEditingCommands } from 'vs/editor/browser/controller/coreCommands';\r\nimport { ICodeEditor, IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction, IActionOptions, ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions';\r\nimport { ReplaceCommand, ReplaceCommandThatPreservesSelection, ReplaceCommandThatSelectsText } from 'vs/editor/common/commands/replaceCommand';\r\nimport { TrimTrailingWhitespaceCommand } from 'vs/editor/common/commands/trimTrailingWhitespaceCommand';\r\nimport { TypeOperations } from 'vs/editor/common/controller/cursorTypeOperations';\r\nimport { EditOperation } from 'vs/editor/common/core/editOperation';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { ICommand } from 'vs/editor/common/editorCommon';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { IIdentifiedSingleEditOperation, ITextModel } from 'vs/editor/common/model';\r\nimport { CopyLinesCommand } from 'vs/editor/contrib/linesOperations/copyLinesCommand';\r\nimport { MoveLinesCommand } from 'vs/editor/contrib/linesOperations/moveLinesCommand';\r\nimport { SortLinesCommand } from 'vs/editor/contrib/linesOperations/sortLinesCommand';\r\nimport { MenuId } from 'vs/platform/actions/common/actions';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\n// copy lines\r\n\r\nabstract class AbstractCopyLinesAction extends EditorAction {\r\n\r\n\tprivate readonly down: boolean;\r\n\r\n\tconstructor(down: boolean, opts: IActionOptions) {\r\n\t\tsuper(opts);\r\n\t\tthis.down = down;\r\n\t}\r\n\r\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst selections = editor.getSelections().map((selection, index) => ({ selection, index, ignore: false }));\r\n\t\tselections.sort((a, b) => Range.compareRangesUsingStarts(a.selection, b.selection));\r\n\r\n\t\t// Remove selections that would result in copying the same line\r\n\t\tlet prev = selections[0];\r\n\t\tfor (let i = 1; i < selections.length; i++) {\r\n\t\t\tconst curr = selections[i];\r\n\t\t\tif (prev.selection.endLineNumber === curr.selection.startLineNumber) {\r\n\t\t\t\t// these two selections would copy the same line\r\n\t\t\t\tif (prev.index < curr.index) {\r\n\t\t\t\t\t// prev wins\r\n\t\t\t\t\tcurr.ignore = true;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// curr wins\r\n\t\t\t\t\tprev.ignore = true;\r\n\t\t\t\t\tprev = curr;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst commands: ICommand[] = [];\r\n\t\tfor (const selection of selections) {\r\n\t\t\tcommands.push(new CopyLinesCommand(selection.selection, this.down, selection.ignore));\r\n\t\t}\r\n\r\n\t\teditor.pushUndoStop();\r\n\t\teditor.executeCommands(this.id, commands);\r\n\t\teditor.pushUndoStop();\r\n\t}\r\n}\r\n\r\nclass CopyLinesUpAction extends AbstractCopyLinesAction {\r\n\tconstructor() {\r\n\t\tsuper(false, {\r\n\t\t\tid: 'editor.action.copyLinesUpAction',\r\n\t\t\tlabel: nls.localize('lines.copyUp', \"Copy Line Up\"),\r\n\t\t\talias: 'Copy Line Up',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.Alt | KeyMod.Shift | KeyCode.UpArrow,\r\n\t\t\t\tlinux: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyMod.Shift | KeyCode.UpArrow },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tmenuOpts: {\r\n\t\t\t\tmenuId: MenuId.MenubarSelectionMenu,\r\n\t\t\t\tgroup: '2_line',\r\n\t\t\t\ttitle: nls.localize({ key: 'miCopyLinesUp', comment: ['&& denotes a mnemonic'] }, \"&&Copy Line Up\"),\r\n\t\t\t\torder: 1\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n\r\nclass CopyLinesDownAction extends AbstractCopyLinesAction {\r\n\tconstructor() {\r\n\t\tsuper(true, {\r\n\t\t\tid: 'editor.action.copyLinesDownAction',\r\n\t\t\tlabel: nls.localize('lines.copyDown', \"Copy Line Down\"),\r\n\t\t\talias: 'Copy Line Down',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.Alt | KeyMod.Shift | KeyCode.DownArrow,\r\n\t\t\t\tlinux: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyMod.Shift | KeyCode.DownArrow },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tmenuOpts: {\r\n\t\t\t\tmenuId: MenuId.MenubarSelectionMenu,\r\n\t\t\t\tgroup: '2_line',\r\n\t\t\t\ttitle: nls.localize({ key: 'miCopyLinesDown', comment: ['&& denotes a mnemonic'] }, \"Co&&py Line Down\"),\r\n\t\t\t\torder: 2\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class DuplicateSelectionAction extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.duplicateSelection',\r\n\t\t\tlabel: nls.localize('duplicateSelection', \"Duplicate Selection\"),\r\n\t\t\talias: 'Duplicate Selection',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tmenuOpts: {\r\n\t\t\t\tmenuId: MenuId.MenubarSelectionMenu,\r\n\t\t\t\tgroup: '2_line',\r\n\t\t\t\ttitle: nls.localize({ key: 'miDuplicateSelection', comment: ['&& denotes a mnemonic'] }, \"&&Duplicate Selection\"),\r\n\t\t\t\torder: 5\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst commands: ICommand[] = [];\r\n\t\tconst selections = editor.getSelections();\r\n\t\tconst model = editor.getModel();\r\n\r\n\t\tfor (const selection of selections) {\r\n\t\t\tif (selection.isEmpty()) {\r\n\t\t\t\tcommands.push(new CopyLinesCommand(selection, true));\r\n\t\t\t} else {\r\n\t\t\t\tconst insertSelection = new Selection(selection.endLineNumber, selection.endColumn, selection.endLineNumber, selection.endColumn);\r\n\t\t\t\tcommands.push(new ReplaceCommandThatSelectsText(insertSelection, model.getValueInRange(selection)));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\teditor.pushUndoStop();\r\n\t\teditor.executeCommands(this.id, commands);\r\n\t\teditor.pushUndoStop();\r\n\t}\r\n}\r\n\r\n// move lines\r\n\r\nabstract class AbstractMoveLinesAction extends EditorAction {\r\n\r\n\tprivate readonly down: boolean;\r\n\r\n\tconstructor(down: boolean, opts: IActionOptions) {\r\n\t\tsuper(opts);\r\n\t\tthis.down = down;\r\n\t}\r\n\r\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\r\n\t\tlet commands: ICommand[] = [];\r\n\t\tlet selections = editor.getSelections() || [];\r\n\t\tconst autoIndent = editor.getOption(EditorOption.autoIndent);\r\n\r\n\t\tfor (const selection of selections) {\r\n\t\t\tcommands.push(new MoveLinesCommand(selection, this.down, autoIndent));\r\n\t\t}\r\n\r\n\t\teditor.pushUndoStop();\r\n\t\teditor.executeCommands(this.id, commands);\r\n\t\teditor.pushUndoStop();\r\n\t}\r\n}\r\n\r\nclass MoveLinesUpAction extends AbstractMoveLinesAction {\r\n\tconstructor() {\r\n\t\tsuper(false, {\r\n\t\t\tid: 'editor.action.moveLinesUpAction',\r\n\t\t\tlabel: nls.localize('lines.moveUp', \"Move Line Up\"),\r\n\t\t\talias: 'Move Line Up',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.Alt | KeyCode.UpArrow,\r\n\t\t\t\tlinux: { primary: KeyMod.Alt | KeyCode.UpArrow },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tmenuOpts: {\r\n\t\t\t\tmenuId: MenuId.MenubarSelectionMenu,\r\n\t\t\t\tgroup: '2_line',\r\n\t\t\t\ttitle: nls.localize({ key: 'miMoveLinesUp', comment: ['&& denotes a mnemonic'] }, \"Mo&&ve Line Up\"),\r\n\t\t\t\torder: 3\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n\r\nclass MoveLinesDownAction extends AbstractMoveLinesAction {\r\n\tconstructor() {\r\n\t\tsuper(true, {\r\n\t\t\tid: 'editor.action.moveLinesDownAction',\r\n\t\t\tlabel: nls.localize('lines.moveDown', \"Move Line Down\"),\r\n\t\t\talias: 'Move Line Down',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.Alt | KeyCode.DownArrow,\r\n\t\t\t\tlinux: { primary: KeyMod.Alt | KeyCode.DownArrow },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tmenuOpts: {\r\n\t\t\t\tmenuId: MenuId.MenubarSelectionMenu,\r\n\t\t\t\tgroup: '2_line',\r\n\t\t\t\ttitle: nls.localize({ key: 'miMoveLinesDown', comment: ['&& denotes a mnemonic'] }, \"Move &&Line Down\"),\r\n\t\t\t\torder: 4\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport abstract class AbstractSortLinesAction extends EditorAction {\r\n\tprivate readonly descending: boolean;\r\n\r\n\tconstructor(descending: boolean, opts: IActionOptions) {\r\n\t\tsuper(opts);\r\n\t\tthis.descending = descending;\r\n\t}\r\n\r\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tconst selections = editor.getSelections() || [];\r\n\r\n\t\tfor (const selection of selections) {\r\n\t\t\tif (!SortLinesCommand.canRun(editor.getModel(), selection, this.descending)) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet commands: ICommand[] = [];\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tcommands[i] = new SortLinesCommand(selections[i], this.descending);\r\n\t\t}\r\n\r\n\t\teditor.pushUndoStop();\r\n\t\teditor.executeCommands(this.id, commands);\r\n\t\teditor.pushUndoStop();\r\n\t}\r\n}\r\n\r\nexport class SortLinesAscendingAction extends AbstractSortLinesAction {\r\n\tconstructor() {\r\n\t\tsuper(false, {\r\n\t\t\tid: 'editor.action.sortLinesAscending',\r\n\t\t\tlabel: nls.localize('lines.sortAscending', \"Sort Lines Ascending\"),\r\n\t\t\talias: 'Sort Lines Ascending',\r\n\t\t\tprecondition: EditorContextKeys.writable\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class SortLinesDescendingAction extends AbstractSortLinesAction {\r\n\tconstructor() {\r\n\t\tsuper(true, {\r\n\t\t\tid: 'editor.action.sortLinesDescending',\r\n\t\t\tlabel: nls.localize('lines.sortDescending', \"Sort Lines Descending\"),\r\n\t\t\talias: 'Sort Lines Descending',\r\n\t\t\tprecondition: EditorContextKeys.writable\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class TrimTrailingWhitespaceAction extends EditorAction {\r\n\r\n\tpublic static readonly ID = 'editor.action.trimTrailingWhitespace';\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: TrimTrailingWhitespaceAction.ID,\r\n\t\t\tlabel: nls.localize('lines.trimTrailingWhitespace', \"Trim Trailing Whitespace\"),\r\n\t\t\talias: 'Trim Trailing Whitespace',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_X),\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {\r\n\r\n\t\tlet cursors: Position[] = [];\r\n\t\tif (args.reason === 'auto-save') {\r\n\t\t\t// See https://github.com/editorconfig/editorconfig-vscode/issues/47\r\n\t\t\t// It is very convenient for the editor config extension to invoke this action.\r\n\t\t\t// So, if we get a reason:'auto-save' passed in, let's preserve cursor positions.\r\n\t\t\tcursors = (editor.getSelections() || []).map(s => new Position(s.positionLineNumber, s.positionColumn));\r\n\t\t}\r\n\r\n\t\tlet selection = editor.getSelection();\r\n\t\tif (selection === null) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet command = new TrimTrailingWhitespaceCommand(selection, cursors);\r\n\r\n\t\teditor.pushUndoStop();\r\n\t\teditor.executeCommands(this.id, [command]);\r\n\t\teditor.pushUndoStop();\r\n\t}\r\n}\r\n\r\n// delete lines\r\n\r\ninterface IDeleteLinesOperation {\r\n\tstartLineNumber: number;\r\n\tendLineNumber: number;\r\n\tpositionColumn: number;\r\n}\r\n\r\nexport class DeleteLinesAction extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.deleteLines',\r\n\t\t\tlabel: nls.localize('lines.delete', \"Delete Line\"),\r\n\t\t\talias: 'Delete Line',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_K,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet ops = this._getLinesToRemove(editor);\r\n\r\n\t\tlet model: ITextModel = editor.getModel();\r\n\t\tif (model.getLineCount() === 1 && model.getLineMaxColumn(1) === 1) {\r\n\t\t\t// Model is empty\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet linesDeleted = 0;\r\n\t\tlet edits: IIdentifiedSingleEditOperation[] = [];\r\n\t\tlet cursorState: Selection[] = [];\r\n\t\tfor (let i = 0, len = ops.length; i < len; i++) {\r\n\t\t\tconst op = ops[i];\r\n\r\n\t\t\tlet startLineNumber = op.startLineNumber;\r\n\t\t\tlet endLineNumber = op.endLineNumber;\r\n\r\n\t\t\tlet startColumn = 1;\r\n\t\t\tlet endColumn = model.getLineMaxColumn(endLineNumber);\r\n\t\t\tif (endLineNumber < model.getLineCount()) {\r\n\t\t\t\tendLineNumber += 1;\r\n\t\t\t\tendColumn = 1;\r\n\t\t\t} else if (startLineNumber > 1) {\r\n\t\t\t\tstartLineNumber -= 1;\r\n\t\t\t\tstartColumn = model.getLineMaxColumn(startLineNumber);\r\n\t\t\t}\r\n\r\n\t\t\tedits.push(EditOperation.replace(new Selection(startLineNumber, startColumn, endLineNumber, endColumn), ''));\r\n\t\t\tcursorState.push(new Selection(startLineNumber - linesDeleted, op.positionColumn, startLineNumber - linesDeleted, op.positionColumn));\r\n\t\t\tlinesDeleted += (op.endLineNumber - op.startLineNumber + 1);\r\n\t\t}\r\n\r\n\t\teditor.pushUndoStop();\r\n\t\teditor.executeEdits(this.id, edits, cursorState);\r\n\t\teditor.pushUndoStop();\r\n\t}\r\n\r\n\tprivate _getLinesToRemove(editor: IActiveCodeEditor): IDeleteLinesOperation[] {\r\n\t\t// Construct delete operations\r\n\t\tlet operations: IDeleteLinesOperation[] = editor.getSelections().map((s) => {\r\n\r\n\t\t\tlet endLineNumber = s.endLineNumber;\r\n\t\t\tif (s.startLineNumber < s.endLineNumber && s.endColumn === 1) {\r\n\t\t\t\tendLineNumber -= 1;\r\n\t\t\t}\r\n\r\n\t\t\treturn {\r\n\t\t\t\tstartLineNumber: s.startLineNumber,\r\n\t\t\t\tselectionStartColumn: s.selectionStartColumn,\r\n\t\t\t\tendLineNumber: endLineNumber,\r\n\t\t\t\tpositionColumn: s.positionColumn\r\n\t\t\t};\r\n\t\t});\r\n\r\n\t\t// Sort delete operations\r\n\t\toperations.sort((a, b) => {\r\n\t\t\tif (a.startLineNumber === b.startLineNumber) {\r\n\t\t\t\treturn a.endLineNumber - b.endLineNumber;\r\n\t\t\t}\r\n\t\t\treturn a.startLineNumber - b.startLineNumber;\r\n\t\t});\r\n\r\n\t\t// Merge delete operations which are adjacent or overlapping\r\n\t\tlet mergedOperations: IDeleteLinesOperation[] = [];\r\n\t\tlet previousOperation = operations[0];\r\n\t\tfor (let i = 1; i < operations.length; i++) {\r\n\t\t\tif (previousOperation.endLineNumber + 1 >= operations[i].startLineNumber) {\r\n\t\t\t\t// Merge current operations into the previous one\r\n\t\t\t\tpreviousOperation.endLineNumber = operations[i].endLineNumber;\r\n\t\t\t} else {\r\n\t\t\t\t// Push previous operation\r\n\t\t\t\tmergedOperations.push(previousOperation);\r\n\t\t\t\tpreviousOperation = operations[i];\r\n\t\t\t}\r\n\t\t}\r\n\t\t// Push the last operation\r\n\t\tmergedOperations.push(previousOperation);\r\n\r\n\t\treturn mergedOperations;\r\n\t}\r\n}\r\n\r\nexport class IndentLinesAction extends EditorAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.indentLines',\r\n\t\t\tlabel: nls.localize('lines.indent', \"Indent Line\"),\r\n\t\t\talias: 'Indent Line',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.US_CLOSE_SQUARE_BRACKET,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tconst viewModel = editor._getViewModel();\r\n\t\tif (!viewModel) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\teditor.pushUndoStop();\r\n\t\teditor.executeCommands(this.id, TypeOperations.indent(viewModel.cursorConfig, editor.getModel(), editor.getSelections()));\r\n\t\teditor.pushUndoStop();\r\n\t}\r\n}\r\n\r\nclass OutdentLinesAction extends EditorAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.outdentLines',\r\n\t\t\tlabel: nls.localize('lines.outdent', \"Outdent Line\"),\r\n\t\t\talias: 'Outdent Line',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.US_OPEN_SQUARE_BRACKET,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tCoreEditingCommands.Outdent.runEditorCommand(_accessor, editor, null);\r\n\t}\r\n}\r\n\r\nexport class InsertLineBeforeAction extends EditorAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.insertLineBefore',\r\n\t\t\tlabel: nls.localize('lines.insertBefore', \"Insert Line Above\"),\r\n\t\t\talias: 'Insert Line Above',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Enter,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tconst viewModel = editor._getViewModel();\r\n\t\tif (!viewModel) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\teditor.pushUndoStop();\r\n\t\teditor.executeCommands(this.id, TypeOperations.lineInsertBefore(viewModel.cursorConfig, editor.getModel(), editor.getSelections()));\r\n\t}\r\n}\r\n\r\nexport class InsertLineAfterAction extends EditorAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.insertLineAfter',\r\n\t\t\tlabel: nls.localize('lines.insertAfter', \"Insert Line Below\"),\r\n\t\t\talias: 'Insert Line Below',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.Enter,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tconst viewModel = editor._getViewModel();\r\n\t\tif (!viewModel) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\teditor.pushUndoStop();\r\n\t\teditor.executeCommands(this.id, TypeOperations.lineInsertAfter(viewModel.cursorConfig, editor.getModel(), editor.getSelections()));\r\n\t}\r\n}\r\n\r\nexport abstract class AbstractDeleteAllToBoundaryAction extends EditorAction {\r\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst primaryCursor = editor.getSelection();\r\n\r\n\t\tlet rangesToDelete = this._getRangesToDelete(editor);\r\n\t\t// merge overlapping selections\r\n\t\tlet effectiveRanges: Range[] = [];\r\n\r\n\t\tfor (let i = 0, count = rangesToDelete.length - 1; i < count; i++) {\r\n\t\t\tlet range = rangesToDelete[i];\r\n\t\t\tlet nextRange = rangesToDelete[i + 1];\r\n\r\n\t\t\tif (Range.intersectRanges(range, nextRange) === null) {\r\n\t\t\t\teffectiveRanges.push(range);\r\n\t\t\t} else {\r\n\t\t\t\trangesToDelete[i + 1] = Range.plusRange(range, nextRange);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\teffectiveRanges.push(rangesToDelete[rangesToDelete.length - 1]);\r\n\r\n\t\tlet endCursorState = this._getEndCursorState(primaryCursor, effectiveRanges);\r\n\r\n\t\tlet edits: IIdentifiedSingleEditOperation[] = effectiveRanges.map(range => {\r\n\t\t\treturn EditOperation.replace(range, '');\r\n\t\t});\r\n\r\n\t\teditor.pushUndoStop();\r\n\t\teditor.executeEdits(this.id, edits, endCursorState);\r\n\t\teditor.pushUndoStop();\r\n\t}\r\n\r\n\t/**\r\n\t * Compute the cursor state after the edit operations were applied.\r\n\t */\r\n\tprotected abstract _getEndCursorState(primaryCursor: Range, rangesToDelete: Range[]): Selection[];\r\n\r\n\tprotected abstract _getRangesToDelete(editor: IActiveCodeEditor): Range[];\r\n}\r\n\r\nexport class DeleteAllLeftAction extends AbstractDeleteAllToBoundaryAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'deleteAllLeft',\r\n\t\t\tlabel: nls.localize('lines.deleteAllLeft', \"Delete All Left\"),\r\n\t\t\talias: 'Delete All Left',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\tprimary: 0,\r\n\t\t\t\tmac: { primary: KeyMod.CtrlCmd | KeyCode.Backspace },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\t_getEndCursorState(primaryCursor: Range, rangesToDelete: Range[]): Selection[] {\r\n\t\tlet endPrimaryCursor: Selection | null = null;\r\n\t\tlet endCursorState: Selection[] = [];\r\n\t\tlet deletedLines = 0;\r\n\r\n\t\trangesToDelete.forEach(range => {\r\n\t\t\tlet endCursor;\r\n\t\t\tif (range.endColumn === 1 && deletedLines > 0) {\r\n\t\t\t\tlet newStartLine = range.startLineNumber - deletedLines;\r\n\t\t\t\tendCursor = new Selection(newStartLine, range.startColumn, newStartLine, range.startColumn);\r\n\t\t\t} else {\r\n\t\t\t\tendCursor = new Selection(range.startLineNumber, range.startColumn, range.startLineNumber, range.startColumn);\r\n\t\t\t}\r\n\r\n\t\t\tdeletedLines += range.endLineNumber - range.startLineNumber;\r\n\r\n\t\t\tif (range.intersectRanges(primaryCursor)) {\r\n\t\t\t\tendPrimaryCursor = endCursor;\r\n\t\t\t} else {\r\n\t\t\t\tendCursorState.push(endCursor);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tif (endPrimaryCursor) {\r\n\t\t\tendCursorState.unshift(endPrimaryCursor);\r\n\t\t}\r\n\r\n\t\treturn endCursorState;\r\n\t}\r\n\r\n\t_getRangesToDelete(editor: IActiveCodeEditor): Range[] {\r\n\t\tlet selections = editor.getSelections();\r\n\t\tif (selections === null) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tlet rangesToDelete: Range[] = selections;\r\n\t\tlet model = editor.getModel();\r\n\r\n\t\tif (model === null) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\trangesToDelete.sort(Range.compareRangesUsingStarts);\r\n\t\trangesToDelete = rangesToDelete.map(selection => {\r\n\t\t\tif (selection.isEmpty()) {\r\n\t\t\t\tif (selection.startColumn === 1) {\r\n\t\t\t\t\tlet deleteFromLine = Math.max(1, selection.startLineNumber - 1);\r\n\t\t\t\t\tlet deleteFromColumn = selection.startLineNumber === 1 ? 1 : model.getLineContent(deleteFromLine).length + 1;\r\n\t\t\t\t\treturn new Range(deleteFromLine, deleteFromColumn, selection.startLineNumber, 1);\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn new Range(selection.startLineNumber, 1, selection.startLineNumber, selection.startColumn);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\treturn new Range(selection.startLineNumber, 1, selection.endLineNumber, selection.endColumn);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\treturn rangesToDelete;\r\n\t}\r\n}\r\n\r\nexport class DeleteAllRightAction extends AbstractDeleteAllToBoundaryAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'deleteAllRight',\r\n\t\t\tlabel: nls.localize('lines.deleteAllRight', \"Delete All Right\"),\r\n\t\t\talias: 'Delete All Right',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\tprimary: 0,\r\n\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyCode.KEY_K, secondary: [KeyMod.CtrlCmd | KeyCode.Delete] },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\t_getEndCursorState(primaryCursor: Range, rangesToDelete: Range[]): Selection[] {\r\n\t\tlet endPrimaryCursor: Selection | null = null;\r\n\t\tlet endCursorState: Selection[] = [];\r\n\t\tfor (let i = 0, len = rangesToDelete.length, offset = 0; i < len; i++) {\r\n\t\t\tlet range = rangesToDelete[i];\r\n\t\t\tlet endCursor = new Selection(range.startLineNumber - offset, range.startColumn, range.startLineNumber - offset, range.startColumn);\r\n\r\n\t\t\tif (range.intersectRanges(primaryCursor)) {\r\n\t\t\t\tendPrimaryCursor = endCursor;\r\n\t\t\t} else {\r\n\t\t\t\tendCursorState.push(endCursor);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (endPrimaryCursor) {\r\n\t\t\tendCursorState.unshift(endPrimaryCursor);\r\n\t\t}\r\n\r\n\t\treturn endCursorState;\r\n\t}\r\n\r\n\t_getRangesToDelete(editor: IActiveCodeEditor): Range[] {\r\n\t\tlet model = editor.getModel();\r\n\t\tif (model === null) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tlet selections = editor.getSelections();\r\n\r\n\t\tif (selections === null) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tlet rangesToDelete: Range[] = selections.map((sel) => {\r\n\t\t\tif (sel.isEmpty()) {\r\n\t\t\t\tconst maxColumn = model.getLineMaxColumn(sel.startLineNumber);\r\n\r\n\t\t\t\tif (sel.startColumn === maxColumn) {\r\n\t\t\t\t\treturn new Range(sel.startLineNumber, sel.startColumn, sel.startLineNumber + 1, 1);\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn new Range(sel.startLineNumber, sel.startColumn, sel.startLineNumber, maxColumn);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn sel;\r\n\t\t});\r\n\r\n\t\trangesToDelete.sort(Range.compareRangesUsingStarts);\r\n\t\treturn rangesToDelete;\r\n\t}\r\n}\r\n\r\nexport class JoinLinesAction extends EditorAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.joinLines',\r\n\t\t\tlabel: nls.localize('lines.joinLines', \"Join Lines\"),\r\n\t\t\talias: 'Join Lines',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: 0,\r\n\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyCode.KEY_J },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tlet selections = editor.getSelections();\r\n\t\tif (selections === null) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet primaryCursor = editor.getSelection();\r\n\t\tif (primaryCursor === null) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tselections.sort(Range.compareRangesUsingStarts);\r\n\t\tlet reducedSelections: Selection[] = [];\r\n\r\n\t\tlet lastSelection = selections.reduce((previousValue, currentValue) => {\r\n\t\t\tif (previousValue.isEmpty()) {\r\n\t\t\t\tif (previousValue.endLineNumber === currentValue.startLineNumber) {\r\n\t\t\t\t\tif (primaryCursor!.equalsSelection(previousValue)) {\r\n\t\t\t\t\t\tprimaryCursor = currentValue;\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn currentValue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (currentValue.startLineNumber > previousValue.endLineNumber + 1) {\r\n\t\t\t\t\treducedSelections.push(previousValue);\r\n\t\t\t\t\treturn currentValue;\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn new Selection(previousValue.startLineNumber, previousValue.startColumn, currentValue.endLineNumber, currentValue.endColumn);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tif (currentValue.startLineNumber > previousValue.endLineNumber) {\r\n\t\t\t\t\treducedSelections.push(previousValue);\r\n\t\t\t\t\treturn currentValue;\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn new Selection(previousValue.startLineNumber, previousValue.startColumn, currentValue.endLineNumber, currentValue.endColumn);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\treducedSelections.push(lastSelection);\r\n\r\n\t\tlet model = editor.getModel();\r\n\t\tif (model === null) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet edits: IIdentifiedSingleEditOperation[] = [];\r\n\t\tlet endCursorState: Selection[] = [];\r\n\t\tlet endPrimaryCursor = primaryCursor;\r\n\t\tlet lineOffset = 0;\r\n\r\n\t\tfor (let i = 0, len = reducedSelections.length; i < len; i++) {\r\n\t\t\tlet selection = reducedSelections[i];\r\n\t\t\tlet startLineNumber = selection.startLineNumber;\r\n\t\t\tlet startColumn = 1;\r\n\t\t\tlet columnDeltaOffset = 0;\r\n\t\t\tlet endLineNumber: number,\r\n\t\t\t\tendColumn: number;\r\n\r\n\t\t\tlet selectionEndPositionOffset = model.getLineContent(selection.endLineNumber).length - selection.endColumn;\r\n\r\n\t\t\tif (selection.isEmpty() || selection.startLineNumber === selection.endLineNumber) {\r\n\t\t\t\tlet position = selection.getStartPosition();\r\n\t\t\t\tif (position.lineNumber < model.getLineCount()) {\r\n\t\t\t\t\tendLineNumber = startLineNumber + 1;\r\n\t\t\t\t\tendColumn = model.getLineMaxColumn(endLineNumber);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tendLineNumber = position.lineNumber;\r\n\t\t\t\t\tendColumn = model.getLineMaxColumn(position.lineNumber);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tendLineNumber = selection.endLineNumber;\r\n\t\t\t\tendColumn = model.getLineMaxColumn(endLineNumber);\r\n\t\t\t}\r\n\r\n\t\t\tlet trimmedLinesContent = model.getLineContent(startLineNumber);\r\n\r\n\t\t\tfor (let i = startLineNumber + 1; i <= endLineNumber; i++) {\r\n\t\t\t\tlet lineText = model.getLineContent(i);\r\n\t\t\t\tlet firstNonWhitespaceIdx = model.getLineFirstNonWhitespaceColumn(i);\r\n\r\n\t\t\t\tif (firstNonWhitespaceIdx >= 1) {\r\n\t\t\t\t\tlet insertSpace = true;\r\n\t\t\t\t\tif (trimmedLinesContent === '') {\r\n\t\t\t\t\t\tinsertSpace = false;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (insertSpace && (trimmedLinesContent.charAt(trimmedLinesContent.length - 1) === ' ' ||\r\n\t\t\t\t\t\ttrimmedLinesContent.charAt(trimmedLinesContent.length - 1) === '\\t')) {\r\n\t\t\t\t\t\tinsertSpace = false;\r\n\t\t\t\t\t\ttrimmedLinesContent = trimmedLinesContent.replace(/[\\s\\uFEFF\\xA0]+$/g, ' ');\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tlet lineTextWithoutIndent = lineText.substr(firstNonWhitespaceIdx - 1);\r\n\r\n\t\t\t\t\ttrimmedLinesContent += (insertSpace ? ' ' : '') + lineTextWithoutIndent;\r\n\r\n\t\t\t\t\tif (insertSpace) {\r\n\t\t\t\t\t\tcolumnDeltaOffset = lineTextWithoutIndent.length + 1;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tcolumnDeltaOffset = lineTextWithoutIndent.length;\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tcolumnDeltaOffset = 0;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tlet deleteSelection = new Range(startLineNumber, startColumn, endLineNumber, endColumn);\r\n\r\n\t\t\tif (!deleteSelection.isEmpty()) {\r\n\t\t\t\tlet resultSelection: Selection;\r\n\r\n\t\t\t\tif (selection.isEmpty()) {\r\n\t\t\t\t\tedits.push(EditOperation.replace(deleteSelection, trimmedLinesContent));\r\n\t\t\t\t\tresultSelection = new Selection(deleteSelection.startLineNumber - lineOffset, trimmedLinesContent.length - columnDeltaOffset + 1, startLineNumber - lineOffset, trimmedLinesContent.length - columnDeltaOffset + 1);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tif (selection.startLineNumber === selection.endLineNumber) {\r\n\t\t\t\t\t\tedits.push(EditOperation.replace(deleteSelection, trimmedLinesContent));\r\n\t\t\t\t\t\tresultSelection = new Selection(selection.startLineNumber - lineOffset, selection.startColumn,\r\n\t\t\t\t\t\t\tselection.endLineNumber - lineOffset, selection.endColumn);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tedits.push(EditOperation.replace(deleteSelection, trimmedLinesContent));\r\n\t\t\t\t\t\tresultSelection = new Selection(selection.startLineNumber - lineOffset, selection.startColumn,\r\n\t\t\t\t\t\t\tselection.startLineNumber - lineOffset, trimmedLinesContent.length - selectionEndPositionOffset);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (Range.intersectRanges(deleteSelection, primaryCursor) !== null) {\r\n\t\t\t\t\tendPrimaryCursor = resultSelection;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tendCursorState.push(resultSelection);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tlineOffset += deleteSelection.endLineNumber - deleteSelection.startLineNumber;\r\n\t\t}\r\n\r\n\t\tendCursorState.unshift(endPrimaryCursor);\r\n\t\teditor.pushUndoStop();\r\n\t\teditor.executeEdits(this.id, edits, endCursorState);\r\n\t\teditor.pushUndoStop();\r\n\t}\r\n}\r\n\r\nexport class TransposeAction extends EditorAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.transpose',\r\n\t\t\tlabel: nls.localize('editor.transpose', \"Transpose characters around the cursor\"),\r\n\t\t\talias: 'Transpose characters around the cursor',\r\n\t\t\tprecondition: EditorContextKeys.writable\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tlet selections = editor.getSelections();\r\n\t\tif (selections === null) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet model = editor.getModel();\r\n\t\tif (model === null) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet commands: ICommand[] = [];\r\n\r\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\r\n\t\t\tlet selection = selections[i];\r\n\r\n\t\t\tif (!selection.isEmpty()) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tlet cursor = selection.getStartPosition();\r\n\t\t\tlet maxColumn = model.getLineMaxColumn(cursor.lineNumber);\r\n\r\n\t\t\tif (cursor.column >= maxColumn) {\r\n\t\t\t\tif (cursor.lineNumber === model.getLineCount()) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// The cursor is at the end of current line and current line is not empty\r\n\t\t\t\t// then we transpose the character before the cursor and the line break if there is any following line.\r\n\t\t\t\tlet deleteSelection = new Range(cursor.lineNumber, Math.max(1, cursor.column - 1), cursor.lineNumber + 1, 1);\r\n\t\t\t\tlet chars = model.getValueInRange(deleteSelection).split('').reverse().join('');\r\n\r\n\t\t\t\tcommands.push(new ReplaceCommand(new Selection(cursor.lineNumber, Math.max(1, cursor.column - 1), cursor.lineNumber + 1, 1), chars));\r\n\t\t\t} else {\r\n\t\t\t\tlet deleteSelection = new Range(cursor.lineNumber, Math.max(1, cursor.column - 1), cursor.lineNumber, cursor.column + 1);\r\n\t\t\t\tlet chars = model.getValueInRange(deleteSelection).split('').reverse().join('');\r\n\t\t\t\tcommands.push(new ReplaceCommandThatPreservesSelection(deleteSelection, chars,\r\n\t\t\t\t\tnew Selection(cursor.lineNumber, cursor.column + 1, cursor.lineNumber, cursor.column + 1)));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\teditor.pushUndoStop();\r\n\t\teditor.executeCommands(this.id, commands);\r\n\t\teditor.pushUndoStop();\r\n\t}\r\n}\r\n\r\nexport abstract class AbstractCaseAction extends EditorAction {\r\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tconst selections = editor.getSelections();\r\n\t\tif (selections === null) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst model = editor.getModel();\r\n\t\tif (model === null) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst wordSeparators = editor.getOption(EditorOption.wordSeparators);\r\n\t\tconst textEdits: IIdentifiedSingleEditOperation[] = [];\r\n\r\n\t\tfor (const selection of selections) {\r\n\t\t\tif (selection.isEmpty()) {\r\n\t\t\t\tconst cursor = selection.getStartPosition();\r\n\t\t\t\tconst word = editor.getConfiguredWordAtPosition(cursor);\r\n\r\n\t\t\t\tif (!word) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst wordRange = new Range(cursor.lineNumber, word.startColumn, cursor.lineNumber, word.endColumn);\r\n\t\t\t\tconst text = model.getValueInRange(wordRange);\r\n\t\t\t\ttextEdits.push(EditOperation.replace(wordRange, this._modifyText(text, wordSeparators)));\r\n\t\t\t} else {\r\n\t\t\t\tconst text = model.getValueInRange(selection);\r\n\t\t\t\ttextEdits.push(EditOperation.replace(selection, this._modifyText(text, wordSeparators)));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\teditor.pushUndoStop();\r\n\t\teditor.executeEdits(this.id, textEdits);\r\n\t\teditor.pushUndoStop();\r\n\t}\r\n\r\n\tprotected abstract _modifyText(text: string, wordSeparators: string): string;\r\n}\r\n\r\nexport class UpperCaseAction extends AbstractCaseAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.transformToUppercase',\r\n\t\t\tlabel: nls.localize('editor.transformToUppercase', \"Transform to Uppercase\"),\r\n\t\t\talias: 'Transform to Uppercase',\r\n\t\t\tprecondition: EditorContextKeys.writable\r\n\t\t});\r\n\t}\r\n\r\n\tprotected _modifyText(text: string, wordSeparators: string): string {\r\n\t\treturn text.toLocaleUpperCase();\r\n\t}\r\n}\r\n\r\nexport class LowerCaseAction extends AbstractCaseAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.transformToLowercase',\r\n\t\t\tlabel: nls.localize('editor.transformToLowercase', \"Transform to Lowercase\"),\r\n\t\t\talias: 'Transform to Lowercase',\r\n\t\t\tprecondition: EditorContextKeys.writable\r\n\t\t});\r\n\t}\r\n\r\n\tprotected _modifyText(text: string, wordSeparators: string): string {\r\n\t\treturn text.toLocaleLowerCase();\r\n\t}\r\n}\r\n\r\nexport class TitleCaseAction extends AbstractCaseAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.transformToTitlecase',\r\n\t\t\tlabel: nls.localize('editor.transformToTitlecase', \"Transform to Title Case\"),\r\n\t\t\talias: 'Transform to Title Case',\r\n\t\t\tprecondition: EditorContextKeys.writable\r\n\t\t});\r\n\t}\r\n\r\n\tprotected _modifyText(text: string, wordSeparators: string): string {\r\n\t\tconst separators = '\\r\\n\\t ' + wordSeparators;\r\n\t\tconst excludedChars = separators.split('');\r\n\r\n\t\tlet title = '';\r\n\t\tlet startUpperCase = true;\r\n\r\n\t\tfor (let i = 0; i < text.length; i++) {\r\n\t\t\tlet currentChar = text[i];\r\n\r\n\t\t\tif (excludedChars.indexOf(currentChar) >= 0) {\r\n\t\t\t\tstartUpperCase = true;\r\n\r\n\t\t\t\ttitle += currentChar;\r\n\t\t\t} else if (startUpperCase) {\r\n\t\t\t\tstartUpperCase = false;\r\n\r\n\t\t\t\ttitle += currentChar.toLocaleUpperCase();\r\n\t\t\t} else {\r\n\t\t\t\ttitle += currentChar.toLocaleLowerCase();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn title;\r\n\t}\r\n}\r\n\r\nexport class SnakeCaseAction extends AbstractCaseAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.transformToSnakecase',\r\n\t\t\tlabel: nls.localize('editor.transformToSnakecase', \"Transform to Snake Case\"),\r\n\t\t\talias: 'Transform to Snake Case',\r\n\t\t\tprecondition: EditorContextKeys.writable\r\n\t\t});\r\n\t}\r\n\r\n\tprotected _modifyText(text: string, wordSeparators: string): string {\r\n\t\treturn (text\r\n\t\t\t.replace(/(\\p{Ll})(\\p{Lu})/gmu, '$1_$2')\r\n\t\t\t.replace(/([^\\b_])(\\p{Lu})(\\p{Ll})/gmu, '$1_$2$3')\r\n\t\t\t.toLocaleLowerCase()\r\n\t\t);\r\n\t}\r\n}\r\n\r\nregisterEditorAction(CopyLinesUpAction);\r\nregisterEditorAction(CopyLinesDownAction);\r\nregisterEditorAction(DuplicateSelectionAction);\r\nregisterEditorAction(MoveLinesUpAction);\r\nregisterEditorAction(MoveLinesDownAction);\r\nregisterEditorAction(SortLinesAscendingAction);\r\nregisterEditorAction(SortLinesDescendingAction);\r\nregisterEditorAction(TrimTrailingWhitespaceAction);\r\nregisterEditorAction(DeleteLinesAction);\r\nregisterEditorAction(IndentLinesAction);\r\nregisterEditorAction(OutdentLinesAction);\r\nregisterEditorAction(InsertLineBeforeAction);\r\nregisterEditorAction(InsertLineAfterAction);\r\nregisterEditorAction(DeleteAllLeftAction);\r\nregisterEditorAction(DeleteAllRightAction);\r\nregisterEditorAction(JoinLinesAction);\r\nregisterEditorAction(TransposeAction);\r\nregisterEditorAction(UpperCaseAction);\r\nregisterEditorAction(LowerCaseAction);\r\nregisterEditorAction(TitleCaseAction);\r\nregisterEditorAction(SnakeCaseAction);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { registerEditorContribution, registerModelAndPositionCommand, EditorAction, EditorCommand, ServicesAccessor, registerEditorAction, registerEditorCommand } from 'vs/editor/browser/editorExtensions';\r\nimport * as arrays from 'vs/base/common/arrays';\r\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { Disposable, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { Position, IPosition } from 'vs/editor/common/core/position';\r\nimport { ITextModel, IModelDeltaDecoration, TrackedRangeStickiness, IIdentifiedSingleEditOperation } from 'vs/editor/common/model';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { IRange, Range } from 'vs/editor/common/core/range';\r\nimport { LinkedEditingRangeProviderRegistry, LinkedEditingRanges } from 'vs/editor/common/modes';\r\nimport { first, createCancelablePromise, CancelablePromise, Delayer } from 'vs/base/common/async';\r\nimport { ModelDecorationOptions } from 'vs/editor/common/model/textModel';\r\nimport { ContextKeyExpr, RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\r\nimport { isPromiseCanceledError, onUnexpectedError, onUnexpectedExternalError } from 'vs/base/common/errors';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { registerColor } from 'vs/platform/theme/common/colorRegistry';\r\nimport { registerThemingParticipant } from 'vs/platform/theme/common/themeService';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';\r\n\r\nexport const CONTEXT_ONTYPE_RENAME_INPUT_VISIBLE = new RawContextKey('LinkedEditingInputVisible', false);\r\n\r\nconst DECORATION_CLASS_NAME = 'linked-editing-decoration';\r\n\r\nexport class LinkedEditingContribution extends Disposable implements IEditorContribution {\r\n\r\n\tpublic static readonly ID = 'editor.contrib.linkedEditing';\r\n\r\n\tprivate static readonly DECORATION = ModelDecorationOptions.register({\r\n\t\tstickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges,\r\n\t\tclassName: DECORATION_CLASS_NAME\r\n\t});\r\n\r\n\tstatic get(editor: ICodeEditor): LinkedEditingContribution {\r\n\t\treturn editor.getContribution(LinkedEditingContribution.ID);\r\n\t}\r\n\r\n\tprivate _debounceDuration = 200;\r\n\r\n\tprivate readonly _editor: ICodeEditor;\r\n\tprivate _enabled: boolean;\r\n\r\n\tprivate readonly _visibleContextKey: IContextKey;\r\n\r\n\tprivate _rangeUpdateTriggerPromise: Promise | null;\r\n\tprivate _rangeSyncTriggerPromise: Promise | null;\r\n\r\n\tprivate _currentRequest: CancelablePromise | null;\r\n\tprivate _currentRequestPosition: Position | null;\r\n\tprivate _currentRequestModelVersion: number | null;\r\n\r\n\tprivate _currentDecorations: string[]; // The one at index 0 is the reference one\r\n\tprivate _languageWordPattern: RegExp | null;\r\n\tprivate _currentWordPattern: RegExp | null;\r\n\tprivate _ignoreChangeEvent: boolean;\r\n\r\n\tprivate readonly _localToDispose = this._register(new DisposableStore());\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService\r\n\t) {\r\n\t\tsuper();\r\n\t\tthis._editor = editor;\r\n\t\tthis._enabled = false;\r\n\t\tthis._visibleContextKey = CONTEXT_ONTYPE_RENAME_INPUT_VISIBLE.bindTo(contextKeyService);\r\n\r\n\t\tthis._currentDecorations = [];\r\n\t\tthis._languageWordPattern = null;\r\n\t\tthis._currentWordPattern = null;\r\n\t\tthis._ignoreChangeEvent = false;\r\n\t\tthis._localToDispose = this._register(new DisposableStore());\r\n\r\n\t\tthis._rangeUpdateTriggerPromise = null;\r\n\t\tthis._rangeSyncTriggerPromise = null;\r\n\r\n\t\tthis._currentRequest = null;\r\n\t\tthis._currentRequestPosition = null;\r\n\t\tthis._currentRequestModelVersion = null;\r\n\r\n\t\tthis._register(this._editor.onDidChangeModel(() => this.reinitialize()));\r\n\r\n\t\tthis._register(this._editor.onDidChangeConfiguration(e => {\r\n\t\t\tif (e.hasChanged(EditorOption.linkedEditing) || e.hasChanged(EditorOption.renameOnType)) {\r\n\t\t\t\tthis.reinitialize();\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._register(LinkedEditingRangeProviderRegistry.onDidChange(() => this.reinitialize()));\r\n\t\tthis._register(this._editor.onDidChangeModelLanguage(() => this.reinitialize()));\r\n\r\n\t\tthis.reinitialize();\r\n\t}\r\n\r\n\tprivate reinitialize() {\r\n\t\tconst model = this._editor.getModel();\r\n\t\tconst isEnabled = model !== null && (this._editor.getOption(EditorOption.linkedEditing) || this._editor.getOption(EditorOption.renameOnType)) && LinkedEditingRangeProviderRegistry.has(model);\r\n\t\tif (isEnabled === this._enabled) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._enabled = isEnabled;\r\n\r\n\t\tthis.clearRanges();\r\n\t\tthis._localToDispose.clear();\r\n\r\n\t\tif (!isEnabled || model === null) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._languageWordPattern = LanguageConfigurationRegistry.getWordDefinition(model.getLanguageIdentifier().id);\r\n\t\tthis._localToDispose.add(model.onDidChangeLanguageConfiguration(() => {\r\n\t\t\tthis._languageWordPattern = LanguageConfigurationRegistry.getWordDefinition(model.getLanguageIdentifier().id);\r\n\t\t}));\r\n\r\n\t\tconst rangeUpdateScheduler = new Delayer(this._debounceDuration);\r\n\t\tconst triggerRangeUpdate = () => {\r\n\t\t\tthis._rangeUpdateTriggerPromise = rangeUpdateScheduler.trigger(() => this.updateRanges(), this._debounceDuration);\r\n\t\t};\r\n\t\tconst rangeSyncScheduler = new Delayer(0);\r\n\t\tconst triggerRangeSync = (decorations: string[]) => {\r\n\t\t\tthis._rangeSyncTriggerPromise = rangeSyncScheduler.trigger(() => this._syncRanges(decorations));\r\n\t\t};\r\n\t\tthis._localToDispose.add(this._editor.onDidChangeCursorPosition(() => {\r\n\t\t\ttriggerRangeUpdate();\r\n\t\t}));\r\n\t\tthis._localToDispose.add(this._editor.onDidChangeModelContent((e) => {\r\n\t\t\tif (!this._ignoreChangeEvent) {\r\n\t\t\t\tif (this._currentDecorations.length > 0) {\r\n\t\t\t\t\tconst referenceRange = model.getDecorationRange(this._currentDecorations[0]);\r\n\t\t\t\t\tif (referenceRange && e.changes.every(c => referenceRange.intersectRanges(c.range))) {\r\n\t\t\t\t\t\ttriggerRangeSync(this._currentDecorations);\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\ttriggerRangeUpdate();\r\n\t\t}));\r\n\t\tthis._localToDispose.add({\r\n\t\t\tdispose: () => {\r\n\t\t\t\trangeUpdateScheduler.cancel();\r\n\t\t\t\trangeSyncScheduler.cancel();\r\n\t\t\t}\r\n\t\t});\r\n\t\tthis.updateRanges();\r\n\t}\r\n\r\n\tprivate _syncRanges(decorations: string[]): void {\r\n\t\t// dalayed invocation, make sure we're still on\r\n\t\tif (!this._editor.hasModel() || decorations !== this._currentDecorations || decorations.length === 0) {\r\n\t\t\t// nothing to do\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst model = this._editor.getModel();\r\n\t\tconst referenceRange = model.getDecorationRange(decorations[0]);\r\n\r\n\t\tif (!referenceRange || referenceRange.startLineNumber !== referenceRange.endLineNumber) {\r\n\t\t\treturn this.clearRanges();\r\n\t\t}\r\n\r\n\t\tconst referenceValue = model.getValueInRange(referenceRange);\r\n\t\tif (this._currentWordPattern) {\r\n\t\t\tconst match = referenceValue.match(this._currentWordPattern);\r\n\t\t\tconst matchLength = match ? match[0].length : 0;\r\n\t\t\tif (matchLength !== referenceValue.length) {\r\n\t\t\t\treturn this.clearRanges();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet edits: IIdentifiedSingleEditOperation[] = [];\r\n\t\tfor (let i = 1, len = decorations.length; i < len; i++) {\r\n\t\t\tconst mirrorRange = model.getDecorationRange(decorations[i]);\r\n\t\t\tif (!mirrorRange) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (mirrorRange.startLineNumber !== mirrorRange.endLineNumber) {\r\n\t\t\t\tedits.push({\r\n\t\t\t\t\trange: mirrorRange,\r\n\t\t\t\t\ttext: referenceValue\r\n\t\t\t\t});\r\n\t\t\t} else {\r\n\t\t\t\tlet oldValue = model.getValueInRange(mirrorRange);\r\n\t\t\t\tlet newValue = referenceValue;\r\n\t\t\t\tlet rangeStartColumn = mirrorRange.startColumn;\r\n\t\t\t\tlet rangeEndColumn = mirrorRange.endColumn;\r\n\r\n\t\t\t\tconst commonPrefixLength = strings.commonPrefixLength(oldValue, newValue);\r\n\t\t\t\trangeStartColumn += commonPrefixLength;\r\n\t\t\t\toldValue = oldValue.substr(commonPrefixLength);\r\n\t\t\t\tnewValue = newValue.substr(commonPrefixLength);\r\n\r\n\t\t\t\tconst commonSuffixLength = strings.commonSuffixLength(oldValue, newValue);\r\n\t\t\t\trangeEndColumn -= commonSuffixLength;\r\n\t\t\t\toldValue = oldValue.substr(0, oldValue.length - commonSuffixLength);\r\n\t\t\t\tnewValue = newValue.substr(0, newValue.length - commonSuffixLength);\r\n\r\n\t\t\t\tif (rangeStartColumn !== rangeEndColumn || newValue.length !== 0) {\r\n\t\t\t\t\tedits.push({\r\n\t\t\t\t\t\trange: new Range(mirrorRange.startLineNumber, rangeStartColumn, mirrorRange.endLineNumber, rangeEndColumn),\r\n\t\t\t\t\t\ttext: newValue\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (edits.length === 0) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\tthis._editor.popUndoStop();\r\n\t\t\tthis._ignoreChangeEvent = true;\r\n\t\t\tconst prevEditOperationType = this._editor._getViewModel().getPrevEditOperationType();\r\n\t\t\tthis._editor.executeEdits('linkedEditing', edits);\r\n\t\t\tthis._editor._getViewModel().setPrevEditOperationType(prevEditOperationType);\r\n\t\t} finally {\r\n\t\t\tthis._ignoreChangeEvent = false;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis.clearRanges();\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tpublic clearRanges(): void {\r\n\t\tthis._visibleContextKey.set(false);\r\n\t\tthis._currentDecorations = this._editor.deltaDecorations(this._currentDecorations, []);\r\n\t\tif (this._currentRequest) {\r\n\t\t\tthis._currentRequest.cancel();\r\n\t\t\tthis._currentRequest = null;\r\n\t\t\tthis._currentRequestPosition = null;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic async updateRanges(force = false): Promise {\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\tthis.clearRanges();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst position = this._editor.getPosition();\r\n\t\tif (!this._enabled && !force || this._editor.getSelections().length > 1) {\r\n\t\t\t// disabled or multicursor\r\n\t\t\tthis.clearRanges();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst model = this._editor.getModel();\r\n\t\tconst modelVersionId = model.getVersionId();\r\n\t\tif (this._currentRequestPosition && this._currentRequestModelVersion === modelVersionId) {\r\n\t\t\tif (position.equals(this._currentRequestPosition)) {\r\n\t\t\t\treturn; // same position\r\n\t\t\t}\r\n\t\t\tif (this._currentDecorations && this._currentDecorations.length > 0) {\r\n\t\t\t\tconst range = model.getDecorationRange(this._currentDecorations[0]);\r\n\t\t\t\tif (range && range.containsPosition(position)) {\r\n\t\t\t\t\treturn; // just moving inside the existing primary range\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._currentRequestPosition = position;\r\n\t\tthis._currentRequestModelVersion = modelVersionId;\r\n\t\tconst request = createCancelablePromise(async token => {\r\n\t\t\ttry {\r\n\t\t\t\tconst response = await getLinkedEditingRanges(model, position, token);\r\n\t\t\t\tif (request !== this._currentRequest) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\tthis._currentRequest = null;\r\n\t\t\t\tif (modelVersionId !== model.getVersionId()) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tlet ranges: IRange[] = [];\r\n\t\t\t\tif (response?.ranges) {\r\n\t\t\t\t\tranges = response.ranges;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis._currentWordPattern = response?.wordPattern || this._languageWordPattern;\r\n\r\n\t\t\t\tlet foundReferenceRange = false;\r\n\t\t\t\tfor (let i = 0, len = ranges.length; i < len; i++) {\r\n\t\t\t\t\tif (Range.containsPosition(ranges[i], position)) {\r\n\t\t\t\t\t\tfoundReferenceRange = true;\r\n\t\t\t\t\t\tif (i !== 0) {\r\n\t\t\t\t\t\t\tconst referenceRange = ranges[i];\r\n\t\t\t\t\t\t\tranges.splice(i, 1);\r\n\t\t\t\t\t\t\tranges.unshift(referenceRange);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (!foundReferenceRange) {\r\n\t\t\t\t\t// Cannot do linked editing if the ranges are not where the cursor is...\r\n\t\t\t\t\tthis.clearRanges();\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst decorations: IModelDeltaDecoration[] = ranges.map(range => ({ range: range, options: LinkedEditingContribution.DECORATION }));\r\n\t\t\t\tthis._visibleContextKey.set(true);\r\n\t\t\t\tthis._currentDecorations = this._editor.deltaDecorations(this._currentDecorations, decorations);\r\n\t\t\t} catch (err) {\r\n\t\t\t\tif (!isPromiseCanceledError(err)) {\r\n\t\t\t\t\tonUnexpectedError(err);\r\n\t\t\t\t}\r\n\t\t\t\tif (this._currentRequest === request || !this._currentRequest) {\r\n\t\t\t\t\t// stop if we are still the latest request\r\n\t\t\t\t\tthis.clearRanges();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\t\tthis._currentRequest = request;\r\n\t\treturn request;\r\n\t}\r\n\r\n\t// private printDecorators(model: ITextModel) {\r\n\t// \treturn this._currentDecorations.map(d => {\r\n\t// \t\tconst range = model.getDecorationRange(d);\r\n\t// \t\tif (range) {\r\n\t// \t\t\treturn this.printRange(range);\r\n\t// \t\t}\r\n\t// \t\treturn 'invalid';\r\n\t// \t}).join(',');\r\n\t// }\r\n\r\n\t// private printChanges(changes: IModelContentChange[]) {\r\n\t// \treturn changes.map(c => {\r\n\t// \t\treturn `${this.printRange(c.range)} - ${c.text}`;\r\n\t// \t}\r\n\t// \t).join(',');\r\n\t// }\r\n\r\n\t// private printRange(range: IRange) {\r\n\t// \treturn `${range.startLineNumber},${range.startColumn}/${range.endLineNumber},${range.endColumn}`;\r\n\t// }\r\n}\r\n\r\nexport class LinkedEditingAction extends EditorAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.linkedEditing',\r\n\t\t\tlabel: nls.localize('linkedEditing.label', \"Start Linked Editing\"),\r\n\t\t\talias: 'Start Linked Editing',\r\n\t\t\tprecondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasRenameProvider),\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.F2,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\trunCommand(accessor: ServicesAccessor, args: [URI, IPosition]): void | Promise {\r\n\t\tconst editorService = accessor.get(ICodeEditorService);\r\n\t\tconst [uri, pos] = Array.isArray(args) && args || [undefined, undefined];\r\n\r\n\t\tif (URI.isUri(uri) && Position.isIPosition(pos)) {\r\n\t\t\treturn editorService.openCodeEditor({ resource: uri }, editorService.getActiveCodeEditor()).then(editor => {\r\n\t\t\t\tif (!editor) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\teditor.setPosition(pos);\r\n\t\t\t\teditor.invokeWithinContext(accessor => {\r\n\t\t\t\t\tthis.reportTelemetry(accessor, editor);\r\n\t\t\t\t\treturn this.run(accessor, editor);\r\n\t\t\t\t});\r\n\t\t\t}, onUnexpectedError);\r\n\t\t}\r\n\r\n\t\treturn super.runCommand(accessor, args);\r\n\t}\r\n\r\n\trun(_accessor: ServicesAccessor, editor: ICodeEditor): Promise {\r\n\t\tconst controller = LinkedEditingContribution.get(editor);\r\n\t\tif (controller) {\r\n\t\t\treturn Promise.resolve(controller.updateRanges(true));\r\n\t\t}\r\n\t\treturn Promise.resolve();\r\n\t}\r\n}\r\n\r\nconst LinkedEditingCommand = EditorCommand.bindToContribution(LinkedEditingContribution.get);\r\nregisterEditorCommand(new LinkedEditingCommand({\r\n\tid: 'cancelLinkedEditingInput',\r\n\tprecondition: CONTEXT_ONTYPE_RENAME_INPUT_VISIBLE,\r\n\thandler: x => x.clearRanges(),\r\n\tkbOpts: {\r\n\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\tweight: KeybindingWeight.EditorContrib + 99,\r\n\t\tprimary: KeyCode.Escape,\r\n\t\tsecondary: [KeyMod.Shift | KeyCode.Escape]\r\n\t}\r\n}));\r\n\r\n\r\nfunction getLinkedEditingRanges(model: ITextModel, position: Position, token: CancellationToken): Promise {\r\n\tconst orderedByScore = LinkedEditingRangeProviderRegistry.ordered(model);\r\n\r\n\t// in order of score ask the linked editing range provider\r\n\t// until someone response with a good result\r\n\t// (good = not null)\r\n\treturn first(orderedByScore.map(provider => async () => {\r\n\t\ttry {\r\n\t\t\treturn await provider.provideLinkedEditingRanges(model, position, token);\r\n\t\t} catch (e) {\r\n\t\t\tonUnexpectedExternalError(e);\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\t}), result => !!result && arrays.isNonEmptyArray(result?.ranges));\r\n}\r\n\r\nexport const editorLinkedEditingBackground = registerColor('editor.linkedEditingBackground', { dark: Color.fromHex('#f00').transparent(0.3), light: Color.fromHex('#f00').transparent(0.3), hc: Color.fromHex('#f00').transparent(0.3) }, nls.localize('editorLinkedEditingBackground', 'Background color when the editor auto renames on type.'));\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst editorLinkedEditingBackgroundColor = theme.getColor(editorLinkedEditingBackground);\r\n\tif (editorLinkedEditingBackgroundColor) {\r\n\t\tcollector.addRule(`.monaco-editor .${DECORATION_CLASS_NAME} { background: ${editorLinkedEditingBackgroundColor}; border-left-color: ${editorLinkedEditingBackgroundColor}; }`);\r\n\t}\r\n});\r\n\r\nregisterModelAndPositionCommand('_executeLinkedEditingProvider', (model, position) => getLinkedEditingRanges(model, position, CancellationToken.None));\r\n\r\nregisterEditorContribution(LinkedEditingContribution.ID, LinkedEditingContribution);\r\nregisterEditorAction(LinkedEditingAction);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./links';\r\nimport * as nls from 'vs/nls';\r\nimport * as async from 'vs/base/common/async';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport { MarkdownString } from 'vs/base/common/htmlContent';\r\nimport { DisposableStore } from 'vs/base/common/lifecycle';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport { ICodeEditor, MouseTargetType } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { IModelDecorationsChangeAccessor, IModelDeltaDecoration, TrackedRangeStickiness } from 'vs/editor/common/model';\r\nimport { ModelDecorationOptions } from 'vs/editor/common/model/textModel';\r\nimport { LinkProviderRegistry } from 'vs/editor/common/modes';\r\nimport { ClickLinkGesture, ClickLinkKeyboardEvent, ClickLinkMouseEvent } from 'vs/editor/contrib/gotoSymbol/link/clickLinkGesture';\r\nimport { Link, getLinks, LinksList } from 'vs/editor/contrib/links/getLinks';\r\nimport { INotificationService } from 'vs/platform/notification/common/notification';\r\nimport { IOpenerService } from 'vs/platform/opener/common/opener';\r\nimport { editorActiveLinkForeground } from 'vs/platform/theme/common/colorRegistry';\r\nimport { registerThemingParticipant } from 'vs/platform/theme/common/themeService';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { Schemas } from 'vs/base/common/network';\r\nimport * as resources from 'vs/base/common/resources';\r\n\r\nfunction getHoverMessage(link: Link, useMetaKey: boolean): MarkdownString {\r\n\tconst executeCmd = link.url && /^command:/i.test(link.url.toString());\r\n\r\n\tconst label = link.tooltip\r\n\t\t? link.tooltip\r\n\t\t: executeCmd\r\n\t\t\t? nls.localize('links.navigate.executeCmd', 'Execute command')\r\n\t\t\t: nls.localize('links.navigate.follow', 'Follow link');\r\n\r\n\tconst kb = useMetaKey\r\n\t\t? platform.isMacintosh\r\n\t\t\t? nls.localize('links.navigate.kb.meta.mac', \"cmd + click\")\r\n\t\t\t: nls.localize('links.navigate.kb.meta', \"ctrl + click\")\r\n\t\t: platform.isMacintosh\r\n\t\t\t? nls.localize('links.navigate.kb.alt.mac', \"option + click\")\r\n\t\t\t: nls.localize('links.navigate.kb.alt', \"alt + click\");\r\n\r\n\tif (link.url) {\r\n\t\tlet nativeLabel = '';\r\n\t\tif (/^command:/i.test(link.url.toString())) {\r\n\t\t\t// Don't show complete command arguments in the native tooltip\r\n\t\t\tconst match = link.url.toString().match(/^command:([^?#]+)/);\r\n\t\t\tif (match) {\r\n\t\t\t\tconst commandId = match[1];\r\n\t\t\t\tconst nativeLabelText = nls.localize('tooltip.explanation', \"Execute command {0}\", commandId);\r\n\t\t\t\tnativeLabel = ` \"${nativeLabelText}\"`;\r\n\t\t\t}\r\n\t\t}\r\n\t\tconst hoverMessage = new MarkdownString('', true).appendMarkdown(`[${label}](${link.url.toString(true)}${nativeLabel}) (${kb})`);\r\n\t\treturn hoverMessage;\r\n\t} else {\r\n\t\treturn new MarkdownString().appendText(`${label} (${kb})`);\r\n\t}\r\n}\r\n\r\nconst decoration = {\r\n\tgeneral: ModelDecorationOptions.register({\r\n\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,\r\n\t\tcollapseOnReplaceEdit: true,\r\n\t\tinlineClassName: 'detected-link'\r\n\t}),\r\n\tactive: ModelDecorationOptions.register({\r\n\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,\r\n\t\tcollapseOnReplaceEdit: true,\r\n\t\tinlineClassName: 'detected-link-active'\r\n\t})\r\n};\r\n\r\n\r\nclass LinkOccurrence {\r\n\r\n\tpublic static decoration(link: Link, useMetaKey: boolean): IModelDeltaDecoration {\r\n\t\treturn {\r\n\t\t\trange: link.range,\r\n\t\t\toptions: LinkOccurrence._getOptions(link, useMetaKey, false)\r\n\t\t};\r\n\t}\r\n\r\n\tprivate static _getOptions(link: Link, useMetaKey: boolean, isActive: boolean): ModelDecorationOptions {\r\n\t\tconst options = { ... (isActive ? decoration.active : decoration.general) };\r\n\t\toptions.hoverMessage = getHoverMessage(link, useMetaKey);\r\n\t\treturn options;\r\n\t}\r\n\r\n\tpublic decorationId: string;\r\n\tpublic link: Link;\r\n\r\n\tconstructor(link: Link, decorationId: string) {\r\n\t\tthis.link = link;\r\n\t\tthis.decorationId = decorationId;\r\n\t}\r\n\r\n\tpublic activate(changeAccessor: IModelDecorationsChangeAccessor, useMetaKey: boolean): void {\r\n\t\tchangeAccessor.changeDecorationOptions(this.decorationId, LinkOccurrence._getOptions(this.link, useMetaKey, true));\r\n\t}\r\n\r\n\tpublic deactivate(changeAccessor: IModelDecorationsChangeAccessor, useMetaKey: boolean): void {\r\n\t\tchangeAccessor.changeDecorationOptions(this.decorationId, LinkOccurrence._getOptions(this.link, useMetaKey, false));\r\n\t}\r\n}\r\n\r\nexport class LinkDetector implements IEditorContribution {\r\n\r\n\tpublic static readonly ID: string = 'editor.linkDetector';\r\n\r\n\tpublic static get(editor: ICodeEditor): LinkDetector {\r\n\t\treturn editor.getContribution(LinkDetector.ID);\r\n\t}\r\n\r\n\tstatic readonly RECOMPUTE_TIME = 1000; // ms\r\n\r\n\tprivate readonly editor: ICodeEditor;\r\n\tprivate enabled: boolean;\r\n\tprivate readonly listenersToRemove = new DisposableStore();\r\n\tprivate readonly timeout: async.TimeoutTimer;\r\n\tprivate computePromise: async.CancelablePromise | null;\r\n\tprivate activeLinksList: LinksList | null;\r\n\tprivate activeLinkDecorationId: string | null;\r\n\tprivate readonly openerService: IOpenerService;\r\n\tprivate readonly notificationService: INotificationService;\r\n\tprivate currentOccurrences: { [decorationId: string]: LinkOccurrence; };\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor,\r\n\t\t@IOpenerService openerService: IOpenerService,\r\n\t\t@INotificationService notificationService: INotificationService\r\n\t) {\r\n\t\tthis.editor = editor;\r\n\t\tthis.openerService = openerService;\r\n\t\tthis.notificationService = notificationService;\r\n\r\n\t\tlet clickLinkGesture = new ClickLinkGesture(editor);\r\n\t\tthis.listenersToRemove.add(clickLinkGesture);\r\n\t\tthis.listenersToRemove.add(clickLinkGesture.onMouseMoveOrRelevantKeyDown(([mouseEvent, keyboardEvent]) => {\r\n\t\t\tthis._onEditorMouseMove(mouseEvent, keyboardEvent);\r\n\t\t}));\r\n\t\tthis.listenersToRemove.add(clickLinkGesture.onExecute((e) => {\r\n\t\t\tthis.onEditorMouseUp(e);\r\n\t\t}));\r\n\t\tthis.listenersToRemove.add(clickLinkGesture.onCancel((e) => {\r\n\t\t\tthis.cleanUpActiveLinkDecoration();\r\n\t\t}));\r\n\r\n\t\tthis.enabled = editor.getOption(EditorOption.links);\r\n\t\tthis.listenersToRemove.add(editor.onDidChangeConfiguration((e) => {\r\n\t\t\tconst enabled = editor.getOption(EditorOption.links);\r\n\t\t\tif (this.enabled === enabled) {\r\n\t\t\t\t// No change in our configuration option\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tthis.enabled = enabled;\r\n\r\n\t\t\t// Remove any links (for the getting disabled case)\r\n\t\t\tthis.updateDecorations([]);\r\n\r\n\t\t\t// Stop any computation (for the getting disabled case)\r\n\t\t\tthis.stop();\r\n\r\n\t\t\t// Start computing (for the getting enabled case)\r\n\t\t\tthis.beginCompute();\r\n\t\t}));\r\n\t\tthis.listenersToRemove.add(editor.onDidChangeModelContent((e) => this.onChange()));\r\n\t\tthis.listenersToRemove.add(editor.onDidChangeModel((e) => this.onModelChanged()));\r\n\t\tthis.listenersToRemove.add(editor.onDidChangeModelLanguage((e) => this.onModelModeChanged()));\r\n\t\tthis.listenersToRemove.add(LinkProviderRegistry.onDidChange((e) => this.onModelModeChanged()));\r\n\r\n\t\tthis.timeout = new async.TimeoutTimer();\r\n\t\tthis.computePromise = null;\r\n\t\tthis.activeLinksList = null;\r\n\t\tthis.currentOccurrences = {};\r\n\t\tthis.activeLinkDecorationId = null;\r\n\t\tthis.beginCompute();\r\n\t}\r\n\r\n\tprivate onModelChanged(): void {\r\n\t\tthis.currentOccurrences = {};\r\n\t\tthis.activeLinkDecorationId = null;\r\n\t\tthis.stop();\r\n\t\tthis.beginCompute();\r\n\t}\r\n\r\n\tprivate onModelModeChanged(): void {\r\n\t\tthis.stop();\r\n\t\tthis.beginCompute();\r\n\t}\r\n\r\n\tprivate onChange(): void {\r\n\t\tthis.timeout.setIfNotSet(() => this.beginCompute(), LinkDetector.RECOMPUTE_TIME);\r\n\t}\r\n\r\n\tprivate async beginCompute(): Promise {\r\n\t\tif (!this.editor.hasModel() || !this.enabled) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst model = this.editor.getModel();\r\n\r\n\t\tif (!LinkProviderRegistry.has(model)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this.activeLinksList) {\r\n\t\t\tthis.activeLinksList.dispose();\r\n\t\t\tthis.activeLinksList = null;\r\n\t\t}\r\n\r\n\t\tthis.computePromise = async.createCancelablePromise(token => getLinks(model, token));\r\n\t\ttry {\r\n\t\t\tthis.activeLinksList = await this.computePromise;\r\n\t\t\tthis.updateDecorations(this.activeLinksList.links);\r\n\t\t} catch (err) {\r\n\t\t\tonUnexpectedError(err);\r\n\t\t} finally {\r\n\t\t\tthis.computePromise = null;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate updateDecorations(links: Link[]): void {\r\n\t\tconst useMetaKey = (this.editor.getOption(EditorOption.multiCursorModifier) === 'altKey');\r\n\t\tlet oldDecorations: string[] = [];\r\n\t\tlet keys = Object.keys(this.currentOccurrences);\r\n\t\tfor (let i = 0, len = keys.length; i < len; i++) {\r\n\t\t\tlet decorationId = keys[i];\r\n\t\t\tlet occurance = this.currentOccurrences[decorationId];\r\n\t\t\toldDecorations.push(occurance.decorationId);\r\n\t\t}\r\n\r\n\t\tlet newDecorations: IModelDeltaDecoration[] = [];\r\n\t\tif (links) {\r\n\t\t\t// Not sure why this is sometimes null\r\n\t\t\tfor (const link of links) {\r\n\t\t\t\tnewDecorations.push(LinkOccurrence.decoration(link, useMetaKey));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet decorations = this.editor.deltaDecorations(oldDecorations, newDecorations);\r\n\r\n\t\tthis.currentOccurrences = {};\r\n\t\tthis.activeLinkDecorationId = null;\r\n\t\tfor (let i = 0, len = decorations.length; i < len; i++) {\r\n\t\t\tlet occurance = new LinkOccurrence(links[i], decorations[i]);\r\n\t\t\tthis.currentOccurrences[occurance.decorationId] = occurance;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _onEditorMouseMove(mouseEvent: ClickLinkMouseEvent, withKey: ClickLinkKeyboardEvent | null): void {\r\n\t\tconst useMetaKey = (this.editor.getOption(EditorOption.multiCursorModifier) === 'altKey');\r\n\t\tif (this.isEnabled(mouseEvent, withKey)) {\r\n\t\t\tthis.cleanUpActiveLinkDecoration(); // always remove previous link decoration as their can only be one\r\n\t\t\tconst occurrence = this.getLinkOccurrence(mouseEvent.target.position);\r\n\t\t\tif (occurrence) {\r\n\t\t\t\tthis.editor.changeDecorations((changeAccessor) => {\r\n\t\t\t\t\toccurrence.activate(changeAccessor, useMetaKey);\r\n\t\t\t\t\tthis.activeLinkDecorationId = occurrence.decorationId;\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tthis.cleanUpActiveLinkDecoration();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate cleanUpActiveLinkDecoration(): void {\r\n\t\tconst useMetaKey = (this.editor.getOption(EditorOption.multiCursorModifier) === 'altKey');\r\n\t\tif (this.activeLinkDecorationId) {\r\n\t\t\tconst occurrence = this.currentOccurrences[this.activeLinkDecorationId];\r\n\t\t\tif (occurrence) {\r\n\t\t\t\tthis.editor.changeDecorations((changeAccessor) => {\r\n\t\t\t\t\toccurrence.deactivate(changeAccessor, useMetaKey);\r\n\t\t\t\t});\r\n\t\t\t}\r\n\r\n\t\t\tthis.activeLinkDecorationId = null;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate onEditorMouseUp(mouseEvent: ClickLinkMouseEvent): void {\r\n\t\tif (!this.isEnabled(mouseEvent)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst occurrence = this.getLinkOccurrence(mouseEvent.target.position);\r\n\t\tif (!occurrence) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis.openLinkOccurrence(occurrence, mouseEvent.hasSideBySideModifier, true /* from user gesture */);\r\n\t}\r\n\r\n\tpublic openLinkOccurrence(occurrence: LinkOccurrence, openToSide: boolean, fromUserGesture = false): void {\r\n\r\n\t\tif (!this.openerService) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst { link } = occurrence;\r\n\r\n\t\tlink.resolve(CancellationToken.None).then(uri => {\r\n\r\n\t\t\t// Support for relative file URIs of the shape file://./relativeFile.txt or file:///./relativeFile.txt\r\n\t\t\tif (typeof uri === 'string' && this.editor.hasModel()) {\r\n\t\t\t\tconst modelUri = this.editor.getModel().uri;\r\n\t\t\t\tif (modelUri.scheme === Schemas.file && uri.startsWith(`${Schemas.file}:`)) {\r\n\t\t\t\t\tconst parsedUri = URI.parse(uri);\r\n\t\t\t\t\tif (parsedUri.scheme === Schemas.file) {\r\n\t\t\t\t\t\tconst fsPath = resources.originalFSPath(parsedUri);\r\n\r\n\t\t\t\t\t\tlet relativePath: string | null = null;\r\n\t\t\t\t\t\tif (fsPath.startsWith('/./')) {\r\n\t\t\t\t\t\t\trelativePath = `.${fsPath.substr(1)}`;\r\n\t\t\t\t\t\t} else if (fsPath.startsWith('//./')) {\r\n\t\t\t\t\t\t\trelativePath = `.${fsPath.substr(2)}`;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif (relativePath) {\r\n\t\t\t\t\t\t\turi = resources.joinPath(modelUri, relativePath);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn this.openerService.open(uri, { openToSide, fromUserGesture, allowContributedOpeners: true });\r\n\r\n\t\t}, err => {\r\n\t\t\tconst messageOrError =\r\n\t\t\t\terr instanceof Error ? (err).message : err;\r\n\t\t\t// different error cases\r\n\t\t\tif (messageOrError === 'invalid') {\r\n\t\t\t\tthis.notificationService.warn(nls.localize('invalid.url', 'Failed to open this link because it is not well-formed: {0}', link.url!.toString()));\r\n\t\t\t} else if (messageOrError === 'missing') {\r\n\t\t\t\tthis.notificationService.warn(nls.localize('missing.url', 'Failed to open this link because its target is missing.'));\r\n\t\t\t} else {\r\n\t\t\t\tonUnexpectedError(err);\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic getLinkOccurrence(position: Position | null): LinkOccurrence | null {\r\n\t\tif (!this.editor.hasModel() || !position) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tconst decorations = this.editor.getModel().getDecorationsInRange({\r\n\t\t\tstartLineNumber: position.lineNumber,\r\n\t\t\tstartColumn: position.column,\r\n\t\t\tendLineNumber: position.lineNumber,\r\n\t\t\tendColumn: position.column\r\n\t\t}, 0, true);\r\n\r\n\t\tfor (const decoration of decorations) {\r\n\t\t\tconst currentOccurrence = this.currentOccurrences[decoration.id];\r\n\t\t\tif (currentOccurrence) {\r\n\t\t\t\treturn currentOccurrence;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate isEnabled(mouseEvent: ClickLinkMouseEvent, withKey?: ClickLinkKeyboardEvent | null): boolean {\r\n\t\treturn Boolean(\r\n\t\t\t(mouseEvent.target.type === MouseTargetType.CONTENT_TEXT)\r\n\t\t\t&& (mouseEvent.hasTriggerModifier || (withKey && withKey.keyCodeIsTriggerKey))\r\n\t\t);\r\n\t}\r\n\r\n\tprivate stop(): void {\r\n\t\tthis.timeout.cancel();\r\n\t\tif (this.activeLinksList) {\r\n\t\t\tthis.activeLinksList?.dispose();\r\n\t\t\tthis.activeLinksList = null;\r\n\t\t}\r\n\t\tif (this.computePromise) {\r\n\t\t\tthis.computePromise.cancel();\r\n\t\t\tthis.computePromise = null;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis.listenersToRemove.dispose();\r\n\t\tthis.stop();\r\n\t\tthis.timeout.dispose();\r\n\t}\r\n}\r\n\r\nclass OpenLinkAction extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.openLink',\r\n\t\t\tlabel: nls.localize('label', \"Open Link\"),\r\n\t\t\talias: 'Open Link',\r\n\t\t\tprecondition: undefined\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tlet linkDetector = LinkDetector.get(editor);\r\n\t\tif (!linkDetector) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet selections = editor.getSelections();\r\n\r\n\t\tfor (let sel of selections) {\r\n\t\t\tlet link = linkDetector.getLinkOccurrence(sel.getEndPosition());\r\n\r\n\t\t\tif (link) {\r\n\t\t\t\tlinkDetector.openLinkOccurrence(link, false);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(LinkDetector.ID, LinkDetector);\r\nregisterEditorAction(OpenLinkAction);\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst activeLinkForeground = theme.getColor(editorActiveLinkForeground);\r\n\tif (activeLinkForeground) {\r\n\t\tcollector.addRule(`.monaco-editor .detected-link-active { color: ${activeLinkForeground} !important; }`);\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./messageController';\r\nimport * as nls from 'vs/nls';\r\nimport { TimeoutTimer } from 'vs/base/common/async';\r\nimport { KeyCode } from 'vs/base/common/keyCodes';\r\nimport { IDisposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';\r\nimport { alert } from 'vs/base/browser/ui/aria/aria';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { IEditorContribution, ScrollType } from 'vs/editor/common/editorCommon';\r\nimport { registerEditorContribution, EditorCommand, registerEditorCommand } from 'vs/editor/browser/editorExtensions';\r\nimport { ICodeEditor, IContentWidget, IContentWidgetPosition, ContentWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';\r\nimport { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IPosition } from 'vs/editor/common/core/position';\r\nimport { registerThemingParticipant } from 'vs/platform/theme/common/themeService';\r\nimport { inputValidationInfoBorder, inputValidationInfoBackground, inputValidationInfoForeground } from 'vs/platform/theme/common/colorRegistry';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { ColorScheme } from 'vs/platform/theme/common/theme';\r\n\r\nexport class MessageController implements IEditorContribution {\r\n\r\n\tpublic static readonly ID = 'editor.contrib.messageController';\r\n\r\n\tstatic readonly MESSAGE_VISIBLE = new RawContextKey('messageVisible', false);\r\n\r\n\tstatic get(editor: ICodeEditor): MessageController {\r\n\t\treturn editor.getContribution(MessageController.ID);\r\n\t}\r\n\r\n\tprivate readonly _editor: ICodeEditor;\r\n\tprivate readonly _visible: IContextKey;\r\n\tprivate readonly _messageWidget = new MutableDisposable();\r\n\tprivate readonly _messageListeners = new DisposableStore();\r\n\tprivate readonly _editorListener: IDisposable;\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService\r\n\t) {\r\n\r\n\t\tthis._editor = editor;\r\n\t\tthis._visible = MessageController.MESSAGE_VISIBLE.bindTo(contextKeyService);\r\n\t\tthis._editorListener = this._editor.onDidAttemptReadOnlyEdit(() => this._onDidAttemptReadOnlyEdit());\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._editorListener.dispose();\r\n\t\tthis._messageListeners.dispose();\r\n\t\tthis._messageWidget.dispose();\r\n\t\tthis._visible.reset();\r\n\t}\r\n\r\n\tshowMessage(message: string, position: IPosition): void {\r\n\r\n\t\talert(message);\r\n\r\n\t\tthis._visible.set(true);\r\n\t\tthis._messageWidget.clear();\r\n\t\tthis._messageListeners.clear();\r\n\t\tthis._messageWidget.value = new MessageWidget(this._editor, position, message);\r\n\r\n\t\t// close on blur, cursor, model change, dispose\r\n\t\tthis._messageListeners.add(this._editor.onDidBlurEditorText(() => this.closeMessage()));\r\n\t\tthis._messageListeners.add(this._editor.onDidChangeCursorPosition(() => this.closeMessage()));\r\n\t\tthis._messageListeners.add(this._editor.onDidDispose(() => this.closeMessage()));\r\n\t\tthis._messageListeners.add(this._editor.onDidChangeModel(() => this.closeMessage()));\r\n\r\n\t\t// 3sec\r\n\t\tthis._messageListeners.add(new TimeoutTimer(() => this.closeMessage(), 3000));\r\n\r\n\t\t// close on mouse move\r\n\t\tlet bounds: Range;\r\n\t\tthis._messageListeners.add(this._editor.onMouseMove(e => {\r\n\t\t\t// outside the text area\r\n\t\t\tif (!e.target.position) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (!bounds) {\r\n\t\t\t\t// define bounding box around position and first mouse occurance\r\n\t\t\t\tbounds = new Range(position.lineNumber - 3, 1, e.target.position.lineNumber + 3, 1);\r\n\t\t\t} else if (!bounds.containsPosition(e.target.position)) {\r\n\t\t\t\t// check if position is still in bounds\r\n\t\t\t\tthis.closeMessage();\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\tcloseMessage(): void {\r\n\t\tthis._visible.reset();\r\n\t\tthis._messageListeners.clear();\r\n\t\tif (this._messageWidget.value) {\r\n\t\t\tthis._messageListeners.add(MessageWidget.fadeOut(this._messageWidget.value));\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _onDidAttemptReadOnlyEdit(): void {\r\n\t\tif (this._editor.hasModel()) {\r\n\t\t\tthis.showMessage(nls.localize('editor.readonly', \"Cannot edit in read-only editor\"), this._editor.getPosition());\r\n\t\t}\r\n\t}\r\n}\r\n\r\nconst MessageCommand = EditorCommand.bindToContribution(MessageController.get);\r\n\r\n\r\nregisterEditorCommand(new MessageCommand({\r\n\tid: 'leaveEditorMessage',\r\n\tprecondition: MessageController.MESSAGE_VISIBLE,\r\n\thandler: c => c.closeMessage(),\r\n\tkbOpts: {\r\n\t\tweight: KeybindingWeight.EditorContrib + 30,\r\n\t\tprimary: KeyCode.Escape\r\n\t}\r\n}));\r\n\r\nclass MessageWidget implements IContentWidget {\r\n\r\n\t// Editor.IContentWidget.allowEditorOverflow\r\n\treadonly allowEditorOverflow = true;\r\n\treadonly suppressMouseDown = false;\r\n\r\n\tprivate readonly _editor: ICodeEditor;\r\n\tprivate readonly _position: IPosition;\r\n\tprivate readonly _domNode: HTMLDivElement;\r\n\r\n\tstatic fadeOut(messageWidget: MessageWidget): IDisposable {\r\n\t\tlet handle: any;\r\n\t\tconst dispose = () => {\r\n\t\t\tmessageWidget.dispose();\r\n\t\t\tclearTimeout(handle);\r\n\t\t\tmessageWidget.getDomNode().removeEventListener('animationend', dispose);\r\n\t\t};\r\n\t\thandle = setTimeout(dispose, 110);\r\n\t\tmessageWidget.getDomNode().addEventListener('animationend', dispose);\r\n\t\tmessageWidget.getDomNode().classList.add('fadeOut');\r\n\t\treturn { dispose };\r\n\t}\r\n\r\n\tconstructor(editor: ICodeEditor, { lineNumber, column }: IPosition, text: string) {\r\n\r\n\t\tthis._editor = editor;\r\n\t\tthis._editor.revealLinesInCenterIfOutsideViewport(lineNumber, lineNumber, ScrollType.Smooth);\r\n\t\tthis._position = { lineNumber, column: column - 1 };\r\n\r\n\t\tthis._domNode = document.createElement('div');\r\n\t\tthis._domNode.classList.add('monaco-editor-overlaymessage');\r\n\r\n\t\tconst anchorTop = document.createElement('div');\r\n\t\tanchorTop.classList.add('anchor', 'top');\r\n\t\tthis._domNode.appendChild(anchorTop);\r\n\r\n\t\tconst message = document.createElement('div');\r\n\t\tmessage.classList.add('message');\r\n\t\tmessage.textContent = text;\r\n\t\tthis._domNode.appendChild(message);\r\n\r\n\t\tconst anchorBottom = document.createElement('div');\r\n\t\tanchorBottom.classList.add('anchor', 'below');\r\n\t\tthis._domNode.appendChild(anchorBottom);\r\n\r\n\t\tthis._editor.addContentWidget(this);\r\n\t\tthis._domNode.classList.add('fadeIn');\r\n\t}\r\n\r\n\tdispose() {\r\n\t\tthis._editor.removeContentWidget(this);\r\n\t}\r\n\r\n\tgetId(): string {\r\n\t\treturn 'messageoverlay';\r\n\t}\r\n\r\n\tgetDomNode(): HTMLElement {\r\n\t\treturn this._domNode;\r\n\t}\r\n\r\n\tgetPosition(): IContentWidgetPosition {\r\n\t\treturn { position: this._position, preference: [ContentWidgetPositionPreference.ABOVE, ContentWidgetPositionPreference.BELOW] };\r\n\t}\r\n\r\n\tafterRender(position: ContentWidgetPositionPreference | null): void {\r\n\t\tthis._domNode.classList.toggle('below', position === ContentWidgetPositionPreference.BELOW);\r\n\t}\r\n\r\n}\r\n\r\nregisterEditorContribution(MessageController.ID, MessageController);\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst border = theme.getColor(inputValidationInfoBorder);\r\n\tif (border) {\r\n\t\tlet borderWidth = theme.type === ColorScheme.HIGH_CONTRAST ? 2 : 1;\r\n\t\tcollector.addRule(`.monaco-editor .monaco-editor-overlaymessage .anchor.below { border-top-color: ${border}; }`);\r\n\t\tcollector.addRule(`.monaco-editor .monaco-editor-overlaymessage .anchor.top { border-bottom-color: ${border}; }`);\r\n\t\tcollector.addRule(`.monaco-editor .monaco-editor-overlaymessage .message { border: ${borderWidth}px solid ${border}; }`);\r\n\t}\r\n\tconst background = theme.getColor(inputValidationInfoBackground);\r\n\tif (background) {\r\n\t\tcollector.addRule(`.monaco-editor .monaco-editor-overlaymessage .message { background-color: ${background}; }`);\r\n\t}\r\n\tconst foreground = theme.getColor(inputValidationInfoForeground);\r\n\tif (foreground) {\r\n\t\tcollector.addRule(`.monaco-editor .monaco-editor-overlaymessage .message { color: ${foreground}; }`);\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IAnchor } from 'vs/base/browser/ui/contextview/contextview';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport { Lazy } from 'vs/base/common/lazy';\r\nimport { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { IPosition } from 'vs/editor/common/core/position';\r\nimport { CodeActionTriggerType } from 'vs/editor/common/modes';\r\nimport { CodeActionItem, CodeActionSet } from 'vs/editor/contrib/codeAction/codeAction';\r\nimport { MessageController } from 'vs/editor/contrib/message/messageController';\r\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\r\nimport { CodeActionMenu, CodeActionShowOptions } from './codeActionMenu';\r\nimport { CodeActionsState } from './codeActionModel';\r\nimport { LightBulbWidget } from './lightBulbWidget';\r\nimport { CodeActionAutoApply, CodeActionTrigger } from './types';\r\n\r\nexport class CodeActionUi extends Disposable {\r\n\r\n\tprivate readonly _codeActionWidget: Lazy;\r\n\tprivate readonly _lightBulbWidget: Lazy;\r\n\tprivate readonly _activeCodeActions = this._register(new MutableDisposable());\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _editor: ICodeEditor,\r\n\t\tquickFixActionId: string,\r\n\t\tpreferredFixActionId: string,\r\n\t\tprivate readonly delegate: {\r\n\t\t\tapplyCodeAction: (action: CodeActionItem, regtriggerAfterApply: boolean) => Promise\r\n\t\t},\r\n\t\t@IInstantiationService instantiationService: IInstantiationService,\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\tthis._codeActionWidget = new Lazy(() => {\r\n\t\t\treturn this._register(instantiationService.createInstance(CodeActionMenu, this._editor, {\r\n\t\t\t\tonSelectCodeAction: async (action) => {\r\n\t\t\t\t\tthis.delegate.applyCodeAction(action, /* retrigger */ true);\r\n\t\t\t\t}\r\n\t\t\t}));\r\n\t\t});\r\n\r\n\t\tthis._lightBulbWidget = new Lazy(() => {\r\n\t\t\tconst widget = this._register(instantiationService.createInstance(LightBulbWidget, this._editor, quickFixActionId, preferredFixActionId));\r\n\t\t\tthis._register(widget.onClick(e => this.showCodeActionList(e.trigger, e.actions, e, { includeDisabledActions: false })));\r\n\t\t\treturn widget;\r\n\t\t});\r\n\t}\r\n\r\n\tpublic async update(newState: CodeActionsState.State): Promise {\r\n\t\tif (newState.type !== CodeActionsState.Type.Triggered) {\r\n\t\t\tthis._lightBulbWidget.rawValue?.hide();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet actions: CodeActionSet;\r\n\t\ttry {\r\n\t\t\tactions = await newState.actions;\r\n\t\t} catch (e) {\r\n\t\t\tonUnexpectedError(e);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._lightBulbWidget.getValue().update(actions, newState.trigger, newState.position);\r\n\r\n\t\tif (newState.trigger.type === CodeActionTriggerType.Manual) {\r\n\t\t\tif (newState.trigger.filter?.include) { // Triggered for specific scope\r\n\t\t\t\t// Check to see if we want to auto apply.\r\n\r\n\t\t\t\tconst validActionToApply = this.tryGetValidActionToApply(newState.trigger, actions);\r\n\t\t\t\tif (validActionToApply) {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tawait this.delegate.applyCodeAction(validActionToApply, false);\r\n\t\t\t\t\t} finally {\r\n\t\t\t\t\t\tactions.dispose();\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Check to see if there is an action that we would have applied were it not invalid\r\n\t\t\t\tif (newState.trigger.context) {\r\n\t\t\t\t\tconst invalidAction = this.getInvalidActionThatWouldHaveBeenApplied(newState.trigger, actions);\r\n\t\t\t\t\tif (invalidAction && invalidAction.action.disabled) {\r\n\t\t\t\t\t\tMessageController.get(this._editor).showMessage(invalidAction.action.disabled, newState.trigger.context.position);\r\n\t\t\t\t\t\tactions.dispose();\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tconst includeDisabledActions = !!newState.trigger.filter?.include;\r\n\t\t\tif (newState.trigger.context) {\r\n\t\t\t\tif (!actions.allActions.length || !includeDisabledActions && !actions.validActions.length) {\r\n\t\t\t\t\tMessageController.get(this._editor).showMessage(newState.trigger.context.notAvailableMessage, newState.trigger.context.position);\r\n\t\t\t\t\tthis._activeCodeActions.value = actions;\r\n\t\t\t\t\tactions.dispose();\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tthis._activeCodeActions.value = actions;\r\n\t\t\tthis._codeActionWidget.getValue().show(newState.trigger, actions, newState.position, { includeDisabledActions });\r\n\t\t} else {\r\n\t\t\t// auto magically triggered\r\n\t\t\tif (this._codeActionWidget.getValue().isVisible) {\r\n\t\t\t\t// TODO: Figure out if we should update the showing menu?\r\n\t\t\t\tactions.dispose();\r\n\t\t\t} else {\r\n\t\t\t\tthis._activeCodeActions.value = actions;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate getInvalidActionThatWouldHaveBeenApplied(trigger: CodeActionTrigger, actions: CodeActionSet): CodeActionItem | undefined {\r\n\t\tif (!actions.allActions.length) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\r\n\t\tif ((trigger.autoApply === CodeActionAutoApply.First && actions.validActions.length === 0)\r\n\t\t\t|| (trigger.autoApply === CodeActionAutoApply.IfSingle && actions.allActions.length === 1)\r\n\t\t) {\r\n\t\t\treturn actions.allActions.find(({ action }) => action.disabled);\r\n\t\t}\r\n\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tprivate tryGetValidActionToApply(trigger: CodeActionTrigger, actions: CodeActionSet): CodeActionItem | undefined {\r\n\t\tif (!actions.validActions.length) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\r\n\t\tif ((trigger.autoApply === CodeActionAutoApply.First && actions.validActions.length > 0)\r\n\t\t\t|| (trigger.autoApply === CodeActionAutoApply.IfSingle && actions.validActions.length === 1)\r\n\t\t) {\r\n\t\t\treturn actions.validActions[0];\r\n\t\t}\r\n\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\tpublic async showCodeActionList(trigger: CodeActionTrigger, actions: CodeActionSet, at: IAnchor | IPosition, options: CodeActionShowOptions): Promise {\r\n\t\tthis._codeActionWidget.getValue().show(trigger, actions, at, options);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IAnchor } from 'vs/base/browser/ui/contextview/contextview';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { IJSONSchema } from 'vs/base/common/jsonSchema';\r\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { Lazy } from 'vs/base/common/lazy';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { escapeRegExpCharacters } from 'vs/base/common/strings';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction, EditorCommand, ServicesAccessor } from 'vs/editor/browser/editorExtensions';\r\nimport { IBulkEditService, ResourceEdit } from 'vs/editor/browser/services/bulkEditService';\r\nimport { IPosition } from 'vs/editor/common/core/position';\r\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { CodeActionTriggerType } from 'vs/editor/common/modes';\r\nimport { codeActionCommandId, CodeActionItem, CodeActionSet, fixAllCommandId, organizeImportsCommandId, refactorCommandId, sourceActionCommandId } from 'vs/editor/contrib/codeAction/codeAction';\r\nimport { CodeActionUi } from 'vs/editor/contrib/codeAction/codeActionUi';\r\nimport { MessageController } from 'vs/editor/contrib/message/messageController';\r\nimport * as nls from 'vs/nls';\r\nimport { ICommandService } from 'vs/platform/commands/common/commands';\r\nimport { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { IMarkerService } from 'vs/platform/markers/common/markers';\r\nimport { INotificationService } from 'vs/platform/notification/common/notification';\r\nimport { IEditorProgressService } from 'vs/platform/progress/common/progress';\r\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\r\nimport { CodeActionModel, CodeActionsState, SUPPORTED_CODE_ACTIONS } from './codeActionModel';\r\nimport { CodeActionAutoApply, CodeActionCommandArgs, CodeActionFilter, CodeActionKind, CodeActionTrigger } from './types';\r\n\r\nfunction contextKeyForSupportedActions(kind: CodeActionKind) {\r\n\treturn ContextKeyExpr.regex(\r\n\t\tSUPPORTED_CODE_ACTIONS.keys()[0],\r\n\t\tnew RegExp('(\\\\s|^)' + escapeRegExpCharacters(kind.value) + '\\\\b'));\r\n}\r\n\r\nconst argsSchema: IJSONSchema = {\r\n\ttype: 'object',\r\n\tdefaultSnippets: [{ body: { kind: '' } }],\r\n\tproperties: {\r\n\t\t'kind': {\r\n\t\t\ttype: 'string',\r\n\t\t\tdescription: nls.localize('args.schema.kind', \"Kind of the code action to run.\"),\r\n\t\t},\r\n\t\t'apply': {\r\n\t\t\ttype: 'string',\r\n\t\t\tdescription: nls.localize('args.schema.apply', \"Controls when the returned actions are applied.\"),\r\n\t\t\tdefault: CodeActionAutoApply.IfSingle,\r\n\t\t\tenum: [CodeActionAutoApply.First, CodeActionAutoApply.IfSingle, CodeActionAutoApply.Never],\r\n\t\t\tenumDescriptions: [\r\n\t\t\t\tnls.localize('args.schema.apply.first', \"Always apply the first returned code action.\"),\r\n\t\t\t\tnls.localize('args.schema.apply.ifSingle', \"Apply the first returned code action if it is the only one.\"),\r\n\t\t\t\tnls.localize('args.schema.apply.never', \"Do not apply the returned code actions.\"),\r\n\t\t\t]\r\n\t\t},\r\n\t\t'preferred': {\r\n\t\t\ttype: 'boolean',\r\n\t\t\tdefault: false,\r\n\t\t\tdescription: nls.localize('args.schema.preferred', \"Controls if only preferred code actions should be returned.\"),\r\n\t\t}\r\n\t}\r\n};\r\n\r\nexport class QuickFixController extends Disposable implements IEditorContribution {\r\n\r\n\tpublic static readonly ID = 'editor.contrib.quickFixController';\r\n\r\n\tpublic static get(editor: ICodeEditor): QuickFixController {\r\n\t\treturn editor.getContribution(QuickFixController.ID);\r\n\t}\r\n\r\n\tprivate readonly _editor: ICodeEditor;\r\n\tprivate readonly _model: CodeActionModel;\r\n\tprivate readonly _ui: Lazy;\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor,\r\n\t\t@IMarkerService markerService: IMarkerService,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\r\n\t\t@IEditorProgressService progressService: IEditorProgressService,\r\n\t\t@IInstantiationService private readonly _instantiationService: IInstantiationService,\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\tthis._editor = editor;\r\n\t\tthis._model = this._register(new CodeActionModel(this._editor, markerService, contextKeyService, progressService));\r\n\t\tthis._register(this._model.onDidChangeState(newState => this.update(newState)));\r\n\r\n\t\tthis._ui = new Lazy(() =>\r\n\t\t\tthis._register(new CodeActionUi(editor, QuickFixAction.Id, AutoFixAction.Id, {\r\n\t\t\t\tapplyCodeAction: async (action, retrigger) => {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tawait this._applyCodeAction(action);\r\n\t\t\t\t\t} finally {\r\n\t\t\t\t\t\tif (retrigger) {\r\n\t\t\t\t\t\t\tthis._trigger({ type: CodeActionTriggerType.Auto, filter: {} });\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}, this._instantiationService))\r\n\t\t);\r\n\t}\r\n\r\n\tprivate update(newState: CodeActionsState.State): void {\r\n\t\tthis._ui.getValue().update(newState);\r\n\t}\r\n\r\n\tpublic showCodeActions(trigger: CodeActionTrigger, actions: CodeActionSet, at: IAnchor | IPosition) {\r\n\t\treturn this._ui.getValue().showCodeActionList(trigger, actions, at, { includeDisabledActions: false });\r\n\t}\r\n\r\n\tpublic manualTriggerAtCurrentPosition(\r\n\t\tnotAvailableMessage: string,\r\n\t\tfilter?: CodeActionFilter,\r\n\t\tautoApply?: CodeActionAutoApply\r\n\t): void {\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tMessageController.get(this._editor).closeMessage();\r\n\t\tconst triggerPosition = this._editor.getPosition();\r\n\t\tthis._trigger({ type: CodeActionTriggerType.Manual, filter, autoApply, context: { notAvailableMessage, position: triggerPosition } });\r\n\t}\r\n\r\n\tprivate _trigger(trigger: CodeActionTrigger) {\r\n\t\treturn this._model.trigger(trigger);\r\n\t}\r\n\r\n\tprivate _applyCodeAction(action: CodeActionItem): Promise {\r\n\t\treturn this._instantiationService.invokeFunction(applyCodeAction, action, this._editor);\r\n\t}\r\n}\r\n\r\nexport async function applyCodeAction(\r\n\taccessor: ServicesAccessor,\r\n\titem: CodeActionItem,\r\n\teditor?: ICodeEditor,\r\n): Promise {\r\n\tconst bulkEditService = accessor.get(IBulkEditService);\r\n\tconst commandService = accessor.get(ICommandService);\r\n\tconst telemetryService = accessor.get(ITelemetryService);\r\n\tconst notificationService = accessor.get(INotificationService);\r\n\r\n\ttype ApplyCodeActionEvent = {\r\n\t\tcodeActionTitle: string;\r\n\t\tcodeActionKind: string | undefined;\r\n\t\tcodeActionIsPreferred: boolean;\r\n\t};\r\n\ttype ApplyCodeEventClassification = {\r\n\t\tcodeActionTitle: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };\r\n\t\tcodeActionKind: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };\r\n\t\tcodeActionIsPreferred: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };\r\n\t};\r\n\r\n\ttelemetryService.publicLog2('codeAction.applyCodeAction', {\r\n\t\tcodeActionTitle: item.action.title,\r\n\t\tcodeActionKind: item.action.kind,\r\n\t\tcodeActionIsPreferred: !!item.action.isPreferred,\r\n\t});\r\n\r\n\tawait item.resolve(CancellationToken.None);\r\n\r\n\tif (item.action.edit) {\r\n\t\tawait bulkEditService.apply(ResourceEdit.convert(item.action.edit), { editor, label: item.action.title });\r\n\t}\r\n\r\n\tif (item.action.command) {\r\n\t\ttry {\r\n\t\t\tawait commandService.executeCommand(item.action.command.id, ...(item.action.command.arguments || []));\r\n\t\t} catch (err) {\r\n\t\t\tconst message = asMessage(err);\r\n\t\t\tnotificationService.error(\r\n\t\t\t\ttypeof message === 'string'\r\n\t\t\t\t\t? message\r\n\t\t\t\t\t: nls.localize('applyCodeActionFailed', \"An unknown error occurred while applying the code action\"));\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction asMessage(err: any): string | undefined {\r\n\tif (typeof err === 'string') {\r\n\t\treturn err;\r\n\t} else if (err instanceof Error && typeof err.message === 'string') {\r\n\t\treturn err.message;\r\n\t} else {\r\n\t\treturn undefined;\r\n\t}\r\n}\r\n\r\nfunction triggerCodeActionsForEditorSelection(\r\n\teditor: ICodeEditor,\r\n\tnotAvailableMessage: string,\r\n\tfilter: CodeActionFilter | undefined,\r\n\tautoApply: CodeActionAutoApply | undefined\r\n): void {\r\n\tif (editor.hasModel()) {\r\n\t\tconst controller = QuickFixController.get(editor);\r\n\t\tif (controller) {\r\n\t\t\tcontroller.manualTriggerAtCurrentPosition(notAvailableMessage, filter, autoApply);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class QuickFixAction extends EditorAction {\r\n\r\n\tstatic readonly Id = 'editor.action.quickFix';\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: QuickFixAction.Id,\r\n\t\t\tlabel: nls.localize('quickfix.trigger.label', \"Quick Fix...\"),\r\n\t\t\talias: 'Quick Fix...',\r\n\t\t\tprecondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider),\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.US_DOT,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\treturn triggerCodeActionsForEditorSelection(editor, nls.localize('editor.action.quickFix.noneMessage', \"No code actions available\"), undefined, undefined);\r\n\t}\r\n}\r\n\r\nexport class CodeActionCommand extends EditorCommand {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: codeActionCommandId,\r\n\t\t\tprecondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider),\r\n\t\t\tdescription: {\r\n\t\t\t\tdescription: 'Trigger a code action',\r\n\t\t\t\targs: [{ name: 'args', schema: argsSchema, }]\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic runEditorCommand(_accessor: ServicesAccessor, editor: ICodeEditor, userArgs: any) {\r\n\t\tconst args = CodeActionCommandArgs.fromUser(userArgs, {\r\n\t\t\tkind: CodeActionKind.Empty,\r\n\t\t\tapply: CodeActionAutoApply.IfSingle,\r\n\t\t});\r\n\t\treturn triggerCodeActionsForEditorSelection(editor,\r\n\t\t\ttypeof userArgs?.kind === 'string'\r\n\t\t\t\t? args.preferred\r\n\t\t\t\t\t? nls.localize('editor.action.codeAction.noneMessage.preferred.kind', \"No preferred code actions for '{0}' available\", userArgs.kind)\r\n\t\t\t\t\t: nls.localize('editor.action.codeAction.noneMessage.kind', \"No code actions for '{0}' available\", userArgs.kind)\r\n\t\t\t\t: args.preferred\r\n\t\t\t\t\t? nls.localize('editor.action.codeAction.noneMessage.preferred', \"No preferred code actions available\")\r\n\t\t\t\t\t: nls.localize('editor.action.codeAction.noneMessage', \"No code actions available\"),\r\n\t\t\t{\r\n\t\t\t\tinclude: args.kind,\r\n\t\t\t\tincludeSourceActions: true,\r\n\t\t\t\tonlyIncludePreferredActions: args.preferred,\r\n\t\t\t},\r\n\t\t\targs.apply);\r\n\t}\r\n}\r\n\r\n\r\nexport class RefactorAction extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: refactorCommandId,\r\n\t\t\tlabel: nls.localize('refactor.label', \"Refactor...\"),\r\n\t\t\talias: 'Refactor...',\r\n\t\t\tprecondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider),\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_R,\r\n\t\t\t\tmac: {\r\n\t\t\t\t\tprimary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_R\r\n\t\t\t\t},\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tcontextMenuOpts: {\r\n\t\t\t\tgroup: '1_modification',\r\n\t\t\t\torder: 2,\r\n\t\t\t\twhen: ContextKeyExpr.and(\r\n\t\t\t\t\tEditorContextKeys.writable,\r\n\t\t\t\t\tcontextKeyForSupportedActions(CodeActionKind.Refactor)),\r\n\t\t\t},\r\n\t\t\tdescription: {\r\n\t\t\t\tdescription: 'Refactor...',\r\n\t\t\t\targs: [{ name: 'args', schema: argsSchema }]\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor, userArgs: any): void {\r\n\t\tconst args = CodeActionCommandArgs.fromUser(userArgs, {\r\n\t\t\tkind: CodeActionKind.Refactor,\r\n\t\t\tapply: CodeActionAutoApply.Never\r\n\t\t});\r\n\t\treturn triggerCodeActionsForEditorSelection(editor,\r\n\t\t\ttypeof userArgs?.kind === 'string'\r\n\t\t\t\t? args.preferred\r\n\t\t\t\t\t? nls.localize('editor.action.refactor.noneMessage.preferred.kind', \"No preferred refactorings for '{0}' available\", userArgs.kind)\r\n\t\t\t\t\t: nls.localize('editor.action.refactor.noneMessage.kind', \"No refactorings for '{0}' available\", userArgs.kind)\r\n\t\t\t\t: args.preferred\r\n\t\t\t\t\t? nls.localize('editor.action.refactor.noneMessage.preferred', \"No preferred refactorings available\")\r\n\t\t\t\t\t: nls.localize('editor.action.refactor.noneMessage', \"No refactorings available\"),\r\n\t\t\t{\r\n\t\t\t\tinclude: CodeActionKind.Refactor.contains(args.kind) ? args.kind : CodeActionKind.None,\r\n\t\t\t\tonlyIncludePreferredActions: args.preferred,\r\n\t\t\t},\r\n\t\t\targs.apply);\r\n\t}\r\n}\r\n\r\nexport class SourceAction extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: sourceActionCommandId,\r\n\t\t\tlabel: nls.localize('source.label', \"Source Action...\"),\r\n\t\t\talias: 'Source Action...',\r\n\t\t\tprecondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider),\r\n\t\t\tcontextMenuOpts: {\r\n\t\t\t\tgroup: '1_modification',\r\n\t\t\t\torder: 2.1,\r\n\t\t\t\twhen: ContextKeyExpr.and(\r\n\t\t\t\t\tEditorContextKeys.writable,\r\n\t\t\t\t\tcontextKeyForSupportedActions(CodeActionKind.Source)),\r\n\t\t\t},\r\n\t\t\tdescription: {\r\n\t\t\t\tdescription: 'Source Action...',\r\n\t\t\t\targs: [{ name: 'args', schema: argsSchema }]\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor, userArgs: any): void {\r\n\t\tconst args = CodeActionCommandArgs.fromUser(userArgs, {\r\n\t\t\tkind: CodeActionKind.Source,\r\n\t\t\tapply: CodeActionAutoApply.Never\r\n\t\t});\r\n\t\treturn triggerCodeActionsForEditorSelection(editor,\r\n\t\t\ttypeof userArgs?.kind === 'string'\r\n\t\t\t\t? args.preferred\r\n\t\t\t\t\t? nls.localize('editor.action.source.noneMessage.preferred.kind', \"No preferred source actions for '{0}' available\", userArgs.kind)\r\n\t\t\t\t\t: nls.localize('editor.action.source.noneMessage.kind', \"No source actions for '{0}' available\", userArgs.kind)\r\n\t\t\t\t: args.preferred\r\n\t\t\t\t\t? nls.localize('editor.action.source.noneMessage.preferred', \"No preferred source actions available\")\r\n\t\t\t\t\t: nls.localize('editor.action.source.noneMessage', \"No source actions available\"),\r\n\t\t\t{\r\n\t\t\t\tinclude: CodeActionKind.Source.contains(args.kind) ? args.kind : CodeActionKind.None,\r\n\t\t\t\tincludeSourceActions: true,\r\n\t\t\t\tonlyIncludePreferredActions: args.preferred,\r\n\t\t\t},\r\n\t\t\targs.apply);\r\n\t}\r\n}\r\n\r\nexport class OrganizeImportsAction extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: organizeImportsCommandId,\r\n\t\t\tlabel: nls.localize('organizeImports.label', \"Organize Imports\"),\r\n\t\t\talias: 'Organize Imports',\r\n\t\t\tprecondition: ContextKeyExpr.and(\r\n\t\t\t\tEditorContextKeys.writable,\r\n\t\t\t\tcontextKeyForSupportedActions(CodeActionKind.SourceOrganizeImports)),\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_O,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\treturn triggerCodeActionsForEditorSelection(editor,\r\n\t\t\tnls.localize('editor.action.organize.noneMessage', \"No organize imports action available\"),\r\n\t\t\t{ include: CodeActionKind.SourceOrganizeImports, includeSourceActions: true },\r\n\t\t\tCodeActionAutoApply.IfSingle);\r\n\t}\r\n}\r\n\r\nexport class FixAllAction extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: fixAllCommandId,\r\n\t\t\tlabel: nls.localize('fixAll.label', \"Fix All\"),\r\n\t\t\talias: 'Fix All',\r\n\t\t\tprecondition: ContextKeyExpr.and(\r\n\t\t\t\tEditorContextKeys.writable,\r\n\t\t\t\tcontextKeyForSupportedActions(CodeActionKind.SourceFixAll))\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\treturn triggerCodeActionsForEditorSelection(editor,\r\n\t\t\tnls.localize('fixAll.noneMessage', \"No fix all action available\"),\r\n\t\t\t{ include: CodeActionKind.SourceFixAll, includeSourceActions: true },\r\n\t\t\tCodeActionAutoApply.IfSingle);\r\n\t}\r\n}\r\n\r\nexport class AutoFixAction extends EditorAction {\r\n\r\n\tstatic readonly Id = 'editor.action.autoFix';\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: AutoFixAction.Id,\r\n\t\t\tlabel: nls.localize('autoFix.label', \"Auto Fix...\"),\r\n\t\t\talias: 'Auto Fix...',\r\n\t\t\tprecondition: ContextKeyExpr.and(\r\n\t\t\t\tEditorContextKeys.writable,\r\n\t\t\t\tcontextKeyForSupportedActions(CodeActionKind.QuickFix)),\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.Alt | KeyMod.Shift | KeyCode.US_DOT,\r\n\t\t\t\tmac: {\r\n\t\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.US_DOT\r\n\t\t\t\t},\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\treturn triggerCodeActionsForEditorSelection(editor,\r\n\t\t\tnls.localize('editor.action.autoFix.noneMessage', \"No auto fixes available\"),\r\n\t\t\t{\r\n\t\t\t\tinclude: CodeActionKind.QuickFix,\r\n\t\t\t\tonlyIncludePreferredActions: true\r\n\t\t\t},\r\n\t\t\tCodeActionAutoApply.IfSingle);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { registerEditorAction, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions';\r\nimport { CodeActionCommand, OrganizeImportsAction, QuickFixAction, QuickFixController, RefactorAction, SourceAction, AutoFixAction, FixAllAction } from 'vs/editor/contrib/codeAction/codeActionCommands';\r\n\r\n\r\nregisterEditorContribution(QuickFixController.ID, QuickFixController);\r\nregisterEditorAction(QuickFixAction);\r\nregisterEditorAction(RefactorAction);\r\nregisterEditorAction(SourceAction);\r\nregisterEditorAction(OrganizeImportsAction);\r\nregisterEditorAction(AutoFixAction);\r\nregisterEditorAction(FixAllAction);\r\nregisterEditorCommand(new CodeActionCommand());\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport { KeyMod, KeyCode } from 'vs/base/common/keyCodes';\r\nimport { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IEditorProgressService } from 'vs/platform/progress/common/progress';\r\nimport { registerEditorAction, registerEditorContribution, ServicesAccessor, EditorAction, EditorCommand, registerEditorCommand, registerModelAndPositionCommand } from 'vs/editor/browser/editorExtensions';\r\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { RenameInputField, CONTEXT_RENAME_INPUT_VISIBLE } from './renameInputField';\r\nimport { WorkspaceEdit, RenameProviderRegistry, RenameProvider, RenameLocation, Rejection } from 'vs/editor/common/modes';\r\nimport { Position, IPosition } from 'vs/editor/common/core/position';\r\nimport { alert } from 'vs/base/browser/ui/aria/aria';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { MessageController } from 'vs/editor/contrib/message/messageController';\r\nimport { CodeEditorStateFlag, EditorStateCancellationTokenSource } from 'vs/editor/browser/core/editorState';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { INotificationService } from 'vs/platform/notification/common/notification';\r\nimport { IBulkEditService, ResourceEdit } from 'vs/editor/browser/services/bulkEditService';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\r\nimport { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\r\nimport { DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { IdleValue, raceCancellation } from 'vs/base/common/async';\r\nimport { ILogService } from 'vs/platform/log/common/log';\r\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\r\nimport { Registry } from 'vs/platform/registry/common/platform';\r\nimport { IConfigurationRegistry, ConfigurationScope, Extensions } from 'vs/platform/configuration/common/configurationRegistry';\r\nimport { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfigurationService';\r\nimport { assertType } from 'vs/base/common/types';\r\n\r\nclass RenameSkeleton {\r\n\r\n\tprivate readonly _providers: RenameProvider[];\r\n\tprivate _providerRenameIdx: number = 0;\r\n\r\n\tconstructor(\r\n\t\tprivate readonly model: ITextModel,\r\n\t\tprivate readonly position: Position\r\n\t) {\r\n\t\tthis._providers = RenameProviderRegistry.ordered(model);\r\n\t}\r\n\r\n\thasProvider() {\r\n\t\treturn this._providers.length > 0;\r\n\t}\r\n\r\n\tasync resolveRenameLocation(token: CancellationToken): Promise {\r\n\r\n\t\tconst rejects: string[] = [];\r\n\r\n\t\tfor (this._providerRenameIdx = 0; this._providerRenameIdx < this._providers.length; this._providerRenameIdx++) {\r\n\t\t\tconst provider = this._providers[this._providerRenameIdx];\r\n\t\t\tif (!provider.resolveRenameLocation) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tlet res = await provider.resolveRenameLocation(this.model, this.position, token);\r\n\t\t\tif (!res) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (res.rejectReason) {\r\n\t\t\t\trejects.push(res.rejectReason);\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\treturn res;\r\n\t\t}\r\n\r\n\t\tconst word = this.model.getWordAtPosition(this.position);\r\n\t\tif (!word) {\r\n\t\t\treturn {\r\n\t\t\t\trange: Range.fromPositions(this.position),\r\n\t\t\t\ttext: '',\r\n\t\t\t\trejectReason: rejects.length > 0 ? rejects.join('\\n') : undefined\r\n\t\t\t};\r\n\t\t}\r\n\t\treturn {\r\n\t\t\trange: new Range(this.position.lineNumber, word.startColumn, this.position.lineNumber, word.endColumn),\r\n\t\t\ttext: word.word,\r\n\t\t\trejectReason: rejects.length > 0 ? rejects.join('\\n') : undefined\r\n\t\t};\r\n\t}\r\n\r\n\tasync provideRenameEdits(newName: string, token: CancellationToken): Promise {\r\n\t\treturn this._provideRenameEdits(newName, this._providerRenameIdx, [], token);\r\n\t}\r\n\r\n\tprivate async _provideRenameEdits(newName: string, i: number, rejects: string[], token: CancellationToken): Promise {\r\n\t\tconst provider = this._providers[i];\r\n\t\tif (!provider) {\r\n\t\t\treturn {\r\n\t\t\t\tedits: [],\r\n\t\t\t\trejectReason: rejects.join('\\n')\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tconst result = await provider.provideRenameEdits(this.model, this.position, newName, token);\r\n\t\tif (!result) {\r\n\t\t\treturn this._provideRenameEdits(newName, i + 1, rejects.concat(nls.localize('no result', \"No result.\")), token);\r\n\t\t} else if (result.rejectReason) {\r\n\t\t\treturn this._provideRenameEdits(newName, i + 1, rejects.concat(result.rejectReason), token);\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n}\r\n\r\nexport async function rename(model: ITextModel, position: Position, newName: string): Promise {\r\n\tconst skeleton = new RenameSkeleton(model, position);\r\n\tconst loc = await skeleton.resolveRenameLocation(CancellationToken.None);\r\n\tif (loc?.rejectReason) {\r\n\t\treturn { edits: [], rejectReason: loc.rejectReason };\r\n\t}\r\n\treturn skeleton.provideRenameEdits(newName, CancellationToken.None);\r\n}\r\n\r\n// --- register actions and commands\r\n\r\nclass RenameController implements IEditorContribution {\r\n\r\n\tpublic static readonly ID = 'editor.contrib.renameController';\r\n\r\n\tstatic get(editor: ICodeEditor): RenameController {\r\n\t\treturn editor.getContribution(RenameController.ID);\r\n\t}\r\n\r\n\tprivate readonly _renameInputField: IdleValue;\r\n\tprivate readonly _dispoableStore = new DisposableStore();\r\n\tprivate _cts: CancellationTokenSource = new CancellationTokenSource();\r\n\r\n\tconstructor(\r\n\t\tprivate readonly editor: ICodeEditor,\r\n\t\t@IInstantiationService private readonly _instaService: IInstantiationService,\r\n\t\t@INotificationService private readonly _notificationService: INotificationService,\r\n\t\t@IBulkEditService private readonly _bulkEditService: IBulkEditService,\r\n\t\t@IEditorProgressService private readonly _progressService: IEditorProgressService,\r\n\t\t@ILogService private readonly _logService: ILogService,\r\n\t\t@ITextResourceConfigurationService private readonly _configService: ITextResourceConfigurationService,\r\n\t) {\r\n\t\tthis._renameInputField = this._dispoableStore.add(new IdleValue(() => this._dispoableStore.add(this._instaService.createInstance(RenameInputField, this.editor, ['acceptRenameInput', 'acceptRenameInputWithPreview']))));\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._dispoableStore.dispose();\r\n\t\tthis._cts.dispose(true);\r\n\t}\r\n\r\n\tasync run(): Promise {\r\n\r\n\t\tthis._cts.dispose(true);\r\n\r\n\t\tif (!this.editor.hasModel()) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\r\n\t\tconst position = this.editor.getPosition();\r\n\t\tconst skeleton = new RenameSkeleton(this.editor.getModel(), position);\r\n\r\n\t\tif (!skeleton.hasProvider()) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\r\n\t\tthis._cts = new EditorStateCancellationTokenSource(this.editor, CodeEditorStateFlag.Position | CodeEditorStateFlag.Value);\r\n\r\n\t\t// resolve rename location\r\n\t\tlet loc: RenameLocation & Rejection | undefined;\r\n\t\ttry {\r\n\t\t\tconst resolveLocationOperation = skeleton.resolveRenameLocation(this._cts.token);\r\n\t\t\tthis._progressService.showWhile(resolveLocationOperation, 250);\r\n\t\t\tloc = await resolveLocationOperation;\r\n\t\t} catch (e) {\r\n\t\t\tMessageController.get(this.editor).showMessage(e || nls.localize('resolveRenameLocationFailed', \"An unknown error occurred while resolving rename location\"), position);\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\r\n\t\tif (!loc) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\r\n\t\tif (loc.rejectReason) {\r\n\t\t\tMessageController.get(this.editor).showMessage(loc.rejectReason, position);\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\r\n\t\tif (this._cts.token.isCancellationRequested) {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\t\tthis._cts.dispose();\r\n\t\tthis._cts = new EditorStateCancellationTokenSource(this.editor, CodeEditorStateFlag.Position | CodeEditorStateFlag.Value, loc.range);\r\n\r\n\t\t// do rename at location\r\n\t\tlet selection = this.editor.getSelection();\r\n\t\tlet selectionStart = 0;\r\n\t\tlet selectionEnd = loc.text.length;\r\n\r\n\t\tif (!Range.isEmpty(selection) && !Range.spansMultipleLines(selection) && Range.containsRange(loc.range, selection)) {\r\n\t\t\tselectionStart = Math.max(0, selection.startColumn - loc.range.startColumn);\r\n\t\t\tselectionEnd = Math.min(loc.range.endColumn, selection.endColumn) - loc.range.startColumn;\r\n\t\t}\r\n\r\n\t\tconst supportPreview = this._bulkEditService.hasPreviewHandler() && this._configService.getValue(this.editor.getModel().uri, 'editor.rename.enablePreview');\r\n\t\tconst inputFieldResult = await this._renameInputField.value.getInput(loc.range, loc.text, selectionStart, selectionEnd, supportPreview, this._cts.token);\r\n\r\n\t\t// no result, only hint to focus the editor or not\r\n\t\tif (typeof inputFieldResult === 'boolean') {\r\n\t\t\tif (inputFieldResult) {\r\n\t\t\t\tthis.editor.focus();\r\n\t\t\t}\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\r\n\t\tthis.editor.focus();\r\n\r\n\t\tconst renameOperation = raceCancellation(skeleton.provideRenameEdits(inputFieldResult.newName, this._cts.token), this._cts.token).then(async renameResult => {\r\n\r\n\t\t\tif (!renameResult || !this.editor.hasModel()) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (renameResult.rejectReason) {\r\n\t\t\t\tthis._notificationService.info(renameResult.rejectReason);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tthis._bulkEditService.apply(ResourceEdit.convert(renameResult), {\r\n\t\t\t\teditor: this.editor,\r\n\t\t\t\tshowPreview: inputFieldResult.wantsPreview,\r\n\t\t\t\tlabel: nls.localize('label', \"Renaming '{0}'\", loc?.text),\r\n\t\t\t\tquotableLabel: nls.localize('quotableLabel', \"Renaming {0}\", loc?.text),\r\n\t\t\t}).then(result => {\r\n\t\t\t\tif (result.ariaSummary) {\r\n\t\t\t\t\talert(nls.localize('aria', \"Successfully renamed '{0}' to '{1}'. Summary: {2}\", loc!.text, inputFieldResult.newName, result.ariaSummary));\r\n\t\t\t\t}\r\n\t\t\t}).catch(err => {\r\n\t\t\t\tthis._notificationService.error(nls.localize('rename.failedApply', \"Rename failed to apply edits\"));\r\n\t\t\t\tthis._logService.error(err);\r\n\t\t\t});\r\n\r\n\t\t}, err => {\r\n\t\t\tthis._notificationService.error(nls.localize('rename.failed', \"Rename failed to compute edits\"));\r\n\t\t\tthis._logService.error(err);\r\n\t\t});\r\n\r\n\t\tthis._progressService.showWhile(renameOperation, 250);\r\n\t\treturn renameOperation;\r\n\r\n\t}\r\n\r\n\tacceptRenameInput(wantsPreview: boolean): void {\r\n\t\tthis._renameInputField.value.acceptInput(wantsPreview);\r\n\t}\r\n\r\n\tcancelRenameInput(): void {\r\n\t\tthis._renameInputField.value.cancelInput(true);\r\n\t}\r\n}\r\n\r\n// ---- action implementation\r\n\r\nexport class RenameAction extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.rename',\r\n\t\t\tlabel: nls.localize('rename.label', \"Rename Symbol\"),\r\n\t\t\talias: 'Rename Symbol',\r\n\t\t\tprecondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasRenameProvider),\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyCode.F2,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tcontextMenuOpts: {\r\n\t\t\t\tgroup: '1_modification',\r\n\t\t\t\torder: 1.1\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\trunCommand(accessor: ServicesAccessor, args: [URI, IPosition]): void | Promise {\r\n\t\tconst editorService = accessor.get(ICodeEditorService);\r\n\t\tconst [uri, pos] = Array.isArray(args) && args || [undefined, undefined];\r\n\r\n\t\tif (URI.isUri(uri) && Position.isIPosition(pos)) {\r\n\t\t\treturn editorService.openCodeEditor({ resource: uri }, editorService.getActiveCodeEditor()).then(editor => {\r\n\t\t\t\tif (!editor) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\teditor.setPosition(pos);\r\n\t\t\t\teditor.invokeWithinContext(accessor => {\r\n\t\t\t\t\tthis.reportTelemetry(accessor, editor);\r\n\t\t\t\t\treturn this.run(accessor, editor);\r\n\t\t\t\t});\r\n\t\t\t}, onUnexpectedError);\r\n\t\t}\r\n\r\n\t\treturn super.runCommand(accessor, args);\r\n\t}\r\n\r\n\trun(accessor: ServicesAccessor, editor: ICodeEditor): Promise {\r\n\t\tconst controller = RenameController.get(editor);\r\n\t\tif (controller) {\r\n\t\t\treturn controller.run();\r\n\t\t}\r\n\t\treturn Promise.resolve();\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(RenameController.ID, RenameController);\r\nregisterEditorAction(RenameAction);\r\n\r\nconst RenameCommand = EditorCommand.bindToContribution(RenameController.get);\r\n\r\nregisterEditorCommand(new RenameCommand({\r\n\tid: 'acceptRenameInput',\r\n\tprecondition: CONTEXT_RENAME_INPUT_VISIBLE,\r\n\thandler: x => x.acceptRenameInput(false),\r\n\tkbOpts: {\r\n\t\tweight: KeybindingWeight.EditorContrib + 99,\r\n\t\tkbExpr: EditorContextKeys.focus,\r\n\t\tprimary: KeyCode.Enter\r\n\t}\r\n}));\r\n\r\nregisterEditorCommand(new RenameCommand({\r\n\tid: 'acceptRenameInputWithPreview',\r\n\tprecondition: ContextKeyExpr.and(CONTEXT_RENAME_INPUT_VISIBLE, ContextKeyExpr.has('config.editor.rename.enablePreview')),\r\n\thandler: x => x.acceptRenameInput(true),\r\n\tkbOpts: {\r\n\t\tweight: KeybindingWeight.EditorContrib + 99,\r\n\t\tkbExpr: EditorContextKeys.focus,\r\n\t\tprimary: KeyMod.Shift + KeyCode.Enter\r\n\t}\r\n}));\r\n\r\nregisterEditorCommand(new RenameCommand({\r\n\tid: 'cancelRenameInput',\r\n\tprecondition: CONTEXT_RENAME_INPUT_VISIBLE,\r\n\thandler: x => x.cancelRenameInput(),\r\n\tkbOpts: {\r\n\t\tweight: KeybindingWeight.EditorContrib + 99,\r\n\t\tkbExpr: EditorContextKeys.focus,\r\n\t\tprimary: KeyCode.Escape,\r\n\t\tsecondary: [KeyMod.Shift | KeyCode.Escape]\r\n\t}\r\n}));\r\n\r\n// ---- api bridge command\r\n\r\nregisterModelAndPositionCommand('_executeDocumentRenameProvider', function (model, position, ...args) {\r\n\tconst [newName] = args;\r\n\tassertType(typeof newName === 'string');\r\n\treturn rename(model, position, newName);\r\n});\r\n\r\n\r\n//todo@jrieken use editor options world\r\nRegistry.as(Extensions.Configuration).registerConfiguration({\r\n\tid: 'editor',\r\n\tproperties: {\r\n\t\t'editor.rename.enablePreview': {\r\n\t\t\tscope: ConfigurationScope.LANGUAGE_OVERRIDABLE,\r\n\t\t\tdescription: nls.localize('enablePreview', \"Enable/disable the ability to preview changes before renaming\"),\r\n\t\t\tdefault: true,\r\n\t\t\ttype: 'boolean'\r\n\t\t}\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as arrays from 'vs/base/common/arrays';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction, IActionOptions, registerEditorAction, registerEditorContribution, ServicesAccessor, registerModelCommand } from 'vs/editor/browser/editorExtensions';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport * as modes from 'vs/editor/common/modes';\r\nimport * as nls from 'vs/nls';\r\nimport { MenuId } from 'vs/platform/actions/common/actions';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { WordSelectionRangeProvider } from 'vs/editor/contrib/smartSelect/wordSelections';\r\nimport { BracketSelectionRangeProvider } from 'vs/editor/contrib/smartSelect/bracketSelections';\r\nimport { CommandsRegistry } from 'vs/platform/commands/common/commands';\r\nimport { onUnexpectedExternalError } from 'vs/base/common/errors';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\nclass SelectionRanges {\r\n\r\n\tconstructor(\r\n\t\treadonly index: number,\r\n\t\treadonly ranges: Range[]\r\n\t) { }\r\n\r\n\tmov(fwd: boolean): SelectionRanges {\r\n\t\tlet index = this.index + (fwd ? 1 : -1);\r\n\t\tif (index < 0 || index >= this.ranges.length) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\tconst res = new SelectionRanges(index, this.ranges);\r\n\t\tif (res.ranges[index].equalsRange(this.ranges[this.index])) {\r\n\t\t\t// next range equals this range, retry with next-next\r\n\t\t\treturn res.mov(fwd);\r\n\t\t}\r\n\t\treturn res;\r\n\t}\r\n}\r\n\r\nclass SmartSelectController implements IEditorContribution {\r\n\r\n\tstatic readonly ID = 'editor.contrib.smartSelectController';\r\n\r\n\tstatic get(editor: ICodeEditor): SmartSelectController {\r\n\t\treturn editor.getContribution(SmartSelectController.ID);\r\n\t}\r\n\r\n\tprivate _state?: SelectionRanges[];\r\n\tprivate _selectionListener?: IDisposable;\r\n\tprivate _ignoreSelection: boolean = false;\r\n\r\n\tconstructor(private readonly _editor: ICodeEditor) { }\r\n\r\n\tdispose(): void {\r\n\t\tthis._selectionListener?.dispose();\r\n\t}\r\n\r\n\tasync run(forward: boolean): Promise {\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst selections = this._editor.getSelections();\r\n\t\tconst model = this._editor.getModel();\r\n\t\tif (!modes.SelectionRangeRegistry.has(model)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!this._state) {\r\n\r\n\t\t\tawait provideSelectionRanges(model, selections.map(s => s.getPosition()), this._editor.getOption(EditorOption.smartSelect), CancellationToken.None).then(ranges => {\r\n\t\t\t\tif (!arrays.isNonEmptyArray(ranges) || ranges.length !== selections.length) {\r\n\t\t\t\t\t// invalid result\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\tif (!this._editor.hasModel() || !arrays.equals(this._editor.getSelections(), selections, (a, b) => a.equalsSelection(b))) {\r\n\t\t\t\t\t// invalid editor state\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfor (let i = 0; i < ranges.length; i++) {\r\n\t\t\t\t\tranges[i] = ranges[i].filter(range => {\r\n\t\t\t\t\t\t// filter ranges inside the selection\r\n\t\t\t\t\t\treturn range.containsPosition(selections[i].getStartPosition()) && range.containsPosition(selections[i].getEndPosition());\r\n\t\t\t\t\t});\r\n\t\t\t\t\t// prepend current selection\r\n\t\t\t\t\tranges[i].unshift(selections[i]);\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\tthis._state = ranges.map(ranges => new SelectionRanges(0, ranges));\r\n\r\n\t\t\t\t// listen to caret move and forget about state\r\n\t\t\t\tthis._selectionListener?.dispose();\r\n\t\t\t\tthis._selectionListener = this._editor.onDidChangeCursorPosition(() => {\r\n\t\t\t\t\tif (!this._ignoreSelection) {\r\n\t\t\t\t\t\tthis._selectionListener?.dispose();\r\n\t\t\t\t\t\tthis._state = undefined;\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tif (!this._state) {\r\n\t\t\t// no state\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._state = this._state.map(state => state.mov(forward));\r\n\t\tconst newSelections = this._state.map(state => Selection.fromPositions(state.ranges[state.index].getStartPosition(), state.ranges[state.index].getEndPosition()));\r\n\t\tthis._ignoreSelection = true;\r\n\t\ttry {\r\n\t\t\tthis._editor.setSelections(newSelections);\r\n\t\t} finally {\r\n\t\t\tthis._ignoreSelection = false;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nabstract class AbstractSmartSelect extends EditorAction {\r\n\r\n\tprivate readonly _forward: boolean;\r\n\r\n\tconstructor(forward: boolean, opts: IActionOptions) {\r\n\t\tsuper(opts);\r\n\t\tthis._forward = forward;\r\n\t}\r\n\r\n\tasync run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise {\r\n\t\tlet controller = SmartSelectController.get(editor);\r\n\t\tif (controller) {\r\n\t\t\tawait controller.run(this._forward);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass GrowSelectionAction extends AbstractSmartSelect {\r\n\tconstructor() {\r\n\t\tsuper(true, {\r\n\t\t\tid: 'editor.action.smartSelect.expand',\r\n\t\t\tlabel: nls.localize('smartSelect.expand', \"Expand Selection\"),\r\n\t\t\talias: 'Expand Selection',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.Shift | KeyMod.Alt | KeyCode.RightArrow,\r\n\t\t\t\tmac: {\r\n\t\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyMod.Shift | KeyCode.RightArrow,\r\n\t\t\t\t\tsecondary: [KeyMod.WinCtrl | KeyMod.Shift | KeyCode.RightArrow],\r\n\t\t\t\t},\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tmenuOpts: {\r\n\t\t\t\tmenuId: MenuId.MenubarSelectionMenu,\r\n\t\t\t\tgroup: '1_basic',\r\n\t\t\t\ttitle: nls.localize({ key: 'miSmartSelectGrow', comment: ['&& denotes a mnemonic'] }, \"&&Expand Selection\"),\r\n\t\t\t\torder: 2\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n\r\n// renamed command id\r\nCommandsRegistry.registerCommandAlias('editor.action.smartSelect.grow', 'editor.action.smartSelect.expand');\r\n\r\nclass ShrinkSelectionAction extends AbstractSmartSelect {\r\n\tconstructor() {\r\n\t\tsuper(false, {\r\n\t\t\tid: 'editor.action.smartSelect.shrink',\r\n\t\t\tlabel: nls.localize('smartSelect.shrink', \"Shrink Selection\"),\r\n\t\t\talias: 'Shrink Selection',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.Shift | KeyMod.Alt | KeyCode.LeftArrow,\r\n\t\t\t\tmac: {\r\n\t\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyMod.Shift | KeyCode.LeftArrow,\r\n\t\t\t\t\tsecondary: [KeyMod.WinCtrl | KeyMod.Shift | KeyCode.LeftArrow],\r\n\t\t\t\t},\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tmenuOpts: {\r\n\t\t\t\tmenuId: MenuId.MenubarSelectionMenu,\r\n\t\t\t\tgroup: '1_basic',\r\n\t\t\t\ttitle: nls.localize({ key: 'miSmartSelectShrink', comment: ['&& denotes a mnemonic'] }, \"&&Shrink Selection\"),\r\n\t\t\t\torder: 3\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(SmartSelectController.ID, SmartSelectController);\r\nregisterEditorAction(GrowSelectionAction);\r\nregisterEditorAction(ShrinkSelectionAction);\r\n\r\n// word selection\r\nmodes.SelectionRangeRegistry.register('*', new WordSelectionRangeProvider());\r\n\r\nexport interface SelectionRangesOptions {\r\n\tselectLeadingAndTrailingWhitespace: boolean\r\n}\r\n\r\nexport async function provideSelectionRanges(model: ITextModel, positions: Position[], options: SelectionRangesOptions, token: CancellationToken): Promise {\r\n\r\n\tconst providers = modes.SelectionRangeRegistry.all(model);\r\n\r\n\tif (providers.length === 1) {\r\n\t\t// add word selection and bracket selection when no provider exists\r\n\t\tproviders.unshift(new BracketSelectionRangeProvider());\r\n\t}\r\n\r\n\tlet work: Promise[] = [];\r\n\tlet allRawRanges: Range[][] = [];\r\n\r\n\tfor (const provider of providers) {\r\n\r\n\t\twork.push(Promise.resolve(provider.provideSelectionRanges(model, positions, token)).then(allProviderRanges => {\r\n\t\t\tif (arrays.isNonEmptyArray(allProviderRanges) && allProviderRanges.length === positions.length) {\r\n\t\t\t\tfor (let i = 0; i < positions.length; i++) {\r\n\t\t\t\t\tif (!allRawRanges[i]) {\r\n\t\t\t\t\t\tallRawRanges[i] = [];\r\n\t\t\t\t\t}\r\n\t\t\t\t\tfor (const oneProviderRanges of allProviderRanges[i]) {\r\n\t\t\t\t\t\tif (Range.isIRange(oneProviderRanges.range) && Range.containsPosition(oneProviderRanges.range, positions[i])) {\r\n\t\t\t\t\t\t\tallRawRanges[i].push(Range.lift(oneProviderRanges.range));\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}, onUnexpectedExternalError));\r\n\t}\r\n\r\n\tawait Promise.all(work);\r\n\r\n\treturn allRawRanges.map(oneRawRanges => {\r\n\r\n\t\tif (oneRawRanges.length === 0) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\t// sort all by start/end position\r\n\t\toneRawRanges.sort((a, b) => {\r\n\t\t\tif (Position.isBefore(a.getStartPosition(), b.getStartPosition())) {\r\n\t\t\t\treturn 1;\r\n\t\t\t} else if (Position.isBefore(b.getStartPosition(), a.getStartPosition())) {\r\n\t\t\t\treturn -1;\r\n\t\t\t} else if (Position.isBefore(a.getEndPosition(), b.getEndPosition())) {\r\n\t\t\t\treturn -1;\r\n\t\t\t} else if (Position.isBefore(b.getEndPosition(), a.getEndPosition())) {\r\n\t\t\t\treturn 1;\r\n\t\t\t} else {\r\n\t\t\t\treturn 0;\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\t// remove ranges that don't contain the former range or that are equal to the\r\n\t\t// former range\r\n\t\tlet oneRanges: Range[] = [];\r\n\t\tlet last: Range | undefined;\r\n\t\tfor (const range of oneRawRanges) {\r\n\t\t\tif (!last || (Range.containsRange(range, last) && !Range.equalsRange(range, last))) {\r\n\t\t\t\toneRanges.push(range);\r\n\t\t\t\tlast = range;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!options.selectLeadingAndTrailingWhitespace) {\r\n\t\t\treturn oneRanges;\r\n\t\t}\r\n\r\n\t\t// add ranges that expand trivia at line starts and ends whenever a range\r\n\t\t// wraps onto the a new line\r\n\t\tlet oneRangesWithTrivia: Range[] = [oneRanges[0]];\r\n\t\tfor (let i = 1; i < oneRanges.length; i++) {\r\n\t\t\tconst prev = oneRanges[i - 1];\r\n\t\t\tconst cur = oneRanges[i];\r\n\t\t\tif (cur.startLineNumber !== prev.startLineNumber || cur.endLineNumber !== prev.endLineNumber) {\r\n\t\t\t\t// add line/block range without leading/failing whitespace\r\n\t\t\t\tconst rangeNoWhitespace = new Range(prev.startLineNumber, model.getLineFirstNonWhitespaceColumn(prev.startLineNumber), prev.endLineNumber, model.getLineLastNonWhitespaceColumn(prev.endLineNumber));\r\n\t\t\t\tif (rangeNoWhitespace.containsRange(prev) && !rangeNoWhitespace.equalsRange(prev) && cur.containsRange(rangeNoWhitespace) && !cur.equalsRange(rangeNoWhitespace)) {\r\n\t\t\t\t\toneRangesWithTrivia.push(rangeNoWhitespace);\r\n\t\t\t\t}\r\n\t\t\t\t// add line/block range\r\n\t\t\t\tconst rangeFull = new Range(prev.startLineNumber, 1, prev.endLineNumber, model.getLineMaxColumn(prev.endLineNumber));\r\n\t\t\t\tif (rangeFull.containsRange(prev) && !rangeFull.equalsRange(rangeNoWhitespace) && cur.containsRange(rangeFull) && !cur.equalsRange(rangeFull)) {\r\n\t\t\t\t\toneRangesWithTrivia.push(rangeFull);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\toneRangesWithTrivia.push(cur);\r\n\t\t}\r\n\t\treturn oneRangesWithTrivia;\r\n\t});\r\n}\r\n\r\nregisterModelCommand('_executeSelectionRangeProvider', function (model, ...args) {\r\n\tconst [positions] = args;\r\n\treturn provideSelectionRanges(model, positions, { selectLeadingAndTrailingWhitespace: true }, CancellationToken.None);\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { onUnexpectedExternalError, canceled, isPromiseCanceledError } from 'vs/base/common/errors';\r\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport * as modes from 'vs/editor/common/modes';\r\nimport { Position, IPosition } from 'vs/editor/common/core/position';\r\nimport { RawContextKey } from 'vs/platform/contextkey/common/contextkey';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { FuzzyScore } from 'vs/base/common/filters';\r\nimport { isDisposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\r\nimport { MenuId } from 'vs/platform/actions/common/actions';\r\nimport { SnippetParser } from 'vs/editor/contrib/snippet/snippetParser';\r\nimport { StopWatch } from 'vs/base/common/stopwatch';\r\nimport { CommandsRegistry } from 'vs/platform/commands/common/commands';\r\nimport { assertType } from 'vs/base/common/types';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { ITextModelService } from 'vs/editor/common/services/resolverService';\r\n\r\nexport const Context = {\r\n\tVisible: new RawContextKey('suggestWidgetVisible', false),\r\n\tDetailsVisible: new RawContextKey('suggestWidgetDetailsVisible', false),\r\n\tMultipleSuggestions: new RawContextKey('suggestWidgetMultipleSuggestions', false),\r\n\tMakesTextEdit: new RawContextKey('suggestionMakesTextEdit', true),\r\n\tAcceptSuggestionsOnEnter: new RawContextKey('acceptSuggestionOnEnter', true),\r\n\tHasInsertAndReplaceRange: new RawContextKey('suggestionHasInsertAndReplaceRange', false),\r\n\tInsertMode: new RawContextKey<'insert' | 'replace'>('suggestionInsertMode', undefined),\r\n\tCanResolve: new RawContextKey('suggestionCanResolve', false),\r\n};\r\n\r\nexport const suggestWidgetStatusbarMenu = new MenuId('suggestWidgetStatusBar');\r\n\r\nexport class CompletionItem {\r\n\r\n\t//\r\n\treadonly editStart: IPosition;\r\n\treadonly editInsertEnd: IPosition;\r\n\treadonly editReplaceEnd: IPosition;\r\n\r\n\t//\r\n\treadonly textLabel: string;\r\n\r\n\t// perf\r\n\treadonly labelLow: string;\r\n\treadonly sortTextLow?: string;\r\n\treadonly filterTextLow?: string;\r\n\r\n\t// validation\r\n\treadonly isInvalid: boolean = false;\r\n\r\n\t// sorting, filtering\r\n\tscore: FuzzyScore = FuzzyScore.Default;\r\n\tdistance: number = 0;\r\n\tidx?: number;\r\n\tword?: string;\r\n\r\n\t// resolving\r\n\tprivate _isResolved?: boolean;\r\n\tprivate _resolveCache?: Promise;\r\n\r\n\tconstructor(\r\n\t\treadonly position: IPosition,\r\n\t\treadonly completion: modes.CompletionItem,\r\n\t\treadonly container: modes.CompletionList,\r\n\t\treadonly provider: modes.CompletionItemProvider,\r\n\t) {\r\n\t\tthis.textLabel = typeof completion.label === 'string'\r\n\t\t\t? completion.label\r\n\t\t\t: completion.label.name;\r\n\r\n\t\t// ensure lower-variants (perf)\r\n\t\tthis.labelLow = this.textLabel.toLowerCase();\r\n\r\n\t\t// validate label\r\n\t\tthis.isInvalid = !this.textLabel;\r\n\r\n\t\tthis.sortTextLow = completion.sortText && completion.sortText.toLowerCase();\r\n\t\tthis.filterTextLow = completion.filterText && completion.filterText.toLowerCase();\r\n\r\n\t\t// normalize ranges\r\n\t\tif (Range.isIRange(completion.range)) {\r\n\t\t\tthis.editStart = new Position(completion.range.startLineNumber, completion.range.startColumn);\r\n\t\t\tthis.editInsertEnd = new Position(completion.range.endLineNumber, completion.range.endColumn);\r\n\t\t\tthis.editReplaceEnd = new Position(completion.range.endLineNumber, completion.range.endColumn);\r\n\r\n\t\t\t// validate range\r\n\t\t\tthis.isInvalid = this.isInvalid\r\n\t\t\t\t|| Range.spansMultipleLines(completion.range) || completion.range.startLineNumber !== position.lineNumber;\r\n\r\n\t\t} else {\r\n\t\t\tthis.editStart = new Position(completion.range.insert.startLineNumber, completion.range.insert.startColumn);\r\n\t\t\tthis.editInsertEnd = new Position(completion.range.insert.endLineNumber, completion.range.insert.endColumn);\r\n\t\t\tthis.editReplaceEnd = new Position(completion.range.replace.endLineNumber, completion.range.replace.endColumn);\r\n\r\n\t\t\t// validate ranges\r\n\t\t\tthis.isInvalid = this.isInvalid\r\n\t\t\t\t|| Range.spansMultipleLines(completion.range.insert) || Range.spansMultipleLines(completion.range.replace)\r\n\t\t\t\t|| completion.range.insert.startLineNumber !== position.lineNumber || completion.range.replace.startLineNumber !== position.lineNumber\r\n\t\t\t\t|| completion.range.insert.startColumn !== completion.range.replace.startColumn;\r\n\t\t}\r\n\r\n\t\t// create the suggestion resolver\r\n\t\tif (typeof provider.resolveCompletionItem !== 'function') {\r\n\t\t\tthis._resolveCache = Promise.resolve();\r\n\t\t\tthis._isResolved = true;\r\n\t\t}\r\n\t}\r\n\r\n\t// ---- resolving\r\n\r\n\tget isResolved(): boolean {\r\n\t\treturn !!this._isResolved;\r\n\t}\r\n\r\n\tasync resolve(token: CancellationToken) {\r\n\t\tif (!this._resolveCache) {\r\n\t\t\tconst sub = token.onCancellationRequested(() => {\r\n\t\t\t\tthis._resolveCache = undefined;\r\n\t\t\t\tthis._isResolved = false;\r\n\t\t\t});\r\n\t\t\tthis._resolveCache = Promise.resolve(this.provider.resolveCompletionItem!(this.completion, token)).then(value => {\r\n\t\t\t\tObject.assign(this.completion, value);\r\n\t\t\t\tthis._isResolved = true;\r\n\t\t\t\tsub.dispose();\r\n\t\t\t}, err => {\r\n\t\t\t\tif (isPromiseCanceledError(err)) {\r\n\t\t\t\t\t// the IPC queue will reject the request with the\r\n\t\t\t\t\t// cancellation error -> reset cached\r\n\t\t\t\t\tthis._resolveCache = undefined;\r\n\t\t\t\t\tthis._isResolved = false;\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\t\treturn this._resolveCache;\r\n\t}\r\n}\r\n\r\nexport const enum SnippetSortOrder {\r\n\tTop, Inline, Bottom\r\n}\r\n\r\nexport class CompletionOptions {\r\n\r\n\tstatic readonly default = new CompletionOptions();\r\n\r\n\tconstructor(\r\n\t\treadonly snippetSortOrder = SnippetSortOrder.Bottom,\r\n\t\treadonly kindFilter = new Set(),\r\n\t\treadonly providerFilter = new Set(),\r\n\t) { }\r\n}\r\n\r\nlet _snippetSuggestSupport: modes.CompletionItemProvider;\r\n\r\nexport function getSnippetSuggestSupport(): modes.CompletionItemProvider {\r\n\treturn _snippetSuggestSupport;\r\n}\r\n\r\nexport interface CompletionDurationEntry {\r\n\treadonly providerName: string;\r\n\treadonly elapsedProvider: number;\r\n\treadonly elapsedOverall: number;\r\n}\r\n\r\nexport interface CompletionDurations {\r\n\treadonly entries: readonly CompletionDurationEntry[];\r\n\treadonly elapsed: number;\r\n}\r\n\r\nexport class CompletionItemModel {\r\n\tconstructor(\r\n\t\treadonly items: CompletionItem[],\r\n\t\treadonly needsClipboard: boolean,\r\n\t\treadonly durations: CompletionDurations,\r\n\t\treadonly disposable: IDisposable,\r\n\t) { }\r\n}\r\n\r\nexport async function provideSuggestionItems(\r\n\tmodel: ITextModel,\r\n\tposition: Position,\r\n\toptions: CompletionOptions = CompletionOptions.default,\r\n\tcontext: modes.CompletionContext = { triggerKind: modes.CompletionTriggerKind.Invoke },\r\n\ttoken: CancellationToken = CancellationToken.None\r\n): Promise {\r\n\r\n\tconst sw = new StopWatch(true);\r\n\tposition = position.clone();\r\n\r\n\tconst word = model.getWordAtPosition(position);\r\n\tconst defaultReplaceRange = word ? new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn) : Range.fromPositions(position);\r\n\tconst defaultRange = { replace: defaultReplaceRange, insert: defaultReplaceRange.setEndPosition(position.lineNumber, position.column) };\r\n\r\n\tconst result: CompletionItem[] = [];\r\n\tconst disposables = new DisposableStore();\r\n\tconst durations: CompletionDurationEntry[] = [];\r\n\tlet needsClipboard = false;\r\n\r\n\tconst onCompletionList = (provider: modes.CompletionItemProvider, container: modes.CompletionList | null | undefined, sw: StopWatch) => {\r\n\t\tif (!container) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tfor (let suggestion of container.suggestions) {\r\n\t\t\tif (!options.kindFilter.has(suggestion.kind)) {\r\n\t\t\t\t// fill in default range when missing\r\n\t\t\t\tif (!suggestion.range) {\r\n\t\t\t\t\tsuggestion.range = defaultRange;\r\n\t\t\t\t}\r\n\t\t\t\t// fill in default sortText when missing\r\n\t\t\t\tif (!suggestion.sortText) {\r\n\t\t\t\t\tsuggestion.sortText = typeof suggestion.label === 'string' ? suggestion.label : suggestion.label.name;\r\n\t\t\t\t}\r\n\t\t\t\tif (!needsClipboard && suggestion.insertTextRules && suggestion.insertTextRules & modes.CompletionItemInsertTextRule.InsertAsSnippet) {\r\n\t\t\t\t\tneedsClipboard = SnippetParser.guessNeedsClipboard(suggestion.insertText);\r\n\t\t\t\t}\r\n\t\t\t\tresult.push(new CompletionItem(position, suggestion, container, provider));\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (isDisposable(container)) {\r\n\t\t\tdisposables.add(container);\r\n\t\t}\r\n\t\tdurations.push({\r\n\t\t\tproviderName: provider._debugDisplayName ?? 'unkown_provider', elapsedProvider: container.duration ?? -1, elapsedOverall: sw.elapsed()\r\n\t\t});\r\n\t};\r\n\r\n\t// ask for snippets in parallel to asking \"real\" providers. Only do something if configured to\r\n\t// do so - no snippet filter, no special-providers-only request\r\n\tconst snippetCompletions = (async () => {\r\n\t\tif (!_snippetSuggestSupport || options.kindFilter.has(modes.CompletionItemKind.Snippet)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (options.providerFilter.size > 0 && !options.providerFilter.has(_snippetSuggestSupport)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst sw = new StopWatch(true);\r\n\t\tconst list = await _snippetSuggestSupport.provideCompletionItems(model, position, context, token);\r\n\t\tonCompletionList(_snippetSuggestSupport, list, sw);\r\n\t})();\r\n\r\n\t// add suggestions from contributed providers - providers are ordered in groups of\r\n\t// equal score and once a group produces a result the process stops\r\n\t// get provider groups, always add snippet suggestion provider\r\n\tfor (let providerGroup of modes.CompletionProviderRegistry.orderedGroups(model)) {\r\n\r\n\t\t// for each support in the group ask for suggestions\r\n\t\tlet lenBefore = result.length;\r\n\r\n\t\tawait Promise.all(providerGroup.map(async provider => {\r\n\t\t\tif (options.providerFilter.size > 0 && !options.providerFilter.has(provider)) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\ttry {\r\n\t\t\t\tconst sw = new StopWatch(true);\r\n\t\t\t\tconst list = await provider.provideCompletionItems(model, position, context, token);\r\n\t\t\t\tonCompletionList(provider, list, sw);\r\n\t\t\t} catch (err) {\r\n\t\t\t\tonUnexpectedExternalError(err);\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tif (lenBefore !== result.length || token.isCancellationRequested) {\r\n\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n\r\n\tawait snippetCompletions;\r\n\r\n\tif (token.isCancellationRequested) {\r\n\t\tdisposables.dispose();\r\n\t\treturn Promise.reject(canceled());\r\n\t}\r\n\r\n\treturn new CompletionItemModel(\r\n\t\tresult.sort(getSuggestionComparator(options.snippetSortOrder)),\r\n\t\tneedsClipboard,\r\n\t\t{ entries: durations, elapsed: sw.elapsed() },\r\n\t\tdisposables,\r\n\t);\r\n}\r\n\r\n\r\nfunction defaultComparator(a: CompletionItem, b: CompletionItem): number {\r\n\t// check with 'sortText'\r\n\tif (a.sortTextLow && b.sortTextLow) {\r\n\t\tif (a.sortTextLow < b.sortTextLow) {\r\n\t\t\treturn -1;\r\n\t\t} else if (a.sortTextLow > b.sortTextLow) {\r\n\t\t\treturn 1;\r\n\t\t}\r\n\t}\r\n\t// check with 'label'\r\n\tif (a.completion.label < b.completion.label) {\r\n\t\treturn -1;\r\n\t} else if (a.completion.label > b.completion.label) {\r\n\t\treturn 1;\r\n\t}\r\n\t// check with 'type'\r\n\treturn a.completion.kind - b.completion.kind;\r\n}\r\n\r\nfunction snippetUpComparator(a: CompletionItem, b: CompletionItem): number {\r\n\tif (a.completion.kind !== b.completion.kind) {\r\n\t\tif (a.completion.kind === modes.CompletionItemKind.Snippet) {\r\n\t\t\treturn -1;\r\n\t\t} else if (b.completion.kind === modes.CompletionItemKind.Snippet) {\r\n\t\t\treturn 1;\r\n\t\t}\r\n\t}\r\n\treturn defaultComparator(a, b);\r\n}\r\n\r\nfunction snippetDownComparator(a: CompletionItem, b: CompletionItem): number {\r\n\tif (a.completion.kind !== b.completion.kind) {\r\n\t\tif (a.completion.kind === modes.CompletionItemKind.Snippet) {\r\n\t\t\treturn 1;\r\n\t\t} else if (b.completion.kind === modes.CompletionItemKind.Snippet) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t}\r\n\treturn defaultComparator(a, b);\r\n}\r\n\r\ninterface Comparator { (a: T, b: T): number; }\r\nconst _snippetComparators = new Map>();\r\n_snippetComparators.set(SnippetSortOrder.Top, snippetUpComparator);\r\n_snippetComparators.set(SnippetSortOrder.Bottom, snippetDownComparator);\r\n_snippetComparators.set(SnippetSortOrder.Inline, defaultComparator);\r\n\r\nexport function getSuggestionComparator(snippetConfig: SnippetSortOrder): (a: CompletionItem, b: CompletionItem) => number {\r\n\treturn _snippetComparators.get(snippetConfig)!;\r\n}\r\n\r\nCommandsRegistry.registerCommand('_executeCompletionItemProvider', async (accessor, ...args: [URI, IPosition, string?, number?]) => {\r\n\tconst [uri, position, triggerCharacter, maxItemsToResolve] = args;\r\n\tassertType(URI.isUri(uri));\r\n\tassertType(Position.isIPosition(position));\r\n\tassertType(typeof triggerCharacter === 'string' || !triggerCharacter);\r\n\tassertType(typeof maxItemsToResolve === 'number' || !maxItemsToResolve);\r\n\r\n\tconst ref = await accessor.get(ITextModelService).createModelReference(uri);\r\n\ttry {\r\n\r\n\t\tconst result: modes.CompletionList = {\r\n\t\t\tincomplete: false,\r\n\t\t\tsuggestions: []\r\n\t\t};\r\n\r\n\t\tconst resolving: Promise[] = [];\r\n\t\tconst completions = await provideSuggestionItems(ref.object.textEditorModel, Position.lift(position), undefined, { triggerCharacter, triggerKind: triggerCharacter ? modes.CompletionTriggerKind.TriggerCharacter : modes.CompletionTriggerKind.Invoke });\r\n\t\tfor (const item of completions.items) {\r\n\t\t\tif (resolving.length < (maxItemsToResolve ?? 0)) {\r\n\t\t\t\tresolving.push(item.resolve(CancellationToken.None));\r\n\t\t\t}\r\n\t\t\tresult.incomplete = result.incomplete || item.container.incomplete;\r\n\t\t\tresult.suggestions.push(item.completion);\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\tawait Promise.all(resolving);\r\n\t\t\treturn result;\r\n\t\t} finally {\r\n\t\t\tsetTimeout(() => completions.disposable.dispose(), 100);\r\n\t\t}\r\n\r\n\t} finally {\r\n\t\tref.dispose();\r\n\t}\r\n\r\n});\r\n\r\ninterface SuggestController extends IEditorContribution {\r\n\ttriggerSuggest(onlyFrom?: Set): void;\r\n}\r\n\r\nconst _provider = new class implements modes.CompletionItemProvider {\r\n\r\n\tonlyOnceSuggestions: modes.CompletionItem[] = [];\r\n\r\n\tprovideCompletionItems(): modes.CompletionList {\r\n\t\tlet suggestions = this.onlyOnceSuggestions.slice(0);\r\n\t\tlet result = { suggestions };\r\n\t\tthis.onlyOnceSuggestions.length = 0;\r\n\t\treturn result;\r\n\t}\r\n};\r\n\r\nmodes.CompletionProviderRegistry.register('*', _provider);\r\n\r\nexport function showSimpleSuggestions(editor: ICodeEditor, suggestions: modes.CompletionItem[]) {\r\n\tsetTimeout(() => {\r\n\t\t_provider.onlyOnceSuggestions.push(...suggestions);\r\n\t\teditor.getContribution('editor.contrib.suggestController').triggerSuggest(new Set().add(_provider));\r\n\t}, 0);\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { alert } from 'vs/base/browser/ui/aria/aria';\r\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction, ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions';\r\nimport { TabFocus } from 'vs/editor/common/config/commonEditorConfig';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\n\r\nexport class ToggleTabFocusModeAction extends EditorAction {\r\n\r\n\tpublic static readonly ID = 'editor.action.toggleTabFocusMode';\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: ToggleTabFocusModeAction.ID,\r\n\t\t\tlabel: nls.localize({ key: 'toggle.tabMovesFocus', comment: ['Turn on/off use of tab key for moving focus around VS Code'] }, \"Toggle Tab Key Moves Focus\"),\r\n\t\t\talias: 'Toggle Tab Key Moves Focus',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: null,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.KEY_M,\r\n\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_M },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tconst oldValue = TabFocus.getTabFocusMode();\r\n\t\tconst newValue = !oldValue;\r\n\t\tTabFocus.setTabFocusMode(newValue);\r\n\t\tif (newValue) {\r\n\t\t\talert(nls.localize('toggle.tabMovesFocus.on', \"Pressing Tab will now move focus to the next focusable element\"));\r\n\t\t} else {\r\n\t\t\talert(nls.localize('toggle.tabMovesFocus.off', \"Pressing Tab will now insert the tab character\"));\r\n\t\t}\r\n\t}\r\n}\r\n\r\nregisterEditorAction(ToggleTabFocusModeAction);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction, ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions';\r\nimport { StopWatch } from 'vs/base/common/stopwatch';\r\n\r\nclass ForceRetokenizeAction extends EditorAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.forceRetokenize',\r\n\t\t\tlabel: nls.localize('forceRetokenize', \"Developer: Force Retokenize\"),\r\n\t\t\talias: 'Developer: Force Retokenize',\r\n\t\t\tprecondition: undefined\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst model = editor.getModel();\r\n\t\tmodel.resetTokenization();\r\n\t\tconst sw = new StopWatch(true);\r\n\t\tmodel.forceTokenization(model.getLineCount());\r\n\t\tsw.stop();\r\n\t\tconsole.log(`tokenization took ${sw.elapsed()}`);\r\n\r\n\t}\r\n}\r\n\r\nregisterEditorAction(ForceRetokenizeAction);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { registerEditorContribution } from 'vs/editor/browser/editorExtensions';\r\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { IDialogService } from 'vs/platform/dialogs/common/dialogs';\r\n\r\nconst ignoreUnusualLineTerminators = 'ignoreUnusualLineTerminators';\r\n\r\nfunction writeIgnoreState(codeEditorService: ICodeEditorService, model: ITextModel, state: boolean): void {\r\n\tcodeEditorService.setModelProperty(model.uri, ignoreUnusualLineTerminators, state);\r\n}\r\n\r\nfunction readIgnoreState(codeEditorService: ICodeEditorService, model: ITextModel): boolean | undefined {\r\n\treturn codeEditorService.getModelProperty(model.uri, ignoreUnusualLineTerminators);\r\n}\r\n\r\nclass UnusualLineTerminatorsDetector extends Disposable implements IEditorContribution {\r\n\r\n\tpublic static readonly ID = 'editor.contrib.unusualLineTerminatorsDetector';\r\n\r\n\tprivate _config: 'auto' | 'off' | 'prompt';\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _editor: ICodeEditor,\r\n\t\t@IDialogService private readonly _dialogService: IDialogService,\r\n\t\t@ICodeEditorService private readonly _codeEditorService: ICodeEditorService\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\tthis._config = this._editor.getOption(EditorOption.unusualLineTerminators);\r\n\t\tthis._register(this._editor.onDidChangeConfiguration((e) => {\r\n\t\t\tif (e.hasChanged(EditorOption.unusualLineTerminators)) {\r\n\t\t\t\tthis._config = this._editor.getOption(EditorOption.unusualLineTerminators);\r\n\t\t\t\tthis._checkForUnusualLineTerminators();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._register(this._editor.onDidChangeModel(() => {\r\n\t\t\tthis._checkForUnusualLineTerminators();\r\n\t\t}));\r\n\r\n\t\tthis._register(this._editor.onDidChangeModelContent((e) => {\r\n\t\t\tif (e.isUndoing) {\r\n\t\t\t\t// skip checking in case of undoing\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tthis._checkForUnusualLineTerminators();\r\n\t\t}));\r\n\t}\r\n\r\n\tprivate async _checkForUnusualLineTerminators(): Promise {\r\n\t\tif (this._config === 'off') {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst model = this._editor.getModel();\r\n\t\tif (!model.mightContainUnusualLineTerminators()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst ignoreState = readIgnoreState(this._codeEditorService, model);\r\n\t\tif (ignoreState === true) {\r\n\t\t\t// this model should be ignored\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (this._editor.getOption(EditorOption.readOnly)) {\r\n\t\t\t// read only editor => sorry!\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this._config === 'auto') {\r\n\t\t\t// just do it!\r\n\t\t\tmodel.removeUnusualLineTerminators(this._editor.getSelections());\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst result = await this._dialogService.confirm({\r\n\t\t\ttitle: nls.localize('unusualLineTerminators.title', \"Unusual Line Terminators\"),\r\n\t\t\tmessage: nls.localize('unusualLineTerminators.message', \"Detected unusual line terminators\"),\r\n\t\t\tdetail: nls.localize('unusualLineTerminators.detail', \"This file contains one or more unusual line terminator characters, like Line Separator (LS) or Paragraph Separator (PS).\\n\\nIt is recommended to remove them from the file. This can be configured via `editor.unusualLineTerminators`.\"),\r\n\t\t\tprimaryButton: nls.localize('unusualLineTerminators.fix', \"Fix this file\"),\r\n\t\t\tsecondaryButton: nls.localize('unusualLineTerminators.ignore', \"Ignore problem for this file\")\r\n\t\t});\r\n\r\n\t\tif (!result.confirmed) {\r\n\t\t\t// this model should be ignored\r\n\t\t\twriteIgnoreState(this._codeEditorService, model, true);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tmodel.removeUnusualLineTerminators(this._editor.getSelections());\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(UnusualLineTerminatorsDetector.ID, UnusualLineTerminatorsDetector);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport * as arrays from 'vs/base/common/arrays';\r\nimport { CancelablePromise, createCancelablePromise, first, timeout } from 'vs/base/common/async';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { onUnexpectedError, onUnexpectedExternalError } from 'vs/base/common/errors';\r\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { Disposable, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { IActiveCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction, IActionOptions, registerEditorAction, registerEditorContribution, registerModelAndPositionCommand } from 'vs/editor/browser/editorExtensions';\r\nimport { CursorChangeReason, ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { IModelDeltaDecoration, ITextModel, OverviewRulerLane, TrackedRangeStickiness, IWordAtPosition } from 'vs/editor/common/model';\r\nimport { ModelDecorationOptions } from 'vs/editor/common/model/textModel';\r\nimport { DocumentHighlight, DocumentHighlightKind, DocumentHighlightProviderRegistry } from 'vs/editor/common/modes';\r\nimport { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';\r\nimport { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { activeContrastBorder, editorSelectionHighlight, editorSelectionHighlightBorder, overviewRulerSelectionHighlightForeground, registerColor } from 'vs/platform/theme/common/colorRegistry';\r\nimport { registerThemingParticipant, themeColorFromId } from 'vs/platform/theme/common/themeService';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { alert } from 'vs/base/browser/ui/aria/aria';\r\n\r\nconst editorWordHighlight = registerColor('editor.wordHighlightBackground', { dark: '#575757B8', light: '#57575740', hc: null }, nls.localize('wordHighlight', 'Background color of a symbol during read-access, like reading a variable. The color must not be opaque so as not to hide underlying decorations.'), true);\r\nconst editorWordHighlightStrong = registerColor('editor.wordHighlightStrongBackground', { dark: '#004972B8', light: '#0e639c40', hc: null }, nls.localize('wordHighlightStrong', 'Background color of a symbol during write-access, like writing to a variable. The color must not be opaque so as not to hide underlying decorations.'), true);\r\nconst editorWordHighlightBorder = registerColor('editor.wordHighlightBorder', { light: null, dark: null, hc: activeContrastBorder }, nls.localize('wordHighlightBorder', 'Border color of a symbol during read-access, like reading a variable.'));\r\nconst editorWordHighlightStrongBorder = registerColor('editor.wordHighlightStrongBorder', { light: null, dark: null, hc: activeContrastBorder }, nls.localize('wordHighlightStrongBorder', 'Border color of a symbol during write-access, like writing to a variable.'));\r\nconst overviewRulerWordHighlightForeground = registerColor('editorOverviewRuler.wordHighlightForeground', { dark: '#A0A0A0CC', light: '#A0A0A0CC', hc: '#A0A0A0CC' }, nls.localize('overviewRulerWordHighlightForeground', 'Overview ruler marker color for symbol highlights. The color must not be opaque so as not to hide underlying decorations.'), true);\r\nconst overviewRulerWordHighlightStrongForeground = registerColor('editorOverviewRuler.wordHighlightStrongForeground', { dark: '#C0A0C0CC', light: '#C0A0C0CC', hc: '#C0A0C0CC' }, nls.localize('overviewRulerWordHighlightStrongForeground', 'Overview ruler marker color for write-access symbol highlights. The color must not be opaque so as not to hide underlying decorations.'), true);\r\nconst ctxHasWordHighlights = new RawContextKey('hasWordHighlights', false);\r\n\r\nexport function getOccurrencesAtPosition(model: ITextModel, position: Position, token: CancellationToken): Promise {\r\n\r\n\tconst orderedByScore = DocumentHighlightProviderRegistry.ordered(model);\r\n\r\n\t// in order of score ask the occurrences provider\r\n\t// until someone response with a good result\r\n\t// (good = none empty array)\r\n\treturn first(orderedByScore.map(provider => () => {\r\n\t\treturn Promise.resolve(provider.provideDocumentHighlights(model, position, token))\r\n\t\t\t.then(undefined, onUnexpectedExternalError);\r\n\t}), arrays.isNonEmptyArray);\r\n}\r\n\r\ninterface IOccurenceAtPositionRequest {\r\n\treadonly result: Promise;\r\n\tisValid(model: ITextModel, selection: Selection, decorationIds: string[]): boolean;\r\n\tcancel(): void;\r\n}\r\n\r\nabstract class OccurenceAtPositionRequest implements IOccurenceAtPositionRequest {\r\n\r\n\tprivate readonly _wordRange: Range | null;\r\n\tpublic readonly result: CancelablePromise;\r\n\r\n\tconstructor(model: ITextModel, selection: Selection, wordSeparators: string) {\r\n\t\tthis._wordRange = this._getCurrentWordRange(model, selection);\r\n\t\tthis.result = createCancelablePromise(token => this._compute(model, selection, wordSeparators, token));\r\n\t}\r\n\r\n\tprotected abstract _compute(model: ITextModel, selection: Selection, wordSeparators: string, token: CancellationToken): Promise;\r\n\r\n\tprivate _getCurrentWordRange(model: ITextModel, selection: Selection): Range | null {\r\n\t\tconst word = model.getWordAtPosition(selection.getPosition());\r\n\t\tif (word) {\r\n\t\t\treturn new Range(selection.startLineNumber, word.startColumn, selection.startLineNumber, word.endColumn);\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic isValid(model: ITextModel, selection: Selection, decorationIds: string[]): boolean {\r\n\r\n\t\tconst lineNumber = selection.startLineNumber;\r\n\t\tconst startColumn = selection.startColumn;\r\n\t\tconst endColumn = selection.endColumn;\r\n\t\tconst currentWordRange = this._getCurrentWordRange(model, selection);\r\n\r\n\t\tlet requestIsValid = Boolean(this._wordRange && this._wordRange.equalsRange(currentWordRange));\r\n\r\n\t\t// Even if we are on a different word, if that word is in the decorations ranges, the request is still valid\r\n\t\t// (Same symbol)\r\n\t\tfor (let i = 0, len = decorationIds.length; !requestIsValid && i < len; i++) {\r\n\t\t\tlet range = model.getDecorationRange(decorationIds[i]);\r\n\t\t\tif (range && range.startLineNumber === lineNumber) {\r\n\t\t\t\tif (range.startColumn <= startColumn && range.endColumn >= endColumn) {\r\n\t\t\t\t\trequestIsValid = true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn requestIsValid;\r\n\t}\r\n\r\n\tpublic cancel(): void {\r\n\t\tthis.result.cancel();\r\n\t}\r\n}\r\n\r\nclass SemanticOccurenceAtPositionRequest extends OccurenceAtPositionRequest {\r\n\tprotected _compute(model: ITextModel, selection: Selection, wordSeparators: string, token: CancellationToken): Promise {\r\n\t\treturn getOccurrencesAtPosition(model, selection.getPosition(), token).then(value => value || []);\r\n\t}\r\n}\r\n\r\nclass TextualOccurenceAtPositionRequest extends OccurenceAtPositionRequest {\r\n\r\n\tprivate readonly _selectionIsEmpty: boolean;\r\n\r\n\tconstructor(model: ITextModel, selection: Selection, wordSeparators: string) {\r\n\t\tsuper(model, selection, wordSeparators);\r\n\t\tthis._selectionIsEmpty = selection.isEmpty();\r\n\t}\r\n\r\n\tprotected _compute(model: ITextModel, selection: Selection, wordSeparators: string, token: CancellationToken): Promise {\r\n\t\treturn timeout(250, token).then(() => {\r\n\t\t\tif (!selection.isEmpty()) {\r\n\t\t\t\treturn [];\r\n\t\t\t}\r\n\r\n\t\t\tconst word = model.getWordAtPosition(selection.getPosition());\r\n\r\n\t\t\tif (!word || word.word.length > 1000) {\r\n\t\t\t\treturn [];\r\n\t\t\t}\r\n\t\t\tconst matches = model.findMatches(word.word, true, false, true, wordSeparators, false);\r\n\t\t\treturn matches.map(m => {\r\n\t\t\t\treturn {\r\n\t\t\t\t\trange: m.range,\r\n\t\t\t\t\tkind: DocumentHighlightKind.Text\r\n\t\t\t\t};\r\n\t\t\t});\r\n\t\t});\r\n\t}\r\n\r\n\tpublic isValid(model: ITextModel, selection: Selection, decorationIds: string[]): boolean {\r\n\t\tconst currentSelectionIsEmpty = selection.isEmpty();\r\n\t\tif (this._selectionIsEmpty !== currentSelectionIsEmpty) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn super.isValid(model, selection, decorationIds);\r\n\t}\r\n}\r\n\r\nfunction computeOccurencesAtPosition(model: ITextModel, selection: Selection, wordSeparators: string): IOccurenceAtPositionRequest {\r\n\tif (DocumentHighlightProviderRegistry.has(model)) {\r\n\t\treturn new SemanticOccurenceAtPositionRequest(model, selection, wordSeparators);\r\n\t}\r\n\treturn new TextualOccurenceAtPositionRequest(model, selection, wordSeparators);\r\n}\r\n\r\nregisterModelAndPositionCommand('_executeDocumentHighlights', (model, position) => getOccurrencesAtPosition(model, position, CancellationToken.None));\r\n\r\nclass WordHighlighter {\r\n\r\n\tprivate readonly editor: IActiveCodeEditor;\r\n\tprivate occurrencesHighlight: boolean;\r\n\tprivate readonly model: ITextModel;\r\n\tprivate _decorationIds: string[];\r\n\tprivate readonly toUnhook = new DisposableStore();\r\n\r\n\tprivate workerRequestTokenId: number = 0;\r\n\tprivate workerRequest: IOccurenceAtPositionRequest | null;\r\n\tprivate workerRequestCompleted: boolean = false;\r\n\tprivate workerRequestValue: DocumentHighlight[] = [];\r\n\r\n\tprivate lastCursorPositionChangeTime: number = 0;\r\n\tprivate renderDecorationsTimer: any = -1;\r\n\r\n\tprivate readonly _hasWordHighlights: IContextKey;\r\n\tprivate _ignorePositionChangeEvent: boolean;\r\n\r\n\tconstructor(editor: IActiveCodeEditor, contextKeyService: IContextKeyService) {\r\n\t\tthis.editor = editor;\r\n\t\tthis._hasWordHighlights = ctxHasWordHighlights.bindTo(contextKeyService);\r\n\t\tthis._ignorePositionChangeEvent = false;\r\n\t\tthis.occurrencesHighlight = this.editor.getOption(EditorOption.occurrencesHighlight);\r\n\t\tthis.model = this.editor.getModel();\r\n\t\tthis.toUnhook.add(editor.onDidChangeCursorPosition((e: ICursorPositionChangedEvent) => {\r\n\r\n\t\t\tif (this._ignorePositionChangeEvent) {\r\n\t\t\t\t// We are changing the position => ignore this event\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (!this.occurrencesHighlight) {\r\n\t\t\t\t// Early exit if nothing needs to be done!\r\n\t\t\t\t// Leave some form of early exit check here if you wish to continue being a cursor position change listener ;)\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tthis._onPositionChanged(e);\r\n\t\t}));\r\n\t\tthis.toUnhook.add(editor.onDidChangeModelContent((e) => {\r\n\t\t\tthis._stopAll();\r\n\t\t}));\r\n\t\tthis.toUnhook.add(editor.onDidChangeConfiguration((e) => {\r\n\t\t\tlet newValue = this.editor.getOption(EditorOption.occurrencesHighlight);\r\n\t\t\tif (this.occurrencesHighlight !== newValue) {\r\n\t\t\t\tthis.occurrencesHighlight = newValue;\r\n\t\t\t\tthis._stopAll();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._decorationIds = [];\r\n\t\tthis.workerRequestTokenId = 0;\r\n\t\tthis.workerRequest = null;\r\n\t\tthis.workerRequestCompleted = false;\r\n\r\n\t\tthis.lastCursorPositionChangeTime = 0;\r\n\t\tthis.renderDecorationsTimer = -1;\r\n\t}\r\n\r\n\tpublic hasDecorations(): boolean {\r\n\t\treturn (this._decorationIds.length > 0);\r\n\t}\r\n\r\n\tpublic restore(): void {\r\n\t\tif (!this.occurrencesHighlight) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._run();\r\n\t}\r\n\r\n\tprivate _getSortedHighlights(): Range[] {\r\n\t\treturn arrays.coalesce(\r\n\t\t\tthis._decorationIds\r\n\t\t\t\t.map((id) => this.model.getDecorationRange(id))\r\n\t\t\t\t.sort(Range.compareRangesUsingStarts)\r\n\t\t);\r\n\t}\r\n\r\n\tpublic moveNext() {\r\n\t\tlet highlights = this._getSortedHighlights();\r\n\t\tlet index = highlights.findIndex((range) => range.containsPosition(this.editor.getPosition()));\r\n\t\tlet newIndex = ((index + 1) % highlights.length);\r\n\t\tlet dest = highlights[newIndex];\r\n\t\ttry {\r\n\t\t\tthis._ignorePositionChangeEvent = true;\r\n\t\t\tthis.editor.setPosition(dest.getStartPosition());\r\n\t\t\tthis.editor.revealRangeInCenterIfOutsideViewport(dest);\r\n\t\t\tconst word = this._getWord();\r\n\t\t\tif (word) {\r\n\t\t\t\tconst lineContent = this.editor.getModel().getLineContent(dest.startLineNumber);\r\n\t\t\t\talert(`${lineContent}, ${newIndex + 1} of ${highlights.length} for '${word.word}'`);\r\n\t\t\t}\r\n\t\t} finally {\r\n\t\t\tthis._ignorePositionChangeEvent = false;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic moveBack() {\r\n\t\tlet highlights = this._getSortedHighlights();\r\n\t\tlet index = highlights.findIndex((range) => range.containsPosition(this.editor.getPosition()));\r\n\t\tlet newIndex = ((index - 1 + highlights.length) % highlights.length);\r\n\t\tlet dest = highlights[newIndex];\r\n\t\ttry {\r\n\t\t\tthis._ignorePositionChangeEvent = true;\r\n\t\t\tthis.editor.setPosition(dest.getStartPosition());\r\n\t\t\tthis.editor.revealRangeInCenterIfOutsideViewport(dest);\r\n\t\t\tconst word = this._getWord();\r\n\t\t\tif (word) {\r\n\t\t\t\tconst lineContent = this.editor.getModel().getLineContent(dest.startLineNumber);\r\n\t\t\t\talert(`${lineContent}, ${newIndex + 1} of ${highlights.length} for '${word.word}'`);\r\n\t\t\t}\r\n\t\t} finally {\r\n\t\t\tthis._ignorePositionChangeEvent = false;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _removeDecorations(): void {\r\n\t\tif (this._decorationIds.length > 0) {\r\n\t\t\t// remove decorations\r\n\t\t\tthis._decorationIds = this.editor.deltaDecorations(this._decorationIds, []);\r\n\t\t\tthis._hasWordHighlights.set(false);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _stopAll(): void {\r\n\t\t// Remove any existing decorations\r\n\t\tthis._removeDecorations();\r\n\r\n\t\t// Cancel any renderDecorationsTimer\r\n\t\tif (this.renderDecorationsTimer !== -1) {\r\n\t\t\tclearTimeout(this.renderDecorationsTimer);\r\n\t\t\tthis.renderDecorationsTimer = -1;\r\n\t\t}\r\n\r\n\t\t// Cancel any worker request\r\n\t\tif (this.workerRequest !== null) {\r\n\t\t\tthis.workerRequest.cancel();\r\n\t\t\tthis.workerRequest = null;\r\n\t\t}\r\n\r\n\t\t// Invalidate any worker request callback\r\n\t\tif (!this.workerRequestCompleted) {\r\n\t\t\tthis.workerRequestTokenId++;\r\n\t\t\tthis.workerRequestCompleted = true;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _onPositionChanged(e: ICursorPositionChangedEvent): void {\r\n\r\n\t\t// disabled\r\n\t\tif (!this.occurrencesHighlight) {\r\n\t\t\tthis._stopAll();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// ignore typing & other\r\n\t\tif (e.reason !== CursorChangeReason.Explicit) {\r\n\t\t\tthis._stopAll();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._run();\r\n\t}\r\n\r\n\tprivate _getWord(): IWordAtPosition | null {\r\n\t\tlet editorSelection = this.editor.getSelection();\r\n\t\tlet lineNumber = editorSelection.startLineNumber;\r\n\t\tlet startColumn = editorSelection.startColumn;\r\n\r\n\t\treturn this.model.getWordAtPosition({\r\n\t\t\tlineNumber: lineNumber,\r\n\t\t\tcolumn: startColumn\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _run(): void {\r\n\t\tlet editorSelection = this.editor.getSelection();\r\n\r\n\t\t// ignore multiline selection\r\n\t\tif (editorSelection.startLineNumber !== editorSelection.endLineNumber) {\r\n\t\t\tthis._stopAll();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet startColumn = editorSelection.startColumn;\r\n\t\tlet endColumn = editorSelection.endColumn;\r\n\r\n\t\tconst word = this._getWord();\r\n\r\n\t\t// The selection must be inside a word or surround one word at most\r\n\t\tif (!word || word.startColumn > startColumn || word.endColumn < endColumn) {\r\n\t\t\tthis._stopAll();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// All the effort below is trying to achieve this:\r\n\t\t// - when cursor is moved to a word, trigger immediately a findOccurrences request\r\n\t\t// - 250ms later after the last cursor move event, render the occurrences\r\n\t\t// - no flickering!\r\n\r\n\t\tconst workerRequestIsValid = (this.workerRequest && this.workerRequest.isValid(this.model, editorSelection, this._decorationIds));\r\n\r\n\t\t// There are 4 cases:\r\n\t\t// a) old workerRequest is valid & completed, renderDecorationsTimer fired\r\n\t\t// b) old workerRequest is valid & completed, renderDecorationsTimer not fired\r\n\t\t// c) old workerRequest is valid, but not completed\r\n\t\t// d) old workerRequest is not valid\r\n\r\n\t\t// For a) no action is needed\r\n\t\t// For c), member 'lastCursorPositionChangeTime' will be used when installing the timer so no action is needed\r\n\r\n\t\tthis.lastCursorPositionChangeTime = (new Date()).getTime();\r\n\r\n\t\tif (workerRequestIsValid) {\r\n\t\t\tif (this.workerRequestCompleted && this.renderDecorationsTimer !== -1) {\r\n\t\t\t\t// case b)\r\n\t\t\t\t// Delay the firing of renderDecorationsTimer by an extra 250 ms\r\n\t\t\t\tclearTimeout(this.renderDecorationsTimer);\r\n\t\t\t\tthis.renderDecorationsTimer = -1;\r\n\t\t\t\tthis._beginRenderDecorations();\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\t// case d)\r\n\t\t\t// Stop all previous actions and start fresh\r\n\t\t\tthis._stopAll();\r\n\r\n\t\t\tlet myRequestId = ++this.workerRequestTokenId;\r\n\t\t\tthis.workerRequestCompleted = false;\r\n\r\n\t\t\tthis.workerRequest = computeOccurencesAtPosition(this.model, this.editor.getSelection(), this.editor.getOption(EditorOption.wordSeparators));\r\n\r\n\t\t\tthis.workerRequest.result.then(data => {\r\n\t\t\t\tif (myRequestId === this.workerRequestTokenId) {\r\n\t\t\t\t\tthis.workerRequestCompleted = true;\r\n\t\t\t\t\tthis.workerRequestValue = data || [];\r\n\t\t\t\t\tthis._beginRenderDecorations();\r\n\t\t\t\t}\r\n\t\t\t}, onUnexpectedError);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _beginRenderDecorations(): void {\r\n\t\tlet currentTime = (new Date()).getTime();\r\n\t\tlet minimumRenderTime = this.lastCursorPositionChangeTime + 250;\r\n\r\n\t\tif (currentTime >= minimumRenderTime) {\r\n\t\t\t// Synchronous\r\n\t\t\tthis.renderDecorationsTimer = -1;\r\n\t\t\tthis.renderDecorations();\r\n\t\t} else {\r\n\t\t\t// Asynchronous\r\n\t\t\tthis.renderDecorationsTimer = setTimeout(() => {\r\n\t\t\t\tthis.renderDecorations();\r\n\t\t\t}, (minimumRenderTime - currentTime));\r\n\t\t}\r\n\t}\r\n\r\n\tprivate renderDecorations(): void {\r\n\t\tthis.renderDecorationsTimer = -1;\r\n\t\tlet decorations: IModelDeltaDecoration[] = [];\r\n\t\tfor (const info of this.workerRequestValue) {\r\n\t\t\tif (info.range) {\r\n\t\t\t\tdecorations.push({\r\n\t\t\t\t\trange: info.range,\r\n\t\t\t\t\toptions: WordHighlighter._getDecorationOptions(info.kind)\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._decorationIds = this.editor.deltaDecorations(this._decorationIds, decorations);\r\n\t\tthis._hasWordHighlights.set(this.hasDecorations());\r\n\t}\r\n\r\n\tprivate static _getDecorationOptions(kind: DocumentHighlightKind | undefined): ModelDecorationOptions {\r\n\t\tif (kind === DocumentHighlightKind.Write) {\r\n\t\t\treturn this._WRITE_OPTIONS;\r\n\t\t} else if (kind === DocumentHighlightKind.Text) {\r\n\t\t\treturn this._TEXT_OPTIONS;\r\n\t\t} else {\r\n\t\t\treturn this._REGULAR_OPTIONS;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static readonly _WRITE_OPTIONS = ModelDecorationOptions.register({\r\n\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,\r\n\t\tclassName: 'wordHighlightStrong',\r\n\t\toverviewRuler: {\r\n\t\t\tcolor: themeColorFromId(overviewRulerWordHighlightStrongForeground),\r\n\t\t\tposition: OverviewRulerLane.Center\r\n\t\t}\r\n\t});\r\n\r\n\tprivate static readonly _TEXT_OPTIONS = ModelDecorationOptions.register({\r\n\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,\r\n\t\tclassName: 'selectionHighlight',\r\n\t\toverviewRuler: {\r\n\t\t\tcolor: themeColorFromId(overviewRulerSelectionHighlightForeground),\r\n\t\t\tposition: OverviewRulerLane.Center\r\n\t\t}\r\n\t});\r\n\r\n\tprivate static readonly _REGULAR_OPTIONS = ModelDecorationOptions.register({\r\n\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,\r\n\t\tclassName: 'wordHighlight',\r\n\t\toverviewRuler: {\r\n\t\t\tcolor: themeColorFromId(overviewRulerWordHighlightForeground),\r\n\t\t\tposition: OverviewRulerLane.Center\r\n\t\t}\r\n\t});\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._stopAll();\r\n\t\tthis.toUnhook.dispose();\r\n\t}\r\n}\r\n\r\nclass WordHighlighterContribution extends Disposable implements IEditorContribution {\r\n\r\n\tpublic static readonly ID = 'editor.contrib.wordHighlighter';\r\n\r\n\tpublic static get(editor: ICodeEditor): WordHighlighterContribution {\r\n\t\treturn editor.getContribution(WordHighlighterContribution.ID);\r\n\t}\r\n\r\n\tprivate wordHighlighter: WordHighlighter | null;\r\n\r\n\tconstructor(editor: ICodeEditor, @IContextKeyService contextKeyService: IContextKeyService) {\r\n\t\tsuper();\r\n\t\tthis.wordHighlighter = null;\r\n\t\tconst createWordHighlighterIfPossible = () => {\r\n\t\t\tif (editor.hasModel()) {\r\n\t\t\t\tthis.wordHighlighter = new WordHighlighter(editor, contextKeyService);\r\n\t\t\t}\r\n\t\t};\r\n\t\tthis._register(editor.onDidChangeModel((e) => {\r\n\t\t\tif (this.wordHighlighter) {\r\n\t\t\t\tthis.wordHighlighter.dispose();\r\n\t\t\t\tthis.wordHighlighter = null;\r\n\t\t\t}\r\n\t\t\tcreateWordHighlighterIfPossible();\r\n\t\t}));\r\n\t\tcreateWordHighlighterIfPossible();\r\n\t}\r\n\r\n\tpublic saveViewState(): boolean {\r\n\t\tif (this.wordHighlighter && this.wordHighlighter.hasDecorations()) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic moveNext() {\r\n\t\tif (this.wordHighlighter) {\r\n\t\t\tthis.wordHighlighter.moveNext();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic moveBack() {\r\n\t\tif (this.wordHighlighter) {\r\n\t\t\tthis.wordHighlighter.moveBack();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic restoreViewState(state: boolean | undefined): void {\r\n\t\tif (this.wordHighlighter && state) {\r\n\t\t\tthis.wordHighlighter.restore();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tif (this.wordHighlighter) {\r\n\t\t\tthis.wordHighlighter.dispose();\r\n\t\t\tthis.wordHighlighter = null;\r\n\t\t}\r\n\t\tsuper.dispose();\r\n\t}\r\n}\r\n\r\n\r\nclass WordHighlightNavigationAction extends EditorAction {\r\n\r\n\tprivate readonly _isNext: boolean;\r\n\r\n\tconstructor(next: boolean, opts: IActionOptions) {\r\n\t\tsuper(opts);\r\n\t\tthis._isNext = next;\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tconst controller = WordHighlighterContribution.get(editor);\r\n\t\tif (!controller) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this._isNext) {\r\n\t\t\tcontroller.moveNext();\r\n\t\t} else {\r\n\t\t\tcontroller.moveBack();\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass NextWordHighlightAction extends WordHighlightNavigationAction {\r\n\tconstructor() {\r\n\t\tsuper(true, {\r\n\t\t\tid: 'editor.action.wordHighlight.next',\r\n\t\t\tlabel: nls.localize('wordHighlight.next.label', \"Go to Next Symbol Highlight\"),\r\n\t\t\talias: 'Go to Next Symbol Highlight',\r\n\t\t\tprecondition: ctxHasWordHighlights,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyCode.F7,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n\r\nclass PrevWordHighlightAction extends WordHighlightNavigationAction {\r\n\tconstructor() {\r\n\t\tsuper(false, {\r\n\t\t\tid: 'editor.action.wordHighlight.prev',\r\n\t\t\tlabel: nls.localize('wordHighlight.previous.label', \"Go to Previous Symbol Highlight\"),\r\n\t\t\talias: 'Go to Previous Symbol Highlight',\r\n\t\t\tprecondition: ctxHasWordHighlights,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.Shift | KeyCode.F7,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n\r\nclass TriggerWordHighlightAction extends EditorAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.wordHighlight.trigger',\r\n\t\t\tlabel: nls.localize('wordHighlight.trigger.label', \"Trigger Symbol Highlight\"),\r\n\t\t\talias: 'Trigger Symbol Highlight',\r\n\t\t\tprecondition: ctxHasWordHighlights.toNegated(),\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: 0,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {\r\n\t\tconst controller = WordHighlighterContribution.get(editor);\r\n\t\tif (!controller) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tcontroller.restoreViewState(true);\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(WordHighlighterContribution.ID, WordHighlighterContribution);\r\nregisterEditorAction(NextWordHighlightAction);\r\nregisterEditorAction(PrevWordHighlightAction);\r\nregisterEditorAction(TriggerWordHighlightAction);\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst selectionHighlight = theme.getColor(editorSelectionHighlight);\r\n\tif (selectionHighlight) {\r\n\t\tcollector.addRule(`.monaco-editor .focused .selectionHighlight { background-color: ${selectionHighlight}; }`);\r\n\t\tcollector.addRule(`.monaco-editor .selectionHighlight { background-color: ${selectionHighlight.transparent(0.5)}; }`);\r\n\t}\r\n\r\n\tconst wordHighlight = theme.getColor(editorWordHighlight);\r\n\tif (wordHighlight) {\r\n\t\tcollector.addRule(`.monaco-editor .wordHighlight { background-color: ${wordHighlight}; }`);\r\n\t}\r\n\r\n\tconst wordHighlightStrong = theme.getColor(editorWordHighlightStrong);\r\n\tif (wordHighlightStrong) {\r\n\t\tcollector.addRule(`.monaco-editor .wordHighlightStrong { background-color: ${wordHighlightStrong}; }`);\r\n\t}\r\n\r\n\tconst selectionHighlightBorder = theme.getColor(editorSelectionHighlightBorder);\r\n\tif (selectionHighlightBorder) {\r\n\t\tcollector.addRule(`.monaco-editor .selectionHighlight { border: 1px ${theme.type === 'hc' ? 'dotted' : 'solid'} ${selectionHighlightBorder}; box-sizing: border-box; }`);\r\n\t}\r\n\r\n\tconst wordHighlightBorder = theme.getColor(editorWordHighlightBorder);\r\n\tif (wordHighlightBorder) {\r\n\t\tcollector.addRule(`.monaco-editor .wordHighlight { border: 1px ${theme.type === 'hc' ? 'dashed' : 'solid'} ${wordHighlightBorder}; box-sizing: border-box; }`);\r\n\t}\r\n\r\n\tconst wordHighlightStrongBorder = theme.getColor(editorWordHighlightStrongBorder);\r\n\tif (wordHighlightStrongBorder) {\r\n\t\tcollector.addRule(`.monaco-editor .wordHighlightStrong { border: 1px ${theme.type === 'hc' ? 'dashed' : 'solid'} ${wordHighlightStrongBorder}; box-sizing: border-box; }`);\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorCommand, ICommandOptions, ServicesAccessor, registerEditorCommand, EditorAction, registerEditorAction } from 'vs/editor/browser/editorExtensions';\r\nimport { ReplaceCommand } from 'vs/editor/common/commands/replaceCommand';\r\nimport { CursorState } from 'vs/editor/common/controller/cursorCommon';\r\nimport { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents';\r\nimport { DeleteWordContext, WordNavigationType, WordOperations } from 'vs/editor/common/controller/cursorWordOperations';\r\nimport { WordCharacterClassifier, getMapForWordSeparators } from 'vs/editor/common/controller/wordCharacterClassifier';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { ScrollType } from 'vs/editor/common/editorCommon';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility';\r\nimport { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';\r\nimport { EditorOption, EditorOptions } from 'vs/editor/common/config/editorOptions';\r\nimport { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';\r\n\r\nexport interface MoveWordOptions extends ICommandOptions {\r\n\tinSelectionMode: boolean;\r\n\twordNavigationType: WordNavigationType;\r\n}\r\n\r\nexport abstract class MoveWordCommand extends EditorCommand {\r\n\r\n\tprivate readonly _inSelectionMode: boolean;\r\n\tprivate readonly _wordNavigationType: WordNavigationType;\r\n\r\n\tconstructor(opts: MoveWordOptions) {\r\n\t\tsuper(opts);\r\n\t\tthis._inSelectionMode = opts.inSelectionMode;\r\n\t\tthis._wordNavigationType = opts.wordNavigationType;\r\n\t}\r\n\r\n\tpublic runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst wordSeparators = getMapForWordSeparators(editor.getOption(EditorOption.wordSeparators));\r\n\t\tconst model = editor.getModel();\r\n\t\tconst selections = editor.getSelections();\r\n\r\n\t\tconst result = selections.map((sel) => {\r\n\t\t\tconst inPosition = new Position(sel.positionLineNumber, sel.positionColumn);\r\n\t\t\tconst outPosition = this._move(wordSeparators, model, inPosition, this._wordNavigationType);\r\n\t\t\treturn this._moveTo(sel, outPosition, this._inSelectionMode);\r\n\t\t});\r\n\r\n\t\tmodel.pushStackElement();\r\n\t\teditor._getViewModel().setCursorStates('moveWordCommand', CursorChangeReason.Explicit, result.map(r => CursorState.fromModelSelection(r)));\r\n\t\tif (result.length === 1) {\r\n\t\t\tconst pos = new Position(result[0].positionLineNumber, result[0].positionColumn);\r\n\t\t\teditor.revealPosition(pos, ScrollType.Smooth);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _moveTo(from: Selection, to: Position, inSelectionMode: boolean): Selection {\r\n\t\tif (inSelectionMode) {\r\n\t\t\t// move just position\r\n\t\t\treturn new Selection(\r\n\t\t\t\tfrom.selectionStartLineNumber,\r\n\t\t\t\tfrom.selectionStartColumn,\r\n\t\t\t\tto.lineNumber,\r\n\t\t\t\tto.column\r\n\t\t\t);\r\n\t\t} else {\r\n\t\t\t// move everything\r\n\t\t\treturn new Selection(\r\n\t\t\t\tto.lineNumber,\r\n\t\t\t\tto.column,\r\n\t\t\t\tto.lineNumber,\r\n\t\t\t\tto.column\r\n\t\t\t);\r\n\t\t}\r\n\t}\r\n\r\n\tprotected abstract _move(wordSeparators: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position;\r\n}\r\n\r\nexport class WordLeftCommand extends MoveWordCommand {\r\n\tprotected _move(wordSeparators: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {\r\n\t\treturn WordOperations.moveWordLeft(wordSeparators, model, position, wordNavigationType);\r\n\t}\r\n}\r\n\r\nexport class WordRightCommand extends MoveWordCommand {\r\n\tprotected _move(wordSeparators: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {\r\n\t\treturn WordOperations.moveWordRight(wordSeparators, model, position, wordNavigationType);\r\n\t}\r\n}\r\n\r\nexport class CursorWordStartLeft extends WordLeftCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tinSelectionMode: false,\r\n\t\t\twordNavigationType: WordNavigationType.WordStart,\r\n\t\t\tid: 'cursorWordStartLeft',\r\n\t\t\tprecondition: undefined\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class CursorWordEndLeft extends WordLeftCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tinSelectionMode: false,\r\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\r\n\t\t\tid: 'cursorWordEndLeft',\r\n\t\t\tprecondition: undefined\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class CursorWordLeft extends WordLeftCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tinSelectionMode: false,\r\n\t\t\twordNavigationType: WordNavigationType.WordStartFast,\r\n\t\t\tid: 'cursorWordLeft',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.LeftArrow,\r\n\t\t\t\tmac: { primary: KeyMod.Alt | KeyCode.LeftArrow },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class CursorWordStartLeftSelect extends WordLeftCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tinSelectionMode: true,\r\n\t\t\twordNavigationType: WordNavigationType.WordStart,\r\n\t\t\tid: 'cursorWordStartLeftSelect',\r\n\t\t\tprecondition: undefined\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class CursorWordEndLeftSelect extends WordLeftCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tinSelectionMode: true,\r\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\r\n\t\t\tid: 'cursorWordEndLeftSelect',\r\n\t\t\tprecondition: undefined\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class CursorWordLeftSelect extends WordLeftCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tinSelectionMode: true,\r\n\t\t\twordNavigationType: WordNavigationType.WordStartFast,\r\n\t\t\tid: 'cursorWordLeftSelect',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.LeftArrow,\r\n\t\t\t\tmac: { primary: KeyMod.Alt | KeyMod.Shift | KeyCode.LeftArrow },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n\r\n// Accessibility navigation commands should only be enabled on windows since they are tuned to what NVDA expects\r\nexport class CursorWordAccessibilityLeft extends WordLeftCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tinSelectionMode: false,\r\n\t\t\twordNavigationType: WordNavigationType.WordAccessibility,\r\n\t\t\tid: 'cursorWordAccessibilityLeft',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: ContextKeyExpr.and(EditorContextKeys.textInputFocus, CONTEXT_ACCESSIBILITY_MODE_ENABLED),\r\n\t\t\t\twin: { primary: KeyMod.CtrlCmd | KeyCode.LeftArrow },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib + 1\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprotected _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {\r\n\t\treturn super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), model, position, wordNavigationType);\r\n\t}\r\n}\r\n\r\nexport class CursorWordAccessibilityLeftSelect extends WordLeftCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tinSelectionMode: true,\r\n\t\t\twordNavigationType: WordNavigationType.WordAccessibility,\r\n\t\t\tid: 'cursorWordAccessibilityLeftSelect',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: ContextKeyExpr.and(EditorContextKeys.textInputFocus, CONTEXT_ACCESSIBILITY_MODE_ENABLED),\r\n\t\t\t\twin: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.LeftArrow },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib + 1\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprotected _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {\r\n\t\treturn super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), model, position, wordNavigationType);\r\n\t}\r\n}\r\n\r\nexport class CursorWordStartRight extends WordRightCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tinSelectionMode: false,\r\n\t\t\twordNavigationType: WordNavigationType.WordStart,\r\n\t\t\tid: 'cursorWordStartRight',\r\n\t\t\tprecondition: undefined\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class CursorWordEndRight extends WordRightCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tinSelectionMode: false,\r\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\r\n\t\t\tid: 'cursorWordEndRight',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.RightArrow,\r\n\t\t\t\tmac: { primary: KeyMod.Alt | KeyCode.RightArrow },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class CursorWordRight extends WordRightCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tinSelectionMode: false,\r\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\r\n\t\t\tid: 'cursorWordRight',\r\n\t\t\tprecondition: undefined\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class CursorWordStartRightSelect extends WordRightCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tinSelectionMode: true,\r\n\t\t\twordNavigationType: WordNavigationType.WordStart,\r\n\t\t\tid: 'cursorWordStartRightSelect',\r\n\t\t\tprecondition: undefined\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class CursorWordEndRightSelect extends WordRightCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tinSelectionMode: true,\r\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\r\n\t\t\tid: 'cursorWordEndRightSelect',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.RightArrow,\r\n\t\t\t\tmac: { primary: KeyMod.Alt | KeyMod.Shift | KeyCode.RightArrow },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class CursorWordRightSelect extends WordRightCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tinSelectionMode: true,\r\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\r\n\t\t\tid: 'cursorWordRightSelect',\r\n\t\t\tprecondition: undefined\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class CursorWordAccessibilityRight extends WordRightCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tinSelectionMode: false,\r\n\t\t\twordNavigationType: WordNavigationType.WordAccessibility,\r\n\t\t\tid: 'cursorWordAccessibilityRight',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: ContextKeyExpr.and(EditorContextKeys.textInputFocus, CONTEXT_ACCESSIBILITY_MODE_ENABLED),\r\n\t\t\t\twin: { primary: KeyMod.CtrlCmd | KeyCode.RightArrow },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib + 1\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprotected _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {\r\n\t\treturn super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), model, position, wordNavigationType);\r\n\t}\r\n}\r\n\r\nexport class CursorWordAccessibilityRightSelect extends WordRightCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tinSelectionMode: true,\r\n\t\t\twordNavigationType: WordNavigationType.WordAccessibility,\r\n\t\t\tid: 'cursorWordAccessibilityRightSelect',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: ContextKeyExpr.and(EditorContextKeys.textInputFocus, CONTEXT_ACCESSIBILITY_MODE_ENABLED),\r\n\t\t\t\twin: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.RightArrow },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib + 1\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprotected _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {\r\n\t\treturn super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), model, position, wordNavigationType);\r\n\t}\r\n}\r\n\r\nexport interface DeleteWordOptions extends ICommandOptions {\r\n\twhitespaceHeuristics: boolean;\r\n\twordNavigationType: WordNavigationType;\r\n}\r\n\r\nexport abstract class DeleteWordCommand extends EditorCommand {\r\n\tprivate readonly _whitespaceHeuristics: boolean;\r\n\tprivate readonly _wordNavigationType: WordNavigationType;\r\n\r\n\tconstructor(opts: DeleteWordOptions) {\r\n\t\tsuper(opts);\r\n\t\tthis._whitespaceHeuristics = opts.whitespaceHeuristics;\r\n\t\tthis._wordNavigationType = opts.wordNavigationType;\r\n\t}\r\n\r\n\tpublic runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst wordSeparators = getMapForWordSeparators(editor.getOption(EditorOption.wordSeparators));\r\n\t\tconst model = editor.getModel();\r\n\t\tconst selections = editor.getSelections();\r\n\t\tconst autoClosingBrackets = editor.getOption(EditorOption.autoClosingBrackets);\r\n\t\tconst autoClosingQuotes = editor.getOption(EditorOption.autoClosingQuotes);\r\n\t\tconst autoClosingPairs = LanguageConfigurationRegistry.getAutoClosingPairs(model.getLanguageIdentifier().id);\r\n\r\n\t\tconst commands = selections.map((sel) => {\r\n\t\t\tconst deleteRange = this._delete({\r\n\t\t\t\twordSeparators,\r\n\t\t\t\tmodel,\r\n\t\t\t\tselection: sel,\r\n\t\t\t\twhitespaceHeuristics: this._whitespaceHeuristics,\r\n\t\t\t\tautoClosingBrackets,\r\n\t\t\t\tautoClosingQuotes,\r\n\t\t\t\tautoClosingPairs,\r\n\t\t\t}, this._wordNavigationType);\r\n\t\t\treturn new ReplaceCommand(deleteRange, '');\r\n\t\t});\r\n\r\n\t\teditor.pushUndoStop();\r\n\t\teditor.executeCommands(this.id, commands);\r\n\t\teditor.pushUndoStop();\r\n\t}\r\n\r\n\tprotected abstract _delete(ctx: DeleteWordContext, wordNavigationType: WordNavigationType): Range;\r\n}\r\n\r\nexport class DeleteWordLeftCommand extends DeleteWordCommand {\r\n\tprotected _delete(ctx: DeleteWordContext, wordNavigationType: WordNavigationType): Range {\r\n\t\tlet r = WordOperations.deleteWordLeft(ctx, wordNavigationType);\r\n\t\tif (r) {\r\n\t\t\treturn r;\r\n\t\t}\r\n\t\treturn new Range(1, 1, 1, 1);\r\n\t}\r\n}\r\n\r\nexport class DeleteWordRightCommand extends DeleteWordCommand {\r\n\tprotected _delete(ctx: DeleteWordContext, wordNavigationType: WordNavigationType): Range {\r\n\t\tlet r = WordOperations.deleteWordRight(ctx, wordNavigationType);\r\n\t\tif (r) {\r\n\t\t\treturn r;\r\n\t\t}\r\n\t\tconst lineCount = ctx.model.getLineCount();\r\n\t\tconst maxColumn = ctx.model.getLineMaxColumn(lineCount);\r\n\t\treturn new Range(lineCount, maxColumn, lineCount, maxColumn);\r\n\t}\r\n}\r\n\r\nexport class DeleteWordStartLeft extends DeleteWordLeftCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\twhitespaceHeuristics: false,\r\n\t\t\twordNavigationType: WordNavigationType.WordStart,\r\n\t\t\tid: 'deleteWordStartLeft',\r\n\t\t\tprecondition: EditorContextKeys.writable\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class DeleteWordEndLeft extends DeleteWordLeftCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\twhitespaceHeuristics: false,\r\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\r\n\t\t\tid: 'deleteWordEndLeft',\r\n\t\t\tprecondition: EditorContextKeys.writable\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class DeleteWordLeft extends DeleteWordLeftCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\twhitespaceHeuristics: true,\r\n\t\t\twordNavigationType: WordNavigationType.WordStart,\r\n\t\t\tid: 'deleteWordLeft',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.Backspace,\r\n\t\t\t\tmac: { primary: KeyMod.Alt | KeyCode.Backspace },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class DeleteWordStartRight extends DeleteWordRightCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\twhitespaceHeuristics: false,\r\n\t\t\twordNavigationType: WordNavigationType.WordStart,\r\n\t\t\tid: 'deleteWordStartRight',\r\n\t\t\tprecondition: EditorContextKeys.writable\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class DeleteWordEndRight extends DeleteWordRightCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\twhitespaceHeuristics: false,\r\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\r\n\t\t\tid: 'deleteWordEndRight',\r\n\t\t\tprecondition: EditorContextKeys.writable\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class DeleteWordRight extends DeleteWordRightCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\twhitespaceHeuristics: true,\r\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\r\n\t\t\tid: 'deleteWordRight',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.Delete,\r\n\t\t\t\tmac: { primary: KeyMod.Alt | KeyCode.Delete },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport class DeleteInsideWord extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'deleteInsideWord',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tlabel: nls.localize('deleteInsideWord', \"Delete Word\"),\r\n\t\t\talias: 'Delete Word'\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst wordSeparators = getMapForWordSeparators(editor.getOption(EditorOption.wordSeparators));\r\n\t\tconst model = editor.getModel();\r\n\t\tconst selections = editor.getSelections();\r\n\r\n\t\tconst commands = selections.map((sel) => {\r\n\t\t\tconst deleteRange = WordOperations.deleteInsideWord(wordSeparators, model, sel);\r\n\t\t\treturn new ReplaceCommand(deleteRange, '');\r\n\t\t});\r\n\r\n\t\teditor.pushUndoStop();\r\n\t\teditor.executeCommands(this.id, commands);\r\n\t\teditor.pushUndoStop();\r\n\t}\r\n}\r\n\r\nregisterEditorCommand(new CursorWordStartLeft());\r\nregisterEditorCommand(new CursorWordEndLeft());\r\nregisterEditorCommand(new CursorWordLeft());\r\nregisterEditorCommand(new CursorWordStartLeftSelect());\r\nregisterEditorCommand(new CursorWordEndLeftSelect());\r\nregisterEditorCommand(new CursorWordLeftSelect());\r\nregisterEditorCommand(new CursorWordStartRight());\r\nregisterEditorCommand(new CursorWordEndRight());\r\nregisterEditorCommand(new CursorWordRight());\r\nregisterEditorCommand(new CursorWordStartRightSelect());\r\nregisterEditorCommand(new CursorWordEndRightSelect());\r\nregisterEditorCommand(new CursorWordRightSelect());\r\nregisterEditorCommand(new CursorWordAccessibilityLeft());\r\nregisterEditorCommand(new CursorWordAccessibilityLeftSelect());\r\nregisterEditorCommand(new CursorWordAccessibilityRight());\r\nregisterEditorCommand(new CursorWordAccessibilityRightSelect());\r\nregisterEditorCommand(new DeleteWordStartLeft());\r\nregisterEditorCommand(new DeleteWordEndLeft());\r\nregisterEditorCommand(new DeleteWordLeft());\r\nregisterEditorCommand(new DeleteWordStartRight());\r\nregisterEditorCommand(new DeleteWordEndRight());\r\nregisterEditorCommand(new DeleteWordRight());\r\nregisterEditorAction(DeleteInsideWord);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { registerEditorCommand } from 'vs/editor/browser/editorExtensions';\r\nimport { DeleteWordContext, WordNavigationType, WordPartOperations } from 'vs/editor/common/controller/cursorWordOperations';\r\nimport { WordCharacterClassifier } from 'vs/editor/common/controller/wordCharacterClassifier';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { DeleteWordCommand, MoveWordCommand } from 'vs/editor/contrib/wordOperations/wordOperations';\r\nimport { CommandsRegistry } from 'vs/platform/commands/common/commands';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\n\r\nexport class DeleteWordPartLeft extends DeleteWordCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\twhitespaceHeuristics: true,\r\n\t\t\twordNavigationType: WordNavigationType.WordStart,\r\n\t\t\tid: 'deleteWordPartLeft',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\tprimary: 0,\r\n\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.Backspace },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprotected _delete(ctx: DeleteWordContext, wordNavigationType: WordNavigationType): Range {\r\n\t\tlet r = WordPartOperations.deleteWordPartLeft(ctx);\r\n\t\tif (r) {\r\n\t\t\treturn r;\r\n\t\t}\r\n\t\treturn new Range(1, 1, 1, 1);\r\n\t}\r\n}\r\n\r\nexport class DeleteWordPartRight extends DeleteWordCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\twhitespaceHeuristics: true,\r\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\r\n\t\t\tid: 'deleteWordPartRight',\r\n\t\t\tprecondition: EditorContextKeys.writable,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\tprimary: 0,\r\n\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.Delete },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprotected _delete(ctx: DeleteWordContext, wordNavigationType: WordNavigationType): Range {\r\n\t\tlet r = WordPartOperations.deleteWordPartRight(ctx);\r\n\t\tif (r) {\r\n\t\t\treturn r;\r\n\t\t}\r\n\t\tconst lineCount = ctx.model.getLineCount();\r\n\t\tconst maxColumn = ctx.model.getLineMaxColumn(lineCount);\r\n\t\treturn new Range(lineCount, maxColumn, lineCount, maxColumn);\r\n\t}\r\n}\r\n\r\nexport class WordPartLeftCommand extends MoveWordCommand {\r\n\tprotected _move(wordSeparators: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {\r\n\t\treturn WordPartOperations.moveWordPartLeft(wordSeparators, model, position);\r\n\t}\r\n}\r\nexport class CursorWordPartLeft extends WordPartLeftCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tinSelectionMode: false,\r\n\t\t\twordNavigationType: WordNavigationType.WordStart,\r\n\t\t\tid: 'cursorWordPartLeft',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\tprimary: 0,\r\n\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.LeftArrow },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n// Register previous id for compatibility purposes\r\nCommandsRegistry.registerCommandAlias('cursorWordPartStartLeft', 'cursorWordPartLeft');\r\n\r\nexport class CursorWordPartLeftSelect extends WordPartLeftCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tinSelectionMode: true,\r\n\t\t\twordNavigationType: WordNavigationType.WordStart,\r\n\t\t\tid: 'cursorWordPartLeftSelect',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\tprimary: 0,\r\n\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyMod.Shift | KeyCode.LeftArrow },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n// Register previous id for compatibility purposes\r\nCommandsRegistry.registerCommandAlias('cursorWordPartStartLeftSelect', 'cursorWordPartLeftSelect');\r\n\r\nexport class WordPartRightCommand extends MoveWordCommand {\r\n\tprotected _move(wordSeparators: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {\r\n\t\treturn WordPartOperations.moveWordPartRight(wordSeparators, model, position);\r\n\t}\r\n}\r\nexport class CursorWordPartRight extends WordPartRightCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tinSelectionMode: false,\r\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\r\n\t\t\tid: 'cursorWordPartRight',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\tprimary: 0,\r\n\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.RightArrow },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\nexport class CursorWordPartRightSelect extends WordPartRightCommand {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tinSelectionMode: true,\r\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\r\n\t\t\tid: 'cursorWordPartRightSelect',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\r\n\t\t\t\tprimary: 0,\r\n\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyMod.Shift | KeyCode.RightArrow },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n\r\n\r\nregisterEditorCommand(new DeleteWordPartLeft());\r\nregisterEditorCommand(new DeleteWordPartRight());\r\nregisterEditorCommand(new CursorWordPartLeft());\r\nregisterEditorCommand(new CursorWordPartLeftSelect());\r\nregisterEditorCommand(new CursorWordPartRight());\r\nregisterEditorCommand(new CursorWordPartRightSelect());\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./accessibilityHelp';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { renderFormattedText } from 'vs/base/browser/formattedTextRenderer';\r\nimport { alert } from 'vs/base/browser/ui/aria/aria';\r\nimport { Widget } from 'vs/base/browser/ui/widget';\r\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction, EditorCommand, registerEditorAction, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { ToggleTabFocusModeAction } from 'vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode';\r\nimport { IStandaloneEditorConstructionOptions } from 'vs/editor/standalone/browser/standaloneCodeEditor';\r\nimport { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { IOpenerService } from 'vs/platform/opener/common/opener';\r\nimport { contrastBorder, editorWidgetBackground, widgetShadow, editorWidgetForeground } from 'vs/platform/theme/common/colorRegistry';\r\nimport { registerThemingParticipant } from 'vs/platform/theme/common/themeService';\r\nimport { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';\r\nimport { AccessibilityHelpNLS } from 'vs/editor/common/standaloneStrings';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\nconst CONTEXT_ACCESSIBILITY_WIDGET_VISIBLE = new RawContextKey('accessibilityHelpWidgetVisible', false);\r\n\r\nclass AccessibilityHelpController extends Disposable\r\n\timplements IEditorContribution {\r\n\tpublic static readonly ID = 'editor.contrib.accessibilityHelpController';\r\n\r\n\tpublic static get(editor: ICodeEditor): AccessibilityHelpController {\r\n\t\treturn editor.getContribution(\r\n\t\t\tAccessibilityHelpController.ID\r\n\t\t);\r\n\t}\r\n\r\n\tprivate readonly _editor: ICodeEditor;\r\n\tprivate readonly _widget: AccessibilityHelpWidget;\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor,\r\n\t\t@IInstantiationService instantiationService: IInstantiationService\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\tthis._editor = editor;\r\n\t\tthis._widget = this._register(\r\n\t\t\tinstantiationService.createInstance(AccessibilityHelpWidget, this._editor)\r\n\t\t);\r\n\t}\r\n\r\n\tpublic show(): void {\r\n\t\tthis._widget.show();\r\n\t}\r\n\r\n\tpublic hide(): void {\r\n\t\tthis._widget.hide();\r\n\t}\r\n}\r\n\r\n\r\nfunction getSelectionLabel(selections: Selection[] | null, charactersSelected: number): string {\r\n\tif (!selections || selections.length === 0) {\r\n\t\treturn AccessibilityHelpNLS.noSelection;\r\n\t}\r\n\r\n\tif (selections.length === 1) {\r\n\t\tif (charactersSelected) {\r\n\t\t\treturn strings.format(AccessibilityHelpNLS.singleSelectionRange, selections[0].positionLineNumber, selections[0].positionColumn, charactersSelected);\r\n\t\t}\r\n\r\n\t\treturn strings.format(AccessibilityHelpNLS.singleSelection, selections[0].positionLineNumber, selections[0].positionColumn);\r\n\t}\r\n\r\n\tif (charactersSelected) {\r\n\t\treturn strings.format(AccessibilityHelpNLS.multiSelectionRange, selections.length, charactersSelected);\r\n\t}\r\n\r\n\tif (selections.length > 0) {\r\n\t\treturn strings.format(AccessibilityHelpNLS.multiSelection, selections.length);\r\n\t}\r\n\r\n\treturn '';\r\n}\r\n\r\nclass AccessibilityHelpWidget extends Widget implements IOverlayWidget {\r\n\tprivate static readonly ID = 'editor.contrib.accessibilityHelpWidget';\r\n\tprivate static readonly WIDTH = 500;\r\n\tprivate static readonly HEIGHT = 300;\r\n\r\n\tprivate readonly _editor: ICodeEditor;\r\n\tprivate readonly _domNode: FastDomNode;\r\n\tprivate readonly _contentDomNode: FastDomNode;\r\n\tprivate _isVisible: boolean;\r\n\tprivate readonly _isVisibleKey: IContextKey;\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor,\r\n\t\t@IContextKeyService private readonly _contextKeyService: IContextKeyService,\r\n\t\t@IKeybindingService private readonly _keybindingService: IKeybindingService,\r\n\t\t@IOpenerService private readonly _openerService: IOpenerService\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\tthis._editor = editor;\r\n\t\tthis._isVisibleKey = CONTEXT_ACCESSIBILITY_WIDGET_VISIBLE.bindTo(\r\n\t\t\tthis._contextKeyService\r\n\t\t);\r\n\r\n\t\tthis._domNode = createFastDomNode(document.createElement('div'));\r\n\t\tthis._domNode.setClassName('accessibilityHelpWidget');\r\n\t\tthis._domNode.setDisplay('none');\r\n\t\tthis._domNode.setAttribute('role', 'dialog');\r\n\t\tthis._domNode.setAttribute('aria-hidden', 'true');\r\n\r\n\t\tthis._contentDomNode = createFastDomNode(document.createElement('div'));\r\n\t\tthis._contentDomNode.setAttribute('role', 'document');\r\n\t\tthis._domNode.appendChild(this._contentDomNode);\r\n\r\n\t\tthis._isVisible = false;\r\n\r\n\t\tthis._register(this._editor.onDidLayoutChange(() => {\r\n\t\t\tif (this._isVisible) {\r\n\t\t\t\tthis._layout();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\t// Intentionally not configurable!\r\n\t\tthis._register(dom.addStandardDisposableListener(this._contentDomNode.domNode, 'keydown', (e) => {\r\n\t\t\tif (!this._isVisible) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (e.equals(KeyMod.CtrlCmd | KeyCode.KEY_E)) {\r\n\t\t\t\talert(AccessibilityHelpNLS.emergencyConfOn);\r\n\r\n\t\t\t\tthis._editor.updateOptions({\r\n\t\t\t\t\taccessibilitySupport: 'on'\r\n\t\t\t\t});\r\n\r\n\t\t\t\tdom.clearNode(this._contentDomNode.domNode);\r\n\t\t\t\tthis._buildContent();\r\n\t\t\t\tthis._contentDomNode.domNode.focus();\r\n\r\n\t\t\t\te.preventDefault();\r\n\t\t\t\te.stopPropagation();\r\n\t\t\t}\r\n\r\n\t\t\tif (e.equals(KeyMod.CtrlCmd | KeyCode.KEY_H)) {\r\n\t\t\t\talert(AccessibilityHelpNLS.openingDocs);\r\n\r\n\t\t\t\tlet url = (this._editor.getRawOptions()).accessibilityHelpUrl;\r\n\t\t\t\tif (typeof url === 'undefined') {\r\n\t\t\t\t\turl = 'https://go.microsoft.com/fwlink/?linkid=852450';\r\n\t\t\t\t}\r\n\t\t\t\tthis._openerService.open(URI.parse(url));\r\n\r\n\t\t\t\te.preventDefault();\r\n\t\t\t\te.stopPropagation();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis.onblur(this._contentDomNode.domNode, () => {\r\n\t\t\tthis.hide();\r\n\t\t});\r\n\r\n\t\tthis._editor.addOverlayWidget(this);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._editor.removeOverlayWidget(this);\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tpublic getId(): string {\r\n\t\treturn AccessibilityHelpWidget.ID;\r\n\t}\r\n\r\n\tpublic getDomNode(): HTMLElement {\r\n\t\treturn this._domNode.domNode;\r\n\t}\r\n\r\n\tpublic getPosition(): IOverlayWidgetPosition {\r\n\t\treturn {\r\n\t\t\tpreference: null\r\n\t\t};\r\n\t}\r\n\r\n\tpublic show(): void {\r\n\t\tif (this._isVisible) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._isVisible = true;\r\n\t\tthis._isVisibleKey.set(true);\r\n\t\tthis._layout();\r\n\t\tthis._domNode.setDisplay('block');\r\n\t\tthis._domNode.setAttribute('aria-hidden', 'false');\r\n\t\tthis._contentDomNode.domNode.tabIndex = 0;\r\n\t\tthis._buildContent();\r\n\t\tthis._contentDomNode.domNode.focus();\r\n\t}\r\n\r\n\tprivate _descriptionForCommand(commandId: string, msg: string, noKbMsg: string): string {\r\n\t\tlet kb = this._keybindingService.lookupKeybinding(commandId);\r\n\t\tif (kb) {\r\n\t\t\treturn strings.format(msg, kb.getAriaLabel());\r\n\t\t}\r\n\t\treturn strings.format(noKbMsg, commandId);\r\n\t}\r\n\r\n\tprivate _buildContent() {\r\n\t\tconst options = this._editor.getOptions();\r\n\r\n\t\tconst selections = this._editor.getSelections();\r\n\t\tlet charactersSelected = 0;\r\n\r\n\t\tif (selections) {\r\n\t\t\tconst model = this._editor.getModel();\r\n\t\t\tif (model) {\r\n\t\t\t\tselections.forEach((selection) => {\r\n\t\t\t\t\tcharactersSelected += model.getValueLengthInRange(selection);\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet text = getSelectionLabel(selections, charactersSelected);\r\n\r\n\t\tif (options.get(EditorOption.inDiffEditor)) {\r\n\t\t\tif (options.get(EditorOption.readOnly)) {\r\n\t\t\t\ttext += AccessibilityHelpNLS.readonlyDiffEditor;\r\n\t\t\t} else {\r\n\t\t\t\ttext += AccessibilityHelpNLS.editableDiffEditor;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tif (options.get(EditorOption.readOnly)) {\r\n\t\t\t\ttext += AccessibilityHelpNLS.readonlyEditor;\r\n\t\t\t} else {\r\n\t\t\t\ttext += AccessibilityHelpNLS.editableEditor;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst turnOnMessage = (\r\n\t\t\tplatform.isMacintosh\r\n\t\t\t\t? AccessibilityHelpNLS.changeConfigToOnMac\r\n\t\t\t\t: AccessibilityHelpNLS.changeConfigToOnWinLinux\r\n\t\t);\r\n\t\tswitch (options.get(EditorOption.accessibilitySupport)) {\r\n\t\t\tcase AccessibilitySupport.Unknown:\r\n\t\t\t\ttext += '\\n\\n - ' + turnOnMessage;\r\n\t\t\t\tbreak;\r\n\t\t\tcase AccessibilitySupport.Enabled:\r\n\t\t\t\ttext += '\\n\\n - ' + AccessibilityHelpNLS.auto_on;\r\n\t\t\t\tbreak;\r\n\t\t\tcase AccessibilitySupport.Disabled:\r\n\t\t\t\ttext += '\\n\\n - ' + AccessibilityHelpNLS.auto_off;\r\n\t\t\t\ttext += ' ' + turnOnMessage;\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\r\n\r\n\t\tif (options.get(EditorOption.tabFocusMode)) {\r\n\t\t\ttext += '\\n\\n - ' + this._descriptionForCommand(ToggleTabFocusModeAction.ID, AccessibilityHelpNLS.tabFocusModeOnMsg, AccessibilityHelpNLS.tabFocusModeOnMsgNoKb);\r\n\t\t} else {\r\n\t\t\ttext += '\\n\\n - ' + this._descriptionForCommand(ToggleTabFocusModeAction.ID, AccessibilityHelpNLS.tabFocusModeOffMsg, AccessibilityHelpNLS.tabFocusModeOffMsgNoKb);\r\n\t\t}\r\n\r\n\t\tconst openDocMessage = (\r\n\t\t\tplatform.isMacintosh\r\n\t\t\t\t? AccessibilityHelpNLS.openDocMac\r\n\t\t\t\t: AccessibilityHelpNLS.openDocWinLinux\r\n\t\t);\r\n\r\n\t\ttext += '\\n\\n - ' + openDocMessage;\r\n\r\n\t\ttext += '\\n\\n' + AccessibilityHelpNLS.outroMsg;\r\n\r\n\t\tthis._contentDomNode.domNode.appendChild(renderFormattedText(text));\r\n\t\t// Per https://www.w3.org/TR/wai-aria/roles#document, Authors SHOULD provide a title or label for documents\r\n\t\tthis._contentDomNode.domNode.setAttribute('aria-label', text);\r\n\t}\r\n\r\n\tpublic hide(): void {\r\n\t\tif (!this._isVisible) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._isVisible = false;\r\n\t\tthis._isVisibleKey.reset();\r\n\t\tthis._domNode.setDisplay('none');\r\n\t\tthis._domNode.setAttribute('aria-hidden', 'true');\r\n\t\tthis._contentDomNode.domNode.tabIndex = -1;\r\n\t\tdom.clearNode(this._contentDomNode.domNode);\r\n\r\n\t\tthis._editor.focus();\r\n\t}\r\n\r\n\tprivate _layout(): void {\r\n\t\tlet editorLayout = this._editor.getLayoutInfo();\r\n\r\n\t\tlet w = Math.max(5, Math.min(AccessibilityHelpWidget.WIDTH, editorLayout.width - 40));\r\n\t\tlet h = Math.max(5, Math.min(AccessibilityHelpWidget.HEIGHT, editorLayout.height - 40));\r\n\r\n\t\tthis._domNode.setWidth(w);\r\n\t\tthis._domNode.setHeight(h);\r\n\r\n\t\tlet top = Math.round((editorLayout.height - h) / 2);\r\n\t\tthis._domNode.setTop(top);\r\n\r\n\t\tlet left = Math.round((editorLayout.width - w) / 2);\r\n\t\tthis._domNode.setLeft(left);\r\n\t}\r\n}\r\n\r\nclass ShowAccessibilityHelpAction extends EditorAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.showAccessibilityHelp',\r\n\t\t\tlabel: AccessibilityHelpNLS.showAccessibilityHelpAction,\r\n\t\t\talias: 'Show Accessibility Help',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tprimary: KeyMod.Alt | KeyCode.F1,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib,\r\n\t\t\t\tlinux: {\r\n\t\t\t\t\tprimary: KeyMod.Alt | KeyMod.Shift | KeyCode.F1,\r\n\t\t\t\t\tsecondary: [KeyMod.Alt | KeyCode.F1]\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tlet controller = AccessibilityHelpController.get(editor);\r\n\t\tif (controller) {\r\n\t\t\tcontroller.show();\r\n\t\t}\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(AccessibilityHelpController.ID, AccessibilityHelpController);\r\nregisterEditorAction(ShowAccessibilityHelpAction);\r\n\r\nconst AccessibilityHelpCommand = EditorCommand.bindToContribution(AccessibilityHelpController.get);\r\n\r\nregisterEditorCommand(\r\n\tnew AccessibilityHelpCommand({\r\n\t\tid: 'closeAccessibilityHelp',\r\n\t\tprecondition: CONTEXT_ACCESSIBILITY_WIDGET_VISIBLE,\r\n\t\thandler: x => x.hide(),\r\n\t\tkbOpts: {\r\n\t\t\tweight: KeybindingWeight.EditorContrib + 100,\r\n\t\t\tkbExpr: EditorContextKeys.focus,\r\n\t\t\tprimary: KeyCode.Escape,\r\n\t\t\tsecondary: [KeyMod.Shift | KeyCode.Escape]\r\n\t\t}\r\n\t})\r\n);\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst widgetBackground = theme.getColor(editorWidgetBackground);\r\n\tif (widgetBackground) {\r\n\t\tcollector.addRule(`.monaco-editor .accessibilityHelpWidget { background-color: ${widgetBackground}; }`);\r\n\t}\r\n\tconst widgetForeground = theme.getColor(editorWidgetForeground);\r\n\tif (widgetForeground) {\r\n\t\tcollector.addRule(`.monaco-editor .accessibilityHelpWidget { color: ${widgetForeground}; }`);\r\n\t}\r\n\r\n\r\n\tconst widgetShadowColor = theme.getColor(widgetShadow);\r\n\tif (widgetShadowColor) {\r\n\t\tcollector.addRule(`.monaco-editor .accessibilityHelpWidget { box-shadow: 0 2px 8px ${widgetShadowColor}; }`);\r\n\t}\r\n\r\n\tconst hcBorder = theme.getColor(contrastBorder);\r\n\tif (hcBorder) {\r\n\t\tcollector.addRule(`.monaco-editor .accessibilityHelpWidget { border: 2px solid ${hcBorder}; }`);\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./iPadShowKeyboard';\r\nimport * as browser from 'vs/base/browser/browser';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';\r\nimport { registerEditorContribution } from 'vs/editor/browser/editorExtensions';\r\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\nexport class IPadShowKeyboard extends Disposable implements IEditorContribution {\r\n\r\n\tpublic static readonly ID = 'editor.contrib.iPadShowKeyboard';\r\n\r\n\tprivate readonly editor: ICodeEditor;\r\n\tprivate widget: ShowKeyboardWidget | null;\r\n\r\n\tconstructor(editor: ICodeEditor) {\r\n\t\tsuper();\r\n\t\tthis.editor = editor;\r\n\t\tthis.widget = null;\r\n\t\tif (browser.isIPad) {\r\n\t\t\tthis._register(editor.onDidChangeConfiguration(() => this.update()));\r\n\t\t\tthis.update();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate update(): void {\r\n\t\tconst shouldHaveWidget = (!this.editor.getOption(EditorOption.readOnly));\r\n\r\n\t\tif (!this.widget && shouldHaveWidget) {\r\n\r\n\t\t\tthis.widget = new ShowKeyboardWidget(this.editor);\r\n\r\n\t\t} else if (this.widget && !shouldHaveWidget) {\r\n\r\n\t\t\tthis.widget.dispose();\r\n\t\t\tthis.widget = null;\r\n\r\n\t\t}\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tsuper.dispose();\r\n\t\tif (this.widget) {\r\n\t\t\tthis.widget.dispose();\r\n\t\t\tthis.widget = null;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass ShowKeyboardWidget extends Disposable implements IOverlayWidget {\r\n\r\n\tprivate static readonly ID = 'editor.contrib.ShowKeyboardWidget';\r\n\r\n\tprivate readonly editor: ICodeEditor;\r\n\r\n\tprivate readonly _domNode: HTMLElement;\r\n\r\n\tconstructor(editor: ICodeEditor) {\r\n\t\tsuper();\r\n\t\tthis.editor = editor;\r\n\t\tthis._domNode = document.createElement('textarea');\r\n\t\tthis._domNode.className = 'iPadShowKeyboard';\r\n\r\n\t\tthis._register(dom.addDisposableListener(this._domNode, 'touchstart', (e) => {\r\n\t\t\tthis.editor.focus();\r\n\t\t}));\r\n\t\tthis._register(dom.addDisposableListener(this._domNode, 'focus', (e) => {\r\n\t\t\tthis.editor.focus();\r\n\t\t}));\r\n\r\n\t\tthis.editor.addOverlayWidget(this);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis.editor.removeOverlayWidget(this);\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\t// ----- IOverlayWidget API\r\n\r\n\tpublic getId(): string {\r\n\t\treturn ShowKeyboardWidget.ID;\r\n\t}\r\n\r\n\tpublic getDomNode(): HTMLElement {\r\n\t\treturn this._domNode;\r\n\t}\r\n\r\n\tpublic getPosition(): IOverlayWidgetPosition {\r\n\t\treturn {\r\n\t\t\tpreference: OverlayWidgetPositionPreference.BOTTOM_RIGHT_CORNER\r\n\t\t};\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(IPadShowKeyboard.ID, IPadShowKeyboard);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./inspectTokens';\r\nimport { $, append, reset } from 'vs/base/browser/dom';\r\nimport { CharCode } from 'vs/base/common/charCode';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { KeyCode } from 'vs/base/common/keyCodes';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { ContentWidgetPositionPreference, IActiveCodeEditor, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Token } from 'vs/editor/common/core/token';\r\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { FontStyle, IState, ITokenizationSupport, LanguageIdentifier, StandardTokenType, TokenMetadata, TokenizationRegistry } from 'vs/editor/common/modes';\r\nimport { NULL_STATE, nullTokenize, nullTokenize2 } from 'vs/editor/common/modes/nullMode';\r\nimport { IModeService } from 'vs/editor/common/services/modeService';\r\nimport { IStandaloneThemeService } from 'vs/editor/standalone/common/standaloneThemeService';\r\nimport { editorHoverBackground, editorHoverBorder, editorHoverForeground } from 'vs/platform/theme/common/colorRegistry';\r\nimport { registerThemingParticipant } from 'vs/platform/theme/common/themeService';\r\nimport { InspectTokensNLS } from 'vs/editor/common/standaloneStrings';\r\nimport { ColorScheme } from 'vs/platform/theme/common/theme';\r\n\r\n\r\nclass InspectTokensController extends Disposable implements IEditorContribution {\r\n\r\n\tpublic static readonly ID = 'editor.contrib.inspectTokens';\r\n\r\n\tpublic static get(editor: ICodeEditor): InspectTokensController {\r\n\t\treturn editor.getContribution(InspectTokensController.ID);\r\n\t}\r\n\r\n\tprivate readonly _editor: ICodeEditor;\r\n\tprivate readonly _modeService: IModeService;\r\n\tprivate _widget: InspectTokensWidget | null;\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor,\r\n\t\t@IStandaloneThemeService standaloneColorService: IStandaloneThemeService,\r\n\t\t@IModeService modeService: IModeService\r\n\t) {\r\n\t\tsuper();\r\n\t\tthis._editor = editor;\r\n\t\tthis._modeService = modeService;\r\n\t\tthis._widget = null;\r\n\r\n\t\tthis._register(this._editor.onDidChangeModel((e) => this.stop()));\r\n\t\tthis._register(this._editor.onDidChangeModelLanguage((e) => this.stop()));\r\n\t\tthis._register(TokenizationRegistry.onDidChange((e) => this.stop()));\r\n\t\tthis._register(this._editor.onKeyUp((e) => e.keyCode === KeyCode.Escape && this.stop()));\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis.stop();\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tpublic launch(): void {\r\n\t\tif (this._widget) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._widget = new InspectTokensWidget(this._editor, this._modeService);\r\n\t}\r\n\r\n\tpublic stop(): void {\r\n\t\tif (this._widget) {\r\n\t\t\tthis._widget.dispose();\r\n\t\t\tthis._widget = null;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass InspectTokens extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.inspectTokens',\r\n\t\t\tlabel: InspectTokensNLS.inspectTokensAction,\r\n\t\t\talias: 'Developer: Inspect Tokens',\r\n\t\t\tprecondition: undefined\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tlet controller = InspectTokensController.get(editor);\r\n\t\tif (controller) {\r\n\t\t\tcontroller.launch();\r\n\t\t}\r\n\t}\r\n}\r\n\r\ninterface ICompleteLineTokenization {\r\n\tstartState: IState;\r\n\ttokens1: Token[];\r\n\ttokens2: Uint32Array;\r\n\tendState: IState;\r\n}\r\n\r\ninterface IDecodedMetadata {\r\n\tlanguageIdentifier: LanguageIdentifier;\r\n\ttokenType: StandardTokenType;\r\n\tfontStyle: FontStyle;\r\n\tforeground: Color;\r\n\tbackground: Color;\r\n}\r\n\r\nfunction renderTokenText(tokenText: string): string {\r\n\tlet result: string = '';\r\n\tfor (let charIndex = 0, len = tokenText.length; charIndex < len; charIndex++) {\r\n\t\tlet charCode = tokenText.charCodeAt(charIndex);\r\n\t\tswitch (charCode) {\r\n\t\t\tcase CharCode.Tab:\r\n\t\t\t\tresult += '\\u2192'; // →\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase CharCode.Space:\r\n\t\t\t\tresult += '\\u00B7'; // ·\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tdefault:\r\n\t\t\t\tresult += String.fromCharCode(charCode);\r\n\t\t}\r\n\t}\r\n\treturn result;\r\n}\r\n\r\nfunction getSafeTokenizationSupport(languageIdentifier: LanguageIdentifier): ITokenizationSupport {\r\n\tlet tokenizationSupport = TokenizationRegistry.get(languageIdentifier.language);\r\n\tif (tokenizationSupport) {\r\n\t\treturn tokenizationSupport;\r\n\t}\r\n\treturn {\r\n\t\tgetInitialState: () => NULL_STATE,\r\n\t\ttokenize: (line: string, hasEOL: boolean, state: IState, deltaOffset: number) => nullTokenize(languageIdentifier.language, line, state, deltaOffset),\r\n\t\ttokenize2: (line: string, hasEOL: boolean, state: IState, deltaOffset: number) => nullTokenize2(languageIdentifier.id, line, state, deltaOffset)\r\n\t};\r\n}\r\n\r\nclass InspectTokensWidget extends Disposable implements IContentWidget {\r\n\r\n\tprivate static readonly _ID = 'editor.contrib.inspectTokensWidget';\r\n\r\n\t// Editor.IContentWidget.allowEditorOverflow\r\n\tpublic allowEditorOverflow = true;\r\n\r\n\tprivate readonly _editor: IActiveCodeEditor;\r\n\tprivate readonly _modeService: IModeService;\r\n\tprivate readonly _tokenizationSupport: ITokenizationSupport;\r\n\tprivate readonly _model: ITextModel;\r\n\tprivate readonly _domNode: HTMLElement;\r\n\r\n\tconstructor(\r\n\t\teditor: IActiveCodeEditor,\r\n\t\tmodeService: IModeService\r\n\t) {\r\n\t\tsuper();\r\n\t\tthis._editor = editor;\r\n\t\tthis._modeService = modeService;\r\n\t\tthis._model = this._editor.getModel();\r\n\t\tthis._domNode = document.createElement('div');\r\n\t\tthis._domNode.className = 'tokens-inspect-widget';\r\n\t\tthis._tokenizationSupport = getSafeTokenizationSupport(this._model.getLanguageIdentifier());\r\n\t\tthis._compute(this._editor.getPosition());\r\n\t\tthis._register(this._editor.onDidChangeCursorPosition((e) => this._compute(this._editor.getPosition())));\r\n\t\tthis._editor.addContentWidget(this);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._editor.removeContentWidget(this);\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tpublic getId(): string {\r\n\t\treturn InspectTokensWidget._ID;\r\n\t}\r\n\r\n\tprivate _compute(position: Position): void {\r\n\t\tlet data = this._getTokensAtLine(position.lineNumber);\r\n\r\n\t\tlet token1Index = 0;\r\n\t\tfor (let i = data.tokens1.length - 1; i >= 0; i--) {\r\n\t\t\tlet t = data.tokens1[i];\r\n\t\t\tif (position.column - 1 >= t.offset) {\r\n\t\t\t\ttoken1Index = i;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet token2Index = 0;\r\n\t\tfor (let i = (data.tokens2.length >>> 1); i >= 0; i--) {\r\n\t\t\tif (position.column - 1 >= data.tokens2[(i << 1)]) {\r\n\t\t\t\ttoken2Index = i;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet lineContent = this._model.getLineContent(position.lineNumber);\r\n\t\tlet tokenText = '';\r\n\t\tif (token1Index < data.tokens1.length) {\r\n\t\t\tlet tokenStartIndex = data.tokens1[token1Index].offset;\r\n\t\t\tlet tokenEndIndex = token1Index + 1 < data.tokens1.length ? data.tokens1[token1Index + 1].offset : lineContent.length;\r\n\t\t\ttokenText = lineContent.substring(tokenStartIndex, tokenEndIndex);\r\n\t\t}\r\n\t\treset(this._domNode,\r\n\t\t\t$('h2.tm-token', undefined, renderTokenText(tokenText),\r\n\t\t\t\t$('span.tm-token-length', undefined, `${tokenText.length} ${tokenText.length === 1 ? 'char' : 'chars'}`)));\r\n\r\n\t\tappend(this._domNode, $('hr.tokens-inspect-separator', { 'style': 'clear:both' }));\r\n\r\n\t\tconst metadata = (token2Index << 1) + 1 < data.tokens2.length ? this._decodeMetadata(data.tokens2[(token2Index << 1) + 1]) : null;\r\n\t\tappend(this._domNode, $('table.tm-metadata-table', undefined,\r\n\t\t\t$('tbody', undefined,\r\n\t\t\t\t$('tr', undefined,\r\n\t\t\t\t\t$('td.tm-metadata-key', undefined, 'language'),\r\n\t\t\t\t\t$('td.tm-metadata-value', undefined, `${metadata ? metadata.languageIdentifier.language : '-?-'}`)\r\n\t\t\t\t),\r\n\t\t\t\t$('tr', undefined,\r\n\t\t\t\t\t$('td.tm-metadata-key', undefined, 'token type' as string),\r\n\t\t\t\t\t$('td.tm-metadata-value', undefined, `${metadata ? this._tokenTypeToString(metadata.tokenType) : '-?-'}`)\r\n\t\t\t\t),\r\n\t\t\t\t$('tr', undefined,\r\n\t\t\t\t\t$('td.tm-metadata-key', undefined, 'font style' as string),\r\n\t\t\t\t\t$('td.tm-metadata-value', undefined, `${metadata ? this._fontStyleToString(metadata.fontStyle) : '-?-'}`)\r\n\t\t\t\t),\r\n\t\t\t\t$('tr', undefined,\r\n\t\t\t\t\t$('td.tm-metadata-key', undefined, 'foreground'),\r\n\t\t\t\t\t$('td.tm-metadata-value', undefined, `${metadata ? Color.Format.CSS.formatHex(metadata.foreground) : '-?-'}`)\r\n\t\t\t\t),\r\n\t\t\t\t$('tr', undefined,\r\n\t\t\t\t\t$('td.tm-metadata-key', undefined, 'background'),\r\n\t\t\t\t\t$('td.tm-metadata-value', undefined, `${metadata ? Color.Format.CSS.formatHex(metadata.background) : '-?-'}`)\r\n\t\t\t\t)\r\n\t\t\t)\r\n\t\t));\r\n\t\tappend(this._domNode, $('hr.tokens-inspect-separator'));\r\n\r\n\t\tif (token1Index < data.tokens1.length) {\r\n\t\t\tappend(this._domNode, $('span.tm-token-type', undefined, data.tokens1[token1Index].type));\r\n\t\t}\r\n\r\n\t\tthis._editor.layoutContentWidget(this);\r\n\t}\r\n\r\n\tprivate _decodeMetadata(metadata: number): IDecodedMetadata {\r\n\t\tlet colorMap = TokenizationRegistry.getColorMap()!;\r\n\t\tlet languageId = TokenMetadata.getLanguageId(metadata);\r\n\t\tlet tokenType = TokenMetadata.getTokenType(metadata);\r\n\t\tlet fontStyle = TokenMetadata.getFontStyle(metadata);\r\n\t\tlet foreground = TokenMetadata.getForeground(metadata);\r\n\t\tlet background = TokenMetadata.getBackground(metadata);\r\n\t\treturn {\r\n\t\t\tlanguageIdentifier: this._modeService.getLanguageIdentifier(languageId)!,\r\n\t\t\ttokenType: tokenType,\r\n\t\t\tfontStyle: fontStyle,\r\n\t\t\tforeground: colorMap[foreground],\r\n\t\t\tbackground: colorMap[background]\r\n\t\t};\r\n\t}\r\n\r\n\tprivate _tokenTypeToString(tokenType: StandardTokenType): string {\r\n\t\tswitch (tokenType) {\r\n\t\t\tcase StandardTokenType.Other: return 'Other';\r\n\t\t\tcase StandardTokenType.Comment: return 'Comment';\r\n\t\t\tcase StandardTokenType.String: return 'String';\r\n\t\t\tcase StandardTokenType.RegEx: return 'RegEx';\r\n\t\t\tdefault: return '??';\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _fontStyleToString(fontStyle: FontStyle): string {\r\n\t\tlet r = '';\r\n\t\tif (fontStyle & FontStyle.Italic) {\r\n\t\t\tr += 'italic ';\r\n\t\t}\r\n\t\tif (fontStyle & FontStyle.Bold) {\r\n\t\t\tr += 'bold ';\r\n\t\t}\r\n\t\tif (fontStyle & FontStyle.Underline) {\r\n\t\t\tr += 'underline ';\r\n\t\t}\r\n\t\tif (r.length === 0) {\r\n\t\t\tr = '---';\r\n\t\t}\r\n\t\treturn r;\r\n\t}\r\n\r\n\tprivate _getTokensAtLine(lineNumber: number): ICompleteLineTokenization {\r\n\t\tlet stateBeforeLine = this._getStateBeforeLine(lineNumber);\r\n\r\n\t\tlet tokenizationResult1 = this._tokenizationSupport.tokenize(this._model.getLineContent(lineNumber), true, stateBeforeLine, 0);\r\n\t\tlet tokenizationResult2 = this._tokenizationSupport.tokenize2(this._model.getLineContent(lineNumber), true, stateBeforeLine, 0);\r\n\r\n\t\treturn {\r\n\t\t\tstartState: stateBeforeLine,\r\n\t\t\ttokens1: tokenizationResult1.tokens,\r\n\t\t\ttokens2: tokenizationResult2.tokens,\r\n\t\t\tendState: tokenizationResult1.endState\r\n\t\t};\r\n\t}\r\n\r\n\tprivate _getStateBeforeLine(lineNumber: number): IState {\r\n\t\tlet state: IState = this._tokenizationSupport.getInitialState();\r\n\r\n\t\tfor (let i = 1; i < lineNumber; i++) {\r\n\t\t\tlet tokenizationResult = this._tokenizationSupport.tokenize(this._model.getLineContent(i), true, state, 0);\r\n\t\t\tstate = tokenizationResult.endState;\r\n\t\t}\r\n\r\n\t\treturn state;\r\n\t}\r\n\r\n\tpublic getDomNode(): HTMLElement {\r\n\t\treturn this._domNode;\r\n\t}\r\n\r\n\tpublic getPosition(): IContentWidgetPosition {\r\n\t\treturn {\r\n\t\t\tposition: this._editor.getPosition(),\r\n\t\t\tpreference: [ContentWidgetPositionPreference.BELOW, ContentWidgetPositionPreference.ABOVE]\r\n\t\t};\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(InspectTokensController.ID, InspectTokensController);\r\nregisterEditorAction(InspectTokens);\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst border = theme.getColor(editorHoverBorder);\r\n\tif (border) {\r\n\t\tlet borderWidth = theme.type === ColorScheme.HIGH_CONTRAST ? 2 : 1;\r\n\t\tcollector.addRule(`.monaco-editor .tokens-inspect-widget { border: ${borderWidth}px solid ${border}; }`);\r\n\t\tcollector.addRule(`.monaco-editor .tokens-inspect-widget .tokens-inspect-separator { background-color: ${border}; }`);\r\n\t}\r\n\tconst background = theme.getColor(editorHoverBackground);\r\n\tif (background) {\r\n\t\tcollector.addRule(`.monaco-editor .tokens-inspect-widget { background-color: ${background}; }`);\r\n\t}\r\n\tconst foreground = theme.getColor(editorHoverForeground);\r\n\tif (foreground) {\r\n\t\tcollector.addRule(`.monaco-editor .tokens-inspect-widget { color: ${foreground}; }`);\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Registry } from 'vs/platform/registry/common/platform';\r\nimport { IQuickAccessRegistry, Extensions } from 'vs/platform/quickinput/common/quickAccess';\r\nimport { QuickCommandNLS } from 'vs/editor/common/standaloneStrings';\r\nimport { ICommandQuickPick } from 'vs/platform/quickinput/browser/commandsQuickAccess';\r\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\r\nimport { AbstractEditorCommandsQuickAccessProvider } from 'vs/editor/contrib/quickAccess/commandsQuickAccess';\r\nimport { IEditor } from 'vs/editor/common/editorCommon';\r\nimport { withNullAsUndefined } from 'vs/base/common/types';\r\nimport { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\r\nimport { ICommandService } from 'vs/platform/commands/common/commands';\r\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\r\nimport { INotificationService } from 'vs/platform/notification/common/notification';\r\nimport { EditorAction, registerEditorAction } from 'vs/editor/browser/editorExtensions';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { KeyCode } from 'vs/base/common/keyCodes';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';\r\n\r\nexport class StandaloneCommandsQuickAccessProvider extends AbstractEditorCommandsQuickAccessProvider {\r\n\r\n\tprotected get activeTextEditorControl(): IEditor | undefined { return withNullAsUndefined(this.codeEditorService.getFocusedCodeEditor()); }\r\n\r\n\tconstructor(\r\n\t\t@IInstantiationService instantiationService: IInstantiationService,\r\n\t\t@ICodeEditorService private readonly codeEditorService: ICodeEditorService,\r\n\t\t@IKeybindingService keybindingService: IKeybindingService,\r\n\t\t@ICommandService commandService: ICommandService,\r\n\t\t@ITelemetryService telemetryService: ITelemetryService,\r\n\t\t@INotificationService notificationService: INotificationService\r\n\t) {\r\n\t\tsuper({ showAlias: false }, instantiationService, keybindingService, commandService, telemetryService, notificationService);\r\n\t}\r\n\r\n\tprotected async getCommandPicks(): Promise> {\r\n\t\treturn this.getCodeEditorCommandPicks();\r\n\t}\r\n}\r\n\r\nRegistry.as(Extensions.Quickaccess).registerQuickAccessProvider({\r\n\tctor: StandaloneCommandsQuickAccessProvider,\r\n\tprefix: StandaloneCommandsQuickAccessProvider.PREFIX,\r\n\thelpEntries: [{ description: QuickCommandNLS.quickCommandHelp, needsEditor: true }]\r\n});\r\n\r\nexport class GotoLineAction extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.quickCommand',\r\n\t\t\tlabel: QuickCommandNLS.quickCommandActionLabel,\r\n\t\t\talias: 'Command Palette',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.focus,\r\n\t\t\t\tprimary: KeyCode.F1,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tcontextMenuOpts: {\r\n\t\t\t\tgroup: 'z_commands',\r\n\t\t\t\torder: 1\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\trun(accessor: ServicesAccessor): void {\r\n\t\taccessor.get(IQuickInputService).quickAccess.show(StandaloneCommandsQuickAccessProvider.PREFIX);\r\n\t}\r\n}\r\n\r\nregisterEditorAction(GotoLineAction);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { AbstractGotoLineQuickAccessProvider } from 'vs/editor/contrib/quickAccess/gotoLineQuickAccess';\r\nimport { Registry } from 'vs/platform/registry/common/platform';\r\nimport { IQuickAccessRegistry, Extensions } from 'vs/platform/quickinput/common/quickAccess';\r\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\r\nimport { withNullAsUndefined } from 'vs/base/common/types';\r\nimport { GoToLineNLS } from 'vs/editor/common/standaloneStrings';\r\nimport { Event } from 'vs/base/common/event';\r\nimport { EditorAction, registerEditorAction, ServicesAccessor } from 'vs/editor/browser/editorExtensions';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { KeyMod, KeyCode } from 'vs/base/common/keyCodes';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';\r\n\r\nexport class StandaloneGotoLineQuickAccessProvider extends AbstractGotoLineQuickAccessProvider {\r\n\r\n\tprotected readonly onDidActiveTextEditorControlChange = Event.None;\r\n\r\n\tconstructor(@ICodeEditorService private readonly editorService: ICodeEditorService) {\r\n\t\tsuper();\r\n\t}\r\n\r\n\tprotected get activeTextEditorControl() {\r\n\t\treturn withNullAsUndefined(this.editorService.getFocusedCodeEditor());\r\n\t}\r\n}\r\n\r\nRegistry.as(Extensions.Quickaccess).registerQuickAccessProvider({\r\n\tctor: StandaloneGotoLineQuickAccessProvider,\r\n\tprefix: StandaloneGotoLineQuickAccessProvider.PREFIX,\r\n\thelpEntries: [{ description: GoToLineNLS.gotoLineActionLabel, needsEditor: true }]\r\n});\r\n\r\nexport class GotoLineAction extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.gotoLine',\r\n\t\t\tlabel: GoToLineNLS.gotoLineActionLabel,\r\n\t\t\talias: 'Go to Line/Column...',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.focus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.KEY_G,\r\n\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyCode.KEY_G },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\trun(accessor: ServicesAccessor): void {\r\n\t\taccessor.get(IQuickInputService).quickAccess.show(StandaloneGotoLineQuickAccessProvider.PREFIX);\r\n\t}\r\n}\r\n\r\nregisterEditorAction(GotoLineAction);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/base/browser/ui/codicons/codiconStyles'; // The codicon symbol styles are defined here and must be loaded\r\nimport 'vs/editor/contrib/symbolIcons/symbolIcons'; // The codicon symbol colors are defined here and must be loaded to get colors\r\nimport { AbstractGotoSymbolQuickAccessProvider } from 'vs/editor/contrib/quickAccess/gotoSymbolQuickAccess';\r\nimport { Registry } from 'vs/platform/registry/common/platform';\r\nimport { IQuickAccessRegistry, Extensions } from 'vs/platform/quickinput/common/quickAccess';\r\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\r\nimport { withNullAsUndefined } from 'vs/base/common/types';\r\nimport { QuickOutlineNLS } from 'vs/editor/common/standaloneStrings';\r\nimport { Event } from 'vs/base/common/event';\r\nimport { EditorAction, registerEditorAction } from 'vs/editor/browser/editorExtensions';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { KeyMod, KeyCode } from 'vs/base/common/keyCodes';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';\r\n\r\nexport class StandaloneGotoSymbolQuickAccessProvider extends AbstractGotoSymbolQuickAccessProvider {\r\n\r\n\tprotected readonly onDidActiveTextEditorControlChange = Event.None;\r\n\r\n\tconstructor(@ICodeEditorService private readonly editorService: ICodeEditorService) {\r\n\t\tsuper();\r\n\t}\r\n\r\n\tprotected get activeTextEditorControl() {\r\n\t\treturn withNullAsUndefined(this.editorService.getFocusedCodeEditor());\r\n\t}\r\n}\r\n\r\nRegistry.as(Extensions.Quickaccess).registerQuickAccessProvider({\r\n\tctor: StandaloneGotoSymbolQuickAccessProvider,\r\n\tprefix: AbstractGotoSymbolQuickAccessProvider.PREFIX,\r\n\thelpEntries: [\r\n\t\t{ description: QuickOutlineNLS.quickOutlineActionLabel, prefix: AbstractGotoSymbolQuickAccessProvider.PREFIX, needsEditor: true },\r\n\t\t{ description: QuickOutlineNLS.quickOutlineByCategoryActionLabel, prefix: AbstractGotoSymbolQuickAccessProvider.PREFIX_BY_CATEGORY, needsEditor: true }\r\n\t]\r\n});\r\n\r\nexport class GotoLineAction extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.quickOutline',\r\n\t\t\tlabel: QuickOutlineNLS.quickOutlineActionLabel,\r\n\t\t\talias: 'Go to Symbol...',\r\n\t\t\tprecondition: EditorContextKeys.hasDocumentSymbolProvider,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.focus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_O,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tcontextMenuOpts: {\r\n\t\t\t\tgroup: 'navigation',\r\n\t\t\t\torder: 3\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\trun(accessor: ServicesAccessor): void {\r\n\t\taccessor.get(IQuickInputService).quickAccess.show(AbstractGotoSymbolQuickAccessProvider.PREFIX);\r\n\t}\r\n}\r\n\r\nregisterEditorAction(GotoLineAction);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction, ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions';\r\nimport { IStandaloneThemeService } from 'vs/editor/standalone/common/standaloneThemeService';\r\nimport { ToggleHighContrastNLS } from 'vs/editor/common/standaloneStrings';\r\n\r\nclass ToggleHighContrast extends EditorAction {\r\n\r\n\tprivate _originalThemeName: string | null;\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.toggleHighContrast',\r\n\t\t\tlabel: ToggleHighContrastNLS.toggleHighContrast,\r\n\t\t\talias: 'Toggle High Contrast Theme',\r\n\t\t\tprecondition: undefined\r\n\t\t});\r\n\t\tthis._originalThemeName = null;\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tconst standaloneThemeService = accessor.get(IStandaloneThemeService);\r\n\t\tif (this._originalThemeName) {\r\n\t\t\t// We must toggle back to the integrator's theme\r\n\t\t\tstandaloneThemeService.setTheme(this._originalThemeName);\r\n\t\t\tthis._originalThemeName = null;\r\n\t\t} else {\r\n\t\t\tthis._originalThemeName = standaloneThemeService.getColorTheme().themeName;\r\n\t\t\tstandaloneThemeService.setTheme('hc-black');\r\n\t\t}\r\n\t}\r\n}\r\n\r\nregisterEditorAction(ToggleHighContrast);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./menuEntryActionViewItem';\r\nimport { asCSSUrl, ModifierKeyEmitter } from 'vs/base/browser/dom';\r\nimport { domEvent } from 'vs/base/browser/event';\r\nimport { IAction, Separator } from 'vs/base/common/actions';\r\nimport { IDisposable, toDisposable, MutableDisposable, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { localize } from 'vs/nls';\r\nimport { ICommandAction, IMenu, IMenuActionOptions, MenuItemAction, SubmenuItemAction, Icon } from 'vs/platform/actions/common/actions';\r\nimport { IContextMenuService } from 'vs/platform/contextview/browser/contextView';\r\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\r\nimport { INotificationService } from 'vs/platform/notification/common/notification';\r\nimport { ThemeIcon } from 'vs/platform/theme/common/themeService';\r\nimport { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';\r\nimport { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdownActionViewItem';\r\nimport { isWindows, isLinux } from 'vs/base/common/platform';\r\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\r\n\r\nexport function createAndFillInActionBarActions(menu: IMenu, options: IMenuActionOptions | undefined, target: IAction[] | { primary: IAction[]; secondary: IAction[]; }, isPrimaryGroup?: (group: string) => boolean): IDisposable {\r\n\tconst groups = menu.getActions(options);\r\n\t// Action bars handle alternative actions on their own so the alternative actions should be ignored\r\n\tfillInActions(groups, target, false, isPrimaryGroup);\r\n\treturn asDisposable(groups);\r\n}\r\n\r\nfunction asDisposable(groups: ReadonlyArray<[string, ReadonlyArray]>): IDisposable {\r\n\tconst disposables = new DisposableStore();\r\n\tfor (const [, actions] of groups) {\r\n\t\tfor (const action of actions) {\r\n\t\t\tdisposables.add(action);\r\n\t\t}\r\n\t}\r\n\treturn disposables;\r\n}\r\n\r\nfunction fillInActions(groups: ReadonlyArray<[string, ReadonlyArray]>, target: IAction[] | { primary: IAction[]; secondary: IAction[]; }, useAlternativeActions: boolean, isPrimaryGroup: (group: string) => boolean = group => group === 'navigation'): void {\r\n\tfor (let [group, actions] of groups) {\r\n\t\tif (useAlternativeActions) {\r\n\t\t\tactions = actions.map(a => (a instanceof MenuItemAction) && !!a.alt ? a.alt : a);\r\n\t\t}\r\n\r\n\t\tif (isPrimaryGroup(group)) {\r\n\t\t\tconst to = Array.isArray(target) ? target : target.primary;\r\n\r\n\t\t\tto.unshift(...actions);\r\n\t\t} else {\r\n\t\t\tconst to = Array.isArray(target) ? target : target.secondary;\r\n\r\n\t\t\tif (to.length > 0) {\r\n\t\t\t\tto.push(new Separator());\r\n\t\t\t}\r\n\r\n\t\t\tto.push(...actions);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class MenuEntryActionViewItem extends ActionViewItem {\r\n\r\n\tprivate _wantsAltCommand: boolean = false;\r\n\tprivate readonly _itemClassDispose = this._register(new MutableDisposable());\r\n\tprivate readonly _altKey: ModifierKeyEmitter;\r\n\r\n\tconstructor(\r\n\t\treadonly _action: MenuItemAction,\r\n\t\t@IKeybindingService protected readonly _keybindingService: IKeybindingService,\r\n\t\t@INotificationService protected _notificationService: INotificationService\r\n\t) {\r\n\t\tsuper(undefined, _action, { icon: !!(_action.class || _action.item.icon), label: !_action.class && !_action.item.icon });\r\n\t\tthis._altKey = ModifierKeyEmitter.getInstance();\r\n\t}\r\n\r\n\tprotected get _commandAction(): MenuItemAction {\r\n\t\treturn this._wantsAltCommand && (this._action).alt || this._action;\r\n\t}\r\n\r\n\tonClick(event: MouseEvent): void {\r\n\t\tevent.preventDefault();\r\n\t\tevent.stopPropagation();\r\n\r\n\t\tthis.actionRunner\r\n\t\t\t.run(this._commandAction, this._context)\r\n\t\t\t.catch(err => this._notificationService.error(err));\r\n\t}\r\n\r\n\trender(container: HTMLElement): void {\r\n\t\tsuper.render(container);\r\n\t\tcontainer.classList.add('menu-entry');\r\n\r\n\t\tthis._updateItemClass(this._action.item);\r\n\r\n\t\tlet mouseOver = false;\r\n\r\n\t\tlet alternativeKeyDown = this._altKey.keyStatus.altKey || ((isWindows || isLinux) && this._altKey.keyStatus.shiftKey);\r\n\r\n\t\tconst updateAltState = () => {\r\n\t\t\tconst wantsAltCommand = mouseOver && alternativeKeyDown;\r\n\t\t\tif (wantsAltCommand !== this._wantsAltCommand) {\r\n\t\t\t\tthis._wantsAltCommand = wantsAltCommand;\r\n\t\t\t\tthis.updateLabel();\r\n\t\t\t\tthis.updateTooltip();\r\n\t\t\t\tthis.updateClass();\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tif (this._action.alt) {\r\n\t\t\tthis._register(this._altKey.event(value => {\r\n\t\t\t\talternativeKeyDown = value.altKey || ((isWindows || isLinux) && value.shiftKey);\r\n\t\t\t\tupdateAltState();\r\n\t\t\t}));\r\n\t\t}\r\n\r\n\t\tthis._register(domEvent(container, 'mouseleave')(_ => {\r\n\t\t\tmouseOver = false;\r\n\t\t\tupdateAltState();\r\n\t\t}));\r\n\r\n\t\tthis._register(domEvent(container, 'mouseenter')(e => {\r\n\t\t\tmouseOver = true;\r\n\t\t\tupdateAltState();\r\n\t\t}));\r\n\t}\r\n\r\n\tupdateLabel(): void {\r\n\t\tif (this.options.label && this.label) {\r\n\t\t\tthis.label.textContent = this._commandAction.label;\r\n\t\t}\r\n\t}\r\n\r\n\tupdateTooltip(): void {\r\n\t\tif (this.label) {\r\n\t\t\tconst keybinding = this._keybindingService.lookupKeybinding(this._commandAction.id);\r\n\t\t\tconst keybindingLabel = keybinding && keybinding.getLabel();\r\n\r\n\t\t\tconst tooltip = this._commandAction.tooltip || this._commandAction.label;\r\n\t\t\tthis.label.title = keybindingLabel\r\n\t\t\t\t? localize('titleAndKb', \"{0} ({1})\", tooltip, keybindingLabel)\r\n\t\t\t\t: tooltip;\r\n\t\t}\r\n\t}\r\n\r\n\tupdateClass(): void {\r\n\t\tif (this.options.icon) {\r\n\t\t\tif (this._commandAction !== this._action) {\r\n\t\t\t\tif (this._action.alt) {\r\n\t\t\t\t\tthis._updateItemClass(this._action.alt.item);\r\n\t\t\t\t}\r\n\t\t\t} else if ((this._action).alt) {\r\n\t\t\t\tthis._updateItemClass(this._action.item);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _updateItemClass(item: ICommandAction): void {\r\n\t\tthis._itemClassDispose.value = undefined;\r\n\r\n\t\tconst { element, label } = this;\r\n\t\tif (!element || !label) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst icon = this._commandAction.checked && (item.toggled as { icon?: Icon })?.icon ? (item.toggled as { icon: Icon }).icon : item.icon;\r\n\r\n\t\tif (!icon) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (ThemeIcon.isThemeIcon(icon)) {\r\n\t\t\t// theme icons\r\n\t\t\tconst iconClass = ThemeIcon.asClassName(icon);\r\n\t\t\tlabel.classList.add(...iconClass.split(' '));\r\n\t\t\tthis._itemClassDispose.value = toDisposable(() => {\r\n\t\t\t\tlabel.classList.remove(...iconClass.split(' '));\r\n\t\t\t});\r\n\r\n\t\t} else {\r\n\t\t\t// icon path/url\r\n\t\t\tif (icon.light) {\r\n\t\t\t\tlabel.style.setProperty('--menu-entry-icon-light', asCSSUrl(icon.light));\r\n\t\t\t}\r\n\t\t\tif (icon.dark) {\r\n\t\t\t\tlabel.style.setProperty('--menu-entry-icon-dark', asCSSUrl(icon.dark));\r\n\t\t\t}\r\n\t\t\tlabel.classList.add('icon');\r\n\t\t\tthis._itemClassDispose.value = toDisposable(() => {\r\n\t\t\t\tlabel.classList.remove('icon');\r\n\t\t\t\tlabel.style.removeProperty('--menu-entry-icon-light');\r\n\t\t\t\tlabel.style.removeProperty('--menu-entry-icon-dark');\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class SubmenuEntryActionViewItem extends DropdownMenuActionViewItem {\r\n\r\n\tconstructor(\r\n\t\taction: SubmenuItemAction,\r\n\t\t@IContextMenuService contextMenuService: IContextMenuService\r\n\t) {\r\n\t\tsuper(action, { getActions: () => action.actions }, contextMenuService, {\r\n\t\t\tmenuAsChild: true,\r\n\t\t\tclassNames: ThemeIcon.isThemeIcon(action.item.icon) ? ThemeIcon.asClassName(action.item.icon) : undefined,\r\n\t\t});\r\n\t}\r\n\r\n\trender(container: HTMLElement): void {\r\n\t\tsuper.render(container);\r\n\t\tif (this.element) {\r\n\t\t\tcontainer.classList.add('menu-entry');\r\n\t\t\tconst { icon } = (this._action).item;\r\n\t\t\tif (icon && !ThemeIcon.isThemeIcon(icon)) {\r\n\t\t\t\tthis.element.classList.add('icon');\r\n\t\t\t\tif (icon.light) {\r\n\t\t\t\t\tthis.element.style.setProperty('--menu-entry-icon-light', asCSSUrl(icon.light));\r\n\t\t\t\t}\r\n\t\t\t\tif (icon.dark) {\r\n\t\t\t\t\tthis.element.style.setProperty('--menu-entry-icon-dark', asCSSUrl(icon.dark));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\n/**\r\n * Creates action view items for menu actions or submenu actions.\r\n */\r\nexport function createActionViewItem(instaService: IInstantiationService, action: IAction): undefined | MenuEntryActionViewItem | SubmenuEntryActionViewItem {\r\n\tif (action instanceof MenuItemAction) {\r\n\t\treturn instaService.createInstance(MenuEntryActionViewItem, action);\r\n\t} else if (action instanceof SubmenuItemAction) {\r\n\t\treturn instaService.createInstance(SubmenuEntryActionViewItem, action);\r\n\t} else {\r\n\t\treturn undefined;\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./media/peekViewWidget';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { IMouseEvent } from 'vs/base/browser/mouseEvent';\r\nimport { ActionBar, ActionsOrientation, IActionBarOptions } from 'vs/base/browser/ui/actionbar/actionbar';\r\nimport { Action } from 'vs/base/common/actions';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { Emitter } from 'vs/base/common/event';\r\nimport * as objects from 'vs/base/common/objects';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\r\nimport { EmbeddedCodeEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget';\r\nimport { IOptions, IStyles, ZoneWidget } from 'vs/editor/contrib/zoneWidget/zoneWidget';\r\nimport * as nls from 'vs/nls';\r\nimport { RawContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\r\nimport { ServicesAccessor, createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IDisposable } from 'vs/base/common/lifecycle';\r\nimport { registerSingleton } from 'vs/platform/instantiation/common/extensions';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { registerEditorContribution } from 'vs/editor/browser/editorExtensions';\r\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { registerColor, contrastBorder, activeContrastBorder } from 'vs/platform/theme/common/colorRegistry';\r\nimport { Codicon } from 'vs/base/common/codicons';\r\nimport { createActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';\r\n\r\nexport const IPeekViewService = createDecorator('IPeekViewService');\r\nexport interface IPeekViewService {\r\n\treadonly _serviceBrand: undefined;\r\n\taddExclusiveWidget(editor: ICodeEditor, widget: PeekViewWidget): void;\r\n}\r\n\r\nregisterSingleton(IPeekViewService, class implements IPeekViewService {\r\n\tdeclare readonly _serviceBrand: undefined;\r\n\r\n\tprivate readonly _widgets = new Map();\r\n\r\n\taddExclusiveWidget(editor: ICodeEditor, widget: PeekViewWidget): void {\r\n\t\tconst existing = this._widgets.get(editor);\r\n\t\tif (existing) {\r\n\t\t\texisting.listener.dispose();\r\n\t\t\texisting.widget.dispose();\r\n\t\t}\r\n\t\tconst remove = () => {\r\n\t\t\tconst data = this._widgets.get(editor);\r\n\t\t\tif (data && data.widget === widget) {\r\n\t\t\t\tdata.listener.dispose();\r\n\t\t\t\tthis._widgets.delete(editor);\r\n\t\t\t}\r\n\t\t};\r\n\t\tthis._widgets.set(editor, { widget, listener: widget.onDidClose(remove) });\r\n\t}\r\n});\r\n\r\nexport namespace PeekContext {\r\n\texport const inPeekEditor = new RawContextKey('inReferenceSearchEditor', true);\r\n\texport const notInPeekEditor = inPeekEditor.toNegated();\r\n}\r\n\r\nclass PeekContextController implements IEditorContribution {\r\n\r\n\tstatic readonly ID = 'editor.contrib.referenceController';\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService\r\n\t) {\r\n\t\tif (editor instanceof EmbeddedCodeEditorWidget) {\r\n\t\t\tPeekContext.inPeekEditor.bindTo(contextKeyService);\r\n\t\t}\r\n\t}\r\n\r\n\tdispose(): void { }\r\n}\r\n\r\nregisterEditorContribution(PeekContextController.ID, PeekContextController);\r\n\r\nexport function getOuterEditor(accessor: ServicesAccessor): ICodeEditor | null {\r\n\tlet editor = accessor.get(ICodeEditorService).getFocusedCodeEditor();\r\n\tif (editor instanceof EmbeddedCodeEditorWidget) {\r\n\t\treturn editor.getParentEditor();\r\n\t}\r\n\treturn editor;\r\n}\r\n\r\nexport interface IPeekViewStyles extends IStyles {\r\n\theaderBackgroundColor?: Color;\r\n\tprimaryHeadingColor?: Color;\r\n\tsecondaryHeadingColor?: Color;\r\n}\r\n\r\nexport type IPeekViewOptions = IOptions & IPeekViewStyles;\r\n\r\nconst defaultOptions: IPeekViewOptions = {\r\n\theaderBackgroundColor: Color.white,\r\n\tprimaryHeadingColor: Color.fromHex('#333333'),\r\n\tsecondaryHeadingColor: Color.fromHex('#6c6c6cb3')\r\n};\r\n\r\nexport abstract class PeekViewWidget extends ZoneWidget {\r\n\r\n\tdeclare readonly _serviceBrand: undefined;\r\n\r\n\tprivate readonly _onDidClose = new Emitter();\r\n\treadonly onDidClose = this._onDidClose.event;\r\n\tprivate disposed?: true;\r\n\r\n\tprotected _headElement?: HTMLDivElement;\r\n\tprotected _primaryHeading?: HTMLElement;\r\n\tprotected _secondaryHeading?: HTMLElement;\r\n\tprotected _metaHeading?: HTMLElement;\r\n\tprotected _actionbarWidget?: ActionBar;\r\n\tprotected _bodyElement?: HTMLDivElement;\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor,\r\n\t\toptions: IPeekViewOptions,\r\n\t\t@IInstantiationService protected readonly instantiationService: IInstantiationService\r\n\t) {\r\n\t\tsuper(editor, options);\r\n\t\tobjects.mixin(this.options, defaultOptions, false);\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tif (!this.disposed) {\r\n\t\t\tthis.disposed = true; // prevent consumers who dispose on onDidClose from looping\r\n\t\t\tsuper.dispose();\r\n\t\t\tthis._onDidClose.fire(this);\r\n\t\t}\r\n\t}\r\n\r\n\tstyle(styles: IPeekViewStyles): void {\r\n\t\tlet options = this.options;\r\n\t\tif (styles.headerBackgroundColor) {\r\n\t\t\toptions.headerBackgroundColor = styles.headerBackgroundColor;\r\n\t\t}\r\n\t\tif (styles.primaryHeadingColor) {\r\n\t\t\toptions.primaryHeadingColor = styles.primaryHeadingColor;\r\n\t\t}\r\n\t\tif (styles.secondaryHeadingColor) {\r\n\t\t\toptions.secondaryHeadingColor = styles.secondaryHeadingColor;\r\n\t\t}\r\n\t\tsuper.style(styles);\r\n\t}\r\n\r\n\tprotected _applyStyles(): void {\r\n\t\tsuper._applyStyles();\r\n\t\tlet options = this.options;\r\n\t\tif (this._headElement && options.headerBackgroundColor) {\r\n\t\t\tthis._headElement.style.backgroundColor = options.headerBackgroundColor.toString();\r\n\t\t}\r\n\t\tif (this._primaryHeading && options.primaryHeadingColor) {\r\n\t\t\tthis._primaryHeading.style.color = options.primaryHeadingColor.toString();\r\n\t\t}\r\n\t\tif (this._secondaryHeading && options.secondaryHeadingColor) {\r\n\t\t\tthis._secondaryHeading.style.color = options.secondaryHeadingColor.toString();\r\n\t\t}\r\n\t\tif (this._bodyElement && options.frameColor) {\r\n\t\t\tthis._bodyElement.style.borderColor = options.frameColor.toString();\r\n\t\t}\r\n\t}\r\n\r\n\tprotected _fillContainer(container: HTMLElement): void {\r\n\t\tthis.setCssClass('peekview-widget');\r\n\r\n\t\tthis._headElement = dom.$('.head');\r\n\t\tthis._bodyElement = dom.$('.body');\r\n\r\n\t\tthis._fillHead(this._headElement);\r\n\t\tthis._fillBody(this._bodyElement);\r\n\r\n\t\tcontainer.appendChild(this._headElement);\r\n\t\tcontainer.appendChild(this._bodyElement);\r\n\t}\r\n\r\n\tprotected _fillHead(container: HTMLElement, noCloseAction?: boolean): void {\r\n\t\tconst titleElement = dom.$('.peekview-title');\r\n\t\tdom.append(this._headElement!, titleElement);\r\n\t\tdom.addStandardDisposableListener(titleElement, 'click', event => this._onTitleClick(event));\r\n\r\n\t\tthis._fillTitleIcon(titleElement);\r\n\t\tthis._primaryHeading = dom.$('span.filename');\r\n\t\tthis._secondaryHeading = dom.$('span.dirname');\r\n\t\tthis._metaHeading = dom.$('span.meta');\r\n\t\tdom.append(titleElement, this._primaryHeading, this._secondaryHeading, this._metaHeading);\r\n\r\n\t\tconst actionsContainer = dom.$('.peekview-actions');\r\n\t\tdom.append(this._headElement!, actionsContainer);\r\n\r\n\t\tconst actionBarOptions = this._getActionBarOptions();\r\n\t\tthis._actionbarWidget = new ActionBar(actionsContainer, actionBarOptions);\r\n\t\tthis._disposables.add(this._actionbarWidget);\r\n\r\n\t\tif (!noCloseAction) {\r\n\t\t\tthis._actionbarWidget.push(new Action('peekview.close', nls.localize('label.close', \"Close\"), Codicon.close.classNames, true, () => {\r\n\t\t\t\tthis.dispose();\r\n\t\t\t\treturn Promise.resolve();\r\n\t\t\t}), { label: false, icon: true });\r\n\t\t}\r\n\t}\r\n\r\n\tprotected _fillTitleIcon(container: HTMLElement): void {\r\n\t}\r\n\r\n\tprotected _getActionBarOptions(): IActionBarOptions {\r\n\t\treturn {\r\n\t\t\tactionViewItemProvider: createActionViewItem.bind(undefined, this.instantiationService),\r\n\t\t\torientation: ActionsOrientation.HORIZONTAL\r\n\t\t};\r\n\t}\r\n\r\n\tprotected _onTitleClick(event: IMouseEvent): void {\r\n\t\t// implement me\r\n\t}\r\n\r\n\tsetTitle(primaryHeading: string, secondaryHeading?: string): void {\r\n\t\tif (this._primaryHeading && this._secondaryHeading) {\r\n\t\t\tthis._primaryHeading.innerText = primaryHeading;\r\n\t\t\tthis._primaryHeading.setAttribute('aria-label', primaryHeading);\r\n\t\t\tif (secondaryHeading) {\r\n\t\t\t\tthis._secondaryHeading.innerText = secondaryHeading;\r\n\t\t\t} else {\r\n\t\t\t\tdom.clearNode(this._secondaryHeading);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tsetMetaTitle(value: string): void {\r\n\t\tif (this._metaHeading) {\r\n\t\t\tif (value) {\r\n\t\t\t\tthis._metaHeading.innerText = value;\r\n\t\t\t\tdom.show(this._metaHeading);\r\n\t\t\t} else {\r\n\t\t\t\tdom.hide(this._metaHeading);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprotected abstract _fillBody(container: HTMLElement): void;\r\n\r\n\tprotected _doLayout(heightInPixel: number, widthInPixel: number): void {\r\n\r\n\t\tif (!this._isShowing && heightInPixel < 0) {\r\n\t\t\t// Looks like the view zone got folded away!\r\n\t\t\tthis.dispose();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst headHeight = Math.ceil(this.editor.getOption(EditorOption.lineHeight) * 1.2);\r\n\t\tconst bodyHeight = Math.round(heightInPixel - (headHeight + 2 /* the border-top/bottom width*/));\r\n\r\n\t\tthis._doLayoutHead(headHeight, widthInPixel);\r\n\t\tthis._doLayoutBody(bodyHeight, widthInPixel);\r\n\t}\r\n\r\n\tprotected _doLayoutHead(heightInPixel: number, widthInPixel: number): void {\r\n\t\tif (this._headElement) {\r\n\t\t\tthis._headElement.style.height = `${heightInPixel}px`;\r\n\t\t\tthis._headElement.style.lineHeight = this._headElement.style.height;\r\n\t\t}\r\n\t}\r\n\r\n\tprotected _doLayoutBody(heightInPixel: number, widthInPixel: number): void {\r\n\t\tif (this._bodyElement) {\r\n\t\t\tthis._bodyElement.style.height = `${heightInPixel}px`;\r\n\t\t}\r\n\t}\r\n}\r\n\r\n\r\nexport const peekViewTitleBackground = registerColor('peekViewTitle.background', { dark: '#1E1E1E', light: '#FFFFFF', hc: '#0C141F' }, nls.localize('peekViewTitleBackground', 'Background color of the peek view title area.'));\r\nexport const peekViewTitleForeground = registerColor('peekViewTitleLabel.foreground', { dark: '#FFFFFF', light: '#333333', hc: '#FFFFFF' }, nls.localize('peekViewTitleForeground', 'Color of the peek view title.'));\r\nexport const peekViewTitleInfoForeground = registerColor('peekViewTitleDescription.foreground', { dark: '#ccccccb3', light: '#616161e6', hc: '#FFFFFF99' }, nls.localize('peekViewTitleInfoForeground', 'Color of the peek view title info.'));\r\nexport const peekViewBorder = registerColor('peekView.border', { dark: '#007acc', light: '#007acc', hc: contrastBorder }, nls.localize('peekViewBorder', 'Color of the peek view borders and arrow.'));\r\n\r\nexport const peekViewResultsBackground = registerColor('peekViewResult.background', { dark: '#252526', light: '#F3F3F3', hc: Color.black }, nls.localize('peekViewResultsBackground', 'Background color of the peek view result list.'));\r\nexport const peekViewResultsMatchForeground = registerColor('peekViewResult.lineForeground', { dark: '#bbbbbb', light: '#646465', hc: Color.white }, nls.localize('peekViewResultsMatchForeground', 'Foreground color for line nodes in the peek view result list.'));\r\nexport const peekViewResultsFileForeground = registerColor('peekViewResult.fileForeground', { dark: Color.white, light: '#1E1E1E', hc: Color.white }, nls.localize('peekViewResultsFileForeground', 'Foreground color for file nodes in the peek view result list.'));\r\nexport const peekViewResultsSelectionBackground = registerColor('peekViewResult.selectionBackground', { dark: '#3399ff33', light: '#3399ff33', hc: null }, nls.localize('peekViewResultsSelectionBackground', 'Background color of the selected entry in the peek view result list.'));\r\nexport const peekViewResultsSelectionForeground = registerColor('peekViewResult.selectionForeground', { dark: Color.white, light: '#6C6C6C', hc: Color.white }, nls.localize('peekViewResultsSelectionForeground', 'Foreground color of the selected entry in the peek view result list.'));\r\nexport const peekViewEditorBackground = registerColor('peekViewEditor.background', { dark: '#001F33', light: '#F2F8FC', hc: Color.black }, nls.localize('peekViewEditorBackground', 'Background color of the peek view editor.'));\r\nexport const peekViewEditorGutterBackground = registerColor('peekViewEditorGutter.background', { dark: peekViewEditorBackground, light: peekViewEditorBackground, hc: peekViewEditorBackground }, nls.localize('peekViewEditorGutterBackground', 'Background color of the gutter in the peek view editor.'));\r\n\r\nexport const peekViewResultsMatchHighlight = registerColor('peekViewResult.matchHighlightBackground', { dark: '#ea5c004d', light: '#ea5c004d', hc: null }, nls.localize('peekViewResultsMatchHighlight', 'Match highlight color in the peek view result list.'));\r\nexport const peekViewEditorMatchHighlight = registerColor('peekViewEditor.matchHighlightBackground', { dark: '#ff8f0099', light: '#f5d802de', hc: null }, nls.localize('peekViewEditorMatchHighlight', 'Match highlight color in the peek view editor.'));\r\nexport const peekViewEditorMatchHighlightBorder = registerColor('peekViewEditor.matchHighlightBorder', { dark: null, light: null, hc: activeContrastBorder }, nls.localize('peekViewEditorMatchHighlightBorder', 'Match highlight border in the peek view editor.'));\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';\r\nimport { IActionViewItemProvider, IAction } from 'vs/base/common/actions';\r\nimport { ResolvedKeybinding } from 'vs/base/common/keyCodes';\r\nimport { DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { suggestWidgetStatusbarMenu } from 'vs/editor/contrib/suggest/suggest';\r\nimport { localize } from 'vs/nls';\r\nimport { MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';\r\nimport { IMenuService, MenuItemAction } from 'vs/platform/actions/common/actions';\r\nimport { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\r\n\r\nclass StatusBarViewItem extends MenuEntryActionViewItem {\r\n\r\n\tupdateLabel() {\r\n\t\tconst kb = this._keybindingService.lookupKeybinding(this._action.id);\r\n\t\tif (!kb) {\r\n\t\t\treturn super.updateLabel();\r\n\t\t}\r\n\t\tif (this.label) {\r\n\t\t\tthis.label.textContent = localize('ddd', '{0} ({1})', this._action.label, StatusBarViewItem.symbolPrintEnter(kb));\r\n\t\t}\r\n\t}\r\n\r\n\tstatic symbolPrintEnter(kb: ResolvedKeybinding) {\r\n\t\treturn kb.getLabel()?.replace(/\\benter\\b/gi, '\\u23CE');\r\n\t}\r\n}\r\n\r\nexport class SuggestWidgetStatus {\r\n\r\n\treadonly element: HTMLElement;\r\n\r\n\tprivate readonly _leftActions: ActionBar;\r\n\tprivate readonly _rightActions: ActionBar;\r\n\tprivate readonly _menuDisposables = new DisposableStore();\r\n\r\n\tconstructor(\r\n\t\tcontainer: HTMLElement,\r\n\t\t@IInstantiationService instantiationService: IInstantiationService,\r\n\t\t@IMenuService private _menuService: IMenuService,\r\n\t\t@IContextKeyService private _contextKeyService: IContextKeyService,\r\n\t) {\r\n\t\tthis.element = dom.append(container, dom.$('.suggest-status-bar'));\r\n\r\n\t\tconst actionViewItemProvider = (action => {\r\n\t\t\treturn action instanceof MenuItemAction ? instantiationService.createInstance(StatusBarViewItem, action) : undefined;\r\n\t\t});\r\n\t\tthis._leftActions = new ActionBar(this.element, { actionViewItemProvider });\r\n\t\tthis._rightActions = new ActionBar(this.element, { actionViewItemProvider });\r\n\r\n\t\tthis._leftActions.domNode.classList.add('left');\r\n\t\tthis._rightActions.domNode.classList.add('right');\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._menuDisposables.dispose();\r\n\t\tthis.element.remove();\r\n\t}\r\n\r\n\tshow(): void {\r\n\t\tconst menu = this._menuService.createMenu(suggestWidgetStatusbarMenu, this._contextKeyService);\r\n\t\tconst renderMenu = () => {\r\n\t\t\tconst left: IAction[] = [];\r\n\t\t\tconst right: IAction[] = [];\r\n\t\t\tfor (let [group, actions] of menu.getActions()) {\r\n\t\t\t\tif (group === 'left') {\r\n\t\t\t\t\tleft.push(...actions);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tright.push(...actions);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tthis._leftActions.clear();\r\n\t\t\tthis._leftActions.push(left);\r\n\t\t\tthis._rightActions.clear();\r\n\t\t\tthis._rightActions.push(right);\r\n\t\t};\r\n\t\tthis._menuDisposables.add(menu.onDidChange(() => renderMenu()));\r\n\t\tthis._menuDisposables.add(menu);\r\n\t}\r\n\r\n\thide(): void {\r\n\t\tthis._menuDisposables.clear();\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { RunOnceScheduler } from 'vs/base/common/async';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { IMenu, IMenuActionOptions, IMenuItem, IMenuService, isIMenuItem, ISubmenuItem, MenuId, MenuItemAction, MenuRegistry, SubmenuItemAction, ILocalizedString } from 'vs/platform/actions/common/actions';\r\nimport { ICommandService } from 'vs/platform/commands/common/commands';\r\nimport { IContextKeyService, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';\r\n\r\nexport class MenuService implements IMenuService {\r\n\r\n\tdeclare readonly _serviceBrand: undefined;\r\n\r\n\tconstructor(\r\n\t\t@ICommandService private readonly _commandService: ICommandService\r\n\t) {\r\n\t\t//\r\n\t}\r\n\r\n\tcreateMenu(id: MenuId, contextKeyService: IContextKeyService): IMenu {\r\n\t\treturn new Menu(id, this._commandService, contextKeyService, this);\r\n\t}\r\n}\r\n\r\n\r\ntype MenuItemGroup = [string, Array];\r\n\r\nclass Menu implements IMenu {\r\n\r\n\tprivate readonly _dispoables = new DisposableStore();\r\n\r\n\tprivate readonly _onDidChange = new Emitter();\r\n\treadonly onDidChange: Event = this._onDidChange.event;\r\n\r\n\tprivate _menuGroups: MenuItemGroup[] = [];\r\n\tprivate _contextKeys: Set = new Set();\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _id: MenuId,\r\n\t\t@ICommandService private readonly _commandService: ICommandService,\r\n\t\t@IContextKeyService private readonly _contextKeyService: IContextKeyService,\r\n\t\t@IMenuService private readonly _menuService: IMenuService\r\n\t) {\r\n\t\tthis._build();\r\n\r\n\t\t// rebuild this menu whenever the menu registry reports an\r\n\t\t// event for this MenuId\r\n\t\tconst rebuildMenuSoon = new RunOnceScheduler(() => this._build(), 50);\r\n\t\tthis._dispoables.add(rebuildMenuSoon);\r\n\t\tthis._dispoables.add(MenuRegistry.onDidChangeMenu(e => {\r\n\t\t\tif (e.has(_id)) {\r\n\t\t\t\trebuildMenuSoon.schedule();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\t// when context keys change we need to check if the menu also\r\n\t\t// has changed\r\n\t\tconst fireChangeSoon = new RunOnceScheduler(() => this._onDidChange.fire(this), 50);\r\n\t\tthis._dispoables.add(fireChangeSoon);\r\n\t\tthis._dispoables.add(_contextKeyService.onDidChangeContext(e => {\r\n\t\t\tif (e.affectsSome(this._contextKeys)) {\r\n\t\t\t\tfireChangeSoon.schedule();\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._dispoables.dispose();\r\n\t\tthis._onDidChange.dispose();\r\n\t}\r\n\r\n\tprivate _build(): void {\r\n\r\n\t\t// reset\r\n\t\tthis._menuGroups.length = 0;\r\n\t\tthis._contextKeys.clear();\r\n\r\n\t\tconst menuItems = MenuRegistry.getMenuItems(this._id);\r\n\r\n\t\tlet group: MenuItemGroup | undefined;\r\n\t\tmenuItems.sort(Menu._compareMenuItems);\r\n\r\n\t\tfor (let item of menuItems) {\r\n\t\t\t// group by groupId\r\n\t\t\tconst groupName = item.group || '';\r\n\t\t\tif (!group || group[0] !== groupName) {\r\n\t\t\t\tgroup = [groupName, []];\r\n\t\t\t\tthis._menuGroups.push(group);\r\n\t\t\t}\r\n\t\t\tgroup![1].push(item);\r\n\r\n\t\t\t// keep keys for eventing\r\n\t\t\tMenu._fillInKbExprKeys(item.when, this._contextKeys);\r\n\r\n\t\t\tif (isIMenuItem(item)) {\r\n\t\t\t\t// keep precondition keys for event if applicable\r\n\t\t\t\tif (item.command.precondition) {\r\n\t\t\t\t\tMenu._fillInKbExprKeys(item.command.precondition, this._contextKeys);\r\n\t\t\t\t}\r\n\t\t\t\t// keep toggled keys for event if applicable\r\n\t\t\t\tif (item.command.toggled) {\r\n\t\t\t\t\tconst toggledExpression: ContextKeyExpression = (item.command.toggled as { condition: ContextKeyExpression }).condition || item.command.toggled;\r\n\t\t\t\t\tMenu._fillInKbExprKeys(toggledExpression, this._contextKeys);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis._onDidChange.fire(this);\r\n\t}\r\n\r\n\tgetActions(options?: IMenuActionOptions): [string, Array][] {\r\n\t\tconst result: [string, Array][] = [];\r\n\t\tfor (let group of this._menuGroups) {\r\n\t\t\tconst [id, items] = group;\r\n\t\t\tconst activeActions: Array = [];\r\n\t\t\tfor (const item of items) {\r\n\t\t\t\tif (this._contextKeyService.contextMatchesRules(item.when)) {\r\n\t\t\t\t\tconst action = isIMenuItem(item)\r\n\t\t\t\t\t\t? new MenuItemAction(item.command, item.alt, options, this._contextKeyService, this._commandService)\r\n\t\t\t\t\t\t: new SubmenuItemAction(item, this._menuService, this._contextKeyService, options);\r\n\r\n\t\t\t\t\tactiveActions.push(action);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (activeActions.length > 0) {\r\n\t\t\t\tresult.push([id, activeActions]);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate static _fillInKbExprKeys(exp: ContextKeyExpression | undefined, set: Set): void {\r\n\t\tif (exp) {\r\n\t\t\tfor (let key of exp.keys()) {\r\n\t\t\t\tset.add(key);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static _compareMenuItems(a: IMenuItem | ISubmenuItem, b: IMenuItem | ISubmenuItem): number {\r\n\r\n\t\tlet aGroup = a.group;\r\n\t\tlet bGroup = b.group;\r\n\r\n\t\tif (aGroup !== bGroup) {\r\n\r\n\t\t\t// Falsy groups come last\r\n\t\t\tif (!aGroup) {\r\n\t\t\t\treturn 1;\r\n\t\t\t} else if (!bGroup) {\r\n\t\t\t\treturn -1;\r\n\t\t\t}\r\n\r\n\t\t\t// 'navigation' group comes first\r\n\t\t\tif (aGroup === 'navigation') {\r\n\t\t\t\treturn -1;\r\n\t\t\t} else if (bGroup === 'navigation') {\r\n\t\t\t\treturn 1;\r\n\t\t\t}\r\n\r\n\t\t\t// lexical sort for groups\r\n\t\t\tlet value = aGroup.localeCompare(bGroup);\r\n\t\t\tif (value !== 0) {\r\n\t\t\t\treturn value;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// sort on priority - default is 0\r\n\t\tlet aPrio = a.order || 0;\r\n\t\tlet bPrio = b.order || 0;\r\n\t\tif (aPrio < bPrio) {\r\n\t\t\treturn -1;\r\n\t\t} else if (aPrio > bPrio) {\r\n\t\t\treturn 1;\r\n\t\t}\r\n\r\n\t\t// sort on titles\r\n\t\treturn Menu._compareTitles(\r\n\t\t\tisIMenuItem(a) ? a.command.title : a.title,\r\n\t\t\tisIMenuItem(b) ? b.command.title : b.title\r\n\t\t);\r\n\t}\r\n\r\n\tprivate static _compareTitles(a: string | ILocalizedString, b: string | ILocalizedString) {\r\n\t\tconst aStr = typeof a === 'string' ? a : a.original;\r\n\t\tconst bStr = typeof b === 'string' ? b : b.original;\r\n\t\treturn aStr.localeCompare(bStr);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { ContextMenuHandler, IContextMenuHandlerOptions } from './contextMenuHandler';\r\nimport { IContextViewService, IContextMenuService } from './contextView';\r\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\r\nimport { INotificationService } from 'vs/platform/notification/common/notification';\r\nimport { IContextMenuDelegate } from 'vs/base/browser/contextmenu';\r\nimport { IThemeService } from 'vs/platform/theme/common/themeService';\r\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { ModifierKeyEmitter } from 'vs/base/browser/dom';\r\n\r\nexport class ContextMenuService extends Disposable implements IContextMenuService {\r\n\tdeclare readonly _serviceBrand: undefined;\r\n\r\n\tprivate contextMenuHandler: ContextMenuHandler;\r\n\r\n\tconstructor(\r\n\t\t@ITelemetryService telemetryService: ITelemetryService,\r\n\t\t@INotificationService notificationService: INotificationService,\r\n\t\t@IContextViewService contextViewService: IContextViewService,\r\n\t\t@IKeybindingService keybindingService: IKeybindingService,\r\n\t\t@IThemeService themeService: IThemeService\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\tthis.contextMenuHandler = new ContextMenuHandler(contextViewService, telemetryService, notificationService, keybindingService, themeService);\r\n\t}\r\n\r\n\tconfigure(options: IContextMenuHandlerOptions): void {\r\n\t\tthis.contextMenuHandler.configure(options);\r\n\t}\r\n\r\n\t// ContextMenu\r\n\r\n\tshowContextMenu(delegate: IContextMenuDelegate): void {\r\n\t\tthis.contextMenuHandler.showContextMenu(delegate);\r\n\t\tModifierKeyEmitter.getInstance().resetKeyStatus();\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { createStyleSheet } from 'vs/base/browser/dom';\r\nimport { IListMouseEvent, IListTouchEvent, IListRenderer, IListVirtualDelegate } from 'vs/base/browser/ui/list/list';\r\nimport { IPagedRenderer, PagedList, IPagedListOptions } from 'vs/base/browser/ui/list/listPaging';\r\nimport { DefaultStyleController, IListOptions, IMultipleSelectionController, isSelectionRangeChangeEvent, isSelectionSingleChangeEvent, List, IListAccessibilityProvider, IListOptionsUpdate } from 'vs/base/browser/ui/list/listWidget';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { Disposable, dispose, IDisposable, toDisposable, DisposableStore, combinedDisposable } from 'vs/base/common/lifecycle';\r\nimport { localize } from 'vs/nls';\r\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\r\nimport { Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';\r\nimport { ContextKeyExpr, IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IEditorOptions } from 'vs/platform/editor/common/editor';\r\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\r\nimport { Registry } from 'vs/platform/registry/common/platform';\r\nimport { attachListStyler, computeStyles, defaultListStyles, IColorMapping } from 'vs/platform/theme/common/styler';\r\nimport { IThemeService } from 'vs/platform/theme/common/themeService';\r\nimport { InputFocusedContextKey } from 'vs/platform/contextkey/common/contextkeys';\r\nimport { ObjectTree, IObjectTreeOptions, ICompressibleTreeRenderer, CompressibleObjectTree, ICompressibleObjectTreeOptions, ICompressibleObjectTreeOptionsUpdate } from 'vs/base/browser/ui/tree/objectTree';\r\nimport { ITreeRenderer, IAsyncDataSource, IDataSource, ITreeEvent } from 'vs/base/browser/ui/tree/tree';\r\nimport { AsyncDataTree, IAsyncDataTreeOptions, CompressibleAsyncDataTree, ITreeCompressionDelegate, ICompressibleAsyncDataTreeOptions, IAsyncDataTreeOptionsUpdate } from 'vs/base/browser/ui/tree/asyncDataTree';\r\nimport { DataTree, IDataTreeOptions } from 'vs/base/browser/ui/tree/dataTree';\r\nimport { IKeyboardNavigationEventFilter, IAbstractTreeOptions, RenderIndentGuides, IAbstractTreeOptionsUpdate } from 'vs/base/browser/ui/tree/abstractTree';\r\nimport { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';\r\n\r\nexport type ListWidget = List | PagedList | ObjectTree | DataTree | AsyncDataTree;\r\nexport type WorkbenchListWidget = WorkbenchList | WorkbenchPagedList | WorkbenchObjectTree | WorkbenchCompressibleObjectTree | WorkbenchDataTree | WorkbenchAsyncDataTree | WorkbenchCompressibleAsyncDataTree;\r\n\r\nexport const IListService = createDecorator('listService');\r\n\r\nexport interface IListService {\r\n\r\n\treadonly _serviceBrand: undefined;\r\n\r\n\t/**\r\n\t * Returns the currently focused list widget if any.\r\n\t */\r\n\treadonly lastFocusedList: WorkbenchListWidget | undefined;\r\n}\r\n\r\ninterface IRegisteredList {\r\n\twidget: WorkbenchListWidget;\r\n\textraContextKeys?: (IContextKey)[];\r\n}\r\n\r\nexport class ListService implements IListService {\r\n\r\n\tdeclare readonly _serviceBrand: undefined;\r\n\r\n\tprivate disposables = new DisposableStore();\r\n\tprivate lists: IRegisteredList[] = [];\r\n\tprivate _lastFocusedWidget: WorkbenchListWidget | undefined = undefined;\r\n\tprivate _hasCreatedStyleController: boolean = false;\r\n\r\n\tget lastFocusedList(): WorkbenchListWidget | undefined {\r\n\t\treturn this._lastFocusedWidget;\r\n\t}\r\n\r\n\tconstructor(@IThemeService private readonly _themeService: IThemeService) {\r\n\t}\r\n\r\n\tregister(widget: WorkbenchListWidget, extraContextKeys?: (IContextKey)[]): IDisposable {\r\n\t\tif (!this._hasCreatedStyleController) {\r\n\t\t\tthis._hasCreatedStyleController = true;\r\n\t\t\t// create a shared default tree style sheet for performance reasons\r\n\t\t\tconst styleController = new DefaultStyleController(createStyleSheet(), '');\r\n\t\t\tthis.disposables.add(attachListStyler(styleController, this._themeService));\r\n\t\t}\r\n\r\n\t\tif (this.lists.some(l => l.widget === widget)) {\r\n\t\t\tthrow new Error('Cannot register the same widget multiple times');\r\n\t\t}\r\n\r\n\t\t// Keep in our lists list\r\n\t\tconst registeredList: IRegisteredList = { widget, extraContextKeys };\r\n\t\tthis.lists.push(registeredList);\r\n\r\n\t\t// Check for currently being focused\r\n\t\tif (widget.getHTMLElement() === document.activeElement) {\r\n\t\t\tthis._lastFocusedWidget = widget;\r\n\t\t}\r\n\r\n\t\treturn combinedDisposable(\r\n\t\t\twidget.onDidFocus(() => this._lastFocusedWidget = widget),\r\n\t\t\ttoDisposable(() => this.lists.splice(this.lists.indexOf(registeredList), 1)),\r\n\t\t\twidget.onDidDispose(() => {\r\n\t\t\t\tthis.lists = this.lists.filter(l => l !== registeredList);\r\n\t\t\t\tif (this._lastFocusedWidget === widget) {\r\n\t\t\t\t\tthis._lastFocusedWidget = undefined;\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t);\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis.disposables.dispose();\r\n\t}\r\n}\r\n\r\nconst RawWorkbenchListFocusContextKey = new RawContextKey('listFocus', true);\r\nexport const WorkbenchListSupportsMultiSelectContextKey = new RawContextKey('listSupportsMultiselect', true);\r\nexport const WorkbenchListFocusContextKey = ContextKeyExpr.and(RawWorkbenchListFocusContextKey, ContextKeyExpr.not(InputFocusedContextKey));\r\nexport const WorkbenchListHasSelectionOrFocus = new RawContextKey('listHasSelectionOrFocus', false);\r\nexport const WorkbenchListDoubleSelection = new RawContextKey('listDoubleSelection', false);\r\nexport const WorkbenchListMultiSelection = new RawContextKey('listMultiSelection', false);\r\nexport const WorkbenchListSupportsKeyboardNavigation = new RawContextKey('listSupportsKeyboardNavigation', true);\r\nexport const WorkbenchListAutomaticKeyboardNavigationKey = 'listAutomaticKeyboardNavigation';\r\nexport const WorkbenchListAutomaticKeyboardNavigation = new RawContextKey(WorkbenchListAutomaticKeyboardNavigationKey, true);\r\nexport let didBindWorkbenchListAutomaticKeyboardNavigation = false;\r\n\r\nfunction createScopedContextKeyService(contextKeyService: IContextKeyService, widget: ListWidget): IContextKeyService {\r\n\tconst result = contextKeyService.createScoped(widget.getHTMLElement());\r\n\tRawWorkbenchListFocusContextKey.bindTo(result);\r\n\treturn result;\r\n}\r\n\r\nconst multiSelectModifierSettingKey = 'workbench.list.multiSelectModifier';\r\nconst openModeSettingKey = 'workbench.list.openMode';\r\nconst horizontalScrollingKey = 'workbench.list.horizontalScrolling';\r\nconst keyboardNavigationSettingKey = 'workbench.list.keyboardNavigation';\r\nconst automaticKeyboardNavigationSettingKey = 'workbench.list.automaticKeyboardNavigation';\r\nconst treeIndentKey = 'workbench.tree.indent';\r\nconst treeRenderIndentGuidesKey = 'workbench.tree.renderIndentGuides';\r\nconst listSmoothScrolling = 'workbench.list.smoothScrolling';\r\nconst treeExpandMode = 'workbench.tree.expandMode';\r\n\r\nfunction useAltAsMultipleSelectionModifier(configurationService: IConfigurationService): boolean {\r\n\treturn configurationService.getValue(multiSelectModifierSettingKey) === 'alt';\r\n}\r\n\r\nclass MultipleSelectionController extends Disposable implements IMultipleSelectionController {\r\n\tprivate useAltAsMultipleSelectionModifier: boolean;\r\n\r\n\tconstructor(private configurationService: IConfigurationService) {\r\n\t\tsuper();\r\n\r\n\t\tthis.useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);\r\n\r\n\t\tthis.registerListeners();\r\n\t}\r\n\r\n\tprivate registerListeners(): void {\r\n\t\tthis._register(this.configurationService.onDidChangeConfiguration(e => {\r\n\t\t\tif (e.affectsConfiguration(multiSelectModifierSettingKey)) {\r\n\t\t\t\tthis.useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(this.configurationService);\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\tisSelectionSingleChangeEvent(event: IListMouseEvent | IListTouchEvent): boolean {\r\n\t\tif (this.useAltAsMultipleSelectionModifier) {\r\n\t\t\treturn event.browserEvent.altKey;\r\n\t\t}\r\n\r\n\t\treturn isSelectionSingleChangeEvent(event);\r\n\t}\r\n\r\n\tisSelectionRangeChangeEvent(event: IListMouseEvent | IListTouchEvent): boolean {\r\n\t\treturn isSelectionRangeChangeEvent(event);\r\n\t}\r\n}\r\n\r\nfunction toWorkbenchListOptions(options: IListOptions, configurationService: IConfigurationService, keybindingService: IKeybindingService): [IListOptions, IDisposable] {\r\n\tconst disposables = new DisposableStore();\r\n\tconst result = { ...options };\r\n\r\n\tif (options.multipleSelectionSupport !== false && !options.multipleSelectionController) {\r\n\t\tconst multipleSelectionController = new MultipleSelectionController(configurationService);\r\n\t\tresult.multipleSelectionController = multipleSelectionController;\r\n\t\tdisposables.add(multipleSelectionController);\r\n\t}\r\n\r\n\tresult.keyboardNavigationDelegate = {\r\n\t\tmightProducePrintableCharacter(e) {\r\n\t\t\treturn keybindingService.mightProducePrintableCharacter(e);\r\n\t\t}\r\n\t};\r\n\r\n\tresult.smoothScrolling = configurationService.getValue(listSmoothScrolling);\r\n\r\n\treturn [result, disposables];\r\n}\r\n\r\nexport interface IWorkbenchListOptionsUpdate extends IListOptionsUpdate {\r\n\treadonly overrideStyles?: IColorMapping;\r\n}\r\n\r\nexport interface IWorkbenchListOptions extends IWorkbenchListOptionsUpdate, IListOptions {\r\n}\r\n\r\nexport class WorkbenchList extends List {\r\n\r\n\treadonly contextKeyService: IContextKeyService;\r\n\tprivate readonly themeService: IThemeService;\r\n\r\n\tprivate listHasSelectionOrFocus: IContextKey;\r\n\tprivate listDoubleSelection: IContextKey;\r\n\tprivate listMultiSelection: IContextKey;\r\n\tprivate horizontalScrolling: boolean | undefined;\r\n\r\n\tprivate _styler: IDisposable | undefined;\r\n\tprivate _useAltAsMultipleSelectionModifier: boolean;\r\n\r\n\tconstructor(\r\n\t\tuser: string,\r\n\t\tcontainer: HTMLElement,\r\n\t\tdelegate: IListVirtualDelegate,\r\n\t\trenderers: IListRenderer[],\r\n\t\toptions: IWorkbenchListOptions,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\r\n\t\t@IListService listService: IListService,\r\n\t\t@IThemeService themeService: IThemeService,\r\n\t\t@IConfigurationService configurationService: IConfigurationService,\r\n\t\t@IKeybindingService keybindingService: IKeybindingService\r\n\t) {\r\n\t\tconst horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : configurationService.getValue(horizontalScrollingKey);\r\n\t\tconst [workbenchListOptions, workbenchListOptionsDisposable] = toWorkbenchListOptions(options, configurationService, keybindingService);\r\n\r\n\t\tsuper(user, container, delegate, renderers,\r\n\t\t\t{\r\n\t\t\t\tkeyboardSupport: false,\r\n\t\t\t\t...computeStyles(themeService.getColorTheme(), defaultListStyles),\r\n\t\t\t\t...workbenchListOptions,\r\n\t\t\t\thorizontalScrolling\r\n\t\t\t}\r\n\t\t);\r\n\r\n\t\tthis.disposables.add(workbenchListOptionsDisposable);\r\n\r\n\t\tthis.contextKeyService = createScopedContextKeyService(contextKeyService, this);\r\n\t\tthis.themeService = themeService;\r\n\r\n\t\tconst listSupportsMultiSelect = WorkbenchListSupportsMultiSelectContextKey.bindTo(this.contextKeyService);\r\n\t\tlistSupportsMultiSelect.set(!(options.multipleSelectionSupport === false));\r\n\r\n\t\tthis.listHasSelectionOrFocus = WorkbenchListHasSelectionOrFocus.bindTo(this.contextKeyService);\r\n\t\tthis.listDoubleSelection = WorkbenchListDoubleSelection.bindTo(this.contextKeyService);\r\n\t\tthis.listMultiSelection = WorkbenchListMultiSelection.bindTo(this.contextKeyService);\r\n\t\tthis.horizontalScrolling = options.horizontalScrolling;\r\n\r\n\t\tthis._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);\r\n\r\n\t\tthis.disposables.add(this.contextKeyService);\r\n\t\tthis.disposables.add((listService as ListService).register(this));\r\n\r\n\t\tif (options.overrideStyles) {\r\n\t\t\tthis.updateStyles(options.overrideStyles);\r\n\t\t}\r\n\r\n\t\tthis.disposables.add(this.onDidChangeSelection(() => {\r\n\t\t\tconst selection = this.getSelection();\r\n\t\t\tconst focus = this.getFocus();\r\n\r\n\t\t\tthis.contextKeyService.bufferChangeEvents(() => {\r\n\t\t\t\tthis.listHasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);\r\n\t\t\t\tthis.listMultiSelection.set(selection.length > 1);\r\n\t\t\t\tthis.listDoubleSelection.set(selection.length === 2);\r\n\t\t\t});\r\n\t\t}));\r\n\t\tthis.disposables.add(this.onDidChangeFocus(() => {\r\n\t\t\tconst selection = this.getSelection();\r\n\t\t\tconst focus = this.getFocus();\r\n\r\n\t\t\tthis.listHasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);\r\n\t\t}));\r\n\t\tthis.disposables.add(configurationService.onDidChangeConfiguration(e => {\r\n\t\t\tif (e.affectsConfiguration(multiSelectModifierSettingKey)) {\r\n\t\t\t\tthis._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);\r\n\t\t\t}\r\n\r\n\t\t\tlet options: IListOptionsUpdate = {};\r\n\r\n\t\t\tif (e.affectsConfiguration(horizontalScrollingKey) && this.horizontalScrolling === undefined) {\r\n\t\t\t\tconst horizontalScrolling = configurationService.getValue(horizontalScrollingKey);\r\n\t\t\t\toptions = { ...options, horizontalScrolling };\r\n\t\t\t}\r\n\t\t\tif (e.affectsConfiguration(listSmoothScrolling)) {\r\n\t\t\t\tconst smoothScrolling = configurationService.getValue(listSmoothScrolling);\r\n\t\t\t\toptions = { ...options, smoothScrolling };\r\n\t\t\t}\r\n\t\t\tif (Object.keys(options).length > 0) {\r\n\t\t\t\tthis.updateOptions(options);\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\tupdateOptions(options: IWorkbenchListOptionsUpdate): void {\r\n\t\tsuper.updateOptions(options);\r\n\r\n\t\tif (options.overrideStyles) {\r\n\t\t\tthis.updateStyles(options.overrideStyles);\r\n\t\t}\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tsuper.dispose();\r\n\t\tif (this._styler) {\r\n\t\t\tthis._styler.dispose();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate updateStyles(styles: IColorMapping): void {\r\n\t\tif (this._styler) {\r\n\t\t\tthis._styler.dispose();\r\n\t\t}\r\n\r\n\t\tthis._styler = attachListStyler(this, this.themeService, styles);\r\n\t}\r\n}\r\n\r\nexport interface IWorkbenchPagedListOptions extends IWorkbenchListOptionsUpdate, IPagedListOptions {\r\n}\r\n\r\nexport class WorkbenchPagedList extends PagedList {\r\n\r\n\treadonly contextKeyService: IContextKeyService;\r\n\r\n\tprivate readonly disposables: DisposableStore;\r\n\r\n\tprivate _useAltAsMultipleSelectionModifier: boolean;\r\n\tprivate horizontalScrolling: boolean | undefined;\r\n\r\n\tconstructor(\r\n\t\tuser: string,\r\n\t\tcontainer: HTMLElement,\r\n\t\tdelegate: IListVirtualDelegate,\r\n\t\trenderers: IPagedRenderer[],\r\n\t\toptions: IWorkbenchPagedListOptions,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\r\n\t\t@IListService listService: IListService,\r\n\t\t@IThemeService themeService: IThemeService,\r\n\t\t@IConfigurationService configurationService: IConfigurationService,\r\n\t\t@IKeybindingService keybindingService: IKeybindingService\r\n\t) {\r\n\t\tconst horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : configurationService.getValue(horizontalScrollingKey);\r\n\t\tconst [workbenchListOptions, workbenchListOptionsDisposable] = toWorkbenchListOptions(options, configurationService, keybindingService);\r\n\t\tsuper(user, container, delegate, renderers,\r\n\t\t\t{\r\n\t\t\t\tkeyboardSupport: false,\r\n\t\t\t\t...computeStyles(themeService.getColorTheme(), defaultListStyles),\r\n\t\t\t\t...workbenchListOptions,\r\n\t\t\t\thorizontalScrolling\r\n\t\t\t}\r\n\t\t);\r\n\r\n\t\tthis.disposables = new DisposableStore();\r\n\t\tthis.disposables.add(workbenchListOptionsDisposable);\r\n\r\n\t\tthis.contextKeyService = createScopedContextKeyService(contextKeyService, this);\r\n\t\tthis.horizontalScrolling = options.horizontalScrolling;\r\n\r\n\t\tconst listSupportsMultiSelect = WorkbenchListSupportsMultiSelectContextKey.bindTo(this.contextKeyService);\r\n\t\tlistSupportsMultiSelect.set(!(options.multipleSelectionSupport === false));\r\n\r\n\t\tthis._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);\r\n\r\n\t\tthis.disposables.add(this.contextKeyService);\r\n\t\tthis.disposables.add((listService as ListService).register(this));\r\n\r\n\t\tif (options.overrideStyles) {\r\n\t\t\tthis.disposables.add(attachListStyler(this, themeService, options.overrideStyles));\r\n\t\t}\r\n\r\n\t\tthis.disposables.add(configurationService.onDidChangeConfiguration(e => {\r\n\t\t\tif (e.affectsConfiguration(multiSelectModifierSettingKey)) {\r\n\t\t\t\tthis._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);\r\n\t\t\t}\r\n\r\n\t\t\tlet options: IListOptionsUpdate = {};\r\n\r\n\t\t\tif (e.affectsConfiguration(horizontalScrollingKey) && this.horizontalScrolling === undefined) {\r\n\t\t\t\tconst horizontalScrolling = configurationService.getValue(horizontalScrollingKey);\r\n\t\t\t\toptions = { ...options, horizontalScrolling };\r\n\t\t\t}\r\n\t\t\tif (e.affectsConfiguration(listSmoothScrolling)) {\r\n\t\t\t\tconst smoothScrolling = configurationService.getValue(listSmoothScrolling);\r\n\t\t\t\toptions = { ...options, smoothScrolling };\r\n\t\t\t}\r\n\t\t\tif (Object.keys(options).length > 0) {\r\n\t\t\t\tthis.updateOptions(options);\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tsuper.dispose();\r\n\r\n\t\tthis.disposables.dispose();\r\n\t}\r\n}\r\n\r\nexport interface IOpenEvent {\r\n\teditorOptions: IEditorOptions;\r\n\tsideBySide: boolean;\r\n\telement: T;\r\n\tbrowserEvent?: UIEvent;\r\n}\r\n\r\nexport interface IResourceNavigatorOptions {\r\n\treadonly configurationService?: IConfigurationService;\r\n\treadonly openOnFocus?: boolean;\r\n\treadonly openOnSingleClick?: boolean;\r\n}\r\n\r\nexport interface SelectionKeyboardEvent extends KeyboardEvent {\r\n\tpreserveFocus?: boolean;\r\n\tpinned?: boolean;\r\n\t__forceEvent?: boolean;\r\n}\r\n\r\nabstract class ResourceNavigator extends Disposable {\r\n\r\n\tprivate readonly openOnFocus: boolean;\r\n\tprivate openOnSingleClick: boolean;\r\n\r\n\tprivate readonly _onDidOpen = this._register(new Emitter>());\r\n\treadonly onDidOpen: Event> = this._onDidOpen.event;\r\n\r\n\tconstructor(\r\n\t\tprotected readonly widget: ListWidget,\r\n\t\toptions?: IResourceNavigatorOptions\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\tthis.openOnFocus = options?.openOnFocus ?? false;\r\n\r\n\t\tthis._register(Event.filter(this.widget.onDidChangeSelection, e => e.browserEvent instanceof KeyboardEvent)(e => this.onSelectionFromKeyboard(e)));\r\n\t\tthis._register(this.widget.onPointer((e: { browserEvent: MouseEvent, element: T | undefined }) => this.onPointer(e.element, e.browserEvent)));\r\n\t\tthis._register(this.widget.onMouseDblClick((e: { browserEvent: MouseEvent, element: T | undefined }) => this.onMouseDblClick(e.element, e.browserEvent)));\r\n\r\n\t\tif (this.openOnFocus) {\r\n\t\t\tthis._register(Event.filter(this.widget.onDidChangeFocus, e => e.browserEvent instanceof KeyboardEvent)(e => this.onFocusFromKeyboard(e)));\r\n\t\t}\r\n\r\n\t\tif (typeof options?.openOnSingleClick !== 'boolean' && options?.configurationService) {\r\n\t\t\tthis.openOnSingleClick = options?.configurationService!.getValue(openModeSettingKey) !== 'doubleClick';\r\n\t\t\tthis._register(options?.configurationService.onDidChangeConfiguration(() => {\r\n\t\t\t\tthis.openOnSingleClick = options?.configurationService!.getValue(openModeSettingKey) !== 'doubleClick';\r\n\t\t\t}));\r\n\t\t} else {\r\n\t\t\tthis.openOnSingleClick = options?.openOnSingleClick ?? true;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate onFocusFromKeyboard(event: ITreeEvent): void {\r\n\t\tconst focus = this.widget.getFocus();\r\n\t\tthis.widget.setSelection(focus, event.browserEvent);\r\n\r\n\t\tconst selectionKeyboardEvent = event.browserEvent as SelectionKeyboardEvent;\r\n\t\tconst preserveFocus = typeof selectionKeyboardEvent.preserveFocus === 'boolean' ? selectionKeyboardEvent.preserveFocus! : true;\r\n\t\tconst pinned = typeof selectionKeyboardEvent.pinned === 'boolean' ? selectionKeyboardEvent.pinned! : !preserveFocus;\r\n\t\tconst sideBySide = false;\r\n\r\n\t\tthis._open(this.getSelectedElement(), preserveFocus, pinned, sideBySide, event.browserEvent);\r\n\t}\r\n\r\n\tprivate onSelectionFromKeyboard(event: ITreeEvent): void {\r\n\t\tif (event.elements.length !== 1) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst selectionKeyboardEvent = event.browserEvent as SelectionKeyboardEvent;\r\n\t\tconst preserveFocus = typeof selectionKeyboardEvent.preserveFocus === 'boolean' ? selectionKeyboardEvent.preserveFocus! : true;\r\n\t\tconst pinned = typeof selectionKeyboardEvent.pinned === 'boolean' ? selectionKeyboardEvent.pinned! : !preserveFocus;\r\n\t\tconst sideBySide = false;\r\n\r\n\t\tthis._open(this.getSelectedElement(), preserveFocus, pinned, sideBySide, event.browserEvent);\r\n\t}\r\n\r\n\tprivate onPointer(element: T | undefined, browserEvent: MouseEvent): void {\r\n\t\tif (!this.openOnSingleClick) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst isDoubleClick = browserEvent.detail === 2;\r\n\r\n\t\tif (isDoubleClick) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst isMiddleClick = browserEvent.button === 1;\r\n\t\tconst preserveFocus = true;\r\n\t\tconst pinned = isMiddleClick;\r\n\t\tconst sideBySide = browserEvent.ctrlKey || browserEvent.metaKey || browserEvent.altKey;\r\n\r\n\t\tthis._open(element, preserveFocus, pinned, sideBySide, browserEvent);\r\n\t}\r\n\r\n\tprivate onMouseDblClick(element: T | undefined, browserEvent?: MouseEvent): void {\r\n\t\tif (!browserEvent) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst preserveFocus = false;\r\n\t\tconst pinned = true;\r\n\t\tconst sideBySide = (browserEvent.ctrlKey || browserEvent.metaKey || browserEvent.altKey);\r\n\r\n\t\tthis._open(element, preserveFocus, pinned, sideBySide, browserEvent);\r\n\t}\r\n\r\n\tprivate _open(element: T | undefined, preserveFocus: boolean, pinned: boolean, sideBySide: boolean, browserEvent?: UIEvent): void {\r\n\t\tif (!element) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._onDidOpen.fire({\r\n\t\t\teditorOptions: {\r\n\t\t\t\tpreserveFocus,\r\n\t\t\t\tpinned,\r\n\t\t\t\trevealIfVisible: true\r\n\t\t\t},\r\n\t\t\tsideBySide,\r\n\t\t\telement,\r\n\t\t\tbrowserEvent\r\n\t\t});\r\n\t}\r\n\r\n\tabstract getSelectedElement(): T | undefined;\r\n}\r\n\r\nclass TreeResourceNavigator extends ResourceNavigator {\r\n\r\n\tconstructor(\r\n\t\tprotected readonly widget: ObjectTree | CompressibleObjectTree | DataTree | AsyncDataTree | CompressibleAsyncDataTree,\r\n\t\toptions: IResourceNavigatorOptions\r\n\t) {\r\n\t\tsuper(widget, options);\r\n\t}\r\n\r\n\tgetSelectedElement(): T | undefined {\r\n\t\treturn this.widget.getSelection()[0] ?? undefined;\r\n\t}\r\n}\r\n\r\nfunction createKeyboardNavigationEventFilter(container: HTMLElement, keybindingService: IKeybindingService): IKeyboardNavigationEventFilter {\r\n\tlet inChord = false;\r\n\r\n\treturn event => {\r\n\t\tif (inChord) {\r\n\t\t\tinChord = false;\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tconst result = keybindingService.softDispatch(event, container);\r\n\r\n\t\tif (result && result.enterChord) {\r\n\t\t\tinChord = true;\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tinChord = false;\r\n\t\treturn true;\r\n\t};\r\n}\r\n\r\nexport interface IWorkbenchObjectTreeOptions extends IObjectTreeOptions, IResourceNavigatorOptions {\r\n\treadonly overrideStyles?: IColorMapping;\r\n}\r\n\r\nexport class WorkbenchObjectTree, TFilterData = void> extends ObjectTree {\r\n\r\n\tprivate internals: WorkbenchTreeInternals;\r\n\r\n\tconstructor(\r\n\t\tuser: string,\r\n\t\tcontainer: HTMLElement,\r\n\t\tdelegate: IListVirtualDelegate,\r\n\t\trenderers: ITreeRenderer[],\r\n\t\toptions: IWorkbenchObjectTreeOptions,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\r\n\t\t@IListService listService: IListService,\r\n\t\t@IThemeService themeService: IThemeService,\r\n\t\t@IConfigurationService configurationService: IConfigurationService,\r\n\t\t@IKeybindingService keybindingService: IKeybindingService,\r\n\t\t@IAccessibilityService accessibilityService: IAccessibilityService\r\n\t) {\r\n\t\tconst { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble>(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);\r\n\t\tsuper(user, container, delegate, renderers, treeOptions);\r\n\t\tthis.disposables.add(disposable);\r\n\t\tthis.internals = new WorkbenchTreeInternals(this, options, getAutomaticKeyboardNavigation, options.overrideStyles, contextKeyService, listService, themeService, configurationService, accessibilityService);\r\n\t\tthis.disposables.add(this.internals);\r\n\t}\r\n}\r\n\r\nexport interface IWorkbenchCompressibleObjectTreeOptionsUpdate extends ICompressibleObjectTreeOptionsUpdate {\r\n\treadonly overrideStyles?: IColorMapping;\r\n}\r\n\r\nexport interface IWorkbenchCompressibleObjectTreeOptions extends IWorkbenchCompressibleObjectTreeOptionsUpdate, ICompressibleObjectTreeOptions, IResourceNavigatorOptions {\r\n}\r\n\r\nexport class WorkbenchCompressibleObjectTree, TFilterData = void> extends CompressibleObjectTree {\r\n\r\n\tprivate internals: WorkbenchTreeInternals;\r\n\r\n\tconstructor(\r\n\t\tuser: string,\r\n\t\tcontainer: HTMLElement,\r\n\t\tdelegate: IListVirtualDelegate,\r\n\t\trenderers: ICompressibleTreeRenderer[],\r\n\t\toptions: IWorkbenchCompressibleObjectTreeOptions,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\r\n\t\t@IListService listService: IListService,\r\n\t\t@IThemeService themeService: IThemeService,\r\n\t\t@IConfigurationService configurationService: IConfigurationService,\r\n\t\t@IKeybindingService keybindingService: IKeybindingService,\r\n\t\t@IAccessibilityService accessibilityService: IAccessibilityService\r\n\t) {\r\n\t\tconst { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble>(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);\r\n\t\tsuper(user, container, delegate, renderers, treeOptions);\r\n\t\tthis.disposables.add(disposable);\r\n\t\tthis.internals = new WorkbenchTreeInternals(this, options, getAutomaticKeyboardNavigation, options.overrideStyles, contextKeyService, listService, themeService, configurationService, accessibilityService);\r\n\t\tthis.disposables.add(this.internals);\r\n\t}\r\n\r\n\tupdateOptions(options: IWorkbenchCompressibleObjectTreeOptionsUpdate = {}): void {\r\n\t\tsuper.updateOptions(options);\r\n\r\n\t\tif (options.overrideStyles) {\r\n\t\t\tthis.internals.updateStyleOverrides(options.overrideStyles);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport interface IWorkbenchDataTreeOptionsUpdate extends IAbstractTreeOptionsUpdate {\r\n\treadonly overrideStyles?: IColorMapping;\r\n}\r\n\r\nexport interface IWorkbenchDataTreeOptions extends IWorkbenchDataTreeOptionsUpdate, IDataTreeOptions, IResourceNavigatorOptions {\r\n}\r\n\r\nexport class WorkbenchDataTree extends DataTree {\r\n\r\n\tprivate internals: WorkbenchTreeInternals;\r\n\r\n\tconstructor(\r\n\t\tuser: string,\r\n\t\tcontainer: HTMLElement,\r\n\t\tdelegate: IListVirtualDelegate,\r\n\t\trenderers: ITreeRenderer[],\r\n\t\tdataSource: IDataSource,\r\n\t\toptions: IWorkbenchDataTreeOptions,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\r\n\t\t@IListService listService: IListService,\r\n\t\t@IThemeService themeService: IThemeService,\r\n\t\t@IConfigurationService configurationService: IConfigurationService,\r\n\t\t@IKeybindingService keybindingService: IKeybindingService,\r\n\t\t@IAccessibilityService accessibilityService: IAccessibilityService\r\n\t) {\r\n\t\tconst { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble>(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);\r\n\t\tsuper(user, container, delegate, renderers, dataSource, treeOptions);\r\n\t\tthis.disposables.add(disposable);\r\n\t\tthis.internals = new WorkbenchTreeInternals(this, options, getAutomaticKeyboardNavigation, options.overrideStyles, contextKeyService, listService, themeService, configurationService, accessibilityService);\r\n\t\tthis.disposables.add(this.internals);\r\n\t}\r\n\r\n\tupdateOptions(options: IWorkbenchDataTreeOptionsUpdate = {}): void {\r\n\t\tsuper.updateOptions(options);\r\n\r\n\t\tif (options.overrideStyles) {\r\n\t\t\tthis.internals.updateStyleOverrides(options.overrideStyles);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport interface IWorkbenchAsyncDataTreeOptionsUpdate extends IAsyncDataTreeOptionsUpdate {\r\n\treadonly overrideStyles?: IColorMapping;\r\n}\r\n\r\nexport interface IWorkbenchAsyncDataTreeOptions extends IWorkbenchAsyncDataTreeOptionsUpdate, IAsyncDataTreeOptions, IResourceNavigatorOptions {\r\n\treadonly accessibilityProvider: IListAccessibilityProvider;\r\n}\r\n\r\nexport class WorkbenchAsyncDataTree extends AsyncDataTree {\r\n\r\n\tprivate internals: WorkbenchTreeInternals;\r\n\tget onDidOpen(): Event> { return this.internals.onDidOpen; }\r\n\r\n\tconstructor(\r\n\t\tuser: string,\r\n\t\tcontainer: HTMLElement,\r\n\t\tdelegate: IListVirtualDelegate,\r\n\t\trenderers: ITreeRenderer[],\r\n\t\tdataSource: IAsyncDataSource,\r\n\t\toptions: IWorkbenchAsyncDataTreeOptions,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\r\n\t\t@IListService listService: IListService,\r\n\t\t@IThemeService themeService: IThemeService,\r\n\t\t@IConfigurationService configurationService: IConfigurationService,\r\n\t\t@IKeybindingService keybindingService: IKeybindingService,\r\n\t\t@IAccessibilityService accessibilityService: IAccessibilityService\r\n\t) {\r\n\t\tconst { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble>(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);\r\n\t\tsuper(user, container, delegate, renderers, dataSource, treeOptions);\r\n\t\tthis.disposables.add(disposable);\r\n\t\tthis.internals = new WorkbenchTreeInternals(this, options, getAutomaticKeyboardNavigation, options.overrideStyles, contextKeyService, listService, themeService, configurationService, accessibilityService);\r\n\t\tthis.disposables.add(this.internals);\r\n\t}\r\n\r\n\tupdateOptions(options: IWorkbenchAsyncDataTreeOptionsUpdate = {}): void {\r\n\t\tsuper.updateOptions(options);\r\n\r\n\t\tif (options.overrideStyles) {\r\n\t\t\tthis.internals.updateStyleOverrides(options.overrideStyles);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport interface IWorkbenchCompressibleAsyncDataTreeOptions extends ICompressibleAsyncDataTreeOptions, IResourceNavigatorOptions {\r\n\treadonly overrideStyles?: IColorMapping;\r\n}\r\n\r\nexport class WorkbenchCompressibleAsyncDataTree extends CompressibleAsyncDataTree {\r\n\r\n\tprivate internals: WorkbenchTreeInternals;\r\n\r\n\tconstructor(\r\n\t\tuser: string,\r\n\t\tcontainer: HTMLElement,\r\n\t\tvirtualDelegate: IListVirtualDelegate,\r\n\t\tcompressionDelegate: ITreeCompressionDelegate,\r\n\t\trenderers: ICompressibleTreeRenderer[],\r\n\t\tdataSource: IAsyncDataSource,\r\n\t\toptions: IWorkbenchCompressibleAsyncDataTreeOptions,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\r\n\t\t@IListService listService: IListService,\r\n\t\t@IThemeService themeService: IThemeService,\r\n\t\t@IConfigurationService configurationService: IConfigurationService,\r\n\t\t@IKeybindingService keybindingService: IKeybindingService,\r\n\t\t@IAccessibilityService accessibilityService: IAccessibilityService\r\n\t) {\r\n\t\tconst { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble>(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);\r\n\t\tsuper(user, container, virtualDelegate, compressionDelegate, renderers, dataSource, treeOptions);\r\n\t\tthis.disposables.add(disposable);\r\n\t\tthis.internals = new WorkbenchTreeInternals(this, options, getAutomaticKeyboardNavigation, options.overrideStyles, contextKeyService, listService, themeService, configurationService, accessibilityService);\r\n\t\tthis.disposables.add(this.internals);\r\n\t}\r\n}\r\n\r\nfunction workbenchTreeDataPreamble | IAsyncDataTreeOptions>(\r\n\tcontainer: HTMLElement,\r\n\toptions: TOptions,\r\n\tcontextKeyService: IContextKeyService,\r\n\tconfigurationService: IConfigurationService,\r\n\tkeybindingService: IKeybindingService,\r\n\taccessibilityService: IAccessibilityService,\r\n): { options: TOptions, getAutomaticKeyboardNavigation: () => boolean | undefined, disposable: IDisposable } {\r\n\tWorkbenchListSupportsKeyboardNavigation.bindTo(contextKeyService);\r\n\r\n\tif (!didBindWorkbenchListAutomaticKeyboardNavigation) {\r\n\t\tWorkbenchListAutomaticKeyboardNavigation.bindTo(contextKeyService);\r\n\t\tdidBindWorkbenchListAutomaticKeyboardNavigation = true;\r\n\t}\r\n\r\n\tconst getAutomaticKeyboardNavigation = () => {\r\n\t\t// give priority to the context key value to disable this completely\r\n\t\tlet automaticKeyboardNavigation = contextKeyService.getContextKeyValue(WorkbenchListAutomaticKeyboardNavigationKey);\r\n\r\n\t\tif (automaticKeyboardNavigation) {\r\n\t\t\tautomaticKeyboardNavigation = configurationService.getValue(automaticKeyboardNavigationSettingKey);\r\n\t\t}\r\n\r\n\t\treturn automaticKeyboardNavigation;\r\n\t};\r\n\r\n\tconst accessibilityOn = accessibilityService.isScreenReaderOptimized();\r\n\tconst keyboardNavigation = options.simpleKeyboardNavigation || accessibilityOn ? 'simple' : configurationService.getValue(keyboardNavigationSettingKey);\r\n\tconst horizontalScrolling = options.horizontalScrolling !== undefined ? options.horizontalScrolling : configurationService.getValue(horizontalScrollingKey);\r\n\tconst [workbenchListOptions, disposable] = toWorkbenchListOptions(options, configurationService, keybindingService);\r\n\tconst additionalScrollHeight = options.additionalScrollHeight;\r\n\r\n\treturn {\r\n\t\tgetAutomaticKeyboardNavigation,\r\n\t\tdisposable,\r\n\t\toptions: {\r\n\t\t\t// ...options, // TODO@Joao why is this not splatted here?\r\n\t\t\tkeyboardSupport: false,\r\n\t\t\t...workbenchListOptions,\r\n\t\t\tindent: configurationService.getValue(treeIndentKey),\r\n\t\t\trenderIndentGuides: configurationService.getValue(treeRenderIndentGuidesKey),\r\n\t\t\tsmoothScrolling: configurationService.getValue(listSmoothScrolling),\r\n\t\t\tautomaticKeyboardNavigation: getAutomaticKeyboardNavigation(),\r\n\t\t\tsimpleKeyboardNavigation: keyboardNavigation === 'simple',\r\n\t\t\tfilterOnType: keyboardNavigation === 'filter',\r\n\t\t\thorizontalScrolling,\r\n\t\t\tkeyboardNavigationEventFilter: createKeyboardNavigationEventFilter(container, keybindingService),\r\n\t\t\tadditionalScrollHeight,\r\n\t\t\thideTwistiesOfChildlessElements: options.hideTwistiesOfChildlessElements,\r\n\t\t\texpandOnlyOnDoubleClick: configurationService.getValue(openModeSettingKey) === 'doubleClick',\r\n\t\t\texpandOnlyOnTwistieClick: options.expandOnlyOnTwistieClick ?? (configurationService.getValue<'singleClick' | 'doubleClick'>(treeExpandMode) === 'doubleClick')\r\n\t\t} as TOptions\r\n\t};\r\n}\r\n\r\nclass WorkbenchTreeInternals {\r\n\r\n\treadonly contextKeyService: IContextKeyService;\r\n\tprivate hasSelectionOrFocus: IContextKey;\r\n\tprivate hasDoubleSelection: IContextKey;\r\n\tprivate hasMultiSelection: IContextKey;\r\n\tprivate _useAltAsMultipleSelectionModifier: boolean;\r\n\tprivate disposables: IDisposable[] = [];\r\n\tprivate styler: IDisposable | undefined;\r\n\tprivate navigator: TreeResourceNavigator;\r\n\r\n\tget onDidOpen(): Event> { return this.navigator.onDidOpen; }\r\n\r\n\tconstructor(\r\n\t\tprivate tree: WorkbenchObjectTree | WorkbenchCompressibleObjectTree | WorkbenchDataTree | WorkbenchAsyncDataTree | WorkbenchCompressibleAsyncDataTree,\r\n\t\toptions: IWorkbenchObjectTreeOptions | IWorkbenchCompressibleObjectTreeOptions | IWorkbenchDataTreeOptions | IWorkbenchAsyncDataTreeOptions | IWorkbenchCompressibleAsyncDataTreeOptions,\r\n\t\tgetAutomaticKeyboardNavigation: () => boolean | undefined,\r\n\t\toverrideStyles: IColorMapping | undefined,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\r\n\t\t@IListService listService: IListService,\r\n\t\t@IThemeService private themeService: IThemeService,\r\n\t\t@IConfigurationService configurationService: IConfigurationService,\r\n\t\t@IAccessibilityService accessibilityService: IAccessibilityService,\r\n\t) {\r\n\t\tthis.contextKeyService = createScopedContextKeyService(contextKeyService, tree);\r\n\r\n\t\tconst listSupportsMultiSelect = WorkbenchListSupportsMultiSelectContextKey.bindTo(this.contextKeyService);\r\n\t\tlistSupportsMultiSelect.set(!(options.multipleSelectionSupport === false));\r\n\r\n\t\tthis.hasSelectionOrFocus = WorkbenchListHasSelectionOrFocus.bindTo(this.contextKeyService);\r\n\t\tthis.hasDoubleSelection = WorkbenchListDoubleSelection.bindTo(this.contextKeyService);\r\n\t\tthis.hasMultiSelection = WorkbenchListMultiSelection.bindTo(this.contextKeyService);\r\n\r\n\t\tthis._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);\r\n\r\n\t\tconst interestingContextKeys = new Set();\r\n\t\tinterestingContextKeys.add(WorkbenchListAutomaticKeyboardNavigationKey);\r\n\t\tconst updateKeyboardNavigation = () => {\r\n\t\t\tconst accessibilityOn = accessibilityService.isScreenReaderOptimized();\r\n\t\t\tconst keyboardNavigation = accessibilityOn ? 'simple' : configurationService.getValue(keyboardNavigationSettingKey);\r\n\t\t\ttree.updateOptions({\r\n\t\t\t\tsimpleKeyboardNavigation: keyboardNavigation === 'simple',\r\n\t\t\t\tfilterOnType: keyboardNavigation === 'filter'\r\n\t\t\t});\r\n\t\t};\r\n\r\n\t\tthis.updateStyleOverrides(overrideStyles);\r\n\r\n\t\tthis.disposables.push(\r\n\t\t\tthis.contextKeyService,\r\n\t\t\t(listService as ListService).register(tree),\r\n\t\t\ttree.onDidChangeSelection(() => {\r\n\t\t\t\tconst selection = tree.getSelection();\r\n\t\t\t\tconst focus = tree.getFocus();\r\n\r\n\t\t\t\tthis.contextKeyService.bufferChangeEvents(() => {\r\n\t\t\t\t\tthis.hasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);\r\n\t\t\t\t\tthis.hasMultiSelection.set(selection.length > 1);\r\n\t\t\t\t\tthis.hasDoubleSelection.set(selection.length === 2);\r\n\t\t\t\t});\r\n\t\t\t}),\r\n\t\t\ttree.onDidChangeFocus(() => {\r\n\t\t\t\tconst selection = tree.getSelection();\r\n\t\t\t\tconst focus = tree.getFocus();\r\n\r\n\t\t\t\tthis.hasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);\r\n\t\t\t}),\r\n\t\t\tconfigurationService.onDidChangeConfiguration(e => {\r\n\t\t\t\tlet newOptions: any = {};\r\n\t\t\t\tif (e.affectsConfiguration(multiSelectModifierSettingKey)) {\r\n\t\t\t\t\tthis._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);\r\n\t\t\t\t}\r\n\t\t\t\tif (e.affectsConfiguration(treeIndentKey)) {\r\n\t\t\t\t\tconst indent = configurationService.getValue(treeIndentKey);\r\n\t\t\t\t\tnewOptions = { ...newOptions, indent };\r\n\t\t\t\t}\r\n\t\t\t\tif (e.affectsConfiguration(treeRenderIndentGuidesKey)) {\r\n\t\t\t\t\tconst renderIndentGuides = configurationService.getValue(treeRenderIndentGuidesKey);\r\n\t\t\t\t\tnewOptions = { ...newOptions, renderIndentGuides };\r\n\t\t\t\t}\r\n\t\t\t\tif (e.affectsConfiguration(listSmoothScrolling)) {\r\n\t\t\t\t\tconst smoothScrolling = configurationService.getValue(listSmoothScrolling);\r\n\t\t\t\t\tnewOptions = { ...newOptions, smoothScrolling };\r\n\t\t\t\t}\r\n\t\t\t\tif (e.affectsConfiguration(keyboardNavigationSettingKey)) {\r\n\t\t\t\t\tupdateKeyboardNavigation();\r\n\t\t\t\t}\r\n\t\t\t\tif (e.affectsConfiguration(automaticKeyboardNavigationSettingKey)) {\r\n\t\t\t\t\tnewOptions = { ...newOptions, automaticKeyboardNavigation: getAutomaticKeyboardNavigation() };\r\n\t\t\t\t}\r\n\t\t\t\tif (e.affectsConfiguration(horizontalScrollingKey) && options.horizontalScrolling === undefined) {\r\n\t\t\t\t\tconst horizontalScrolling = configurationService.getValue(horizontalScrollingKey);\r\n\t\t\t\t\tnewOptions = { ...newOptions, horizontalScrolling };\r\n\t\t\t\t}\r\n\t\t\t\tif (e.affectsConfiguration(openModeSettingKey)) {\r\n\t\t\t\t\tnewOptions = { ...newOptions, expandOnlyOnDoubleClick: configurationService.getValue(openModeSettingKey) === 'doubleClick' };\r\n\t\t\t\t}\r\n\t\t\t\tif (e.affectsConfiguration(treeExpandMode) && options.expandOnlyOnTwistieClick === undefined) {\r\n\t\t\t\t\tnewOptions = { ...newOptions, expandOnlyOnTwistieClick: configurationService.getValue<'singleClick' | 'doubleClick'>(treeExpandMode) === 'doubleClick' };\r\n\t\t\t\t}\r\n\t\t\t\tif (Object.keys(newOptions).length > 0) {\r\n\t\t\t\t\ttree.updateOptions(newOptions);\r\n\t\t\t\t}\r\n\t\t\t}),\r\n\t\t\tthis.contextKeyService.onDidChangeContext(e => {\r\n\t\t\t\tif (e.affectsSome(interestingContextKeys)) {\r\n\t\t\t\t\ttree.updateOptions({ automaticKeyboardNavigation: getAutomaticKeyboardNavigation() });\r\n\t\t\t\t}\r\n\t\t\t}),\r\n\t\t\taccessibilityService.onDidChangeScreenReaderOptimized(() => updateKeyboardNavigation())\r\n\t\t);\r\n\r\n\t\tthis.navigator = new TreeResourceNavigator(tree, { configurationService, ...options });\r\n\t\tthis.disposables.push(this.navigator);\r\n\t}\r\n\r\n\tupdateStyleOverrides(overrideStyles?: IColorMapping): void {\r\n\t\tdispose(this.styler);\r\n\t\tthis.styler = overrideStyles ? attachListStyler(this.tree, this.themeService, overrideStyles) : Disposable.None;\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis.disposables = dispose(this.disposables);\r\n\t\tdispose(this.styler);\r\n\t\tthis.styler = undefined;\r\n\t}\r\n}\r\n\r\nconst configurationRegistry = Registry.as(ConfigurationExtensions.Configuration);\r\n\r\nconfigurationRegistry.registerConfiguration({\r\n\t'id': 'workbench',\r\n\t'order': 7,\r\n\t'title': localize('workbenchConfigurationTitle', \"Workbench\"),\r\n\t'type': 'object',\r\n\t'properties': {\r\n\t\t[multiSelectModifierSettingKey]: {\r\n\t\t\t'type': 'string',\r\n\t\t\t'enum': ['ctrlCmd', 'alt'],\r\n\t\t\t'enumDescriptions': [\r\n\t\t\t\tlocalize('multiSelectModifier.ctrlCmd', \"Maps to `Control` on Windows and Linux and to `Command` on macOS.\"),\r\n\t\t\t\tlocalize('multiSelectModifier.alt', \"Maps to `Alt` on Windows and Linux and to `Option` on macOS.\")\r\n\t\t\t],\r\n\t\t\t'default': 'ctrlCmd',\r\n\t\t\t'description': localize({\r\n\t\t\t\tkey: 'multiSelectModifier',\r\n\t\t\t\tcomment: [\r\n\t\t\t\t\t'- `ctrlCmd` refers to a value the setting can take and should not be localized.',\r\n\t\t\t\t\t'- `Control` and `Command` refer to the modifier keys Ctrl or Cmd on the keyboard and can be localized.'\r\n\t\t\t\t]\r\n\t\t\t}, \"The modifier to be used to add an item in trees and lists to a multi-selection with the mouse (for example in the explorer, open editors and scm view). The 'Open to Side' mouse gestures - if supported - will adapt such that they do not conflict with the multiselect modifier.\")\r\n\t\t},\r\n\t\t[openModeSettingKey]: {\r\n\t\t\t'type': 'string',\r\n\t\t\t'enum': ['singleClick', 'doubleClick'],\r\n\t\t\t'default': 'singleClick',\r\n\t\t\t'description': localize({\r\n\t\t\t\tkey: 'openModeModifier',\r\n\t\t\t\tcomment: ['`singleClick` and `doubleClick` refers to a value the setting can take and should not be localized.']\r\n\t\t\t}, \"Controls how to open items in trees and lists using the mouse (if supported). For parents with children in trees, this setting will control if a single click expands the parent or a double click. Note that some trees and lists might choose to ignore this setting if it is not applicable. \")\r\n\t\t},\r\n\t\t[horizontalScrollingKey]: {\r\n\t\t\t'type': 'boolean',\r\n\t\t\t'default': false,\r\n\t\t\t'description': localize('horizontalScrolling setting', \"Controls whether lists and trees support horizontal scrolling in the workbench. Warning: turning on this setting has a performance implication.\")\r\n\t\t},\r\n\t\t[treeIndentKey]: {\r\n\t\t\t'type': 'number',\r\n\t\t\t'default': 8,\r\n\t\t\tminimum: 0,\r\n\t\t\tmaximum: 40,\r\n\t\t\t'description': localize('tree indent setting', \"Controls tree indentation in pixels.\")\r\n\t\t},\r\n\t\t[treeRenderIndentGuidesKey]: {\r\n\t\t\ttype: 'string',\r\n\t\t\tenum: ['none', 'onHover', 'always'],\r\n\t\t\tdefault: 'onHover',\r\n\t\t\tdescription: localize('render tree indent guides', \"Controls whether the tree should render indent guides.\")\r\n\t\t},\r\n\t\t[listSmoothScrolling]: {\r\n\t\t\ttype: 'boolean',\r\n\t\t\tdefault: false,\r\n\t\t\tdescription: localize('list smoothScrolling setting', \"Controls whether lists and trees have smooth scrolling.\"),\r\n\t\t},\r\n\t\t[keyboardNavigationSettingKey]: {\r\n\t\t\t'type': 'string',\r\n\t\t\t'enum': ['simple', 'highlight', 'filter'],\r\n\t\t\t'enumDescriptions': [\r\n\t\t\t\tlocalize('keyboardNavigationSettingKey.simple', \"Simple keyboard navigation focuses elements which match the keyboard input. Matching is done only on prefixes.\"),\r\n\t\t\t\tlocalize('keyboardNavigationSettingKey.highlight', \"Highlight keyboard navigation highlights elements which match the keyboard input. Further up and down navigation will traverse only the highlighted elements.\"),\r\n\t\t\t\tlocalize('keyboardNavigationSettingKey.filter', \"Filter keyboard navigation will filter out and hide all the elements which do not match the keyboard input.\")\r\n\t\t\t],\r\n\t\t\t'default': 'highlight',\r\n\t\t\t'description': localize('keyboardNavigationSettingKey', \"Controls the keyboard navigation style for lists and trees in the workbench. Can be simple, highlight and filter.\")\r\n\t\t},\r\n\t\t[automaticKeyboardNavigationSettingKey]: {\r\n\t\t\t'type': 'boolean',\r\n\t\t\t'default': true,\r\n\t\t\tmarkdownDescription: localize('automatic keyboard navigation setting', \"Controls whether keyboard navigation in lists and trees is automatically triggered simply by typing. If set to `false`, keyboard navigation is only triggered when executing the `list.toggleKeyboardNavigation` command, for which you can assign a keyboard shortcut.\")\r\n\t\t},\r\n\t\t[treeExpandMode]: {\r\n\t\t\ttype: 'string',\r\n\t\t\tenum: ['singleClick', 'doubleClick'],\r\n\t\t\tdefault: 'singleClick',\r\n\t\t\tdescription: localize('expand mode', \"Controls how tree folders are expanded when clicking the folder names.\"),\r\n\t\t}\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { IQuickInputService, IQuickPickItem, IPickOptions, IQuickPick, QuickPickInput } from 'vs/platform/quickinput/common/quickInput';\r\nimport { ILayoutService } from 'vs/platform/layout/browser/layoutService';\r\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IThemeService, Themable } from 'vs/platform/theme/common/themeService';\r\nimport { inputBackground, inputForeground, inputBorder, inputValidationInfoBackground, inputValidationInfoForeground, inputValidationInfoBorder, inputValidationWarningBackground, inputValidationWarningForeground, inputValidationWarningBorder, inputValidationErrorBackground, inputValidationErrorForeground, inputValidationErrorBorder, badgeBackground, badgeForeground, contrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, progressBarBackground, widgetShadow, listFocusForeground, listFocusBackground, activeContrastBorder, pickerGroupBorder, pickerGroupForeground, quickInputForeground, quickInputBackground, quickInputTitleBackground } from 'vs/platform/theme/common/colorRegistry';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { computeStyles } from 'vs/platform/theme/common/styler';\r\nimport { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';\r\nimport { QuickInputController, IQuickInputStyles, IQuickInputOptions } from 'vs/base/parts/quickinput/browser/quickInput';\r\nimport { WorkbenchList, IWorkbenchListOptions } from 'vs/platform/list/browser/listService';\r\nimport { List } from 'vs/base/browser/ui/list/listWidget';\r\nimport { IListVirtualDelegate, IListRenderer } from 'vs/base/browser/ui/list/list';\r\nimport { IQuickAccessController } from 'vs/platform/quickinput/common/quickAccess';\r\nimport { QuickAccessController } from 'vs/platform/quickinput/browser/quickAccess';\r\n\r\nexport interface IQuickInputControllerHost extends ILayoutService { }\r\n\r\nexport class QuickInputService extends Themable implements IQuickInputService {\r\n\r\n\tdeclare readonly _serviceBrand: undefined;\r\n\r\n\tprivate _controller: QuickInputController | undefined;\r\n\tprivate get controller(): QuickInputController {\r\n\t\tif (!this._controller) {\r\n\t\t\tthis._controller = this._register(this.createController());\r\n\t\t}\r\n\r\n\t\treturn this._controller;\r\n\t}\r\n\r\n\tprivate _quickAccess: IQuickAccessController | undefined;\r\n\tget quickAccess(): IQuickAccessController {\r\n\t\tif (!this._quickAccess) {\r\n\t\t\tthis._quickAccess = this._register(this.instantiationService.createInstance(QuickAccessController));\r\n\t\t}\r\n\r\n\t\treturn this._quickAccess;\r\n\t}\r\n\r\n\tprivate readonly contexts = new Map>();\r\n\r\n\tconstructor(\r\n\t\t@IInstantiationService private readonly instantiationService: IInstantiationService,\r\n\t\t@IContextKeyService protected readonly contextKeyService: IContextKeyService,\r\n\t\t@IThemeService themeService: IThemeService,\r\n\t\t@IAccessibilityService private readonly accessibilityService: IAccessibilityService,\r\n\t\t@ILayoutService protected readonly layoutService: ILayoutService\r\n\t) {\r\n\t\tsuper(themeService);\r\n\t}\r\n\r\n\tprotected createController(host: IQuickInputControllerHost = this.layoutService, options?: Partial): QuickInputController {\r\n\t\tconst defaultOptions: IQuickInputOptions = {\r\n\t\t\tidPrefix: 'quickInput_', // Constant since there is still only one.\r\n\t\t\tcontainer: host.container,\r\n\t\t\tignoreFocusOut: () => false,\r\n\t\t\tisScreenReaderOptimized: () => this.accessibilityService.isScreenReaderOptimized(),\r\n\t\t\tbackKeybindingLabel: () => undefined,\r\n\t\t\tsetContextKey: (id?: string) => this.setContextKey(id),\r\n\t\t\treturnFocus: () => host.focus(),\r\n\t\t\tcreateList: (\r\n\t\t\t\tuser: string,\r\n\t\t\t\tcontainer: HTMLElement,\r\n\t\t\t\tdelegate: IListVirtualDelegate,\r\n\t\t\t\trenderers: IListRenderer[],\r\n\t\t\t\toptions: IWorkbenchListOptions,\r\n\t\t\t) => this.instantiationService.createInstance(WorkbenchList, user, container, delegate, renderers, options) as List,\r\n\t\t\tstyles: this.computeStyles()\r\n\t\t};\r\n\r\n\t\tconst controller = this._register(new QuickInputController({\r\n\t\t\t...defaultOptions,\r\n\t\t\t...options\r\n\t\t}));\r\n\r\n\t\tcontroller.layout(host.dimension, host.offset?.top ?? 0);\r\n\r\n\t\t// Layout changes\r\n\t\tthis._register(host.onLayout(dimension => controller.layout(dimension, host.offset?.top ?? 0)));\r\n\r\n\t\t// Context keys\r\n\t\tthis._register(controller.onShow(() => this.resetContextKeys()));\r\n\t\tthis._register(controller.onHide(() => this.resetContextKeys()));\r\n\r\n\t\treturn controller;\r\n\t}\r\n\r\n\tprivate setContextKey(id?: string) {\r\n\t\tlet key: IContextKey | undefined;\r\n\t\tif (id) {\r\n\t\t\tkey = this.contexts.get(id);\r\n\t\t\tif (!key) {\r\n\t\t\t\tkey = new RawContextKey(id, false)\r\n\t\t\t\t\t.bindTo(this.contextKeyService);\r\n\t\t\t\tthis.contexts.set(id, key);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (key && key.get()) {\r\n\t\t\treturn; // already active context\r\n\t\t}\r\n\r\n\t\tthis.resetContextKeys();\r\n\r\n\t\tif (key) {\r\n\t\t\tkey.set(true);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate resetContextKeys() {\r\n\t\tthis.contexts.forEach(context => {\r\n\t\t\tif (context.get()) {\r\n\t\t\t\tcontext.reset();\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpick>(picks: Promise[]> | QuickPickInput[], options: O = {}, token: CancellationToken = CancellationToken.None): Promise<(O extends { canPickMany: true } ? T[] : T) | undefined> {\r\n\t\treturn this.controller.pick(picks, options, token);\r\n\t}\r\n\r\n\tcreateQuickPick(): IQuickPick {\r\n\t\treturn this.controller.createQuickPick();\r\n\t}\r\n\r\n\tprotected updateStyles() {\r\n\t\tthis.controller.applyStyles(this.computeStyles());\r\n\t}\r\n\r\n\tprivate computeStyles(): IQuickInputStyles {\r\n\t\treturn {\r\n\t\t\twidget: {\r\n\t\t\t\t...computeStyles(this.theme, {\r\n\t\t\t\t\tquickInputBackground,\r\n\t\t\t\t\tquickInputForeground,\r\n\t\t\t\t\tquickInputTitleBackground,\r\n\t\t\t\t\tcontrastBorder,\r\n\t\t\t\t\twidgetShadow\r\n\t\t\t\t}),\r\n\t\t\t},\r\n\t\t\tinputBox: computeStyles(this.theme, {\r\n\t\t\t\tinputForeground,\r\n\t\t\t\tinputBackground,\r\n\t\t\t\tinputBorder,\r\n\t\t\t\tinputValidationInfoBackground,\r\n\t\t\t\tinputValidationInfoForeground,\r\n\t\t\t\tinputValidationInfoBorder,\r\n\t\t\t\tinputValidationWarningBackground,\r\n\t\t\t\tinputValidationWarningForeground,\r\n\t\t\t\tinputValidationWarningBorder,\r\n\t\t\t\tinputValidationErrorBackground,\r\n\t\t\t\tinputValidationErrorForeground,\r\n\t\t\t\tinputValidationErrorBorder\r\n\t\t\t}),\r\n\t\t\tcountBadge: computeStyles(this.theme, {\r\n\t\t\t\tbadgeBackground,\r\n\t\t\t\tbadgeForeground,\r\n\t\t\t\tbadgeBorder: contrastBorder\r\n\t\t\t}),\r\n\t\t\tbutton: computeStyles(this.theme, {\r\n\t\t\t\tbuttonForeground,\r\n\t\t\t\tbuttonBackground,\r\n\t\t\t\tbuttonHoverBackground,\r\n\t\t\t\tbuttonBorder: contrastBorder\r\n\t\t\t}),\r\n\t\t\tprogressBar: computeStyles(this.theme, {\r\n\t\t\t\tprogressBarBackground\r\n\t\t\t}),\r\n\t\t\tlist: computeStyles(this.theme, {\r\n\t\t\t\tlistBackground: quickInputBackground,\r\n\t\t\t\t// Look like focused when inactive.\r\n\t\t\t\tlistInactiveFocusForeground: listFocusForeground,\r\n\t\t\t\tlistInactiveFocusBackground: listFocusBackground,\r\n\t\t\t\tlistFocusOutline: activeContrastBorder,\r\n\t\t\t\tlistInactiveFocusOutline: activeContrastBorder,\r\n\t\t\t\tpickerGroupBorder,\r\n\t\t\t\tpickerGroupForeground\r\n\t\t\t})\r\n\t\t};\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./standaloneQuickInput';\r\nimport { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';\r\nimport { registerEditorContribution } from 'vs/editor/browser/editorExtensions';\r\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { IThemeService } from 'vs/platform/theme/common/themeService';\r\nimport { IQuickInputService, IQuickPickItem, IQuickPick, IPickOptions, QuickPickInput } from 'vs/platform/quickinput/common/quickInput';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';\r\nimport { ILayoutService } from 'vs/platform/layout/browser/layoutService';\r\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\r\nimport { QuickInputController } from 'vs/base/parts/quickinput/browser/quickInput';\r\nimport { QuickInputService, IQuickInputControllerHost } from 'vs/platform/quickinput/browser/quickInput';\r\nimport { once } from 'vs/base/common/functional';\r\nimport { IQuickAccessController } from 'vs/platform/quickinput/common/quickAccess';\r\n\r\nexport class EditorScopedQuickInputServiceImpl extends QuickInputService {\r\n\r\n\tprivate host: IQuickInputControllerHost | undefined = undefined;\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor,\r\n\t\t@IInstantiationService instantiationService: IInstantiationService,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\r\n\t\t@IThemeService themeService: IThemeService,\r\n\t\t@IAccessibilityService accessibilityService: IAccessibilityService,\r\n\t\t@ILayoutService layoutService: ILayoutService\r\n\t) {\r\n\t\tsuper(instantiationService, contextKeyService, themeService, accessibilityService, layoutService);\r\n\r\n\t\t// Use the passed in code editor as host for the quick input widget\r\n\t\tconst contribution = QuickInputEditorContribution.get(editor);\r\n\t\tthis.host = {\r\n\t\t\t_serviceBrand: undefined,\r\n\t\t\tget container() { return contribution.widget.getDomNode(); },\r\n\t\t\tget dimension() { return editor.getLayoutInfo(); },\r\n\t\t\tget onLayout() { return editor.onDidLayoutChange; },\r\n\t\t\tfocus: () => editor.focus()\r\n\t\t};\r\n\t}\r\n\r\n\tprotected createController(): QuickInputController {\r\n\t\treturn super.createController(this.host);\r\n\t}\r\n}\r\n\r\nexport class StandaloneQuickInputServiceImpl implements IQuickInputService {\r\n\r\n\tdeclare readonly _serviceBrand: undefined;\r\n\r\n\tprivate mapEditorToService = new Map();\r\n\tprivate get activeService(): IQuickInputService {\r\n\t\tconst editor = this.codeEditorService.getFocusedCodeEditor();\r\n\t\tif (!editor) {\r\n\t\t\tthrow new Error('Quick input service needs a focused editor to work.');\r\n\t\t}\r\n\r\n\t\t// Find the quick input implementation for the focused\r\n\t\t// editor or create it lazily if not yet created\r\n\t\tlet quickInputService = this.mapEditorToService.get(editor);\r\n\t\tif (!quickInputService) {\r\n\t\t\tconst newQuickInputService = quickInputService = this.instantiationService.createInstance(EditorScopedQuickInputServiceImpl, editor);\r\n\t\t\tthis.mapEditorToService.set(editor, quickInputService);\r\n\r\n\t\t\tonce(editor.onDidDispose)(() => {\r\n\t\t\t\tnewQuickInputService.dispose();\r\n\t\t\t\tthis.mapEditorToService.delete(editor);\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\treturn quickInputService;\r\n\t}\r\n\r\n\tget quickAccess(): IQuickAccessController { return this.activeService.quickAccess; }\r\n\r\n\tconstructor(\r\n\t\t@IInstantiationService private readonly instantiationService: IInstantiationService,\r\n\t\t@ICodeEditorService private readonly codeEditorService: ICodeEditorService\r\n\t) {\r\n\t}\r\n\r\n\tpick>(picks: Promise[]> | QuickPickInput[], options: O = {}, token: CancellationToken = CancellationToken.None): Promise<(O extends { canPickMany: true } ? T[] : T) | undefined> {\r\n\t\treturn (this.activeService as unknown as QuickInputController /* TS fail */).pick(picks, options, token);\r\n\t}\r\n\r\n\tcreateQuickPick(): IQuickPick {\r\n\t\treturn this.activeService.createQuickPick();\r\n\t}\r\n}\r\n\r\nexport class QuickInputEditorContribution implements IEditorContribution {\r\n\r\n\tstatic readonly ID = 'editor.controller.quickInput';\r\n\r\n\tstatic get(editor: ICodeEditor): QuickInputEditorContribution {\r\n\t\treturn editor.getContribution(QuickInputEditorContribution.ID);\r\n\t}\r\n\r\n\treadonly widget = new QuickInputEditorWidget(this.editor);\r\n\r\n\tconstructor(private editor: ICodeEditor) { }\r\n\r\n\tdispose(): void {\r\n\t\tthis.widget.dispose();\r\n\t}\r\n}\r\n\r\nexport class QuickInputEditorWidget implements IOverlayWidget {\r\n\r\n\tprivate static readonly ID = 'editor.contrib.quickInputWidget';\r\n\r\n\tprivate domNode: HTMLElement;\r\n\r\n\tconstructor(private codeEditor: ICodeEditor) {\r\n\t\tthis.domNode = document.createElement('div');\r\n\r\n\t\tthis.codeEditor.addOverlayWidget(this);\r\n\t}\r\n\r\n\tgetId(): string {\r\n\t\treturn QuickInputEditorWidget.ID;\r\n\t}\r\n\r\n\tgetDomNode(): HTMLElement {\r\n\t\treturn this.domNode;\r\n\t}\r\n\r\n\tgetPosition(): IOverlayWidgetPosition | null {\r\n\t\treturn { preference: OverlayWidgetPositionPreference.TOP_CENTER };\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis.codeEditor.removeOverlayWidget(this);\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(QuickInputEditorContribution.ID, QuickInputEditorContribution);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport Severity from 'vs/base/common/severity';\r\nimport { registerThemingParticipant } from 'vs/platform/theme/common/themeService';\r\nimport { problemsErrorIconForeground, problemsInfoIconForeground, problemsWarningIconForeground } from 'vs/platform/theme/common/colorRegistry';\r\nimport { Codicon } from 'vs/base/common/codicons';\r\n\r\nexport namespace SeverityIcon {\r\n\r\n\texport function className(severity: Severity): string {\r\n\t\tswitch (severity) {\r\n\t\t\tcase Severity.Ignore:\r\n\t\t\t\treturn 'severity-ignore ' + Codicon.info.classNames;\r\n\t\t\tcase Severity.Info:\r\n\t\t\t\treturn Codicon.info.classNames;\r\n\t\t\tcase Severity.Warning:\r\n\t\t\t\treturn Codicon.warning.classNames;\r\n\t\t\tcase Severity.Error:\r\n\t\t\t\treturn Codicon.error.classNames;\r\n\t\t\tdefault:\r\n\t\t\t\treturn '';\r\n\t\t}\r\n\t}\r\n}\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\r\n\tconst errorIconForeground = theme.getColor(problemsErrorIconForeground);\r\n\tif (errorIconForeground) {\r\n\t\tconst errorCodiconSelector = Codicon.error.cssSelector;\r\n\t\tcollector.addRule(`\r\n\t\t\t.monaco-editor .zone-widget ${errorCodiconSelector},\r\n\t\t\t.markers-panel .marker-icon${errorCodiconSelector},\r\n\t\t\t.extensions-viewlet > .extensions ${errorCodiconSelector} {\r\n\t\t\t\tcolor: ${errorIconForeground};\r\n\t\t\t}\r\n\t\t`);\r\n\t}\r\n\r\n\tconst warningIconForeground = theme.getColor(problemsWarningIconForeground);\r\n\tif (warningIconForeground) {\r\n\t\tconst warningCodiconSelector = Codicon.warning.cssSelector;\r\n\t\tcollector.addRule(`\r\n\t\t\t.monaco-editor .zone-widget ${warningCodiconSelector},\r\n\t\t\t.markers-panel .marker-icon${warningCodiconSelector},\r\n\t\t\t.extensions-viewlet > .extensions ${warningCodiconSelector},\r\n\t\t\t.extension-editor ${warningCodiconSelector} {\r\n\t\t\t\tcolor: ${warningIconForeground};\r\n\t\t\t}\r\n\t\t`);\r\n\t}\r\n\r\n\tconst infoIconForeground = theme.getColor(problemsInfoIconForeground);\r\n\tif (infoIconForeground) {\r\n\t\tconst infoCodiconSelector = Codicon.info.cssSelector;\r\n\t\tcollector.addRule(`\r\n\t\t\t.monaco-editor .zone-widget ${infoCodiconSelector},\r\n\t\t\t.markers-panel .marker-icon${infoCodiconSelector},\r\n\t\t\t.extensions-viewlet > .extensions ${infoCodiconSelector},\r\n\t\t\t.extension-editor ${infoCodiconSelector} {\r\n\t\t\t\tcolor: ${infoIconForeground};\r\n\t\t\t}\r\n\t\t`);\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./media/gotoErrorWidget';\r\nimport * as nls from 'vs/nls';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { dispose, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { IMarker, MarkerSeverity, IRelatedInformation } from 'vs/platform/markers/common/markers';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { registerColor, oneOf, textLinkForeground, editorErrorForeground, editorErrorBorder, editorWarningForeground, editorWarningBorder, editorInfoForeground, editorInfoBorder } from 'vs/platform/theme/common/colorRegistry';\r\nimport { IThemeService, IColorTheme, registerThemingParticipant } from 'vs/platform/theme/common/themeService';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';\r\nimport { ScrollbarVisibility } from 'vs/base/common/scrollable';\r\nimport { ScrollType } from 'vs/editor/common/editorCommon';\r\nimport { getBaseLabel } from 'vs/base/common/labels';\r\nimport { isNonEmptyArray } from 'vs/base/common/arrays';\r\nimport { Event, Emitter } from 'vs/base/common/event';\r\nimport { PeekViewWidget, peekViewTitleForeground, peekViewTitleInfoForeground } from 'vs/editor/contrib/peekView/peekView';\r\nimport { basename } from 'vs/base/common/resources';\r\nimport { IAction } from 'vs/base/common/actions';\r\nimport { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { IOpenerService } from 'vs/platform/opener/common/opener';\r\nimport { MenuId, IMenuService } from 'vs/platform/actions/common/actions';\r\nimport { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\r\nimport { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';\r\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\r\nimport { splitLines } from 'vs/base/common/strings';\r\nimport { ILabelService } from 'vs/platform/label/common/label';\r\n\r\nclass MessageWidget {\r\n\r\n\tprivate _lines: number = 0;\r\n\tprivate _longestLineLength: number = 0;\r\n\r\n\tprivate readonly _editor: ICodeEditor;\r\n\tprivate readonly _messageBlock: HTMLDivElement;\r\n\tprivate readonly _relatedBlock: HTMLDivElement;\r\n\tprivate readonly _scrollable: ScrollableElement;\r\n\tprivate readonly _relatedDiagnostics = new WeakMap();\r\n\tprivate readonly _disposables: DisposableStore = new DisposableStore();\r\n\r\n\tprivate _codeLink?: HTMLElement;\r\n\r\n\tconstructor(\r\n\t\tparent: HTMLElement,\r\n\t\teditor: ICodeEditor,\r\n\t\tonRelatedInformation: (related: IRelatedInformation) => void,\r\n\t\tprivate readonly _openerService: IOpenerService,\r\n\t\tprivate readonly _labelService: ILabelService\r\n\t) {\r\n\t\tthis._editor = editor;\r\n\r\n\t\tconst domNode = document.createElement('div');\r\n\t\tdomNode.className = 'descriptioncontainer';\r\n\r\n\t\tthis._messageBlock = document.createElement('div');\r\n\t\tthis._messageBlock.classList.add('message');\r\n\t\tthis._messageBlock.setAttribute('aria-live', 'assertive');\r\n\t\tthis._messageBlock.setAttribute('role', 'alert');\r\n\t\tdomNode.appendChild(this._messageBlock);\r\n\r\n\t\tthis._relatedBlock = document.createElement('div');\r\n\t\tdomNode.appendChild(this._relatedBlock);\r\n\t\tthis._disposables.add(dom.addStandardDisposableListener(this._relatedBlock, 'click', event => {\r\n\t\t\tevent.preventDefault();\r\n\t\t\tconst related = this._relatedDiagnostics.get(event.target);\r\n\t\t\tif (related) {\r\n\t\t\t\tonRelatedInformation(related);\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._scrollable = new ScrollableElement(domNode, {\r\n\t\t\thorizontal: ScrollbarVisibility.Auto,\r\n\t\t\tvertical: ScrollbarVisibility.Auto,\r\n\t\t\tuseShadows: false,\r\n\t\t\thorizontalScrollbarSize: 3,\r\n\t\t\tverticalScrollbarSize: 3\r\n\t\t});\r\n\t\tparent.appendChild(this._scrollable.getDomNode());\r\n\t\tthis._disposables.add(this._scrollable.onScroll(e => {\r\n\t\t\tdomNode.style.left = `-${e.scrollLeft}px`;\r\n\t\t\tdomNode.style.top = `-${e.scrollTop}px`;\r\n\t\t}));\r\n\t\tthis._disposables.add(this._scrollable);\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tdispose(this._disposables);\r\n\t}\r\n\r\n\tupdate(marker: IMarker): void {\r\n\t\tconst { source, message, relatedInformation, code } = marker;\r\n\t\tlet sourceAndCodeLength = (source?.length || 0) + '()'.length;\r\n\t\tif (code) {\r\n\t\t\tif (typeof code === 'string') {\r\n\t\t\t\tsourceAndCodeLength += code.length;\r\n\t\t\t} else {\r\n\t\t\t\tsourceAndCodeLength += code.value.length;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst lines = splitLines(message);\r\n\t\tthis._lines = lines.length;\r\n\t\tthis._longestLineLength = 0;\r\n\t\tfor (const line of lines) {\r\n\t\t\tthis._longestLineLength = Math.max(line.length + sourceAndCodeLength, this._longestLineLength);\r\n\t\t}\r\n\r\n\t\tdom.clearNode(this._messageBlock);\r\n\t\tthis._messageBlock.setAttribute('aria-label', this.getAriaLabel(marker));\r\n\t\tthis._editor.applyFontInfo(this._messageBlock);\r\n\t\tlet lastLineElement = this._messageBlock;\r\n\t\tfor (const line of lines) {\r\n\t\t\tlastLineElement = document.createElement('div');\r\n\t\t\tlastLineElement.innerText = line;\r\n\t\t\tif (line === '') {\r\n\t\t\t\tlastLineElement.style.height = this._messageBlock.style.lineHeight;\r\n\t\t\t}\r\n\t\t\tthis._messageBlock.appendChild(lastLineElement);\r\n\t\t}\r\n\t\tif (source || code) {\r\n\t\t\tconst detailsElement = document.createElement('span');\r\n\t\t\tdetailsElement.classList.add('details');\r\n\t\t\tlastLineElement.appendChild(detailsElement);\r\n\t\t\tif (source) {\r\n\t\t\t\tconst sourceElement = document.createElement('span');\r\n\t\t\t\tsourceElement.innerText = source;\r\n\t\t\t\tsourceElement.classList.add('source');\r\n\t\t\t\tdetailsElement.appendChild(sourceElement);\r\n\t\t\t}\r\n\t\t\tif (code) {\r\n\t\t\t\tif (typeof code === 'string') {\r\n\t\t\t\t\tconst codeElement = document.createElement('span');\r\n\t\t\t\t\tcodeElement.innerText = `(${code})`;\r\n\t\t\t\t\tcodeElement.classList.add('code');\r\n\t\t\t\t\tdetailsElement.appendChild(codeElement);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis._codeLink = dom.$('a.code-link');\r\n\t\t\t\t\tthis._codeLink.setAttribute('href', `${code.target.toString()}`);\r\n\r\n\t\t\t\t\tthis._codeLink.onclick = (e) => {\r\n\t\t\t\t\t\tthis._openerService.open(code.target);\r\n\t\t\t\t\t\te.preventDefault();\r\n\t\t\t\t\t\te.stopPropagation();\r\n\t\t\t\t\t};\r\n\r\n\t\t\t\t\tconst codeElement = dom.append(this._codeLink, dom.$('span'));\r\n\t\t\t\t\tcodeElement.innerText = code.value;\r\n\t\t\t\t\tdetailsElement.appendChild(this._codeLink);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tdom.clearNode(this._relatedBlock);\r\n\t\tthis._editor.applyFontInfo(this._relatedBlock);\r\n\t\tif (isNonEmptyArray(relatedInformation)) {\r\n\t\t\tconst relatedInformationNode = this._relatedBlock.appendChild(document.createElement('div'));\r\n\t\t\trelatedInformationNode.style.paddingTop = `${Math.floor(this._editor.getOption(EditorOption.lineHeight) * 0.66)}px`;\r\n\t\t\tthis._lines += 1;\r\n\r\n\t\t\tfor (const related of relatedInformation) {\r\n\r\n\t\t\t\tlet container = document.createElement('div');\r\n\r\n\t\t\t\tlet relatedResource = document.createElement('a');\r\n\t\t\t\trelatedResource.classList.add('filename');\r\n\t\t\t\trelatedResource.innerText = `${getBaseLabel(related.resource)}(${related.startLineNumber}, ${related.startColumn}): `;\r\n\t\t\t\trelatedResource.title = this._labelService.getUriLabel(related.resource);\r\n\t\t\t\tthis._relatedDiagnostics.set(relatedResource, related);\r\n\r\n\t\t\t\tlet relatedMessage = document.createElement('span');\r\n\t\t\t\trelatedMessage.innerText = related.message;\r\n\r\n\t\t\t\tcontainer.appendChild(relatedResource);\r\n\t\t\t\tcontainer.appendChild(relatedMessage);\r\n\r\n\t\t\t\tthis._lines += 1;\r\n\t\t\t\trelatedInformationNode.appendChild(container);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst fontInfo = this._editor.getOption(EditorOption.fontInfo);\r\n\t\tconst scrollWidth = Math.ceil(fontInfo.typicalFullwidthCharacterWidth * this._longestLineLength * 0.75);\r\n\t\tconst scrollHeight = fontInfo.lineHeight * this._lines;\r\n\t\tthis._scrollable.setScrollDimensions({ scrollWidth, scrollHeight });\r\n\t}\r\n\r\n\tlayout(height: number, width: number): void {\r\n\t\tthis._scrollable.getDomNode().style.height = `${height}px`;\r\n\t\tthis._scrollable.getDomNode().style.width = `${width}px`;\r\n\t\tthis._scrollable.setScrollDimensions({ width, height });\r\n\t}\r\n\r\n\tgetHeightInLines(): number {\r\n\t\treturn Math.min(17, this._lines);\r\n\t}\r\n\r\n\tprivate getAriaLabel(marker: IMarker): string {\r\n\t\tlet severityLabel = '';\r\n\t\tswitch (marker.severity) {\r\n\t\t\tcase MarkerSeverity.Error:\r\n\t\t\t\tseverityLabel = nls.localize('Error', \"Error\");\r\n\t\t\t\tbreak;\r\n\t\t\tcase MarkerSeverity.Warning:\r\n\t\t\t\tseverityLabel = nls.localize('Warning', \"Warning\");\r\n\t\t\t\tbreak;\r\n\t\t\tcase MarkerSeverity.Info:\r\n\t\t\t\tseverityLabel = nls.localize('Info', \"Info\");\r\n\t\t\t\tbreak;\r\n\t\t\tcase MarkerSeverity.Hint:\r\n\t\t\t\tseverityLabel = nls.localize('Hint', \"Hint\");\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tlet ariaLabel = nls.localize('marker aria', \"{0} at {1}. \", severityLabel, marker.startLineNumber + ':' + marker.startColumn);\r\n\t\tconst model = this._editor.getModel();\r\n\t\tif (model && (marker.startLineNumber <= model.getLineCount()) && (marker.startLineNumber >= 1)) {\r\n\t\t\tconst lineContent = model.getLineContent(marker.startLineNumber);\r\n\t\t\tariaLabel = `${lineContent}, ${ariaLabel}`;\r\n\t\t}\r\n\t\treturn ariaLabel;\r\n\t}\r\n}\r\n\r\nexport class MarkerNavigationWidget extends PeekViewWidget {\r\n\r\n\tstatic readonly TitleMenu = new MenuId('gotoErrorTitleMenu');\r\n\r\n\tprivate _parentContainer!: HTMLElement;\r\n\tprivate _container!: HTMLElement;\r\n\tprivate _icon!: HTMLElement;\r\n\tprivate _message!: MessageWidget;\r\n\tprivate readonly _callOnDispose = new DisposableStore();\r\n\tprivate _severity: MarkerSeverity;\r\n\tprivate _backgroundColor?: Color;\r\n\tprivate readonly _onDidSelectRelatedInformation = new Emitter();\r\n\tprivate _heightInPixel!: number;\r\n\r\n\treadonly onDidSelectRelatedInformation: Event = this._onDidSelectRelatedInformation.event;\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor,\r\n\t\t@IThemeService private readonly _themeService: IThemeService,\r\n\t\t@IOpenerService private readonly _openerService: IOpenerService,\r\n\t\t@IMenuService private readonly _menuService: IMenuService,\r\n\t\t@IInstantiationService instantiationService: IInstantiationService,\r\n\t\t@IContextKeyService private readonly _contextKeyService: IContextKeyService,\r\n\t\t@ILabelService private readonly _labelService: ILabelService\r\n\t) {\r\n\t\tsuper(editor, { showArrow: true, showFrame: true, isAccessible: true }, instantiationService);\r\n\t\tthis._severity = MarkerSeverity.Warning;\r\n\t\tthis._backgroundColor = Color.white;\r\n\r\n\t\tthis._applyTheme(_themeService.getColorTheme());\r\n\t\tthis._callOnDispose.add(_themeService.onDidColorThemeChange(this._applyTheme.bind(this)));\r\n\r\n\t\tthis.create();\r\n\t}\r\n\r\n\tprivate _applyTheme(theme: IColorTheme) {\r\n\t\tthis._backgroundColor = theme.getColor(editorMarkerNavigationBackground);\r\n\t\tlet colorId = editorMarkerNavigationError;\r\n\t\tif (this._severity === MarkerSeverity.Warning) {\r\n\t\t\tcolorId = editorMarkerNavigationWarning;\r\n\t\t} else if (this._severity === MarkerSeverity.Info) {\r\n\t\t\tcolorId = editorMarkerNavigationInfo;\r\n\t\t}\r\n\t\tconst frameColor = theme.getColor(colorId);\r\n\t\tthis.style({\r\n\t\t\tarrowColor: frameColor,\r\n\t\t\tframeColor: frameColor,\r\n\t\t\theaderBackgroundColor: this._backgroundColor,\r\n\t\t\tprimaryHeadingColor: theme.getColor(peekViewTitleForeground),\r\n\t\t\tsecondaryHeadingColor: theme.getColor(peekViewTitleInfoForeground)\r\n\t\t}); // style() will trigger _applyStyles\r\n\t}\r\n\r\n\tprotected _applyStyles(): void {\r\n\t\tif (this._parentContainer) {\r\n\t\t\tthis._parentContainer.style.backgroundColor = this._backgroundColor ? this._backgroundColor.toString() : '';\r\n\t\t}\r\n\t\tsuper._applyStyles();\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._callOnDispose.dispose();\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tprotected _fillHead(container: HTMLElement): void {\r\n\t\tsuper._fillHead(container);\r\n\r\n\t\tthis._disposables.add(this._actionbarWidget!.actionRunner.onBeforeRun(e => this.editor.focus()));\r\n\r\n\t\tconst actions: IAction[] = [];\r\n\t\tconst menu = this._menuService.createMenu(MarkerNavigationWidget.TitleMenu, this._contextKeyService);\r\n\t\tcreateAndFillInActionBarActions(menu, undefined, actions);\r\n\t\tthis._actionbarWidget!.push(actions, { label: false, icon: true, index: 0 });\r\n\t\tmenu.dispose();\r\n\t}\r\n\r\n\tprotected _fillTitleIcon(container: HTMLElement): void {\r\n\t\tthis._icon = dom.append(container, dom.$(''));\r\n\t}\r\n\r\n\tprotected _fillBody(container: HTMLElement): void {\r\n\t\tthis._parentContainer = container;\r\n\t\tcontainer.classList.add('marker-widget');\r\n\t\tthis._parentContainer.tabIndex = 0;\r\n\t\tthis._parentContainer.setAttribute('role', 'tooltip');\r\n\r\n\t\tthis._container = document.createElement('div');\r\n\t\tcontainer.appendChild(this._container);\r\n\r\n\t\tthis._message = new MessageWidget(this._container, this.editor, related => this._onDidSelectRelatedInformation.fire(related), this._openerService, this._labelService);\r\n\t\tthis._disposables.add(this._message);\r\n\t}\r\n\r\n\tshow(): void {\r\n\t\tthrow new Error('call showAtMarker');\r\n\t}\r\n\r\n\tshowAtMarker(marker: IMarker, markerIdx: number, markerCount: number): void {\r\n\t\t// update:\r\n\t\t// * title\r\n\t\t// * message\r\n\t\tthis._container.classList.remove('stale');\r\n\t\tthis._message.update(marker);\r\n\r\n\t\t// update frame color (only applied on 'show')\r\n\t\tthis._severity = marker.severity;\r\n\t\tthis._applyTheme(this._themeService.getColorTheme());\r\n\r\n\t\t// show\r\n\t\tlet range = Range.lift(marker);\r\n\t\tconst editorPosition = this.editor.getPosition();\r\n\t\tlet position = editorPosition && range.containsPosition(editorPosition) ? editorPosition : range.getStartPosition();\r\n\t\tsuper.show(position, this.computeRequiredHeight());\r\n\r\n\t\tconst model = this.editor.getModel();\r\n\t\tif (model) {\r\n\t\t\tconst detail = markerCount > 1\r\n\t\t\t\t? nls.localize('problems', \"{0} of {1} problems\", markerIdx, markerCount)\r\n\t\t\t\t: nls.localize('change', \"{0} of {1} problem\", markerIdx, markerCount);\r\n\t\t\tthis.setTitle(basename(model.uri), detail);\r\n\t\t}\r\n\t\tthis._icon.className = `codicon ${SeverityIcon.className(MarkerSeverity.toSeverity(this._severity))}`;\r\n\r\n\t\tthis.editor.revealPositionNearTop(position, ScrollType.Smooth);\r\n\t\tthis.editor.focus();\r\n\t}\r\n\r\n\tupdateMarker(marker: IMarker): void {\r\n\t\tthis._container.classList.remove('stale');\r\n\t\tthis._message.update(marker);\r\n\t}\r\n\r\n\tshowStale() {\r\n\t\tthis._container.classList.add('stale');\r\n\t\tthis._relayout();\r\n\t}\r\n\r\n\tprotected _doLayoutBody(heightInPixel: number, widthInPixel: number): void {\r\n\t\tsuper._doLayoutBody(heightInPixel, widthInPixel);\r\n\t\tthis._heightInPixel = heightInPixel;\r\n\t\tthis._message.layout(heightInPixel, widthInPixel);\r\n\t\tthis._container.style.height = `${heightInPixel}px`;\r\n\t}\r\n\r\n\tpublic _onWidth(widthInPixel: number): void {\r\n\t\tthis._message.layout(this._heightInPixel, widthInPixel);\r\n\t}\r\n\r\n\tprotected _relayout(): void {\r\n\t\tsuper._relayout(this.computeRequiredHeight());\r\n\t}\r\n\r\n\tprivate computeRequiredHeight() {\r\n\t\treturn 3 + this._message.getHeightInLines();\r\n\t}\r\n}\r\n\r\n// theming\r\n\r\nlet errorDefault = oneOf(editorErrorForeground, editorErrorBorder);\r\nlet warningDefault = oneOf(editorWarningForeground, editorWarningBorder);\r\nlet infoDefault = oneOf(editorInfoForeground, editorInfoBorder);\r\n\r\nexport const editorMarkerNavigationError = registerColor('editorMarkerNavigationError.background', { dark: errorDefault, light: errorDefault, hc: errorDefault }, nls.localize('editorMarkerNavigationError', 'Editor marker navigation widget error color.'));\r\nexport const editorMarkerNavigationWarning = registerColor('editorMarkerNavigationWarning.background', { dark: warningDefault, light: warningDefault, hc: warningDefault }, nls.localize('editorMarkerNavigationWarning', 'Editor marker navigation widget warning color.'));\r\nexport const editorMarkerNavigationInfo = registerColor('editorMarkerNavigationInfo.background', { dark: infoDefault, light: infoDefault, hc: infoDefault }, nls.localize('editorMarkerNavigationInfo', 'Editor marker navigation widget info color.'));\r\nexport const editorMarkerNavigationBackground = registerColor('editorMarkerNavigation.background', { dark: '#2D2D30', light: Color.white, hc: '#0C141F' }, nls.localize('editorMarkerNavigationBackground', 'Editor marker navigation widget background.'));\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst linkFg = theme.getColor(textLinkForeground);\r\n\tif (linkFg) {\r\n\t\tcollector.addRule(`.monaco-editor .marker-widget a { color: ${linkFg}; }`);\r\n\t\tcollector.addRule(`.monaco-editor .marker-widget a.code-link span:hover { color: ${linkFg}; }`);\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as platform from 'vs/platform/registry/common/platform';\r\nimport { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema';\r\nimport { ThemeIcon } from 'vs/platform/theme/common/themeService';\r\nimport { Event, Emitter } from 'vs/base/common/event';\r\nimport { localize } from 'vs/nls';\r\nimport { Extensions as JSONExtensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';\r\nimport { RunOnceScheduler } from 'vs/base/common/async';\r\nimport * as Codicons from 'vs/base/common/codicons';\r\n\r\n// ------ API types\r\n\r\n\r\n// color registry\r\nexport const Extensions = {\r\n\tIconContribution: 'base.contributions.icons'\r\n};\r\n\r\nexport type IconDefaults = ThemeIcon | IconDefinition;\r\n\r\nexport interface IconDefinition {\r\n\tcharacter: string;\r\n}\r\n\r\nexport interface IconContribution {\r\n\tid: string;\r\n\tdescription: string | undefined;\r\n\tdeprecationMessage?: string;\r\n\tdefaults: IconDefaults;\r\n}\r\n\r\nexport interface IIconRegistry {\r\n\r\n\treadonly onDidChange: Event;\r\n\r\n\t/**\r\n\t * The CSS for all icons\r\n\t */\r\n\tgetCSS(): string;\r\n\r\n}\r\n\r\nclass IconRegistry implements IIconRegistry {\r\n\r\n\tprivate readonly _onDidChange = new Emitter();\r\n\treadonly onDidChange: Event = this._onDidChange.event;\r\n\r\n\tprivate iconsById: { [key: string]: IconContribution };\r\n\tprivate iconSchema: IJSONSchema & { properties: IJSONSchemaMap } = {\r\n\t\tdefinitions: {\r\n\t\t\ticons: {\r\n\t\t\t\ttype: 'object',\r\n\t\t\t\tproperties: {\r\n\t\t\t\t\tfontId: { type: 'string', description: localize('iconDefintion.fontId', 'The id of the font to use. If not set, the font that is defined first is used.') },\r\n\t\t\t\t\tfontCharacter: { type: 'string', description: localize('iconDefintion.fontCharacter', 'The font character associated with the icon definition.') }\r\n\t\t\t\t},\r\n\t\t\t\tadditionalProperties: false,\r\n\t\t\t\tdefaultSnippets: [{ body: { fontCharacter: '\\\\\\\\e030' } }]\r\n\t\t\t}\r\n\t\t},\r\n\t\ttype: 'object',\r\n\t\tproperties: {}\r\n\t};\r\n\tprivate iconReferenceSchema: IJSONSchema & { enum: string[], enumDescriptions: string[] } = { type: 'string', enum: [], enumDescriptions: [] };\r\n\r\n\tconstructor() {\r\n\t\tthis.iconsById = {};\r\n\t}\r\n\r\n\tpublic registerIcon(id: string, defaults: IconDefaults, description?: string, deprecationMessage?: string): ThemeIcon {\r\n\t\tconst existing = this.iconsById[id];\r\n\t\tif (existing) {\r\n\t\t\tif (description && !existing.description) {\r\n\t\t\t\texisting.description = description;\r\n\t\t\t\tthis.iconSchema.properties[id].markdownDescription = `${description} $(${id})`;\r\n\t\t\t\tconst enumIndex = this.iconReferenceSchema.enum.indexOf(id);\r\n\t\t\t\tif (enumIndex !== -1) {\r\n\t\t\t\t\tthis.iconReferenceSchema.enumDescriptions[enumIndex] = description;\r\n\t\t\t\t}\r\n\t\t\t\tthis._onDidChange.fire();\r\n\t\t\t}\r\n\t\t\treturn existing;\r\n\t\t}\r\n\t\tlet iconContribution: IconContribution = { id, description, defaults, deprecationMessage };\r\n\t\tthis.iconsById[id] = iconContribution;\r\n\t\tlet propertySchema: IJSONSchema = { $ref: '#/definitions/icons' };\r\n\t\tif (deprecationMessage) {\r\n\t\t\tpropertySchema.deprecationMessage = deprecationMessage;\r\n\t\t}\r\n\t\tif (description) {\r\n\t\t\tpropertySchema.markdownDescription = `${description}: $(${id})`;\r\n\t\t}\r\n\t\tthis.iconSchema.properties[id] = propertySchema;\r\n\t\tthis.iconReferenceSchema.enum.push(id);\r\n\t\tthis.iconReferenceSchema.enumDescriptions.push(description || '');\r\n\r\n\t\tthis._onDidChange.fire();\r\n\t\treturn { id };\r\n\t}\r\n\r\n\tpublic getIconSchema(): IJSONSchema {\r\n\t\treturn this.iconSchema;\r\n\t}\r\n\r\n\tpublic getCSS() {\r\n\t\tconst rules = [];\r\n\t\tfor (let id in this.iconsById) {\r\n\t\t\tconst rule = this.formatRule(id);\r\n\t\t\tif (rule) {\r\n\t\t\t\trules.push(rule);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn rules.join('\\n');\r\n\t}\r\n\r\n\tprivate formatRule(id: string): string | undefined {\r\n\t\tlet definition = this.iconsById[id].defaults;\r\n\t\twhile (ThemeIcon.isThemeIcon(definition)) {\r\n\t\t\tconst c = this.iconsById[definition.id];\r\n\t\t\tif (!c) {\r\n\t\t\t\treturn undefined;\r\n\t\t\t}\r\n\t\t\tdefinition = c.defaults;\r\n\t\t}\r\n\t\treturn `.codicon-${id}:before { content: '${definition.character}'; }`;\r\n\t}\r\n\r\n\tpublic toString() {\r\n\t\tconst sorter = (i1: IconContribution, i2: IconContribution) => {\r\n\t\t\treturn i1.id.localeCompare(i2.id);\r\n\t\t};\r\n\t\tconst classNames = (i: IconContribution) => {\r\n\t\t\twhile (ThemeIcon.isThemeIcon(i.defaults)) {\r\n\t\t\t\ti = this.iconsById[i.defaults.id];\r\n\t\t\t}\r\n\t\t\treturn `codicon codicon-${i ? i.id : ''}`;\r\n\t\t};\r\n\r\n\t\tlet reference = [];\r\n\r\n\t\treference.push(`| preview | identifier | default codicon id | description`);\r\n\t\treference.push(`| ----------- | --------------------------------- | --------------------------------- | --------------------------------- |`);\r\n\t\tconst contributions = Object.keys(this.iconsById).map(key => this.iconsById[key]);\r\n\r\n\t\tfor (const i of contributions.filter(i => !!i.description).sort(sorter)) {\r\n\t\t\treference.push(`||${i.id}|${ThemeIcon.isThemeIcon(i.defaults) ? i.defaults.id : i.id}|${i.description || ''}|`);\r\n\t\t}\r\n\r\n\t\treference.push(`| preview | identifier `);\r\n\t\treference.push(`| ----------- | --------------------------------- |`);\r\n\r\n\t\tfor (const i of contributions.filter(i => !ThemeIcon.isThemeIcon(i.defaults)).sort(sorter)) {\r\n\t\t\treference.push(`||${i.id}|`);\r\n\r\n\t\t}\r\n\r\n\t\treturn reference.join('\\n');\r\n\t}\r\n\r\n}\r\n\r\nconst iconRegistry = new IconRegistry();\r\nplatform.Registry.add(Extensions.IconContribution, iconRegistry);\r\n\r\nexport function registerIcon(id: string, defaults: IconDefaults, description: string, deprecationMessage?: string): ThemeIcon {\r\n\treturn iconRegistry.registerIcon(id, defaults, description, deprecationMessage);\r\n}\r\n\r\nexport function getIconRegistry(): IIconRegistry {\r\n\treturn iconRegistry;\r\n}\r\n\r\nfunction initialize() {\r\n\tfor (const icon of Codicons.iconRegistry.all) {\r\n\t\ticonRegistry.registerIcon(icon.id, icon.definition, icon.description);\r\n\t}\r\n\tCodicons.iconRegistry.onDidRegister(icon => iconRegistry.registerIcon(icon.id, icon.definition, icon.description));\r\n}\r\ninitialize();\r\n\r\nexport const iconsSchemaId = 'vscode://schemas/icons';\r\n\r\nlet schemaRegistry = platform.Registry.as(JSONExtensions.JSONContribution);\r\nschemaRegistry.registerSchema(iconsSchemaId, iconRegistry.getIconSchema());\r\n\r\nconst delayer = new RunOnceScheduler(() => schemaRegistry.notifySchemaChanged(iconsSchemaId), 200);\r\niconRegistry.onDidChange(() => {\r\n\tif (!delayer.isScheduled()) {\r\n\t\tdelayer.schedule();\r\n\t}\r\n});\r\n\r\n\r\n//setTimeout(_ => console.log(iconRegistry.toString()), 5000);\r\n\r\n\r\n// common icons\r\n\r\nexport const widgetClose = registerIcon('widget-close', Codicons.Codicon.close, localize('widgetClose', 'Icon for the close action in widgets.'));\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./media/diffReview';\r\nimport * as nls from 'vs/nls';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';\r\nimport { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';\r\nimport { Action } from 'vs/base/common/actions';\r\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { Configuration } from 'vs/editor/browser/config/configuration';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction, ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions';\r\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\r\nimport { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget';\r\nimport { IComputedEditorOptions, EditorOption, EditorFontLigatures } from 'vs/editor/common/config/editorOptions';\r\nimport { LineTokens } from 'vs/editor/common/core/lineTokens';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { ILineChange, ScrollType } from 'vs/editor/common/editorCommon';\r\nimport { ITextModel, TextModelResolvedOptions } from 'vs/editor/common/model';\r\nimport { ColorId, FontStyle, MetadataConsts } from 'vs/editor/common/modes';\r\nimport { editorLineNumbers } from 'vs/editor/common/view/editorColorRegistry';\r\nimport { RenderLineInput, renderViewLine2 as renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer';\r\nimport { ViewLineRenderingData } from 'vs/editor/common/viewModel/viewModel';\r\nimport { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { scrollbarShadow } from 'vs/platform/theme/common/colorRegistry';\r\nimport { registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService';\r\nimport { Constants } from 'vs/base/common/uint';\r\nimport { Codicon } from 'vs/base/common/codicons';\r\nimport { registerIcon } from 'vs/platform/theme/common/iconRegistry';\r\n\r\nconst DIFF_LINES_PADDING = 3;\r\n\r\nconst enum DiffEntryType {\r\n\tEqual = 0,\r\n\tInsert = 1,\r\n\tDelete = 2\r\n}\r\n\r\nclass DiffEntry {\r\n\treadonly originalLineStart: number;\r\n\treadonly originalLineEnd: number;\r\n\treadonly modifiedLineStart: number;\r\n\treadonly modifiedLineEnd: number;\r\n\r\n\tconstructor(originalLineStart: number, originalLineEnd: number, modifiedLineStart: number, modifiedLineEnd: number) {\r\n\t\tthis.originalLineStart = originalLineStart;\r\n\t\tthis.originalLineEnd = originalLineEnd;\r\n\t\tthis.modifiedLineStart = modifiedLineStart;\r\n\t\tthis.modifiedLineEnd = modifiedLineEnd;\r\n\t}\r\n\r\n\tpublic getType(): DiffEntryType {\r\n\t\tif (this.originalLineStart === 0) {\r\n\t\t\treturn DiffEntryType.Insert;\r\n\t\t}\r\n\t\tif (this.modifiedLineStart === 0) {\r\n\t\t\treturn DiffEntryType.Delete;\r\n\t\t}\r\n\t\treturn DiffEntryType.Equal;\r\n\t}\r\n}\r\n\r\nclass Diff {\r\n\treadonly entries: DiffEntry[];\r\n\r\n\tconstructor(entries: DiffEntry[]) {\r\n\t\tthis.entries = entries;\r\n\t}\r\n}\r\n\r\nconst diffReviewInsertIcon = registerIcon('diff-review-insert', Codicon.add, nls.localize('diffReviewInsertIcon', 'Icon for \\'Insert\\' in diff review.'));\r\nconst diffReviewRemoveIcon = registerIcon('diff-review-remove', Codicon.remove, nls.localize('diffReviewRemoveIcon', 'Icon for \\'Remove\\' in diff review.'));\r\nconst diffReviewCloseIcon = registerIcon('diff-review-close', Codicon.close, nls.localize('diffReviewCloseIcon', 'Icon for \\'Close\\' in diff review.'));\r\n\r\nexport class DiffReview extends Disposable {\r\n\r\n\tprivate static _ttPolicy = window.trustedTypes?.createPolicy('diffReview', { createHTML: value => value });\r\n\r\n\tprivate readonly _diffEditor: DiffEditorWidget;\r\n\tprivate _isVisible: boolean;\r\n\tpublic readonly shadow: FastDomNode;\r\n\tprivate readonly _actionBar: ActionBar;\r\n\tpublic readonly actionBarContainer: FastDomNode;\r\n\tpublic readonly domNode: FastDomNode;\r\n\tprivate readonly _content: FastDomNode;\r\n\tprivate readonly scrollbar: DomScrollableElement;\r\n\tprivate _diffs: Diff[];\r\n\tprivate _currentDiff: Diff | null;\r\n\r\n\tconstructor(diffEditor: DiffEditorWidget) {\r\n\t\tsuper();\r\n\t\tthis._diffEditor = diffEditor;\r\n\t\tthis._isVisible = false;\r\n\r\n\t\tthis.shadow = createFastDomNode(document.createElement('div'));\r\n\t\tthis.shadow.setClassName('diff-review-shadow');\r\n\r\n\t\tthis.actionBarContainer = createFastDomNode(document.createElement('div'));\r\n\t\tthis.actionBarContainer.setClassName('diff-review-actions');\r\n\t\tthis._actionBar = this._register(new ActionBar(\r\n\t\t\tthis.actionBarContainer.domNode\r\n\t\t));\r\n\r\n\t\tthis._actionBar.push(new Action('diffreview.close', nls.localize('label.close', \"Close\"), 'close-diff-review ' + ThemeIcon.asClassName(diffReviewCloseIcon), true, () => {\r\n\t\t\tthis.hide();\r\n\t\t\treturn Promise.resolve(null);\r\n\t\t}), { label: false, icon: true });\r\n\r\n\t\tthis.domNode = createFastDomNode(document.createElement('div'));\r\n\t\tthis.domNode.setClassName('diff-review monaco-editor-background');\r\n\r\n\t\tthis._content = createFastDomNode(document.createElement('div'));\r\n\t\tthis._content.setClassName('diff-review-content');\r\n\t\tthis._content.setAttribute('role', 'code');\r\n\t\tthis.scrollbar = this._register(new DomScrollableElement(this._content.domNode, {}));\r\n\t\tthis.domNode.domNode.appendChild(this.scrollbar.getDomNode());\r\n\r\n\t\tthis._register(diffEditor.onDidUpdateDiff(() => {\r\n\t\t\tif (!this._isVisible) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tthis._diffs = this._compute();\r\n\t\t\tthis._render();\r\n\t\t}));\r\n\t\tthis._register(diffEditor.getModifiedEditor().onDidChangeCursorPosition(() => {\r\n\t\t\tif (!this._isVisible) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tthis._render();\r\n\t\t}));\r\n\t\tthis._register(dom.addStandardDisposableListener(this.domNode.domNode, 'click', (e) => {\r\n\t\t\te.preventDefault();\r\n\r\n\t\t\tlet row = dom.findParentWithClass(e.target, 'diff-review-row');\r\n\t\t\tif (row) {\r\n\t\t\t\tthis._goToRow(row);\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._register(dom.addStandardDisposableListener(this.domNode.domNode, 'keydown', (e) => {\r\n\t\t\tif (\r\n\t\t\t\te.equals(KeyCode.DownArrow)\r\n\t\t\t\t|| e.equals(KeyMod.CtrlCmd | KeyCode.DownArrow)\r\n\t\t\t\t|| e.equals(KeyMod.Alt | KeyCode.DownArrow)\r\n\t\t\t) {\r\n\t\t\t\te.preventDefault();\r\n\t\t\t\tthis._goToRow(this._getNextRow());\r\n\t\t\t}\r\n\r\n\t\t\tif (\r\n\t\t\t\te.equals(KeyCode.UpArrow)\r\n\t\t\t\t|| e.equals(KeyMod.CtrlCmd | KeyCode.UpArrow)\r\n\t\t\t\t|| e.equals(KeyMod.Alt | KeyCode.UpArrow)\r\n\t\t\t) {\r\n\t\t\t\te.preventDefault();\r\n\t\t\t\tthis._goToRow(this._getPrevRow());\r\n\t\t\t}\r\n\r\n\t\t\tif (\r\n\t\t\t\te.equals(KeyCode.Escape)\r\n\t\t\t\t|| e.equals(KeyMod.CtrlCmd | KeyCode.Escape)\r\n\t\t\t\t|| e.equals(KeyMod.Alt | KeyCode.Escape)\r\n\t\t\t\t|| e.equals(KeyMod.Shift | KeyCode.Escape)\r\n\t\t\t) {\r\n\t\t\t\te.preventDefault();\r\n\t\t\t\tthis.hide();\r\n\t\t\t}\r\n\r\n\t\t\tif (\r\n\t\t\t\te.equals(KeyCode.Space)\r\n\t\t\t\t|| e.equals(KeyCode.Enter)\r\n\t\t\t) {\r\n\t\t\t\te.preventDefault();\r\n\t\t\t\tthis.accept();\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._diffs = [];\r\n\t\tthis._currentDiff = null;\r\n\t}\r\n\r\n\tpublic prev(): void {\r\n\t\tlet index = 0;\r\n\r\n\t\tif (!this._isVisible) {\r\n\t\t\tthis._diffs = this._compute();\r\n\t\t}\r\n\r\n\t\tif (this._isVisible) {\r\n\t\t\tlet currentIndex = -1;\r\n\t\t\tfor (let i = 0, len = this._diffs.length; i < len; i++) {\r\n\t\t\t\tif (this._diffs[i] === this._currentDiff) {\r\n\t\t\t\t\tcurrentIndex = i;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tindex = (this._diffs.length + currentIndex - 1);\r\n\t\t} else {\r\n\t\t\tindex = this._findDiffIndex(this._diffEditor.getPosition()!);\r\n\t\t}\r\n\r\n\t\tif (this._diffs.length === 0) {\r\n\t\t\t// Nothing to do\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tindex = index % this._diffs.length;\r\n\t\tconst entries = this._diffs[index].entries;\r\n\t\tthis._diffEditor.setPosition(new Position(entries[0].modifiedLineStart, 1));\r\n\t\tthis._diffEditor.setSelection({ startColumn: 1, startLineNumber: entries[0].modifiedLineStart, endColumn: Constants.MAX_SAFE_SMALL_INTEGER, endLineNumber: entries[entries.length - 1].modifiedLineEnd });\r\n\t\tthis._isVisible = true;\r\n\t\tthis._diffEditor.doLayout();\r\n\t\tthis._render();\r\n\t\tthis._goToRow(this._getNextRow());\r\n\t}\r\n\r\n\tpublic next(): void {\r\n\t\tlet index = 0;\r\n\r\n\t\tif (!this._isVisible) {\r\n\t\t\tthis._diffs = this._compute();\r\n\t\t}\r\n\r\n\t\tif (this._isVisible) {\r\n\t\t\tlet currentIndex = -1;\r\n\t\t\tfor (let i = 0, len = this._diffs.length; i < len; i++) {\r\n\t\t\t\tif (this._diffs[i] === this._currentDiff) {\r\n\t\t\t\t\tcurrentIndex = i;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tindex = (currentIndex + 1);\r\n\t\t} else {\r\n\t\t\tindex = this._findDiffIndex(this._diffEditor.getPosition()!);\r\n\t\t}\r\n\r\n\t\tif (this._diffs.length === 0) {\r\n\t\t\t// Nothing to do\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tindex = index % this._diffs.length;\r\n\t\tconst entries = this._diffs[index].entries;\r\n\t\tthis._diffEditor.setPosition(new Position(entries[0].modifiedLineStart, 1));\r\n\t\tthis._diffEditor.setSelection({ startColumn: 1, startLineNumber: entries[0].modifiedLineStart, endColumn: Constants.MAX_SAFE_SMALL_INTEGER, endLineNumber: entries[entries.length - 1].modifiedLineEnd });\r\n\t\tthis._isVisible = true;\r\n\t\tthis._diffEditor.doLayout();\r\n\t\tthis._render();\r\n\t\tthis._goToRow(this._getNextRow());\r\n\t}\r\n\r\n\tprivate accept(): void {\r\n\t\tlet jumpToLineNumber = -1;\r\n\t\tlet current = this._getCurrentFocusedRow();\r\n\t\tif (current) {\r\n\t\t\tlet lineNumber = parseInt(current.getAttribute('data-line')!, 10);\r\n\t\t\tif (!isNaN(lineNumber)) {\r\n\t\t\t\tjumpToLineNumber = lineNumber;\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis.hide();\r\n\r\n\t\tif (jumpToLineNumber !== -1) {\r\n\t\t\tthis._diffEditor.setPosition(new Position(jumpToLineNumber, 1));\r\n\t\t\tthis._diffEditor.revealPosition(new Position(jumpToLineNumber, 1), ScrollType.Immediate);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate hide(): void {\r\n\t\tthis._isVisible = false;\r\n\t\tthis._diffEditor.updateOptions({ readOnly: false });\r\n\t\tthis._diffEditor.focus();\r\n\t\tthis._diffEditor.doLayout();\r\n\t\tthis._render();\r\n\t}\r\n\r\n\tprivate _getPrevRow(): HTMLElement {\r\n\t\tlet current = this._getCurrentFocusedRow();\r\n\t\tif (!current) {\r\n\t\t\treturn this._getFirstRow();\r\n\t\t}\r\n\t\tif (current.previousElementSibling) {\r\n\t\t\treturn current.previousElementSibling;\r\n\t\t}\r\n\t\treturn current;\r\n\t}\r\n\r\n\tprivate _getNextRow(): HTMLElement {\r\n\t\tlet current = this._getCurrentFocusedRow();\r\n\t\tif (!current) {\r\n\t\t\treturn this._getFirstRow();\r\n\t\t}\r\n\t\tif (current.nextElementSibling) {\r\n\t\t\treturn current.nextElementSibling;\r\n\t\t}\r\n\t\treturn current;\r\n\t}\r\n\r\n\tprivate _getFirstRow(): HTMLElement {\r\n\t\treturn this.domNode.domNode.querySelector('.diff-review-row');\r\n\t}\r\n\r\n\tprivate _getCurrentFocusedRow(): HTMLElement | null {\r\n\t\tlet result = document.activeElement;\r\n\t\tif (result && /diff-review-row/.test(result.className)) {\r\n\t\t\treturn result;\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate _goToRow(row: HTMLElement): void {\r\n\t\tlet prev = this._getCurrentFocusedRow();\r\n\t\trow.tabIndex = 0;\r\n\t\trow.focus();\r\n\t\tif (prev && prev !== row) {\r\n\t\t\tprev.tabIndex = -1;\r\n\t\t}\r\n\t\tthis.scrollbar.scanDomNode();\r\n\t}\r\n\r\n\tpublic isVisible(): boolean {\r\n\t\treturn this._isVisible;\r\n\t}\r\n\r\n\tprivate _width: number = 0;\r\n\r\n\tpublic layout(top: number, width: number, height: number): void {\r\n\t\tthis._width = width;\r\n\t\tthis.shadow.setTop(top - 6);\r\n\t\tthis.shadow.setWidth(width);\r\n\t\tthis.shadow.setHeight(this._isVisible ? 6 : 0);\r\n\t\tthis.domNode.setTop(top);\r\n\t\tthis.domNode.setWidth(width);\r\n\t\tthis.domNode.setHeight(height);\r\n\t\tthis._content.setHeight(height);\r\n\t\tthis._content.setWidth(width);\r\n\r\n\t\tif (this._isVisible) {\r\n\t\t\tthis.actionBarContainer.setAttribute('aria-hidden', 'false');\r\n\t\t\tthis.actionBarContainer.setDisplay('block');\r\n\t\t} else {\r\n\t\t\tthis.actionBarContainer.setAttribute('aria-hidden', 'true');\r\n\t\t\tthis.actionBarContainer.setDisplay('none');\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _compute(): Diff[] {\r\n\t\tconst lineChanges = this._diffEditor.getLineChanges();\r\n\t\tif (!lineChanges || lineChanges.length === 0) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\t\tconst originalModel = this._diffEditor.getOriginalEditor().getModel();\r\n\t\tconst modifiedModel = this._diffEditor.getModifiedEditor().getModel();\r\n\r\n\t\tif (!originalModel || !modifiedModel) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\treturn DiffReview._mergeAdjacent(lineChanges, originalModel.getLineCount(), modifiedModel.getLineCount());\r\n\t}\r\n\r\n\tprivate static _mergeAdjacent(lineChanges: ILineChange[], originalLineCount: number, modifiedLineCount: number): Diff[] {\r\n\t\tif (!lineChanges || lineChanges.length === 0) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tlet diffs: Diff[] = [], diffsLength = 0;\r\n\r\n\t\tfor (let i = 0, len = lineChanges.length; i < len; i++) {\r\n\t\t\tconst lineChange = lineChanges[i];\r\n\r\n\t\t\tconst originalStart = lineChange.originalStartLineNumber;\r\n\t\t\tconst originalEnd = lineChange.originalEndLineNumber;\r\n\t\t\tconst modifiedStart = lineChange.modifiedStartLineNumber;\r\n\t\t\tconst modifiedEnd = lineChange.modifiedEndLineNumber;\r\n\r\n\t\t\tlet r: DiffEntry[] = [], rLength = 0;\r\n\r\n\t\t\t// Emit before anchors\r\n\t\t\t{\r\n\t\t\t\tconst originalEqualAbove = (originalEnd === 0 ? originalStart : originalStart - 1);\r\n\t\t\t\tconst modifiedEqualAbove = (modifiedEnd === 0 ? modifiedStart : modifiedStart - 1);\r\n\r\n\t\t\t\t// Make sure we don't step into the previous diff\r\n\t\t\t\tlet minOriginal = 1;\r\n\t\t\t\tlet minModified = 1;\r\n\t\t\t\tif (i > 0) {\r\n\t\t\t\t\tconst prevLineChange = lineChanges[i - 1];\r\n\r\n\t\t\t\t\tif (prevLineChange.originalEndLineNumber === 0) {\r\n\t\t\t\t\t\tminOriginal = prevLineChange.originalStartLineNumber + 1;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tminOriginal = prevLineChange.originalEndLineNumber + 1;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (prevLineChange.modifiedEndLineNumber === 0) {\r\n\t\t\t\t\t\tminModified = prevLineChange.modifiedStartLineNumber + 1;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tminModified = prevLineChange.modifiedEndLineNumber + 1;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tlet fromOriginal = originalEqualAbove - DIFF_LINES_PADDING + 1;\r\n\t\t\t\tlet fromModified = modifiedEqualAbove - DIFF_LINES_PADDING + 1;\r\n\t\t\t\tif (fromOriginal < minOriginal) {\r\n\t\t\t\t\tconst delta = minOriginal - fromOriginal;\r\n\t\t\t\t\tfromOriginal = fromOriginal + delta;\r\n\t\t\t\t\tfromModified = fromModified + delta;\r\n\t\t\t\t}\r\n\t\t\t\tif (fromModified < minModified) {\r\n\t\t\t\t\tconst delta = minModified - fromModified;\r\n\t\t\t\t\tfromOriginal = fromOriginal + delta;\r\n\t\t\t\t\tfromModified = fromModified + delta;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tr[rLength++] = new DiffEntry(\r\n\t\t\t\t\tfromOriginal, originalEqualAbove,\r\n\t\t\t\t\tfromModified, modifiedEqualAbove\r\n\t\t\t\t);\r\n\t\t\t}\r\n\r\n\t\t\t// Emit deleted lines\r\n\t\t\t{\r\n\t\t\t\tif (originalEnd !== 0) {\r\n\t\t\t\t\tr[rLength++] = new DiffEntry(originalStart, originalEnd, 0, 0);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// Emit inserted lines\r\n\t\t\t{\r\n\t\t\t\tif (modifiedEnd !== 0) {\r\n\t\t\t\t\tr[rLength++] = new DiffEntry(0, 0, modifiedStart, modifiedEnd);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// Emit after anchors\r\n\t\t\t{\r\n\t\t\t\tconst originalEqualBelow = (originalEnd === 0 ? originalStart + 1 : originalEnd + 1);\r\n\t\t\t\tconst modifiedEqualBelow = (modifiedEnd === 0 ? modifiedStart + 1 : modifiedEnd + 1);\r\n\r\n\t\t\t\t// Make sure we don't step into the next diff\r\n\t\t\t\tlet maxOriginal = originalLineCount;\r\n\t\t\t\tlet maxModified = modifiedLineCount;\r\n\t\t\t\tif (i + 1 < len) {\r\n\t\t\t\t\tconst nextLineChange = lineChanges[i + 1];\r\n\r\n\t\t\t\t\tif (nextLineChange.originalEndLineNumber === 0) {\r\n\t\t\t\t\t\tmaxOriginal = nextLineChange.originalStartLineNumber;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tmaxOriginal = nextLineChange.originalStartLineNumber - 1;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (nextLineChange.modifiedEndLineNumber === 0) {\r\n\t\t\t\t\t\tmaxModified = nextLineChange.modifiedStartLineNumber;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tmaxModified = nextLineChange.modifiedStartLineNumber - 1;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tlet toOriginal = originalEqualBelow + DIFF_LINES_PADDING - 1;\r\n\t\t\t\tlet toModified = modifiedEqualBelow + DIFF_LINES_PADDING - 1;\r\n\r\n\t\t\t\tif (toOriginal > maxOriginal) {\r\n\t\t\t\t\tconst delta = maxOriginal - toOriginal;\r\n\t\t\t\t\ttoOriginal = toOriginal + delta;\r\n\t\t\t\t\ttoModified = toModified + delta;\r\n\t\t\t\t}\r\n\t\t\t\tif (toModified > maxModified) {\r\n\t\t\t\t\tconst delta = maxModified - toModified;\r\n\t\t\t\t\ttoOriginal = toOriginal + delta;\r\n\t\t\t\t\ttoModified = toModified + delta;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tr[rLength++] = new DiffEntry(\r\n\t\t\t\t\toriginalEqualBelow, toOriginal,\r\n\t\t\t\t\tmodifiedEqualBelow, toModified,\r\n\t\t\t\t);\r\n\t\t\t}\r\n\r\n\t\t\tdiffs[diffsLength++] = new Diff(r);\r\n\t\t}\r\n\r\n\t\t// Merge adjacent diffs\r\n\t\tlet curr: DiffEntry[] = diffs[0].entries;\r\n\t\tlet r: Diff[] = [], rLength = 0;\r\n\t\tfor (let i = 1, len = diffs.length; i < len; i++) {\r\n\t\t\tconst thisDiff = diffs[i].entries;\r\n\r\n\t\t\tconst currLast = curr[curr.length - 1];\r\n\t\t\tconst thisFirst = thisDiff[0];\r\n\r\n\t\t\tif (\r\n\t\t\t\tcurrLast.getType() === DiffEntryType.Equal\r\n\t\t\t\t&& thisFirst.getType() === DiffEntryType.Equal\r\n\t\t\t\t&& thisFirst.originalLineStart <= currLast.originalLineEnd\r\n\t\t\t) {\r\n\t\t\t\t// We are dealing with equal lines that overlap\r\n\r\n\t\t\t\tcurr[curr.length - 1] = new DiffEntry(\r\n\t\t\t\t\tcurrLast.originalLineStart, thisFirst.originalLineEnd,\r\n\t\t\t\t\tcurrLast.modifiedLineStart, thisFirst.modifiedLineEnd\r\n\t\t\t\t);\r\n\t\t\t\tcurr = curr.concat(thisDiff.slice(1));\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tr[rLength++] = new Diff(curr);\r\n\t\t\tcurr = thisDiff;\r\n\t\t}\r\n\t\tr[rLength++] = new Diff(curr);\r\n\t\treturn r;\r\n\t}\r\n\r\n\tprivate _findDiffIndex(pos: Position): number {\r\n\t\tconst lineNumber = pos.lineNumber;\r\n\t\tfor (let i = 0, len = this._diffs.length; i < len; i++) {\r\n\t\t\tconst diff = this._diffs[i].entries;\r\n\t\t\tconst lastModifiedLine = diff[diff.length - 1].modifiedLineEnd;\r\n\t\t\tif (lineNumber <= lastModifiedLine) {\r\n\t\t\t\treturn i;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn 0;\r\n\t}\r\n\r\n\tprivate _render(): void {\r\n\r\n\t\tconst originalOptions = this._diffEditor.getOriginalEditor().getOptions();\r\n\t\tconst modifiedOptions = this._diffEditor.getModifiedEditor().getOptions();\r\n\r\n\t\tconst originalModel = this._diffEditor.getOriginalEditor().getModel();\r\n\t\tconst modifiedModel = this._diffEditor.getModifiedEditor().getModel();\r\n\r\n\t\tconst originalModelOpts = originalModel!.getOptions();\r\n\t\tconst modifiedModelOpts = modifiedModel!.getOptions();\r\n\r\n\t\tif (!this._isVisible || !originalModel || !modifiedModel) {\r\n\t\t\tdom.clearNode(this._content.domNode);\r\n\t\t\tthis._currentDiff = null;\r\n\t\t\tthis.scrollbar.scanDomNode();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._diffEditor.updateOptions({ readOnly: true });\r\n\t\tconst diffIndex = this._findDiffIndex(this._diffEditor.getPosition()!);\r\n\r\n\t\tif (this._diffs[diffIndex] === this._currentDiff) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._currentDiff = this._diffs[diffIndex];\r\n\r\n\t\tconst diffs = this._diffs[diffIndex].entries;\r\n\t\tlet container = document.createElement('div');\r\n\t\tcontainer.className = 'diff-review-table';\r\n\t\tcontainer.setAttribute('role', 'list');\r\n\t\tcontainer.setAttribute('aria-label', 'Difference review. Use \"Stage | Unstage | Revert Selected Ranges\" commands');\r\n\t\tConfiguration.applyFontInfoSlow(container, modifiedOptions.get(EditorOption.fontInfo));\r\n\r\n\t\tlet minOriginalLine = 0;\r\n\t\tlet maxOriginalLine = 0;\r\n\t\tlet minModifiedLine = 0;\r\n\t\tlet maxModifiedLine = 0;\r\n\t\tfor (let i = 0, len = diffs.length; i < len; i++) {\r\n\t\t\tconst diffEntry = diffs[i];\r\n\t\t\tconst originalLineStart = diffEntry.originalLineStart;\r\n\t\t\tconst originalLineEnd = diffEntry.originalLineEnd;\r\n\t\t\tconst modifiedLineStart = diffEntry.modifiedLineStart;\r\n\t\t\tconst modifiedLineEnd = diffEntry.modifiedLineEnd;\r\n\r\n\t\t\tif (originalLineStart !== 0 && ((minOriginalLine === 0 || originalLineStart < minOriginalLine))) {\r\n\t\t\t\tminOriginalLine = originalLineStart;\r\n\t\t\t}\r\n\t\t\tif (originalLineEnd !== 0 && ((maxOriginalLine === 0 || originalLineEnd > maxOriginalLine))) {\r\n\t\t\t\tmaxOriginalLine = originalLineEnd;\r\n\t\t\t}\r\n\t\t\tif (modifiedLineStart !== 0 && ((minModifiedLine === 0 || modifiedLineStart < minModifiedLine))) {\r\n\t\t\t\tminModifiedLine = modifiedLineStart;\r\n\t\t\t}\r\n\t\t\tif (modifiedLineEnd !== 0 && ((maxModifiedLine === 0 || modifiedLineEnd > maxModifiedLine))) {\r\n\t\t\t\tmaxModifiedLine = modifiedLineEnd;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet header = document.createElement('div');\r\n\t\theader.className = 'diff-review-row';\r\n\r\n\t\tlet cell = document.createElement('div');\r\n\t\tcell.className = 'diff-review-cell diff-review-summary';\r\n\t\tconst originalChangedLinesCnt = maxOriginalLine - minOriginalLine + 1;\r\n\t\tconst modifiedChangedLinesCnt = maxModifiedLine - minModifiedLine + 1;\r\n\t\tcell.appendChild(document.createTextNode(`${diffIndex + 1}/${this._diffs.length}: @@ -${minOriginalLine},${originalChangedLinesCnt} +${minModifiedLine},${modifiedChangedLinesCnt} @@`));\r\n\t\theader.setAttribute('data-line', String(minModifiedLine));\r\n\r\n\t\tconst getAriaLines = (lines: number) => {\r\n\t\t\tif (lines === 0) {\r\n\t\t\t\treturn nls.localize('no_lines_changed', \"no lines changed\");\r\n\t\t\t} else if (lines === 1) {\r\n\t\t\t\treturn nls.localize('one_line_changed', \"1 line changed\");\r\n\t\t\t} else {\r\n\t\t\t\treturn nls.localize('more_lines_changed', \"{0} lines changed\", lines);\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tconst originalChangedLinesCntAria = getAriaLines(originalChangedLinesCnt);\r\n\t\tconst modifiedChangedLinesCntAria = getAriaLines(modifiedChangedLinesCnt);\r\n\t\theader.setAttribute('aria-label', nls.localize({\r\n\t\t\tkey: 'header',\r\n\t\t\tcomment: [\r\n\t\t\t\t'This is the ARIA label for a git diff header.',\r\n\t\t\t\t'A git diff header looks like this: @@ -154,12 +159,39 @@.',\r\n\t\t\t\t'That encodes that at original line 154 (which is now line 159), 12 lines were removed/changed with 39 lines.',\r\n\t\t\t\t'Variables 0 and 1 refer to the diff index out of total number of diffs.',\r\n\t\t\t\t'Variables 2 and 4 will be numbers (a line number).',\r\n\t\t\t\t'Variables 3 and 5 will be \"no lines changed\", \"1 line changed\" or \"X lines changed\", localized separately.'\r\n\t\t\t]\r\n\t\t}, \"Difference {0} of {1}: original line {2}, {3}, modified line {4}, {5}\", (diffIndex + 1), this._diffs.length, minOriginalLine, originalChangedLinesCntAria, minModifiedLine, modifiedChangedLinesCntAria));\r\n\t\theader.appendChild(cell);\r\n\r\n\t\t// @@ -504,7 +517,7 @@\r\n\t\theader.setAttribute('role', 'listitem');\r\n\t\tcontainer.appendChild(header);\r\n\r\n\t\tconst lineHeight = modifiedOptions.get(EditorOption.lineHeight);\r\n\t\tlet modLine = minModifiedLine;\r\n\t\tfor (let i = 0, len = diffs.length; i < len; i++) {\r\n\t\t\tconst diffEntry = diffs[i];\r\n\t\t\tDiffReview._renderSection(container, diffEntry, modLine, lineHeight, this._width, originalOptions, originalModel, originalModelOpts, modifiedOptions, modifiedModel, modifiedModelOpts);\r\n\t\t\tif (diffEntry.modifiedLineStart !== 0) {\r\n\t\t\t\tmodLine = diffEntry.modifiedLineEnd;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tdom.clearNode(this._content.domNode);\r\n\t\tthis._content.domNode.appendChild(container);\r\n\t\tthis.scrollbar.scanDomNode();\r\n\t}\r\n\r\n\tprivate static _renderSection(\r\n\t\tdest: HTMLElement, diffEntry: DiffEntry, modLine: number, lineHeight: number, width: number,\r\n\t\toriginalOptions: IComputedEditorOptions, originalModel: ITextModel, originalModelOpts: TextModelResolvedOptions,\r\n\t\tmodifiedOptions: IComputedEditorOptions, modifiedModel: ITextModel, modifiedModelOpts: TextModelResolvedOptions\r\n\t): void {\r\n\r\n\t\tconst type = diffEntry.getType();\r\n\r\n\t\tlet rowClassName: string = 'diff-review-row';\r\n\t\tlet lineNumbersExtraClassName: string = '';\r\n\t\tconst spacerClassName: string = 'diff-review-spacer';\r\n\t\tlet spacerIcon: ThemeIcon | null = null;\r\n\t\tswitch (type) {\r\n\t\t\tcase DiffEntryType.Insert:\r\n\t\t\t\trowClassName = 'diff-review-row line-insert';\r\n\t\t\t\tlineNumbersExtraClassName = ' char-insert';\r\n\t\t\t\tspacerIcon = diffReviewInsertIcon;\r\n\t\t\t\tbreak;\r\n\t\t\tcase DiffEntryType.Delete:\r\n\t\t\t\trowClassName = 'diff-review-row line-delete';\r\n\t\t\t\tlineNumbersExtraClassName = ' char-delete';\r\n\t\t\t\tspacerIcon = diffReviewRemoveIcon;\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tconst originalLineStart = diffEntry.originalLineStart;\r\n\t\tconst originalLineEnd = diffEntry.originalLineEnd;\r\n\t\tconst modifiedLineStart = diffEntry.modifiedLineStart;\r\n\t\tconst modifiedLineEnd = diffEntry.modifiedLineEnd;\r\n\r\n\t\tconst cnt = Math.max(\r\n\t\t\tmodifiedLineEnd - modifiedLineStart,\r\n\t\t\toriginalLineEnd - originalLineStart\r\n\t\t);\r\n\r\n\t\tconst originalLayoutInfo = originalOptions.get(EditorOption.layoutInfo);\r\n\t\tconst originalLineNumbersWidth = originalLayoutInfo.glyphMarginWidth + originalLayoutInfo.lineNumbersWidth;\r\n\r\n\t\tconst modifiedLayoutInfo = modifiedOptions.get(EditorOption.layoutInfo);\r\n\t\tconst modifiedLineNumbersWidth = 10 + modifiedLayoutInfo.glyphMarginWidth + modifiedLayoutInfo.lineNumbersWidth;\r\n\r\n\t\tfor (let i = 0; i <= cnt; i++) {\r\n\t\t\tconst originalLine = (originalLineStart === 0 ? 0 : originalLineStart + i);\r\n\t\t\tconst modifiedLine = (modifiedLineStart === 0 ? 0 : modifiedLineStart + i);\r\n\r\n\t\t\tconst row = document.createElement('div');\r\n\t\t\trow.style.minWidth = width + 'px';\r\n\t\t\trow.className = rowClassName;\r\n\t\t\trow.setAttribute('role', 'listitem');\r\n\t\t\tif (modifiedLine !== 0) {\r\n\t\t\t\tmodLine = modifiedLine;\r\n\t\t\t}\r\n\t\t\trow.setAttribute('data-line', String(modLine));\r\n\r\n\t\t\tlet cell = document.createElement('div');\r\n\t\t\tcell.className = 'diff-review-cell';\r\n\t\t\tcell.style.height = `${lineHeight}px`;\r\n\t\t\trow.appendChild(cell);\r\n\r\n\t\t\tconst originalLineNumber = document.createElement('span');\r\n\t\t\toriginalLineNumber.style.width = (originalLineNumbersWidth + 'px');\r\n\t\t\toriginalLineNumber.style.minWidth = (originalLineNumbersWidth + 'px');\r\n\t\t\toriginalLineNumber.className = 'diff-review-line-number' + lineNumbersExtraClassName;\r\n\t\t\tif (originalLine !== 0) {\r\n\t\t\t\toriginalLineNumber.appendChild(document.createTextNode(String(originalLine)));\r\n\t\t\t} else {\r\n\t\t\t\toriginalLineNumber.innerText = '\\u00a0';\r\n\t\t\t}\r\n\t\t\tcell.appendChild(originalLineNumber);\r\n\r\n\t\t\tconst modifiedLineNumber = document.createElement('span');\r\n\t\t\tmodifiedLineNumber.style.width = (modifiedLineNumbersWidth + 'px');\r\n\t\t\tmodifiedLineNumber.style.minWidth = (modifiedLineNumbersWidth + 'px');\r\n\t\t\tmodifiedLineNumber.style.paddingRight = '10px';\r\n\t\t\tmodifiedLineNumber.className = 'diff-review-line-number' + lineNumbersExtraClassName;\r\n\t\t\tif (modifiedLine !== 0) {\r\n\t\t\t\tmodifiedLineNumber.appendChild(document.createTextNode(String(modifiedLine)));\r\n\t\t\t} else {\r\n\t\t\t\tmodifiedLineNumber.innerText = '\\u00a0';\r\n\t\t\t}\r\n\t\t\tcell.appendChild(modifiedLineNumber);\r\n\r\n\t\t\tconst spacer = document.createElement('span');\r\n\t\t\tspacer.className = spacerClassName;\r\n\r\n\t\t\tif (spacerIcon) {\r\n\t\t\t\tconst spacerCodicon = document.createElement('span');\r\n\t\t\t\tspacerCodicon.className = ThemeIcon.asClassName(spacerIcon);\r\n\t\t\t\tspacerCodicon.innerText = '\\u00a0\\u00a0';\r\n\t\t\t\tspacer.appendChild(spacerCodicon);\r\n\t\t\t} else {\r\n\t\t\t\tspacer.innerText = '\\u00a0\\u00a0';\r\n\t\t\t}\r\n\t\t\tcell.appendChild(spacer);\r\n\r\n\t\t\tlet lineContent: string;\r\n\t\t\tif (modifiedLine !== 0) {\r\n\t\t\t\tlet html: string | TrustedHTML = this._renderLine(modifiedModel, modifiedOptions, modifiedModelOpts.tabSize, modifiedLine);\r\n\t\t\t\tif (DiffReview._ttPolicy) {\r\n\t\t\t\t\thtml = DiffReview._ttPolicy.createHTML(html as string);\r\n\t\t\t\t}\r\n\t\t\t\tcell.insertAdjacentHTML('beforeend', html as string);\r\n\t\t\t\tlineContent = modifiedModel.getLineContent(modifiedLine);\r\n\t\t\t} else {\r\n\t\t\t\tlet html: string | TrustedHTML = this._renderLine(originalModel, originalOptions, originalModelOpts.tabSize, originalLine);\r\n\t\t\t\tif (DiffReview._ttPolicy) {\r\n\t\t\t\t\thtml = DiffReview._ttPolicy.createHTML(html as string);\r\n\t\t\t\t}\r\n\t\t\t\tcell.insertAdjacentHTML('beforeend', html as string);\r\n\t\t\t\tlineContent = originalModel.getLineContent(originalLine);\r\n\t\t\t}\r\n\r\n\t\t\tif (lineContent.length === 0) {\r\n\t\t\t\tlineContent = nls.localize('blankLine', \"blank\");\r\n\t\t\t}\r\n\r\n\t\t\tlet ariaLabel: string = '';\r\n\t\t\tswitch (type) {\r\n\t\t\t\tcase DiffEntryType.Equal:\r\n\t\t\t\t\tif (originalLine === modifiedLine) {\r\n\t\t\t\t\t\tariaLabel = nls.localize({ key: 'unchangedLine', comment: ['The placeholders are contents of the line and should not be translated.'] }, \"{0} unchanged line {1}\", lineContent, originalLine);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tariaLabel = nls.localize('equalLine', \"{0} original line {1} modified line {2}\", lineContent, originalLine, modifiedLine);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase DiffEntryType.Insert:\r\n\t\t\t\t\tariaLabel = nls.localize('insertLine', \"+ {0} modified line {1}\", lineContent, modifiedLine);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase DiffEntryType.Delete:\r\n\t\t\t\t\tariaLabel = nls.localize('deleteLine', \"- {0} original line {1}\", lineContent, originalLine);\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\trow.setAttribute('aria-label', ariaLabel);\r\n\r\n\t\t\tdest.appendChild(row);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static _renderLine(model: ITextModel, options: IComputedEditorOptions, tabSize: number, lineNumber: number): string {\r\n\t\tconst lineContent = model.getLineContent(lineNumber);\r\n\t\tconst fontInfo = options.get(EditorOption.fontInfo);\r\n\r\n\t\tconst defaultMetadata = (\r\n\t\t\t(FontStyle.None << MetadataConsts.FONT_STYLE_OFFSET)\r\n\t\t\t| (ColorId.DefaultForeground << MetadataConsts.FOREGROUND_OFFSET)\r\n\t\t\t| (ColorId.DefaultBackground << MetadataConsts.BACKGROUND_OFFSET)\r\n\t\t) >>> 0;\r\n\r\n\t\tconst tokens = new Uint32Array(2);\r\n\t\ttokens[0] = lineContent.length;\r\n\t\ttokens[1] = defaultMetadata;\r\n\r\n\t\tconst lineTokens = new LineTokens(tokens, lineContent);\r\n\r\n\t\tconst isBasicASCII = ViewLineRenderingData.isBasicASCII(lineContent, model.mightContainNonBasicASCII());\r\n\t\tconst containsRTL = ViewLineRenderingData.containsRTL(lineContent, isBasicASCII, model.mightContainRTL());\r\n\t\tconst r = renderViewLine(new RenderLineInput(\r\n\t\t\t(fontInfo.isMonospace && !options.get(EditorOption.disableMonospaceOptimizations)),\r\n\t\t\tfontInfo.canUseHalfwidthRightwardsArrow,\r\n\t\t\tlineContent,\r\n\t\t\tfalse,\r\n\t\t\tisBasicASCII,\r\n\t\t\tcontainsRTL,\r\n\t\t\t0,\r\n\t\t\tlineTokens,\r\n\t\t\t[],\r\n\t\t\ttabSize,\r\n\t\t\t0,\r\n\t\t\tfontInfo.spaceWidth,\r\n\t\t\tfontInfo.middotWidth,\r\n\t\t\tfontInfo.wsmiddotWidth,\r\n\t\t\toptions.get(EditorOption.stopRenderingLineAfter),\r\n\t\t\toptions.get(EditorOption.renderWhitespace),\r\n\t\t\toptions.get(EditorOption.renderControlCharacters),\r\n\t\t\toptions.get(EditorOption.fontLigatures) !== EditorFontLigatures.OFF,\r\n\t\t\tnull\r\n\t\t));\r\n\r\n\t\treturn r.html;\r\n\t}\r\n}\r\n\r\n// theming\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst lineNumbers = theme.getColor(editorLineNumbers);\r\n\tif (lineNumbers) {\r\n\t\tcollector.addRule(`.monaco-diff-editor .diff-review-line-number { color: ${lineNumbers}; }`);\r\n\t}\r\n\r\n\tconst shadow = theme.getColor(scrollbarShadow);\r\n\tif (shadow) {\r\n\t\tcollector.addRule(`.monaco-diff-editor .diff-review-shadow { box-shadow: ${shadow} 0 -6px 6px -6px inset; }`);\r\n\t}\r\n});\r\n\r\nclass DiffReviewNext extends EditorAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.diffReview.next',\r\n\t\t\tlabel: nls.localize('editor.action.diffReview.next', \"Go to Next Difference\"),\r\n\t\t\talias: 'Go to Next Difference',\r\n\t\t\tprecondition: ContextKeyExpr.has('isInDiffEditor'),\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: null,\r\n\t\t\t\tprimary: KeyCode.F7,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tconst diffEditor = findFocusedDiffEditor(accessor);\r\n\t\tif (diffEditor) {\r\n\t\t\tdiffEditor.diffReviewNext();\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass DiffReviewPrev extends EditorAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.diffReview.prev',\r\n\t\t\tlabel: nls.localize('editor.action.diffReview.prev', \"Go to Previous Difference\"),\r\n\t\t\talias: 'Go to Previous Difference',\r\n\t\t\tprecondition: ContextKeyExpr.has('isInDiffEditor'),\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: null,\r\n\t\t\t\tprimary: KeyMod.Shift | KeyCode.F7,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tconst diffEditor = findFocusedDiffEditor(accessor);\r\n\t\tif (diffEditor) {\r\n\t\t\tdiffEditor.diffReviewPrev();\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction findFocusedDiffEditor(accessor: ServicesAccessor): DiffEditorWidget | null {\r\n\tconst codeEditorService = accessor.get(ICodeEditorService);\r\n\tconst diffEditors = codeEditorService.listDiffEditors();\r\n\tconst activeCodeEditor = codeEditorService.getActiveCodeEditor();\r\n\tif (!activeCodeEditor) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\tfor (let i = 0, len = diffEditors.length; i < len; i++) {\r\n\t\tconst diffEditor = diffEditors[i];\r\n\t\tif (diffEditor.getModifiedEditor().getId() === activeCodeEditor.getId() || diffEditor.getOriginalEditor().getId() === activeCodeEditor.getId()) {\r\n\t\t\treturn diffEditor;\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n}\r\n\r\nregisterEditorAction(DiffReviewNext);\r\nregisterEditorAction(DiffReviewPrev);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./media/diffEditor';\r\nimport * as nls from 'vs/nls';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\r\nimport { ISashEvent, IVerticalSashLayoutProvider, Sash, SashState, Orientation } from 'vs/base/browser/ui/sash/sash';\r\nimport { RunOnceScheduler } from 'vs/base/common/async';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { Configuration } from 'vs/editor/browser/config/configuration';\r\nimport { StableEditorScrollState } from 'vs/editor/browser/core/editorState';\r\nimport * as editorBrowser from 'vs/editor/browser/editorBrowser';\r\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\r\nimport { CodeEditorWidget, ICodeEditorWidgetOptions } from 'vs/editor/browser/widget/codeEditorWidget';\r\nimport { DiffReview } from 'vs/editor/browser/widget/diffReview';\r\nimport { IDiffEditorOptions, EditorLayoutInfo, EditorOption, EditorOptions, EditorFontLigatures, stringSet as validateStringSetOption, boolean as validateBooleanOption } from 'vs/editor/common/config/editorOptions';\r\nimport { IPosition, Position } from 'vs/editor/common/core/position';\r\nimport { IRange, Range } from 'vs/editor/common/core/range';\r\nimport { ISelection, Selection } from 'vs/editor/common/core/selection';\r\nimport { IStringBuilder, createStringBuilder } from 'vs/editor/common/core/stringBuilder';\r\nimport * as editorCommon from 'vs/editor/common/editorCommon';\r\nimport { IModelDecorationsChangeAccessor, IModelDeltaDecoration, ITextModel } from 'vs/editor/common/model';\r\nimport { ModelDecorationOptions } from 'vs/editor/common/model/textModel';\r\nimport { IDiffComputationResult, IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';\r\nimport { OverviewRulerZone } from 'vs/editor/common/view/overviewZoneManager';\r\nimport { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations';\r\nimport { RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer';\r\nimport { IEditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout';\r\nimport { ILineBreaksComputer, InlineDecoration, InlineDecorationType, IViewModel, ViewLineRenderingData } from 'vs/editor/common/viewModel/viewModel';\r\nimport { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\r\nimport { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';\r\nimport { INotificationService } from 'vs/platform/notification/common/notification';\r\nimport { defaultInsertColor, defaultRemoveColor, diffBorder, diffInserted, diffInsertedOutline, diffRemoved, diffRemovedOutline, scrollbarShadow, scrollbarSliderBackground, scrollbarSliderHoverBackground, scrollbarSliderActiveBackground, diffDiagonalFill } from 'vs/platform/theme/common/colorRegistry';\r\nimport { IColorTheme, IThemeService, getThemeTypeSelector, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService';\r\nimport { IContextMenuService } from 'vs/platform/contextview/browser/contextView';\r\nimport { IDiffLinesChange, InlineDiffMargin } from 'vs/editor/browser/widget/inlineDiffMargin';\r\nimport { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';\r\nimport { Constants } from 'vs/base/common/uint';\r\nimport { EditorExtensionsRegistry, IDiffEditorContributionDescription } from 'vs/editor/browser/editorExtensions';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport { IEditorProgressService, IProgressRunner } from 'vs/platform/progress/common/progress';\r\nimport { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver';\r\nimport { Codicon } from 'vs/base/common/codicons';\r\nimport { MOUSE_CURSOR_TEXT_CSS_CLASS_NAME } from 'vs/base/browser/ui/mouseCursor/mouseCursor';\r\nimport { IViewLineTokens } from 'vs/editor/common/core/lineTokens';\r\nimport { FontInfo } from 'vs/editor/common/config/fontInfo';\r\nimport { registerIcon } from 'vs/platform/theme/common/iconRegistry';\r\n\r\nexport interface IDiffCodeEditorWidgetOptions {\r\n\toriginalEditor?: ICodeEditorWidgetOptions;\r\n\tmodifiedEditor?: ICodeEditorWidgetOptions;\r\n}\r\n\r\ninterface IEditorDiffDecorations {\r\n\tdecorations: IModelDeltaDecoration[];\r\n\toverviewZones: OverviewRulerZone[];\r\n}\r\n\r\ninterface IEditorDiffDecorationsWithZones extends IEditorDiffDecorations {\r\n\tzones: IMyViewZone[];\r\n}\r\n\r\ninterface IEditorsDiffDecorationsWithZones {\r\n\toriginal: IEditorDiffDecorationsWithZones;\r\n\tmodified: IEditorDiffDecorationsWithZones;\r\n}\r\n\r\ninterface IEditorsZones {\r\n\toriginal: IMyViewZone[];\r\n\tmodified: IMyViewZone[];\r\n}\r\n\r\nclass VisualEditorState {\r\n\tprivate _zones: string[];\r\n\tprivate _inlineDiffMargins: InlineDiffMargin[];\r\n\tprivate _zonesMap: { [zoneId: string]: boolean; };\r\n\tprivate _decorations: string[];\r\n\r\n\tconstructor(\r\n\t\tprivate _contextMenuService: IContextMenuService,\r\n\t\tprivate _clipboardService: IClipboardService\r\n\t) {\r\n\t\tthis._zones = [];\r\n\t\tthis._inlineDiffMargins = [];\r\n\t\tthis._zonesMap = {};\r\n\t\tthis._decorations = [];\r\n\t}\r\n\r\n\tpublic getForeignViewZones(allViewZones: IEditorWhitespace[]): IEditorWhitespace[] {\r\n\t\treturn allViewZones.filter((z) => !this._zonesMap[String(z.id)]);\r\n\t}\r\n\r\n\tpublic clean(editor: CodeEditorWidget): void {\r\n\t\t// (1) View zones\r\n\t\tif (this._zones.length > 0) {\r\n\t\t\teditor.changeViewZones((viewChangeAccessor: editorBrowser.IViewZoneChangeAccessor) => {\r\n\t\t\t\tfor (const zoneId of this._zones) {\r\n\t\t\t\t\tviewChangeAccessor.removeZone(zoneId);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\t\tthis._zones = [];\r\n\t\tthis._zonesMap = {};\r\n\r\n\t\t// (2) Model decorations\r\n\t\tthis._decorations = editor.deltaDecorations(this._decorations, []);\r\n\t}\r\n\r\n\tpublic apply(editor: CodeEditorWidget, overviewRuler: editorBrowser.IOverviewRuler | null, newDecorations: IEditorDiffDecorationsWithZones, restoreScrollState: boolean): void {\r\n\r\n\t\tconst scrollState = restoreScrollState ? StableEditorScrollState.capture(editor) : null;\r\n\r\n\t\t// view zones\r\n\t\teditor.changeViewZones((viewChangeAccessor: editorBrowser.IViewZoneChangeAccessor) => {\r\n\t\t\tfor (const zoneId of this._zones) {\r\n\t\t\t\tviewChangeAccessor.removeZone(zoneId);\r\n\t\t\t}\r\n\t\t\tfor (const inlineDiffMargin of this._inlineDiffMargins) {\r\n\t\t\t\tinlineDiffMargin.dispose();\r\n\t\t\t}\r\n\t\t\tthis._zones = [];\r\n\t\t\tthis._zonesMap = {};\r\n\t\t\tthis._inlineDiffMargins = [];\r\n\t\t\tfor (let i = 0, length = newDecorations.zones.length; i < length; i++) {\r\n\t\t\t\tconst viewZone = newDecorations.zones[i];\r\n\t\t\t\tviewZone.suppressMouseDown = true;\r\n\t\t\t\tconst zoneId = viewChangeAccessor.addZone(viewZone);\r\n\t\t\t\tthis._zones.push(zoneId);\r\n\t\t\t\tthis._zonesMap[String(zoneId)] = true;\r\n\r\n\t\t\t\tif (newDecorations.zones[i].diff && viewZone.marginDomNode) {\r\n\t\t\t\t\tviewZone.suppressMouseDown = false;\r\n\t\t\t\t\tthis._inlineDiffMargins.push(new InlineDiffMargin(zoneId, viewZone.marginDomNode, editor, newDecorations.zones[i].diff!, this._contextMenuService, this._clipboardService));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tif (scrollState) {\r\n\t\t\tscrollState.restore(editor);\r\n\t\t}\r\n\r\n\t\t// decorations\r\n\t\tthis._decorations = editor.deltaDecorations(this._decorations, newDecorations.decorations);\r\n\r\n\t\t// overview ruler\r\n\t\tif (overviewRuler) {\r\n\t\t\toverviewRuler.setZones(newDecorations.overviewZones);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nlet DIFF_EDITOR_ID = 0;\r\n\r\n\r\nconst diffInsertIcon = registerIcon('diff-insert', Codicon.add, nls.localize('diffInsertIcon', 'Line decoration for inserts in the diff editor.'));\r\nconst diffRemoveIcon = registerIcon('diff-remove', Codicon.remove, nls.localize('diffRemoveIcon', 'Line decoration for removals in the diff editor.'));\r\nconst ttPolicy = window.trustedTypes?.createPolicy('diffEditorWidget', { createHTML: value => value });\r\n\r\nexport class DiffEditorWidget extends Disposable implements editorBrowser.IDiffEditor {\r\n\r\n\tprivate static readonly ONE_OVERVIEW_WIDTH = 15;\r\n\tpublic static readonly ENTIRE_DIFF_OVERVIEW_WIDTH = 30;\r\n\tprivate static readonly UPDATE_DIFF_DECORATIONS_DELAY = 200; // ms\r\n\r\n\tprivate readonly _onDidDispose: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidDispose: Event = this._onDidDispose.event;\r\n\r\n\tprivate readonly _onDidUpdateDiff: Emitter = this._register(new Emitter());\r\n\tpublic readonly onDidUpdateDiff: Event = this._onDidUpdateDiff.event;\r\n\r\n\tprivate readonly _onDidContentSizeChange: Emitter = this._register(new Emitter());\r\n\r\n\tprivate readonly _id: number;\r\n\tprivate _state: editorBrowser.DiffEditorState;\r\n\tprivate _updatingDiffProgress: IProgressRunner | null;\r\n\r\n\tprivate readonly _domElement: HTMLElement;\r\n\tprotected readonly _containerDomElement: HTMLElement;\r\n\tprivate readonly _overviewDomElement: HTMLElement;\r\n\tprivate readonly _overviewViewportDomElement: FastDomNode;\r\n\r\n\tprivate readonly _elementSizeObserver: ElementSizeObserver;\r\n\r\n\tprivate readonly _originalEditor: CodeEditorWidget;\r\n\tprivate readonly _originalDomNode: HTMLElement;\r\n\tprivate readonly _originalEditorState: VisualEditorState;\r\n\tprivate _originalOverviewRuler: editorBrowser.IOverviewRuler | null;\r\n\r\n\tprivate readonly _modifiedEditor: CodeEditorWidget;\r\n\tprivate readonly _modifiedDomNode: HTMLElement;\r\n\tprivate readonly _modifiedEditorState: VisualEditorState;\r\n\tprivate _modifiedOverviewRuler: editorBrowser.IOverviewRuler | null;\r\n\r\n\tprivate _currentlyChangingViewZones: boolean;\r\n\tprivate _beginUpdateDecorationsTimeout: number;\r\n\tprivate _diffComputationToken: number;\r\n\tprivate _diffComputationResult: IDiffComputationResult | null;\r\n\r\n\tprivate _isVisible: boolean;\r\n\tprivate _isHandlingScrollEvent: boolean;\r\n\r\n\tprivate _ignoreTrimWhitespace: boolean;\r\n\tprivate _originalIsEditable: boolean;\r\n\tprivate _diffCodeLens: boolean;\r\n\tprivate _diffWordWrap: 'off' | 'on' | 'inherit';\r\n\r\n\tprivate _renderSideBySide: boolean;\r\n\tprivate _maxComputationTime: number;\r\n\tprivate _renderIndicators: boolean;\r\n\tprivate _enableSplitViewResizing: boolean;\r\n\tprivate _renderOverviewRuler: boolean;\r\n\tprivate _strategy!: DiffEditorWidgetStyle;\r\n\r\n\tprivate readonly _updateDecorationsRunner: RunOnceScheduler;\r\n\r\n\tprivate readonly _editorWorkerService: IEditorWorkerService;\r\n\tprotected _contextKeyService: IContextKeyService;\r\n\tprivate readonly _codeEditorService: ICodeEditorService;\r\n\tprivate readonly _themeService: IThemeService;\r\n\tprivate readonly _notificationService: INotificationService;\r\n\r\n\tprivate readonly _reviewPane: DiffReview;\r\n\r\n\tconstructor(\r\n\t\tdomElement: HTMLElement,\r\n\t\toptions: Readonly,\r\n\t\tcodeEditorWidgetOptions: IDiffCodeEditorWidgetOptions,\r\n\t\t@IClipboardService clipboardService: IClipboardService,\r\n\t\t@IEditorWorkerService editorWorkerService: IEditorWorkerService,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\r\n\t\t@IInstantiationService instantiationService: IInstantiationService,\r\n\t\t@ICodeEditorService codeEditorService: ICodeEditorService,\r\n\t\t@IThemeService themeService: IThemeService,\r\n\t\t@INotificationService notificationService: INotificationService,\r\n\t\t@IContextMenuService contextMenuService: IContextMenuService,\r\n\t\t@IEditorProgressService private readonly _editorProgressService: IEditorProgressService\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\tthis._editorWorkerService = editorWorkerService;\r\n\t\tthis._codeEditorService = codeEditorService;\r\n\t\tthis._contextKeyService = this._register(contextKeyService.createScoped(domElement));\r\n\t\tthis._contextKeyService.createKey('isInDiffEditor', true);\r\n\t\tthis._themeService = themeService;\r\n\t\tthis._notificationService = notificationService;\r\n\r\n\t\tthis._id = (++DIFF_EDITOR_ID);\r\n\t\tthis._state = editorBrowser.DiffEditorState.Idle;\r\n\t\tthis._updatingDiffProgress = null;\r\n\r\n\t\tthis._domElement = domElement;\r\n\t\toptions = options || {};\r\n\r\n\t\t// renderSideBySide\r\n\t\tthis._renderSideBySide = true;\r\n\t\tif (typeof options.renderSideBySide !== 'undefined') {\r\n\t\t\tthis._renderSideBySide = options.renderSideBySide;\r\n\t\t}\r\n\r\n\t\t// maxComputationTime\r\n\t\tthis._maxComputationTime = 5000;\r\n\t\tif (typeof options.maxComputationTime !== 'undefined') {\r\n\t\t\tthis._maxComputationTime = options.maxComputationTime;\r\n\t\t}\r\n\r\n\t\t// ignoreTrimWhitespace\r\n\t\tthis._ignoreTrimWhitespace = true;\r\n\t\tif (typeof options.ignoreTrimWhitespace !== 'undefined') {\r\n\t\t\tthis._ignoreTrimWhitespace = options.ignoreTrimWhitespace;\r\n\t\t}\r\n\r\n\t\t// renderIndicators\r\n\t\tthis._renderIndicators = true;\r\n\t\tif (typeof options.renderIndicators !== 'undefined') {\r\n\t\t\tthis._renderIndicators = options.renderIndicators;\r\n\t\t}\r\n\r\n\t\tthis._originalIsEditable = validateBooleanOption(options.originalEditable, false);\r\n\t\tthis._diffCodeLens = validateBooleanOption(options.diffCodeLens, false);\r\n\t\tthis._diffWordWrap = validateDiffWordWrap(options.diffWordWrap, 'inherit');\r\n\r\n\t\tif (typeof options.isInEmbeddedEditor !== 'undefined') {\r\n\t\t\tthis._contextKeyService.createKey('isInEmbeddedDiffEditor', options.isInEmbeddedEditor);\r\n\t\t} else {\r\n\t\t\tthis._contextKeyService.createKey('isInEmbeddedDiffEditor', false);\r\n\t\t}\r\n\r\n\t\tthis._renderOverviewRuler = true;\r\n\t\tif (typeof options.renderOverviewRuler !== 'undefined') {\r\n\t\t\tthis._renderOverviewRuler = Boolean(options.renderOverviewRuler);\r\n\t\t}\r\n\r\n\t\tthis._updateDecorationsRunner = this._register(new RunOnceScheduler(() => this._updateDecorations(), 0));\r\n\r\n\t\tthis._containerDomElement = document.createElement('div');\r\n\t\tthis._containerDomElement.className = DiffEditorWidget._getClassName(this._themeService.getColorTheme(), this._renderSideBySide);\r\n\t\tthis._containerDomElement.style.position = 'relative';\r\n\t\tthis._containerDomElement.style.height = '100%';\r\n\t\tthis._domElement.appendChild(this._containerDomElement);\r\n\r\n\t\tthis._overviewViewportDomElement = createFastDomNode(document.createElement('div'));\r\n\t\tthis._overviewViewportDomElement.setClassName('diffViewport');\r\n\t\tthis._overviewViewportDomElement.setPosition('absolute');\r\n\r\n\t\tthis._overviewDomElement = document.createElement('div');\r\n\t\tthis._overviewDomElement.className = 'diffOverview';\r\n\t\tthis._overviewDomElement.style.position = 'absolute';\r\n\r\n\t\tthis._overviewDomElement.appendChild(this._overviewViewportDomElement.domNode);\r\n\r\n\t\tthis._register(dom.addStandardDisposableListener(this._overviewDomElement, 'mousedown', (e) => {\r\n\t\t\tthis._modifiedEditor.delegateVerticalScrollbarMouseDown(e);\r\n\t\t}));\r\n\t\tif (this._renderOverviewRuler) {\r\n\t\t\tthis._containerDomElement.appendChild(this._overviewDomElement);\r\n\t\t}\r\n\r\n\t\t// Create left side\r\n\t\tthis._originalDomNode = document.createElement('div');\r\n\t\tthis._originalDomNode.className = 'editor original';\r\n\t\tthis._originalDomNode.style.position = 'absolute';\r\n\t\tthis._originalDomNode.style.height = '100%';\r\n\t\tthis._containerDomElement.appendChild(this._originalDomNode);\r\n\r\n\t\t// Create right side\r\n\t\tthis._modifiedDomNode = document.createElement('div');\r\n\t\tthis._modifiedDomNode.className = 'editor modified';\r\n\t\tthis._modifiedDomNode.style.position = 'absolute';\r\n\t\tthis._modifiedDomNode.style.height = '100%';\r\n\t\tthis._containerDomElement.appendChild(this._modifiedDomNode);\r\n\r\n\t\tthis._beginUpdateDecorationsTimeout = -1;\r\n\t\tthis._currentlyChangingViewZones = false;\r\n\t\tthis._diffComputationToken = 0;\r\n\r\n\t\tthis._originalEditorState = new VisualEditorState(contextMenuService, clipboardService);\r\n\t\tthis._modifiedEditorState = new VisualEditorState(contextMenuService, clipboardService);\r\n\r\n\t\tthis._isVisible = true;\r\n\t\tthis._isHandlingScrollEvent = false;\r\n\r\n\t\tthis._elementSizeObserver = this._register(new ElementSizeObserver(this._containerDomElement, options.dimension, () => this._onDidContainerSizeChanged()));\r\n\t\tif (options.automaticLayout) {\r\n\t\t\tthis._elementSizeObserver.startObserving();\r\n\t\t}\r\n\r\n\t\tthis._diffComputationResult = null;\r\n\r\n\t\tconst leftContextKeyService = this._contextKeyService.createScoped();\r\n\r\n\t\tconst leftServices = new ServiceCollection();\r\n\t\tleftServices.set(IContextKeyService, leftContextKeyService);\r\n\t\tconst leftScopedInstantiationService = instantiationService.createChild(leftServices);\r\n\r\n\t\tconst rightContextKeyService = this._contextKeyService.createScoped();\r\n\r\n\t\tconst rightServices = new ServiceCollection();\r\n\t\trightServices.set(IContextKeyService, rightContextKeyService);\r\n\t\tconst rightScopedInstantiationService = instantiationService.createChild(rightServices);\r\n\r\n\t\tthis._originalEditor = this._createLeftHandSideEditor(options, codeEditorWidgetOptions.originalEditor || {}, leftScopedInstantiationService, leftContextKeyService);\r\n\t\tthis._modifiedEditor = this._createRightHandSideEditor(options, codeEditorWidgetOptions.modifiedEditor || {}, rightScopedInstantiationService, rightContextKeyService);\r\n\r\n\t\tthis._originalOverviewRuler = null;\r\n\t\tthis._modifiedOverviewRuler = null;\r\n\r\n\t\tthis._reviewPane = new DiffReview(this);\r\n\t\tthis._containerDomElement.appendChild(this._reviewPane.domNode.domNode);\r\n\t\tthis._containerDomElement.appendChild(this._reviewPane.shadow.domNode);\r\n\t\tthis._containerDomElement.appendChild(this._reviewPane.actionBarContainer.domNode);\r\n\r\n\t\t// enableSplitViewResizing\r\n\t\tthis._enableSplitViewResizing = true;\r\n\t\tif (typeof options.enableSplitViewResizing !== 'undefined') {\r\n\t\t\tthis._enableSplitViewResizing = options.enableSplitViewResizing;\r\n\t\t}\r\n\r\n\t\tif (this._renderSideBySide) {\r\n\t\t\tthis._setStrategy(new DiffEditorWidgetSideBySide(this._createDataSource(), this._enableSplitViewResizing));\r\n\t\t} else {\r\n\t\t\tthis._setStrategy(new DiffEditorWidgetInline(this._createDataSource(), this._enableSplitViewResizing));\r\n\t\t}\r\n\r\n\t\tthis._register(themeService.onDidColorThemeChange(t => {\r\n\t\t\tif (this._strategy && this._strategy.applyColors(t)) {\r\n\t\t\t\tthis._updateDecorationsRunner.schedule();\r\n\t\t\t}\r\n\t\t\tthis._containerDomElement.className = DiffEditorWidget._getClassName(this._themeService.getColorTheme(), this._renderSideBySide);\r\n\t\t}));\r\n\r\n\t\tconst contributions: IDiffEditorContributionDescription[] = EditorExtensionsRegistry.getDiffEditorContributions();\r\n\t\tfor (const desc of contributions) {\r\n\t\t\ttry {\r\n\t\t\t\tthis._register(instantiationService.createInstance(desc.ctor, this));\r\n\t\t\t} catch (err) {\r\n\t\t\t\tonUnexpectedError(err);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._codeEditorService.addDiffEditor(this);\r\n\t}\r\n\r\n\tprivate _setState(newState: editorBrowser.DiffEditorState): void {\r\n\t\tif (this._state === newState) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._state = newState;\r\n\r\n\t\tif (this._updatingDiffProgress) {\r\n\t\t\tthis._updatingDiffProgress.done();\r\n\t\t\tthis._updatingDiffProgress = null;\r\n\t\t}\r\n\r\n\t\tif (this._state === editorBrowser.DiffEditorState.ComputingDiff) {\r\n\t\t\tthis._updatingDiffProgress = this._editorProgressService.show(true, 1000);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic diffReviewNext(): void {\r\n\t\tthis._reviewPane.next();\r\n\t}\r\n\r\n\tpublic diffReviewPrev(): void {\r\n\t\tthis._reviewPane.prev();\r\n\t}\r\n\r\n\tprivate static _getClassName(theme: IColorTheme, renderSideBySide: boolean): string {\r\n\t\tlet result = 'monaco-diff-editor monaco-editor-background ';\r\n\t\tif (renderSideBySide) {\r\n\t\t\tresult += 'side-by-side ';\r\n\t\t}\r\n\t\tresult += getThemeTypeSelector(theme.type);\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprivate _recreateOverviewRulers(): void {\r\n\t\tif (!this._renderOverviewRuler) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this._originalOverviewRuler) {\r\n\t\t\tthis._overviewDomElement.removeChild(this._originalOverviewRuler.getDomNode());\r\n\t\t\tthis._originalOverviewRuler.dispose();\r\n\t\t}\r\n\t\tif (this._originalEditor.hasModel()) {\r\n\t\t\tthis._originalOverviewRuler = this._originalEditor.createOverviewRuler('original diffOverviewRuler')!;\r\n\t\t\tthis._overviewDomElement.appendChild(this._originalOverviewRuler.getDomNode());\r\n\t\t}\r\n\r\n\t\tif (this._modifiedOverviewRuler) {\r\n\t\t\tthis._overviewDomElement.removeChild(this._modifiedOverviewRuler.getDomNode());\r\n\t\t\tthis._modifiedOverviewRuler.dispose();\r\n\t\t}\r\n\t\tif (this._modifiedEditor.hasModel()) {\r\n\t\t\tthis._modifiedOverviewRuler = this._modifiedEditor.createOverviewRuler('modified diffOverviewRuler')!;\r\n\t\t\tthis._overviewDomElement.appendChild(this._modifiedOverviewRuler.getDomNode());\r\n\t\t}\r\n\r\n\t\tthis._layoutOverviewRulers();\r\n\t}\r\n\r\n\tprivate _createLeftHandSideEditor(options: Readonly, codeEditorWidgetOptions: ICodeEditorWidgetOptions, instantiationService: IInstantiationService, contextKeyService: IContextKeyService): CodeEditorWidget {\r\n\t\tconst editor = this._createInnerEditor(instantiationService, this._originalDomNode, this._adjustOptionsForLeftHandSide(options), codeEditorWidgetOptions);\r\n\r\n\t\tthis._register(editor.onDidScrollChange((e) => {\r\n\t\t\tif (this._isHandlingScrollEvent) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (!e.scrollTopChanged && !e.scrollLeftChanged && !e.scrollHeightChanged) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tthis._isHandlingScrollEvent = true;\r\n\t\t\tthis._modifiedEditor.setScrollPosition({\r\n\t\t\t\tscrollLeft: e.scrollLeft,\r\n\t\t\t\tscrollTop: e.scrollTop\r\n\t\t\t});\r\n\t\t\tthis._isHandlingScrollEvent = false;\r\n\r\n\t\t\tthis._layoutOverviewViewport();\r\n\t\t}));\r\n\r\n\t\tthis._register(editor.onDidChangeViewZones(() => {\r\n\t\t\tthis._onViewZonesChanged();\r\n\t\t}));\r\n\r\n\t\tthis._register(editor.onDidChangeConfiguration((e) => {\r\n\t\t\tif (!editor.getModel()) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (e.hasChanged(EditorOption.fontInfo)) {\r\n\t\t\t\tthis._updateDecorationsRunner.schedule();\r\n\t\t\t}\r\n\t\t\tif (e.hasChanged(EditorOption.wrappingInfo)) {\r\n\t\t\t\tthis._updateDecorationsRunner.cancel();\r\n\t\t\t\tthis._updateDecorations();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._register(editor.onDidChangeModelContent(() => {\r\n\t\t\tif (this._isVisible) {\r\n\t\t\t\tthis._beginUpdateDecorationsSoon();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tconst isInDiffLeftEditorKey = contextKeyService.createKey('isInDiffLeftEditor', undefined);\r\n\t\tthis._register(editor.onDidFocusEditorWidget(() => isInDiffLeftEditorKey.set(true)));\r\n\t\tthis._register(editor.onDidBlurEditorWidget(() => isInDiffLeftEditorKey.set(false)));\r\n\r\n\t\tthis._register(editor.onDidContentSizeChange(e => {\r\n\t\t\tconst width = this._originalEditor.getContentWidth() + this._modifiedEditor.getContentWidth() + DiffEditorWidget.ONE_OVERVIEW_WIDTH;\r\n\t\t\tconst height = Math.max(this._modifiedEditor.getContentHeight(), this._originalEditor.getContentHeight());\r\n\r\n\t\t\tthis._onDidContentSizeChange.fire({\r\n\t\t\t\tcontentHeight: height,\r\n\t\t\t\tcontentWidth: width,\r\n\t\t\t\tcontentHeightChanged: e.contentHeightChanged,\r\n\t\t\t\tcontentWidthChanged: e.contentWidthChanged\r\n\t\t\t});\r\n\t\t}));\r\n\r\n\t\treturn editor;\r\n\t}\r\n\r\n\tprivate _createRightHandSideEditor(options: Readonly, codeEditorWidgetOptions: ICodeEditorWidgetOptions, instantiationService: IInstantiationService, contextKeyService: IContextKeyService): CodeEditorWidget {\r\n\t\tconst editor = this._createInnerEditor(instantiationService, this._modifiedDomNode, this._adjustOptionsForRightHandSide(options), codeEditorWidgetOptions);\r\n\r\n\t\tthis._register(editor.onDidScrollChange((e) => {\r\n\t\t\tif (this._isHandlingScrollEvent) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (!e.scrollTopChanged && !e.scrollLeftChanged && !e.scrollHeightChanged) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tthis._isHandlingScrollEvent = true;\r\n\t\t\tthis._originalEditor.setScrollPosition({\r\n\t\t\t\tscrollLeft: e.scrollLeft,\r\n\t\t\t\tscrollTop: e.scrollTop\r\n\t\t\t});\r\n\t\t\tthis._isHandlingScrollEvent = false;\r\n\r\n\t\t\tthis._layoutOverviewViewport();\r\n\t\t}));\r\n\r\n\t\tthis._register(editor.onDidChangeViewZones(() => {\r\n\t\t\tthis._onViewZonesChanged();\r\n\t\t}));\r\n\r\n\t\tthis._register(editor.onDidChangeConfiguration((e) => {\r\n\t\t\tif (!editor.getModel()) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (e.hasChanged(EditorOption.fontInfo)) {\r\n\t\t\t\tthis._updateDecorationsRunner.schedule();\r\n\t\t\t}\r\n\t\t\tif (e.hasChanged(EditorOption.wrappingInfo)) {\r\n\t\t\t\tthis._updateDecorationsRunner.cancel();\r\n\t\t\t\tthis._updateDecorations();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._register(editor.onDidChangeModelContent(() => {\r\n\t\t\tif (this._isVisible) {\r\n\t\t\t\tthis._beginUpdateDecorationsSoon();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._register(editor.onDidChangeModelOptions((e) => {\r\n\t\t\tif (e.tabSize) {\r\n\t\t\t\tthis._updateDecorationsRunner.schedule();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tconst isInDiffRightEditorKey = contextKeyService.createKey('isInDiffRightEditor', undefined);\r\n\t\tthis._register(editor.onDidFocusEditorWidget(() => isInDiffRightEditorKey.set(true)));\r\n\t\tthis._register(editor.onDidBlurEditorWidget(() => isInDiffRightEditorKey.set(false)));\r\n\r\n\t\tthis._register(editor.onDidContentSizeChange(e => {\r\n\t\t\tconst width = this._originalEditor.getContentWidth() + this._modifiedEditor.getContentWidth() + DiffEditorWidget.ONE_OVERVIEW_WIDTH;\r\n\t\t\tconst height = Math.max(this._modifiedEditor.getContentHeight(), this._originalEditor.getContentHeight());\r\n\r\n\t\t\tthis._onDidContentSizeChange.fire({\r\n\t\t\t\tcontentHeight: height,\r\n\t\t\t\tcontentWidth: width,\r\n\t\t\t\tcontentHeightChanged: e.contentHeightChanged,\r\n\t\t\t\tcontentWidthChanged: e.contentWidthChanged\r\n\t\t\t});\r\n\t\t}));\r\n\r\n\t\treturn editor;\r\n\t}\r\n\r\n\tprotected _createInnerEditor(instantiationService: IInstantiationService, container: HTMLElement, options: Readonly, editorWidgetOptions: ICodeEditorWidgetOptions): CodeEditorWidget {\r\n\t\treturn instantiationService.createInstance(CodeEditorWidget, container, options, editorWidgetOptions);\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._codeEditorService.removeDiffEditor(this);\r\n\r\n\t\tif (this._beginUpdateDecorationsTimeout !== -1) {\r\n\t\t\twindow.clearTimeout(this._beginUpdateDecorationsTimeout);\r\n\t\t\tthis._beginUpdateDecorationsTimeout = -1;\r\n\t\t}\r\n\r\n\t\tthis._cleanViewZonesAndDecorations();\r\n\r\n\t\tif (this._originalOverviewRuler) {\r\n\t\t\tthis._overviewDomElement.removeChild(this._originalOverviewRuler.getDomNode());\r\n\t\t\tthis._originalOverviewRuler.dispose();\r\n\t\t}\r\n\t\tif (this._modifiedOverviewRuler) {\r\n\t\t\tthis._overviewDomElement.removeChild(this._modifiedOverviewRuler.getDomNode());\r\n\t\t\tthis._modifiedOverviewRuler.dispose();\r\n\t\t}\r\n\t\tthis._overviewDomElement.removeChild(this._overviewViewportDomElement.domNode);\r\n\t\tif (this._renderOverviewRuler) {\r\n\t\t\tthis._containerDomElement.removeChild(this._overviewDomElement);\r\n\t\t}\r\n\r\n\t\tthis._containerDomElement.removeChild(this._originalDomNode);\r\n\t\tthis._originalEditor.dispose();\r\n\r\n\t\tthis._containerDomElement.removeChild(this._modifiedDomNode);\r\n\t\tthis._modifiedEditor.dispose();\r\n\r\n\t\tthis._strategy.dispose();\r\n\r\n\t\tthis._containerDomElement.removeChild(this._reviewPane.domNode.domNode);\r\n\t\tthis._containerDomElement.removeChild(this._reviewPane.shadow.domNode);\r\n\t\tthis._containerDomElement.removeChild(this._reviewPane.actionBarContainer.domNode);\r\n\t\tthis._reviewPane.dispose();\r\n\r\n\t\tthis._domElement.removeChild(this._containerDomElement);\r\n\r\n\t\tthis._onDidDispose.fire();\r\n\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\t//------------ begin IDiffEditor methods\r\n\r\n\tpublic getId(): string {\r\n\t\treturn this.getEditorType() + ':' + this._id;\r\n\t}\r\n\r\n\tpublic getEditorType(): string {\r\n\t\treturn editorCommon.EditorType.IDiffEditor;\r\n\t}\r\n\r\n\tpublic getLineChanges(): editorCommon.ILineChange[] | null {\r\n\t\tif (!this._diffComputationResult) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn this._diffComputationResult.changes;\r\n\t}\r\n\r\n\tpublic getOriginalEditor(): editorBrowser.ICodeEditor {\r\n\t\treturn this._originalEditor;\r\n\t}\r\n\r\n\tpublic getModifiedEditor(): editorBrowser.ICodeEditor {\r\n\t\treturn this._modifiedEditor;\r\n\t}\r\n\r\n\tpublic updateOptions(newOptions: Readonly): void {\r\n\r\n\t\t// Handle side by side\r\n\t\tlet renderSideBySideChanged = false;\r\n\t\tif (typeof newOptions.renderSideBySide !== 'undefined') {\r\n\t\t\tif (this._renderSideBySide !== newOptions.renderSideBySide) {\r\n\t\t\t\tthis._renderSideBySide = newOptions.renderSideBySide;\r\n\t\t\t\trenderSideBySideChanged = true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (typeof newOptions.maxComputationTime !== 'undefined') {\r\n\t\t\tthis._maxComputationTime = newOptions.maxComputationTime;\r\n\t\t\tif (this._isVisible) {\r\n\t\t\t\tthis._beginUpdateDecorationsSoon();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet beginUpdateDecorations = false;\r\n\r\n\t\tif (typeof newOptions.ignoreTrimWhitespace !== 'undefined') {\r\n\t\t\tif (this._ignoreTrimWhitespace !== newOptions.ignoreTrimWhitespace) {\r\n\t\t\t\tthis._ignoreTrimWhitespace = newOptions.ignoreTrimWhitespace;\r\n\t\t\t\t// Begin comparing\r\n\t\t\t\tbeginUpdateDecorations = true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (typeof newOptions.renderIndicators !== 'undefined') {\r\n\t\t\tif (this._renderIndicators !== newOptions.renderIndicators) {\r\n\t\t\t\tthis._renderIndicators = newOptions.renderIndicators;\r\n\t\t\t\tbeginUpdateDecorations = true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (beginUpdateDecorations) {\r\n\t\t\tthis._beginUpdateDecorations();\r\n\t\t}\r\n\r\n\t\tthis._originalIsEditable = validateBooleanOption(newOptions.originalEditable, this._originalIsEditable);\r\n\t\tthis._diffCodeLens = validateBooleanOption(newOptions.diffCodeLens, this._diffCodeLens);\r\n\t\tthis._diffWordWrap = validateDiffWordWrap(newOptions.diffWordWrap, this._diffWordWrap);\r\n\r\n\t\tthis._modifiedEditor.updateOptions(this._adjustOptionsForRightHandSide(newOptions));\r\n\t\tthis._originalEditor.updateOptions(this._adjustOptionsForLeftHandSide(newOptions));\r\n\r\n\t\t// enableSplitViewResizing\r\n\t\tif (typeof newOptions.enableSplitViewResizing !== 'undefined') {\r\n\t\t\tthis._enableSplitViewResizing = newOptions.enableSplitViewResizing;\r\n\t\t}\r\n\t\tthis._strategy.setEnableSplitViewResizing(this._enableSplitViewResizing);\r\n\r\n\t\t// renderSideBySide\r\n\t\tif (renderSideBySideChanged) {\r\n\t\t\tif (this._renderSideBySide) {\r\n\t\t\t\tthis._setStrategy(new DiffEditorWidgetSideBySide(this._createDataSource(), this._enableSplitViewResizing));\r\n\t\t\t} else {\r\n\t\t\t\tthis._setStrategy(new DiffEditorWidgetInline(this._createDataSource(), this._enableSplitViewResizing));\r\n\t\t\t}\r\n\t\t\t// Update class name\r\n\t\t\tthis._containerDomElement.className = DiffEditorWidget._getClassName(this._themeService.getColorTheme(), this._renderSideBySide);\r\n\t\t}\r\n\r\n\t\t// renderOverviewRuler\r\n\t\tif (typeof newOptions.renderOverviewRuler !== 'undefined' && this._renderOverviewRuler !== newOptions.renderOverviewRuler) {\r\n\t\t\tthis._renderOverviewRuler = newOptions.renderOverviewRuler;\r\n\t\t\tif (this._renderOverviewRuler) {\r\n\t\t\t\tthis._containerDomElement.appendChild(this._overviewDomElement);\r\n\t\t\t} else {\r\n\t\t\t\tthis._containerDomElement.removeChild(this._overviewDomElement);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getModel(): editorCommon.IDiffEditorModel {\r\n\t\treturn {\r\n\t\t\toriginal: this._originalEditor.getModel()!,\r\n\t\t\tmodified: this._modifiedEditor.getModel()!\r\n\t\t};\r\n\t}\r\n\r\n\tpublic setModel(model: editorCommon.IDiffEditorModel | null): void {\r\n\t\t// Guard us against partial null model\r\n\t\tif (model && (!model.original || !model.modified)) {\r\n\t\t\tthrow new Error(!model.original ? 'DiffEditorWidget.setModel: Original model is null' : 'DiffEditorWidget.setModel: Modified model is null');\r\n\t\t}\r\n\r\n\t\t// Remove all view zones & decorations\r\n\t\tthis._cleanViewZonesAndDecorations();\r\n\r\n\t\t// Update code editor models\r\n\t\tthis._originalEditor.setModel(model ? model.original : null);\r\n\t\tthis._modifiedEditor.setModel(model ? model.modified : null);\r\n\t\tthis._updateDecorationsRunner.cancel();\r\n\r\n\t\t// this.originalEditor.onDidChangeModelOptions\r\n\r\n\t\tif (model) {\r\n\t\t\tthis._originalEditor.setScrollTop(0);\r\n\t\t\tthis._modifiedEditor.setScrollTop(0);\r\n\t\t}\r\n\r\n\t\t// Disable any diff computations that will come in\r\n\t\tthis._diffComputationResult = null;\r\n\t\tthis._diffComputationToken++;\r\n\t\tthis._setState(editorBrowser.DiffEditorState.Idle);\r\n\r\n\t\tif (model) {\r\n\t\t\tthis._recreateOverviewRulers();\r\n\r\n\t\t\t// Begin comparing\r\n\t\t\tthis._beginUpdateDecorations();\r\n\t\t}\r\n\r\n\t\tthis._layoutOverviewViewport();\r\n\t}\r\n\r\n\tpublic getDomNode(): HTMLElement {\r\n\t\treturn this._domElement;\r\n\t}\r\n\r\n\tpublic getVisibleColumnFromPosition(position: IPosition): number {\r\n\t\treturn this._modifiedEditor.getVisibleColumnFromPosition(position);\r\n\t}\r\n\r\n\tpublic getPosition(): Position | null {\r\n\t\treturn this._modifiedEditor.getPosition();\r\n\t}\r\n\r\n\tpublic setPosition(position: IPosition): void {\r\n\t\tthis._modifiedEditor.setPosition(position);\r\n\t}\r\n\r\n\tpublic revealLine(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._modifiedEditor.revealLine(lineNumber, scrollType);\r\n\t}\r\n\r\n\tpublic revealLineInCenter(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._modifiedEditor.revealLineInCenter(lineNumber, scrollType);\r\n\t}\r\n\r\n\tpublic revealLineInCenterIfOutsideViewport(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._modifiedEditor.revealLineInCenterIfOutsideViewport(lineNumber, scrollType);\r\n\t}\r\n\r\n\tpublic revealLineNearTop(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._modifiedEditor.revealLineNearTop(lineNumber, scrollType);\r\n\t}\r\n\r\n\tpublic revealPosition(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._modifiedEditor.revealPosition(position, scrollType);\r\n\t}\r\n\r\n\tpublic revealPositionInCenter(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._modifiedEditor.revealPositionInCenter(position, scrollType);\r\n\t}\r\n\r\n\tpublic revealPositionInCenterIfOutsideViewport(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._modifiedEditor.revealPositionInCenterIfOutsideViewport(position, scrollType);\r\n\t}\r\n\r\n\tpublic revealPositionNearTop(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._modifiedEditor.revealPositionNearTop(position, scrollType);\r\n\t}\r\n\r\n\tpublic getSelection(): Selection | null {\r\n\t\treturn this._modifiedEditor.getSelection();\r\n\t}\r\n\r\n\tpublic getSelections(): Selection[] | null {\r\n\t\treturn this._modifiedEditor.getSelections();\r\n\t}\r\n\r\n\tpublic setSelection(range: IRange): void;\r\n\tpublic setSelection(editorRange: Range): void;\r\n\tpublic setSelection(selection: ISelection): void;\r\n\tpublic setSelection(editorSelection: Selection): void;\r\n\tpublic setSelection(something: any): void {\r\n\t\tthis._modifiedEditor.setSelection(something);\r\n\t}\r\n\r\n\tpublic setSelections(ranges: readonly ISelection[]): void {\r\n\t\tthis._modifiedEditor.setSelections(ranges);\r\n\t}\r\n\r\n\tpublic revealLines(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._modifiedEditor.revealLines(startLineNumber, endLineNumber, scrollType);\r\n\t}\r\n\r\n\tpublic revealLinesInCenter(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._modifiedEditor.revealLinesInCenter(startLineNumber, endLineNumber, scrollType);\r\n\t}\r\n\r\n\tpublic revealLinesInCenterIfOutsideViewport(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._modifiedEditor.revealLinesInCenterIfOutsideViewport(startLineNumber, endLineNumber, scrollType);\r\n\t}\r\n\r\n\tpublic revealLinesNearTop(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._modifiedEditor.revealLinesNearTop(startLineNumber, endLineNumber, scrollType);\r\n\t}\r\n\r\n\tpublic revealRange(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth, revealVerticalInCenter: boolean = false, revealHorizontal: boolean = true): void {\r\n\t\tthis._modifiedEditor.revealRange(range, scrollType, revealVerticalInCenter, revealHorizontal);\r\n\t}\r\n\r\n\tpublic revealRangeInCenter(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._modifiedEditor.revealRangeInCenter(range, scrollType);\r\n\t}\r\n\r\n\tpublic revealRangeInCenterIfOutsideViewport(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._modifiedEditor.revealRangeInCenterIfOutsideViewport(range, scrollType);\r\n\t}\r\n\r\n\tpublic revealRangeNearTop(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._modifiedEditor.revealRangeNearTop(range, scrollType);\r\n\t}\r\n\r\n\tpublic revealRangeNearTopIfOutsideViewport(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._modifiedEditor.revealRangeNearTopIfOutsideViewport(range, scrollType);\r\n\t}\r\n\r\n\tpublic revealRangeAtTop(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {\r\n\t\tthis._modifiedEditor.revealRangeAtTop(range, scrollType);\r\n\t}\r\n\r\n\tpublic getSupportedActions(): editorCommon.IEditorAction[] {\r\n\t\treturn this._modifiedEditor.getSupportedActions();\r\n\t}\r\n\r\n\tpublic saveViewState(): editorCommon.IDiffEditorViewState {\r\n\t\tconst originalViewState = this._originalEditor.saveViewState();\r\n\t\tconst modifiedViewState = this._modifiedEditor.saveViewState();\r\n\t\treturn {\r\n\t\t\toriginal: originalViewState,\r\n\t\t\tmodified: modifiedViewState\r\n\t\t};\r\n\t}\r\n\r\n\tpublic restoreViewState(s: editorCommon.IDiffEditorViewState): void {\r\n\t\tif (s && s.original && s.modified) {\r\n\t\t\tconst diffEditorState = s;\r\n\t\t\tthis._originalEditor.restoreViewState(diffEditorState.original);\r\n\t\t\tthis._modifiedEditor.restoreViewState(diffEditorState.modified);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic layout(dimension?: editorCommon.IDimension): void {\r\n\t\tthis._elementSizeObserver.observe(dimension);\r\n\t}\r\n\r\n\tpublic focus(): void {\r\n\t\tthis._modifiedEditor.focus();\r\n\t}\r\n\r\n\tpublic hasTextFocus(): boolean {\r\n\t\treturn this._originalEditor.hasTextFocus() || this._modifiedEditor.hasTextFocus();\r\n\t}\r\n\r\n\tpublic trigger(source: string | null | undefined, handlerId: string, payload: any): void {\r\n\t\tthis._modifiedEditor.trigger(source, handlerId, payload);\r\n\t}\r\n\r\n\tpublic changeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => any): any {\r\n\t\treturn this._modifiedEditor.changeDecorations(callback);\r\n\t}\r\n\r\n\t//------------ end IDiffEditor methods\r\n\r\n\r\n\r\n\t//------------ begin layouting methods\r\n\r\n\tprivate _onDidContainerSizeChanged(): void {\r\n\t\tthis._doLayout();\r\n\t}\r\n\r\n\tprivate _getReviewHeight(): number {\r\n\t\treturn this._reviewPane.isVisible() ? this._elementSizeObserver.getHeight() : 0;\r\n\t}\r\n\r\n\tprivate _layoutOverviewRulers(): void {\r\n\t\tif (!this._renderOverviewRuler) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!this._originalOverviewRuler || !this._modifiedOverviewRuler) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst height = this._elementSizeObserver.getHeight();\r\n\t\tconst reviewHeight = this._getReviewHeight();\r\n\r\n\t\tconst freeSpace = DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH - 2 * DiffEditorWidget.ONE_OVERVIEW_WIDTH;\r\n\t\tconst layoutInfo = this._modifiedEditor.getLayoutInfo();\r\n\t\tif (layoutInfo) {\r\n\t\t\tthis._originalOverviewRuler.setLayout({\r\n\t\t\t\ttop: 0,\r\n\t\t\t\twidth: DiffEditorWidget.ONE_OVERVIEW_WIDTH,\r\n\t\t\t\tright: freeSpace + DiffEditorWidget.ONE_OVERVIEW_WIDTH,\r\n\t\t\t\theight: (height - reviewHeight)\r\n\t\t\t});\r\n\t\t\tthis._modifiedOverviewRuler.setLayout({\r\n\t\t\t\ttop: 0,\r\n\t\t\t\tright: 0,\r\n\t\t\t\twidth: DiffEditorWidget.ONE_OVERVIEW_WIDTH,\r\n\t\t\t\theight: (height - reviewHeight)\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\t//------------ end layouting methods\r\n\r\n\tprivate _onViewZonesChanged(): void {\r\n\t\tif (this._currentlyChangingViewZones) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._updateDecorationsRunner.schedule();\r\n\t}\r\n\r\n\tprivate _beginUpdateDecorationsSoon(): void {\r\n\t\t// Clear previous timeout if necessary\r\n\t\tif (this._beginUpdateDecorationsTimeout !== -1) {\r\n\t\t\twindow.clearTimeout(this._beginUpdateDecorationsTimeout);\r\n\t\t\tthis._beginUpdateDecorationsTimeout = -1;\r\n\t\t}\r\n\t\tthis._beginUpdateDecorationsTimeout = window.setTimeout(() => this._beginUpdateDecorations(), DiffEditorWidget.UPDATE_DIFF_DECORATIONS_DELAY);\r\n\t}\r\n\r\n\tprivate _lastOriginalWarning: URI | null = null;\r\n\tprivate _lastModifiedWarning: URI | null = null;\r\n\r\n\tprivate static _equals(a: URI | null, b: URI | null): boolean {\r\n\t\tif (!a && !b) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (!a || !b) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn (a.toString() === b.toString());\r\n\t}\r\n\r\n\tprivate _beginUpdateDecorations(): void {\r\n\t\tthis._beginUpdateDecorationsTimeout = -1;\r\n\t\tconst currentOriginalModel = this._originalEditor.getModel();\r\n\t\tconst currentModifiedModel = this._modifiedEditor.getModel();\r\n\t\tif (!currentOriginalModel || !currentModifiedModel) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// Prevent old diff requests to come if a new request has been initiated\r\n\t\t// The best method would be to call cancel on the Promise, but this is not\r\n\t\t// yet supported, so using tokens for now.\r\n\t\tthis._diffComputationToken++;\r\n\t\tconst currentToken = this._diffComputationToken;\r\n\t\tthis._setState(editorBrowser.DiffEditorState.ComputingDiff);\r\n\r\n\t\tif (!this._editorWorkerService.canComputeDiff(currentOriginalModel.uri, currentModifiedModel.uri)) {\r\n\t\t\tif (\r\n\t\t\t\t!DiffEditorWidget._equals(currentOriginalModel.uri, this._lastOriginalWarning)\r\n\t\t\t\t|| !DiffEditorWidget._equals(currentModifiedModel.uri, this._lastModifiedWarning)\r\n\t\t\t) {\r\n\t\t\t\tthis._lastOriginalWarning = currentOriginalModel.uri;\r\n\t\t\t\tthis._lastModifiedWarning = currentModifiedModel.uri;\r\n\t\t\t\tthis._notificationService.warn(nls.localize(\"diff.tooLarge\", \"Cannot compare files because one file is too large.\"));\r\n\t\t\t}\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._editorWorkerService.computeDiff(currentOriginalModel.uri, currentModifiedModel.uri, this._ignoreTrimWhitespace, this._maxComputationTime).then((result) => {\r\n\t\t\tif (currentToken === this._diffComputationToken\r\n\t\t\t\t&& currentOriginalModel === this._originalEditor.getModel()\r\n\t\t\t\t&& currentModifiedModel === this._modifiedEditor.getModel()\r\n\t\t\t) {\r\n\t\t\t\tthis._setState(editorBrowser.DiffEditorState.DiffComputed);\r\n\t\t\t\tthis._diffComputationResult = result;\r\n\t\t\t\tthis._updateDecorationsRunner.schedule();\r\n\t\t\t\tthis._onDidUpdateDiff.fire();\r\n\t\t\t}\r\n\t\t}, (error) => {\r\n\t\t\tif (currentToken === this._diffComputationToken\r\n\t\t\t\t&& currentOriginalModel === this._originalEditor.getModel()\r\n\t\t\t\t&& currentModifiedModel === this._modifiedEditor.getModel()\r\n\t\t\t) {\r\n\t\t\t\tthis._setState(editorBrowser.DiffEditorState.DiffComputed);\r\n\t\t\t\tthis._diffComputationResult = null;\r\n\t\t\t\tthis._updateDecorationsRunner.schedule();\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _cleanViewZonesAndDecorations(): void {\r\n\t\tthis._originalEditorState.clean(this._originalEditor);\r\n\t\tthis._modifiedEditorState.clean(this._modifiedEditor);\r\n\t}\r\n\r\n\tprivate _updateDecorations(): void {\r\n\t\tif (!this._originalEditor.getModel() || !this._modifiedEditor.getModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst lineChanges = (this._diffComputationResult ? this._diffComputationResult.changes : []);\r\n\r\n\t\tconst foreignOriginal = this._originalEditorState.getForeignViewZones(this._originalEditor.getWhitespaces());\r\n\t\tconst foreignModified = this._modifiedEditorState.getForeignViewZones(this._modifiedEditor.getWhitespaces());\r\n\r\n\t\tconst diffDecorations = this._strategy.getEditorsDiffDecorations(lineChanges, this._ignoreTrimWhitespace, this._renderIndicators, foreignOriginal, foreignModified);\r\n\r\n\t\ttry {\r\n\t\t\tthis._currentlyChangingViewZones = true;\r\n\t\t\tthis._originalEditorState.apply(this._originalEditor, this._originalOverviewRuler, diffDecorations.original, false);\r\n\t\t\tthis._modifiedEditorState.apply(this._modifiedEditor, this._modifiedOverviewRuler, diffDecorations.modified, true);\r\n\t\t} finally {\r\n\t\t\tthis._currentlyChangingViewZones = false;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _adjustOptionsForSubEditor(options: Readonly): editorBrowser.IEditorConstructionOptions {\r\n\t\tconst clonedOptions = { ...options };\r\n\t\tclonedOptions.inDiffEditor = true;\r\n\t\tclonedOptions.automaticLayout = false;\r\n\t\tclonedOptions.scrollbar = clonedOptions.scrollbar || {};\r\n\t\tclonedOptions.scrollbar.vertical = 'visible';\r\n\t\tclonedOptions.folding = false;\r\n\t\tclonedOptions.codeLens = this._diffCodeLens;\r\n\t\tclonedOptions.fixedOverflowWidgets = true;\r\n\t\t// clonedOptions.lineDecorationsWidth = '2ch';\r\n\t\tif (!clonedOptions.minimap) {\r\n\t\t\tclonedOptions.minimap = {};\r\n\t\t}\r\n\t\tclonedOptions.minimap.enabled = false;\r\n\t\treturn clonedOptions;\r\n\t}\r\n\r\n\tprivate _adjustOptionsForLeftHandSide(options: Readonly): editorBrowser.IEditorConstructionOptions {\r\n\t\tconst result = this._adjustOptionsForSubEditor(options);\r\n\t\tif (!this._renderSideBySide) {\r\n\t\t\t// never wrap hidden editor\r\n\t\t\tresult.wordWrapOverride1 = 'off';\r\n\t\t} else {\r\n\t\t\tresult.wordWrapOverride1 = this._diffWordWrap;\r\n\t\t}\r\n\t\tresult.readOnly = !this._originalIsEditable;\r\n\t\tresult.extraEditorClassName = 'original-in-monaco-diff-editor';\r\n\t\treturn {\r\n\t\t\t...result,\r\n\t\t\tdimension: {\r\n\t\t\t\theight: 0,\r\n\t\t\t\twidth: 0\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\tprivate _adjustOptionsForRightHandSide(options: Readonly): editorBrowser.IEditorConstructionOptions {\r\n\t\tconst result = this._adjustOptionsForSubEditor(options);\r\n\t\tresult.wordWrapOverride1 = this._diffWordWrap;\r\n\t\tresult.revealHorizontalRightPadding = EditorOptions.revealHorizontalRightPadding.defaultValue + DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH;\r\n\t\tresult.scrollbar!.verticalHasArrows = false;\r\n\t\tresult.extraEditorClassName = 'modified-in-monaco-diff-editor';\r\n\t\treturn {\r\n\t\t\t...result,\r\n\t\t\tdimension: {\r\n\t\t\t\theight: 0,\r\n\t\t\t\twidth: 0\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\tpublic doLayout(): void {\r\n\t\tthis._elementSizeObserver.observe();\r\n\t\tthis._doLayout();\r\n\t}\r\n\r\n\tprivate _doLayout(): void {\r\n\t\tconst width = this._elementSizeObserver.getWidth();\r\n\t\tconst height = this._elementSizeObserver.getHeight();\r\n\t\tconst reviewHeight = this._getReviewHeight();\r\n\r\n\t\tconst splitPoint = this._strategy.layout();\r\n\r\n\t\tthis._originalDomNode.style.width = splitPoint + 'px';\r\n\t\tthis._originalDomNode.style.left = '0px';\r\n\r\n\t\tthis._modifiedDomNode.style.width = (width - splitPoint) + 'px';\r\n\t\tthis._modifiedDomNode.style.left = splitPoint + 'px';\r\n\r\n\t\tthis._overviewDomElement.style.top = '0px';\r\n\t\tthis._overviewDomElement.style.height = (height - reviewHeight) + 'px';\r\n\t\tthis._overviewDomElement.style.width = DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH + 'px';\r\n\t\tthis._overviewDomElement.style.left = (width - DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH) + 'px';\r\n\t\tthis._overviewViewportDomElement.setWidth(DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH);\r\n\t\tthis._overviewViewportDomElement.setHeight(30);\r\n\r\n\t\tthis._originalEditor.layout({ width: splitPoint, height: (height - reviewHeight) });\r\n\t\tthis._modifiedEditor.layout({ width: width - splitPoint - (this._renderOverviewRuler ? DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH : 0), height: (height - reviewHeight) });\r\n\r\n\t\tif (this._originalOverviewRuler || this._modifiedOverviewRuler) {\r\n\t\t\tthis._layoutOverviewRulers();\r\n\t\t}\r\n\r\n\t\tthis._reviewPane.layout(height - reviewHeight, width, reviewHeight);\r\n\r\n\t\tthis._layoutOverviewViewport();\r\n\t}\r\n\r\n\tprivate _layoutOverviewViewport(): void {\r\n\t\tconst layout = this._computeOverviewViewport();\r\n\t\tif (!layout) {\r\n\t\t\tthis._overviewViewportDomElement.setTop(0);\r\n\t\t\tthis._overviewViewportDomElement.setHeight(0);\r\n\t\t} else {\r\n\t\t\tthis._overviewViewportDomElement.setTop(layout.top);\r\n\t\t\tthis._overviewViewportDomElement.setHeight(layout.height);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _computeOverviewViewport(): { height: number; top: number; } | null {\r\n\t\tconst layoutInfo = this._modifiedEditor.getLayoutInfo();\r\n\t\tif (!layoutInfo) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst scrollTop = this._modifiedEditor.getScrollTop();\r\n\t\tconst scrollHeight = this._modifiedEditor.getScrollHeight();\r\n\r\n\t\tconst computedAvailableSize = Math.max(0, layoutInfo.height);\r\n\t\tconst computedRepresentableSize = Math.max(0, computedAvailableSize - 2 * 0);\r\n\t\tconst computedRatio = scrollHeight > 0 ? (computedRepresentableSize / scrollHeight) : 0;\r\n\r\n\t\tconst computedSliderSize = Math.max(0, Math.floor(layoutInfo.height * computedRatio));\r\n\t\tconst computedSliderPosition = Math.floor(scrollTop * computedRatio);\r\n\r\n\t\treturn {\r\n\t\t\theight: computedSliderSize,\r\n\t\t\ttop: computedSliderPosition\r\n\t\t};\r\n\t}\r\n\r\n\tprivate _createDataSource(): IDataSource {\r\n\t\treturn {\r\n\t\t\tgetWidth: () => {\r\n\t\t\t\treturn this._elementSizeObserver.getWidth();\r\n\t\t\t},\r\n\r\n\t\t\tgetHeight: () => {\r\n\t\t\t\treturn (this._elementSizeObserver.getHeight() - this._getReviewHeight());\r\n\t\t\t},\r\n\r\n\t\t\tgetOptions: () => {\r\n\t\t\t\treturn {\r\n\t\t\t\t\trenderOverviewRuler: this._renderOverviewRuler\r\n\t\t\t\t};\r\n\t\t\t},\r\n\r\n\t\t\tgetContainerDomNode: () => {\r\n\t\t\t\treturn this._containerDomElement;\r\n\t\t\t},\r\n\r\n\t\t\trelayoutEditors: () => {\r\n\t\t\t\tthis._doLayout();\r\n\t\t\t},\r\n\r\n\t\t\tgetOriginalEditor: () => {\r\n\t\t\t\treturn this._originalEditor;\r\n\t\t\t},\r\n\r\n\t\t\tgetModifiedEditor: () => {\r\n\t\t\t\treturn this._modifiedEditor;\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\tprivate _setStrategy(newStrategy: DiffEditorWidgetStyle): void {\r\n\t\tif (this._strategy) {\r\n\t\t\tthis._strategy.dispose();\r\n\t\t}\r\n\r\n\t\tthis._strategy = newStrategy;\r\n\t\tnewStrategy.applyColors(this._themeService.getColorTheme());\r\n\r\n\t\tif (this._diffComputationResult) {\r\n\t\t\tthis._updateDecorations();\r\n\t\t}\r\n\r\n\t\t// Just do a layout, the strategy might need it\r\n\t\tthis._doLayout();\r\n\t}\r\n\r\n\tprivate _getLineChangeAtOrBeforeLineNumber(lineNumber: number, startLineNumberExtractor: (lineChange: editorCommon.ILineChange) => number): editorCommon.ILineChange | null {\r\n\t\tconst lineChanges = (this._diffComputationResult ? this._diffComputationResult.changes : []);\r\n\t\tif (lineChanges.length === 0 || lineNumber < startLineNumberExtractor(lineChanges[0])) {\r\n\t\t\t// There are no changes or `lineNumber` is before the first change\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tlet min = 0;\r\n\t\tlet max = lineChanges.length - 1;\r\n\t\twhile (min < max) {\r\n\t\t\tconst mid = Math.floor((min + max) / 2);\r\n\t\t\tconst midStart = startLineNumberExtractor(lineChanges[mid]);\r\n\t\t\tconst midEnd = (mid + 1 <= max ? startLineNumberExtractor(lineChanges[mid + 1]) : Constants.MAX_SAFE_SMALL_INTEGER);\r\n\r\n\t\t\tif (lineNumber < midStart) {\r\n\t\t\t\tmax = mid - 1;\r\n\t\t\t} else if (lineNumber >= midEnd) {\r\n\t\t\t\tmin = mid + 1;\r\n\t\t\t} else {\r\n\t\t\t\t// HIT!\r\n\t\t\t\tmin = mid;\r\n\t\t\t\tmax = mid;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn lineChanges[min];\r\n\t}\r\n\r\n\tprivate _getEquivalentLineForOriginalLineNumber(lineNumber: number): number {\r\n\t\tconst lineChange = this._getLineChangeAtOrBeforeLineNumber(lineNumber, (lineChange) => lineChange.originalStartLineNumber);\r\n\r\n\t\tif (!lineChange) {\r\n\t\t\treturn lineNumber;\r\n\t\t}\r\n\r\n\t\tconst originalEquivalentLineNumber = lineChange.originalStartLineNumber + (lineChange.originalEndLineNumber > 0 ? -1 : 0);\r\n\t\tconst modifiedEquivalentLineNumber = lineChange.modifiedStartLineNumber + (lineChange.modifiedEndLineNumber > 0 ? -1 : 0);\r\n\t\tconst lineChangeOriginalLength = (lineChange.originalEndLineNumber > 0 ? (lineChange.originalEndLineNumber - lineChange.originalStartLineNumber + 1) : 0);\r\n\t\tconst lineChangeModifiedLength = (lineChange.modifiedEndLineNumber > 0 ? (lineChange.modifiedEndLineNumber - lineChange.modifiedStartLineNumber + 1) : 0);\r\n\r\n\r\n\t\tconst delta = lineNumber - originalEquivalentLineNumber;\r\n\r\n\t\tif (delta <= lineChangeOriginalLength) {\r\n\t\t\treturn modifiedEquivalentLineNumber + Math.min(delta, lineChangeModifiedLength);\r\n\t\t}\r\n\r\n\t\treturn modifiedEquivalentLineNumber + lineChangeModifiedLength - lineChangeOriginalLength + delta;\r\n\t}\r\n\r\n\tprivate _getEquivalentLineForModifiedLineNumber(lineNumber: number): number {\r\n\t\tconst lineChange = this._getLineChangeAtOrBeforeLineNumber(lineNumber, (lineChange) => lineChange.modifiedStartLineNumber);\r\n\r\n\t\tif (!lineChange) {\r\n\t\t\treturn lineNumber;\r\n\t\t}\r\n\r\n\t\tconst originalEquivalentLineNumber = lineChange.originalStartLineNumber + (lineChange.originalEndLineNumber > 0 ? -1 : 0);\r\n\t\tconst modifiedEquivalentLineNumber = lineChange.modifiedStartLineNumber + (lineChange.modifiedEndLineNumber > 0 ? -1 : 0);\r\n\t\tconst lineChangeOriginalLength = (lineChange.originalEndLineNumber > 0 ? (lineChange.originalEndLineNumber - lineChange.originalStartLineNumber + 1) : 0);\r\n\t\tconst lineChangeModifiedLength = (lineChange.modifiedEndLineNumber > 0 ? (lineChange.modifiedEndLineNumber - lineChange.modifiedStartLineNumber + 1) : 0);\r\n\r\n\r\n\t\tconst delta = lineNumber - modifiedEquivalentLineNumber;\r\n\r\n\t\tif (delta <= lineChangeModifiedLength) {\r\n\t\t\treturn originalEquivalentLineNumber + Math.min(delta, lineChangeOriginalLength);\r\n\t\t}\r\n\r\n\t\treturn originalEquivalentLineNumber + lineChangeOriginalLength - lineChangeModifiedLength + delta;\r\n\t}\r\n\r\n\tpublic getDiffLineInformationForOriginal(lineNumber: number): editorBrowser.IDiffLineInformation | null {\r\n\t\tif (!this._diffComputationResult) {\r\n\t\t\t// Cannot answer that which I don't know\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn {\r\n\t\t\tequivalentLineNumber: this._getEquivalentLineForOriginalLineNumber(lineNumber)\r\n\t\t};\r\n\t}\r\n\r\n\tpublic getDiffLineInformationForModified(lineNumber: number): editorBrowser.IDiffLineInformation | null {\r\n\t\tif (!this._diffComputationResult) {\r\n\t\t\t// Cannot answer that which I don't know\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn {\r\n\t\t\tequivalentLineNumber: this._getEquivalentLineForModifiedLineNumber(lineNumber)\r\n\t\t};\r\n\t}\r\n}\r\n\r\ninterface IDataSource {\r\n\tgetWidth(): number;\r\n\tgetHeight(): number;\r\n\tgetOptions(): { renderOverviewRuler: boolean; };\r\n\tgetContainerDomNode(): HTMLElement;\r\n\trelayoutEditors(): void;\r\n\r\n\tgetOriginalEditor(): CodeEditorWidget;\r\n\tgetModifiedEditor(): CodeEditorWidget;\r\n}\r\n\r\nabstract class DiffEditorWidgetStyle extends Disposable {\r\n\r\n\tprotected _dataSource: IDataSource;\r\n\tprotected _insertColor: Color | null;\r\n\tprotected _removeColor: Color | null;\r\n\r\n\tconstructor(dataSource: IDataSource) {\r\n\t\tsuper();\r\n\t\tthis._dataSource = dataSource;\r\n\t\tthis._insertColor = null;\r\n\t\tthis._removeColor = null;\r\n\t}\r\n\r\n\tpublic applyColors(theme: IColorTheme): boolean {\r\n\t\tconst newInsertColor = (theme.getColor(diffInserted) || defaultInsertColor).transparent(2);\r\n\t\tconst newRemoveColor = (theme.getColor(diffRemoved) || defaultRemoveColor).transparent(2);\r\n\t\tconst hasChanges = !newInsertColor.equals(this._insertColor) || !newRemoveColor.equals(this._removeColor);\r\n\t\tthis._insertColor = newInsertColor;\r\n\t\tthis._removeColor = newRemoveColor;\r\n\t\treturn hasChanges;\r\n\t}\r\n\r\n\tpublic getEditorsDiffDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalWhitespaces: IEditorWhitespace[], modifiedWhitespaces: IEditorWhitespace[]): IEditorsDiffDecorationsWithZones {\r\n\t\t// Get view zones\r\n\t\tmodifiedWhitespaces = modifiedWhitespaces.sort((a, b) => {\r\n\t\t\treturn a.afterLineNumber - b.afterLineNumber;\r\n\t\t});\r\n\t\toriginalWhitespaces = originalWhitespaces.sort((a, b) => {\r\n\t\t\treturn a.afterLineNumber - b.afterLineNumber;\r\n\t\t});\r\n\t\tconst zones = this._getViewZones(lineChanges, originalWhitespaces, modifiedWhitespaces, renderIndicators);\r\n\r\n\t\t// Get decorations & overview ruler zones\r\n\t\tconst originalDecorations = this._getOriginalEditorDecorations(lineChanges, ignoreTrimWhitespace, renderIndicators);\r\n\t\tconst modifiedDecorations = this._getModifiedEditorDecorations(lineChanges, ignoreTrimWhitespace, renderIndicators);\r\n\r\n\t\treturn {\r\n\t\t\toriginal: {\r\n\t\t\t\tdecorations: originalDecorations.decorations,\r\n\t\t\t\toverviewZones: originalDecorations.overviewZones,\r\n\t\t\t\tzones: zones.original\r\n\t\t\t},\r\n\t\t\tmodified: {\r\n\t\t\t\tdecorations: modifiedDecorations.decorations,\r\n\t\t\t\toverviewZones: modifiedDecorations.overviewZones,\r\n\t\t\t\tzones: zones.modified\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\tprotected abstract _getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], renderIndicators: boolean): IEditorsZones;\r\n\tprotected abstract _getOriginalEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean): IEditorDiffDecorations;\r\n\tprotected abstract _getModifiedEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean): IEditorDiffDecorations;\r\n\r\n\tpublic abstract setEnableSplitViewResizing(enableSplitViewResizing: boolean): void;\r\n\tpublic abstract layout(): number;\r\n}\r\n\r\ninterface IMyViewZone {\r\n\tshouldNotShrink?: boolean;\r\n\tafterLineNumber: number;\r\n\tafterColumn?: number;\r\n\theightInLines: number;\r\n\tdomNode: HTMLElement | null;\r\n\tmarginDomNode?: HTMLElement | null;\r\n\tdiff?: IDiffLinesChange;\r\n}\r\n\r\nclass ForeignViewZonesIterator {\r\n\r\n\tprivate _index: number;\r\n\tprivate readonly _source: IEditorWhitespace[];\r\n\tpublic current: IEditorWhitespace | null;\r\n\r\n\tconstructor(source: IEditorWhitespace[]) {\r\n\t\tthis._source = source;\r\n\t\tthis._index = -1;\r\n\t\tthis.current = null;\r\n\t\tthis.advance();\r\n\t}\r\n\r\n\tpublic advance(): void {\r\n\t\tthis._index++;\r\n\t\tif (this._index < this._source.length) {\r\n\t\t\tthis.current = this._source[this._index];\r\n\t\t} else {\r\n\t\t\tthis.current = null;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nabstract class ViewZonesComputer {\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _lineChanges: editorCommon.ILineChange[],\r\n\t\tprivate readonly _originalForeignVZ: IEditorWhitespace[],\r\n\t\tprivate readonly _modifiedForeignVZ: IEditorWhitespace[],\r\n\t\tprotected readonly _originalEditor: CodeEditorWidget,\r\n\t\tprotected readonly _modifiedEditor: CodeEditorWidget\r\n\t) {\r\n\t}\r\n\r\n\tprivate static _getViewLineCount(editor: CodeEditorWidget, startLineNumber: number, endLineNumber: number): number {\r\n\t\tconst model = editor.getModel();\r\n\t\tconst viewModel = editor._getViewModel();\r\n\t\tif (model && viewModel) {\r\n\t\t\tconst viewRange = getViewRange(model, viewModel, startLineNumber, endLineNumber);\r\n\t\t\treturn (viewRange.endLineNumber - viewRange.startLineNumber + 1);\r\n\t\t}\r\n\r\n\t\treturn (endLineNumber - startLineNumber + 1);\r\n\t}\r\n\r\n\tpublic getViewZones(): IEditorsZones {\r\n\t\tconst originalLineHeight = this._originalEditor.getOption(EditorOption.lineHeight);\r\n\t\tconst modifiedLineHeight = this._modifiedEditor.getOption(EditorOption.lineHeight);\r\n\t\tconst originalHasWrapping = (this._originalEditor.getOption(EditorOption.wrappingInfo).wrappingColumn !== -1);\r\n\t\tconst modifiedHasWrapping = (this._modifiedEditor.getOption(EditorOption.wrappingInfo).wrappingColumn !== -1);\r\n\t\tconst hasWrapping = (originalHasWrapping || modifiedHasWrapping);\r\n\t\tconst originalModel = this._originalEditor.getModel()!;\r\n\t\tconst originalCoordinatesConverter = this._originalEditor._getViewModel()!.coordinatesConverter;\r\n\t\tconst modifiedCoordinatesConverter = this._modifiedEditor._getViewModel()!.coordinatesConverter;\r\n\r\n\t\tconst result: { original: IMyViewZone[]; modified: IMyViewZone[]; } = {\r\n\t\t\toriginal: [],\r\n\t\t\tmodified: []\r\n\t\t};\r\n\r\n\t\tlet lineChangeModifiedLength: number = 0;\r\n\t\tlet lineChangeOriginalLength: number = 0;\r\n\t\tlet originalEquivalentLineNumber: number = 0;\r\n\t\tlet modifiedEquivalentLineNumber: number = 0;\r\n\t\tlet originalEndEquivalentLineNumber: number = 0;\r\n\t\tlet modifiedEndEquivalentLineNumber: number = 0;\r\n\r\n\t\tconst sortMyViewZones = (a: IMyViewZone, b: IMyViewZone) => {\r\n\t\t\treturn a.afterLineNumber - b.afterLineNumber;\r\n\t\t};\r\n\r\n\t\tconst addAndCombineIfPossible = (destination: IMyViewZone[], item: IMyViewZone) => {\r\n\t\t\tif (item.domNode === null && destination.length > 0) {\r\n\t\t\t\tconst lastItem = destination[destination.length - 1];\r\n\t\t\t\tif (lastItem.afterLineNumber === item.afterLineNumber && lastItem.domNode === null) {\r\n\t\t\t\t\tlastItem.heightInLines += item.heightInLines;\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tdestination.push(item);\r\n\t\t};\r\n\r\n\t\tconst modifiedForeignVZ = new ForeignViewZonesIterator(this._modifiedForeignVZ);\r\n\t\tconst originalForeignVZ = new ForeignViewZonesIterator(this._originalForeignVZ);\r\n\r\n\t\tlet lastOriginalLineNumber = 1;\r\n\t\tlet lastModifiedLineNumber = 1;\r\n\r\n\t\t// In order to include foreign view zones after the last line change, the for loop will iterate once more after the end of the `lineChanges` array\r\n\t\tfor (let i = 0, length = this._lineChanges.length; i <= length; i++) {\r\n\t\t\tconst lineChange = (i < length ? this._lineChanges[i] : null);\r\n\r\n\t\t\tif (lineChange !== null) {\r\n\t\t\t\toriginalEquivalentLineNumber = lineChange.originalStartLineNumber + (lineChange.originalEndLineNumber > 0 ? -1 : 0);\r\n\t\t\t\tmodifiedEquivalentLineNumber = lineChange.modifiedStartLineNumber + (lineChange.modifiedEndLineNumber > 0 ? -1 : 0);\r\n\t\t\t\tlineChangeOriginalLength = (lineChange.originalEndLineNumber > 0 ? ViewZonesComputer._getViewLineCount(this._originalEditor, lineChange.originalStartLineNumber, lineChange.originalEndLineNumber) : 0);\r\n\t\t\t\tlineChangeModifiedLength = (lineChange.modifiedEndLineNumber > 0 ? ViewZonesComputer._getViewLineCount(this._modifiedEditor, lineChange.modifiedStartLineNumber, lineChange.modifiedEndLineNumber) : 0);\r\n\t\t\t\toriginalEndEquivalentLineNumber = Math.max(lineChange.originalStartLineNumber, lineChange.originalEndLineNumber);\r\n\t\t\t\tmodifiedEndEquivalentLineNumber = Math.max(lineChange.modifiedStartLineNumber, lineChange.modifiedEndLineNumber);\r\n\t\t\t} else {\r\n\t\t\t\t// Increase to very large value to get the producing tests of foreign view zones running\r\n\t\t\t\toriginalEquivalentLineNumber += 10000000 + lineChangeOriginalLength;\r\n\t\t\t\tmodifiedEquivalentLineNumber += 10000000 + lineChangeModifiedLength;\r\n\t\t\t\toriginalEndEquivalentLineNumber = originalEquivalentLineNumber;\r\n\t\t\t\tmodifiedEndEquivalentLineNumber = modifiedEquivalentLineNumber;\r\n\t\t\t}\r\n\r\n\t\t\t// Each step produces view zones, and after producing them, we try to cancel them out, to avoid empty-empty view zone cases\r\n\t\t\tlet stepOriginal: IMyViewZone[] = [];\r\n\t\t\tlet stepModified: IMyViewZone[] = [];\r\n\r\n\t\t\t// ---------------------------- PRODUCE VIEW ZONES\r\n\r\n\t\t\t// [PRODUCE] View zones due to line mapping differences (equal lines but wrapped differently)\r\n\t\t\tif (hasWrapping) {\r\n\t\t\t\tlet count: number;\r\n\t\t\t\tif (lineChange) {\r\n\t\t\t\t\tif (lineChange.originalEndLineNumber > 0) {\r\n\t\t\t\t\t\tcount = lineChange.originalStartLineNumber - lastOriginalLineNumber;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tcount = lineChange.modifiedStartLineNumber - lastModifiedLineNumber;\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tcount = originalModel.getLineCount() - lastOriginalLineNumber;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfor (let i = 0; i < count; i++) {\r\n\t\t\t\t\tconst originalLineNumber = lastOriginalLineNumber + i;\r\n\t\t\t\t\tconst modifiedLineNumber = lastModifiedLineNumber + i;\r\n\r\n\t\t\t\t\tconst originalViewLineCount = originalCoordinatesConverter.getModelLineViewLineCount(originalLineNumber);\r\n\t\t\t\t\tconst modifiedViewLineCount = modifiedCoordinatesConverter.getModelLineViewLineCount(modifiedLineNumber);\r\n\r\n\t\t\t\t\tif (originalViewLineCount < modifiedViewLineCount) {\r\n\t\t\t\t\t\tstepOriginal.push({\r\n\t\t\t\t\t\t\tafterLineNumber: originalLineNumber,\r\n\t\t\t\t\t\t\theightInLines: modifiedViewLineCount - originalViewLineCount,\r\n\t\t\t\t\t\t\tdomNode: null,\r\n\t\t\t\t\t\t\tmarginDomNode: null\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t} else if (originalViewLineCount > modifiedViewLineCount) {\r\n\t\t\t\t\t\tstepModified.push({\r\n\t\t\t\t\t\t\tafterLineNumber: modifiedLineNumber,\r\n\t\t\t\t\t\t\theightInLines: originalViewLineCount - modifiedViewLineCount,\r\n\t\t\t\t\t\t\tdomNode: null,\r\n\t\t\t\t\t\t\tmarginDomNode: null\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tif (lineChange) {\r\n\t\t\t\t\tlastOriginalLineNumber = (lineChange.originalEndLineNumber > 0 ? lineChange.originalEndLineNumber : lineChange.originalStartLineNumber) + 1;\r\n\t\t\t\t\tlastModifiedLineNumber = (lineChange.modifiedEndLineNumber > 0 ? lineChange.modifiedEndLineNumber : lineChange.modifiedStartLineNumber) + 1;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// [PRODUCE] View zone(s) in original-side due to foreign view zone(s) in modified-side\r\n\t\t\twhile (modifiedForeignVZ.current && modifiedForeignVZ.current.afterLineNumber <= modifiedEndEquivalentLineNumber) {\r\n\t\t\t\tlet viewZoneLineNumber: number;\r\n\t\t\t\tif (modifiedForeignVZ.current.afterLineNumber <= modifiedEquivalentLineNumber) {\r\n\t\t\t\t\tviewZoneLineNumber = originalEquivalentLineNumber - modifiedEquivalentLineNumber + modifiedForeignVZ.current.afterLineNumber;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tviewZoneLineNumber = originalEndEquivalentLineNumber;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tlet marginDomNode: HTMLDivElement | null = null;\r\n\t\t\t\tif (lineChange && lineChange.modifiedStartLineNumber <= modifiedForeignVZ.current.afterLineNumber && modifiedForeignVZ.current.afterLineNumber <= lineChange.modifiedEndLineNumber) {\r\n\t\t\t\t\tmarginDomNode = this._createOriginalMarginDomNodeForModifiedForeignViewZoneInAddedRegion();\r\n\t\t\t\t}\r\n\r\n\t\t\t\tstepOriginal.push({\r\n\t\t\t\t\tafterLineNumber: viewZoneLineNumber,\r\n\t\t\t\t\theightInLines: modifiedForeignVZ.current.height / modifiedLineHeight,\r\n\t\t\t\t\tdomNode: null,\r\n\t\t\t\t\tmarginDomNode: marginDomNode\r\n\t\t\t\t});\r\n\t\t\t\tmodifiedForeignVZ.advance();\r\n\t\t\t}\r\n\r\n\t\t\t// [PRODUCE] View zone(s) in modified-side due to foreign view zone(s) in original-side\r\n\t\t\twhile (originalForeignVZ.current && originalForeignVZ.current.afterLineNumber <= originalEndEquivalentLineNumber) {\r\n\t\t\t\tlet viewZoneLineNumber: number;\r\n\t\t\t\tif (originalForeignVZ.current.afterLineNumber <= originalEquivalentLineNumber) {\r\n\t\t\t\t\tviewZoneLineNumber = modifiedEquivalentLineNumber - originalEquivalentLineNumber + originalForeignVZ.current.afterLineNumber;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tviewZoneLineNumber = modifiedEndEquivalentLineNumber;\r\n\t\t\t\t}\r\n\t\t\t\tstepModified.push({\r\n\t\t\t\t\tafterLineNumber: viewZoneLineNumber,\r\n\t\t\t\t\theightInLines: originalForeignVZ.current.height / originalLineHeight,\r\n\t\t\t\t\tdomNode: null\r\n\t\t\t\t});\r\n\t\t\t\toriginalForeignVZ.advance();\r\n\t\t\t}\r\n\r\n\t\t\tif (lineChange !== null && isChangeOrInsert(lineChange)) {\r\n\t\t\t\tconst r = this._produceOriginalFromDiff(lineChange, lineChangeOriginalLength, lineChangeModifiedLength);\r\n\t\t\t\tif (r) {\r\n\t\t\t\t\tstepOriginal.push(r);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (lineChange !== null && isChangeOrDelete(lineChange)) {\r\n\t\t\t\tconst r = this._produceModifiedFromDiff(lineChange, lineChangeOriginalLength, lineChangeModifiedLength);\r\n\t\t\t\tif (r) {\r\n\t\t\t\t\tstepModified.push(r);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// ---------------------------- END PRODUCE VIEW ZONES\r\n\r\n\r\n\t\t\t// ---------------------------- EMIT MINIMAL VIEW ZONES\r\n\r\n\t\t\t// [CANCEL & EMIT] Try to cancel view zones out\r\n\t\t\tlet stepOriginalIndex = 0;\r\n\t\t\tlet stepModifiedIndex = 0;\r\n\r\n\t\t\tstepOriginal = stepOriginal.sort(sortMyViewZones);\r\n\t\t\tstepModified = stepModified.sort(sortMyViewZones);\r\n\r\n\t\t\twhile (stepOriginalIndex < stepOriginal.length && stepModifiedIndex < stepModified.length) {\r\n\t\t\t\tconst original = stepOriginal[stepOriginalIndex];\r\n\t\t\t\tconst modified = stepModified[stepModifiedIndex];\r\n\r\n\t\t\t\tconst originalDelta = original.afterLineNumber - originalEquivalentLineNumber;\r\n\t\t\t\tconst modifiedDelta = modified.afterLineNumber - modifiedEquivalentLineNumber;\r\n\r\n\t\t\t\tif (originalDelta < modifiedDelta) {\r\n\t\t\t\t\taddAndCombineIfPossible(result.original, original);\r\n\t\t\t\t\tstepOriginalIndex++;\r\n\t\t\t\t} else if (modifiedDelta < originalDelta) {\r\n\t\t\t\t\taddAndCombineIfPossible(result.modified, modified);\r\n\t\t\t\t\tstepModifiedIndex++;\r\n\t\t\t\t} else if (original.shouldNotShrink) {\r\n\t\t\t\t\taddAndCombineIfPossible(result.original, original);\r\n\t\t\t\t\tstepOriginalIndex++;\r\n\t\t\t\t} else if (modified.shouldNotShrink) {\r\n\t\t\t\t\taddAndCombineIfPossible(result.modified, modified);\r\n\t\t\t\t\tstepModifiedIndex++;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tif (original.heightInLines >= modified.heightInLines) {\r\n\t\t\t\t\t\t// modified view zone gets removed\r\n\t\t\t\t\t\toriginal.heightInLines -= modified.heightInLines;\r\n\t\t\t\t\t\tstepModifiedIndex++;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t// original view zone gets removed\r\n\t\t\t\t\t\tmodified.heightInLines -= original.heightInLines;\r\n\t\t\t\t\t\tstepOriginalIndex++;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// [EMIT] Remaining original view zones\r\n\t\t\twhile (stepOriginalIndex < stepOriginal.length) {\r\n\t\t\t\taddAndCombineIfPossible(result.original, stepOriginal[stepOriginalIndex]);\r\n\t\t\t\tstepOriginalIndex++;\r\n\t\t\t}\r\n\r\n\t\t\t// [EMIT] Remaining modified view zones\r\n\t\t\twhile (stepModifiedIndex < stepModified.length) {\r\n\t\t\t\taddAndCombineIfPossible(result.modified, stepModified[stepModifiedIndex]);\r\n\t\t\t\tstepModifiedIndex++;\r\n\t\t\t}\r\n\r\n\t\t\t// ---------------------------- END EMIT MINIMAL VIEW ZONES\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\toriginal: ViewZonesComputer._ensureDomNodes(result.original),\r\n\t\t\tmodified: ViewZonesComputer._ensureDomNodes(result.modified),\r\n\t\t};\r\n\t}\r\n\r\n\tprivate static _ensureDomNodes(zones: IMyViewZone[]): IMyViewZone[] {\r\n\t\treturn zones.map((z) => {\r\n\t\t\tif (!z.domNode) {\r\n\t\t\t\tz.domNode = createFakeLinesDiv();\r\n\t\t\t}\r\n\t\t\treturn z;\r\n\t\t});\r\n\t}\r\n\r\n\tprotected abstract _createOriginalMarginDomNodeForModifiedForeignViewZoneInAddedRegion(): HTMLDivElement | null;\r\n\r\n\tprotected abstract _produceOriginalFromDiff(lineChange: editorCommon.ILineChange, lineChangeOriginalLength: number, lineChangeModifiedLength: number): IMyViewZone | null;\r\n\r\n\tprotected abstract _produceModifiedFromDiff(lineChange: editorCommon.ILineChange, lineChangeOriginalLength: number, lineChangeModifiedLength: number): IMyViewZone | null;\r\n}\r\n\r\nfunction createDecoration(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, options: ModelDecorationOptions) {\r\n\treturn {\r\n\t\trange: new Range(startLineNumber, startColumn, endLineNumber, endColumn),\r\n\t\toptions: options\r\n\t};\r\n}\r\n\r\nconst DECORATIONS = {\r\n\r\n\tcharDelete: ModelDecorationOptions.register({\r\n\t\tclassName: 'char-delete'\r\n\t}),\r\n\tcharDeleteWholeLine: ModelDecorationOptions.register({\r\n\t\tclassName: 'char-delete',\r\n\t\tisWholeLine: true\r\n\t}),\r\n\r\n\tcharInsert: ModelDecorationOptions.register({\r\n\t\tclassName: 'char-insert'\r\n\t}),\r\n\tcharInsertWholeLine: ModelDecorationOptions.register({\r\n\t\tclassName: 'char-insert',\r\n\t\tisWholeLine: true\r\n\t}),\r\n\r\n\tlineInsert: ModelDecorationOptions.register({\r\n\t\tclassName: 'line-insert',\r\n\t\tmarginClassName: 'line-insert',\r\n\t\tisWholeLine: true\r\n\t}),\r\n\tlineInsertWithSign: ModelDecorationOptions.register({\r\n\t\tclassName: 'line-insert',\r\n\t\tlinesDecorationsClassName: 'insert-sign ' + ThemeIcon.asClassName(diffInsertIcon),\r\n\t\tmarginClassName: 'line-insert',\r\n\t\tisWholeLine: true\r\n\t}),\r\n\r\n\tlineDelete: ModelDecorationOptions.register({\r\n\t\tclassName: 'line-delete',\r\n\t\tmarginClassName: 'line-delete',\r\n\t\tisWholeLine: true\r\n\t}),\r\n\tlineDeleteWithSign: ModelDecorationOptions.register({\r\n\t\tclassName: 'line-delete',\r\n\t\tlinesDecorationsClassName: 'delete-sign ' + ThemeIcon.asClassName(diffRemoveIcon),\r\n\t\tmarginClassName: 'line-delete',\r\n\t\tisWholeLine: true\r\n\r\n\t}),\r\n\tlineDeleteMargin: ModelDecorationOptions.register({\r\n\t\tmarginClassName: 'line-delete',\r\n\t})\r\n\r\n};\r\n\r\nclass DiffEditorWidgetSideBySide extends DiffEditorWidgetStyle implements IVerticalSashLayoutProvider {\r\n\r\n\tstatic readonly MINIMUM_EDITOR_WIDTH = 100;\r\n\r\n\tprivate _disableSash: boolean;\r\n\tprivate readonly _sash: Sash;\r\n\tprivate _sashRatio: number | null;\r\n\tprivate _sashPosition: number | null;\r\n\tprivate _startSashPosition: number | null;\r\n\r\n\tconstructor(dataSource: IDataSource, enableSplitViewResizing: boolean) {\r\n\t\tsuper(dataSource);\r\n\r\n\t\tthis._disableSash = (enableSplitViewResizing === false);\r\n\t\tthis._sashRatio = null;\r\n\t\tthis._sashPosition = null;\r\n\t\tthis._startSashPosition = null;\r\n\t\tthis._sash = this._register(new Sash(this._dataSource.getContainerDomNode(), this, { orientation: Orientation.VERTICAL }));\r\n\r\n\t\tif (this._disableSash) {\r\n\t\t\tthis._sash.state = SashState.Disabled;\r\n\t\t}\r\n\r\n\t\tthis._sash.onDidStart(() => this._onSashDragStart());\r\n\t\tthis._sash.onDidChange((e: ISashEvent) => this._onSashDrag(e));\r\n\t\tthis._sash.onDidEnd(() => this._onSashDragEnd());\r\n\t\tthis._sash.onDidReset(() => this._onSashReset());\r\n\t}\r\n\r\n\tpublic setEnableSplitViewResizing(enableSplitViewResizing: boolean): void {\r\n\t\tconst newDisableSash = (enableSplitViewResizing === false);\r\n\t\tif (this._disableSash !== newDisableSash) {\r\n\t\t\tthis._disableSash = newDisableSash;\r\n\t\t\tthis._sash.state = this._disableSash ? SashState.Disabled : SashState.Enabled;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic layout(sashRatio: number | null = this._sashRatio): number {\r\n\t\tconst w = this._dataSource.getWidth();\r\n\t\tconst contentWidth = w - (this._dataSource.getOptions().renderOverviewRuler ? DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH : 0);\r\n\r\n\t\tlet sashPosition = Math.floor((sashRatio || 0.5) * contentWidth);\r\n\t\tconst midPoint = Math.floor(0.5 * contentWidth);\r\n\r\n\t\tsashPosition = this._disableSash ? midPoint : sashPosition || midPoint;\r\n\r\n\t\tif (contentWidth > DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH * 2) {\r\n\t\t\tif (sashPosition < DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH) {\r\n\t\t\t\tsashPosition = DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH;\r\n\t\t\t}\r\n\r\n\t\t\tif (sashPosition > contentWidth - DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH) {\r\n\t\t\t\tsashPosition = contentWidth - DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tsashPosition = midPoint;\r\n\t\t}\r\n\r\n\t\tif (this._sashPosition !== sashPosition) {\r\n\t\t\tthis._sashPosition = sashPosition;\r\n\t\t\tthis._sash.layout();\r\n\t\t}\r\n\r\n\t\treturn this._sashPosition;\r\n\t}\r\n\r\n\tprivate _onSashDragStart(): void {\r\n\t\tthis._startSashPosition = this._sashPosition!;\r\n\t}\r\n\r\n\tprivate _onSashDrag(e: ISashEvent): void {\r\n\t\tconst w = this._dataSource.getWidth();\r\n\t\tconst contentWidth = w - (this._dataSource.getOptions().renderOverviewRuler ? DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH : 0);\r\n\t\tconst sashPosition = this.layout((this._startSashPosition! + (e.currentX - e.startX)) / contentWidth);\r\n\r\n\t\tthis._sashRatio = sashPosition / contentWidth;\r\n\r\n\t\tthis._dataSource.relayoutEditors();\r\n\t}\r\n\r\n\tprivate _onSashDragEnd(): void {\r\n\t\tthis._sash.layout();\r\n\t}\r\n\r\n\tprivate _onSashReset(): void {\r\n\t\tthis._sashRatio = 0.5;\r\n\t\tthis._dataSource.relayoutEditors();\r\n\t\tthis._sash.layout();\r\n\t}\r\n\r\n\tpublic getVerticalSashTop(sash: Sash): number {\r\n\t\treturn 0;\r\n\t}\r\n\r\n\tpublic getVerticalSashLeft(sash: Sash): number {\r\n\t\treturn this._sashPosition!;\r\n\t}\r\n\r\n\tpublic getVerticalSashHeight(sash: Sash): number {\r\n\t\treturn this._dataSource.getHeight();\r\n\t}\r\n\r\n\tprotected _getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[]): IEditorsZones {\r\n\t\tconst originalEditor = this._dataSource.getOriginalEditor();\r\n\t\tconst modifiedEditor = this._dataSource.getModifiedEditor();\r\n\t\tconst c = new SideBySideViewZonesComputer(lineChanges, originalForeignVZ, modifiedForeignVZ, originalEditor, modifiedEditor);\r\n\t\treturn c.getViewZones();\r\n\t}\r\n\r\n\tprotected _getOriginalEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean): IEditorDiffDecorations {\r\n\t\tconst originalEditor = this._dataSource.getOriginalEditor();\r\n\t\tconst overviewZoneColor = String(this._removeColor);\r\n\r\n\t\tconst result: IEditorDiffDecorations = {\r\n\t\t\tdecorations: [],\r\n\t\t\toverviewZones: []\r\n\t\t};\r\n\r\n\t\tconst originalModel = originalEditor.getModel()!;\r\n\t\tconst originalViewModel = originalEditor._getViewModel()!;\r\n\r\n\t\tfor (const lineChange of lineChanges) {\r\n\r\n\t\t\tif (isChangeOrDelete(lineChange)) {\r\n\t\t\t\tresult.decorations.push({\r\n\t\t\t\t\trange: new Range(lineChange.originalStartLineNumber, 1, lineChange.originalEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER),\r\n\t\t\t\t\toptions: (renderIndicators ? DECORATIONS.lineDeleteWithSign : DECORATIONS.lineDelete)\r\n\t\t\t\t});\r\n\t\t\t\tif (!isChangeOrInsert(lineChange) || !lineChange.charChanges) {\r\n\t\t\t\t\tresult.decorations.push(createDecoration(lineChange.originalStartLineNumber, 1, lineChange.originalEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER, DECORATIONS.charDeleteWholeLine));\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst viewRange = getViewRange(originalModel, originalViewModel, lineChange.originalStartLineNumber, lineChange.originalEndLineNumber);\r\n\t\t\t\tresult.overviewZones.push(new OverviewRulerZone(viewRange.startLineNumber, viewRange.endLineNumber, overviewZoneColor));\r\n\r\n\t\t\t\tif (lineChange.charChanges) {\r\n\t\t\t\t\tfor (const charChange of lineChange.charChanges) {\r\n\t\t\t\t\t\tif (isChangeOrDelete(charChange)) {\r\n\t\t\t\t\t\t\tif (ignoreTrimWhitespace) {\r\n\t\t\t\t\t\t\t\tfor (let lineNumber = charChange.originalStartLineNumber; lineNumber <= charChange.originalEndLineNumber; lineNumber++) {\r\n\t\t\t\t\t\t\t\t\tlet startColumn: number;\r\n\t\t\t\t\t\t\t\t\tlet endColumn: number;\r\n\t\t\t\t\t\t\t\t\tif (lineNumber === charChange.originalStartLineNumber) {\r\n\t\t\t\t\t\t\t\t\t\tstartColumn = charChange.originalStartColumn;\r\n\t\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\t\tstartColumn = originalModel.getLineFirstNonWhitespaceColumn(lineNumber);\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\tif (lineNumber === charChange.originalEndLineNumber) {\r\n\t\t\t\t\t\t\t\t\t\tendColumn = charChange.originalEndColumn;\r\n\t\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\t\tendColumn = originalModel.getLineLastNonWhitespaceColumn(lineNumber);\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\tresult.decorations.push(createDecoration(lineNumber, startColumn, lineNumber, endColumn, DECORATIONS.charDelete));\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\tresult.decorations.push(createDecoration(charChange.originalStartLineNumber, charChange.originalStartColumn, charChange.originalEndLineNumber, charChange.originalEndColumn, DECORATIONS.charDelete));\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprotected _getModifiedEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean): IEditorDiffDecorations {\r\n\t\tconst modifiedEditor = this._dataSource.getModifiedEditor();\r\n\t\tconst overviewZoneColor = String(this._insertColor);\r\n\r\n\t\tconst result: IEditorDiffDecorations = {\r\n\t\t\tdecorations: [],\r\n\t\t\toverviewZones: []\r\n\t\t};\r\n\r\n\t\tconst modifiedModel = modifiedEditor.getModel()!;\r\n\t\tconst modifiedViewModel = modifiedEditor._getViewModel()!;\r\n\r\n\t\tfor (const lineChange of lineChanges) {\r\n\r\n\t\t\tif (isChangeOrInsert(lineChange)) {\r\n\r\n\t\t\t\tresult.decorations.push({\r\n\t\t\t\t\trange: new Range(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER),\r\n\t\t\t\t\toptions: (renderIndicators ? DECORATIONS.lineInsertWithSign : DECORATIONS.lineInsert)\r\n\t\t\t\t});\r\n\t\t\t\tif (!isChangeOrDelete(lineChange) || !lineChange.charChanges) {\r\n\t\t\t\t\tresult.decorations.push(createDecoration(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER, DECORATIONS.charInsertWholeLine));\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst viewRange = getViewRange(modifiedModel, modifiedViewModel, lineChange.modifiedStartLineNumber, lineChange.modifiedEndLineNumber);\r\n\t\t\t\tresult.overviewZones.push(new OverviewRulerZone(viewRange.startLineNumber, viewRange.endLineNumber, overviewZoneColor));\r\n\r\n\t\t\t\tif (lineChange.charChanges) {\r\n\t\t\t\t\tfor (const charChange of lineChange.charChanges) {\r\n\t\t\t\t\t\tif (isChangeOrInsert(charChange)) {\r\n\t\t\t\t\t\t\tif (ignoreTrimWhitespace) {\r\n\t\t\t\t\t\t\t\tfor (let lineNumber = charChange.modifiedStartLineNumber; lineNumber <= charChange.modifiedEndLineNumber; lineNumber++) {\r\n\t\t\t\t\t\t\t\t\tlet startColumn: number;\r\n\t\t\t\t\t\t\t\t\tlet endColumn: number;\r\n\t\t\t\t\t\t\t\t\tif (lineNumber === charChange.modifiedStartLineNumber) {\r\n\t\t\t\t\t\t\t\t\t\tstartColumn = charChange.modifiedStartColumn;\r\n\t\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\t\tstartColumn = modifiedModel.getLineFirstNonWhitespaceColumn(lineNumber);\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\tif (lineNumber === charChange.modifiedEndLineNumber) {\r\n\t\t\t\t\t\t\t\t\t\tendColumn = charChange.modifiedEndColumn;\r\n\t\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\t\tendColumn = modifiedModel.getLineLastNonWhitespaceColumn(lineNumber);\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\tresult.decorations.push(createDecoration(lineNumber, startColumn, lineNumber, endColumn, DECORATIONS.charInsert));\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\tresult.decorations.push(createDecoration(charChange.modifiedStartLineNumber, charChange.modifiedStartColumn, charChange.modifiedEndLineNumber, charChange.modifiedEndColumn, DECORATIONS.charInsert));\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n}\r\n\r\nclass SideBySideViewZonesComputer extends ViewZonesComputer {\r\n\r\n\tconstructor(\r\n\t\tlineChanges: editorCommon.ILineChange[],\r\n\t\toriginalForeignVZ: IEditorWhitespace[],\r\n\t\tmodifiedForeignVZ: IEditorWhitespace[],\r\n\t\toriginalEditor: CodeEditorWidget,\r\n\t\tmodifiedEditor: CodeEditorWidget,\r\n\t) {\r\n\t\tsuper(lineChanges, originalForeignVZ, modifiedForeignVZ, originalEditor, modifiedEditor);\r\n\t}\r\n\r\n\tprotected _createOriginalMarginDomNodeForModifiedForeignViewZoneInAddedRegion(): HTMLDivElement | null {\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprotected _produceOriginalFromDiff(lineChange: editorCommon.ILineChange, lineChangeOriginalLength: number, lineChangeModifiedLength: number): IMyViewZone | null {\r\n\t\tif (lineChangeModifiedLength > lineChangeOriginalLength) {\r\n\t\t\treturn {\r\n\t\t\t\tafterLineNumber: Math.max(lineChange.originalStartLineNumber, lineChange.originalEndLineNumber),\r\n\t\t\t\theightInLines: (lineChangeModifiedLength - lineChangeOriginalLength),\r\n\t\t\t\tdomNode: null\r\n\t\t\t};\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprotected _produceModifiedFromDiff(lineChange: editorCommon.ILineChange, lineChangeOriginalLength: number, lineChangeModifiedLength: number): IMyViewZone | null {\r\n\t\tif (lineChangeOriginalLength > lineChangeModifiedLength) {\r\n\t\t\treturn {\r\n\t\t\t\tafterLineNumber: Math.max(lineChange.modifiedStartLineNumber, lineChange.modifiedEndLineNumber),\r\n\t\t\t\theightInLines: (lineChangeOriginalLength - lineChangeModifiedLength),\r\n\t\t\t\tdomNode: null\r\n\t\t\t};\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n}\r\n\r\nclass DiffEditorWidgetInline extends DiffEditorWidgetStyle {\r\n\r\n\tprivate _decorationsLeft: number;\r\n\r\n\tconstructor(dataSource: IDataSource, enableSplitViewResizing: boolean) {\r\n\t\tsuper(dataSource);\r\n\r\n\t\tthis._decorationsLeft = dataSource.getOriginalEditor().getLayoutInfo().decorationsLeft;\r\n\r\n\t\tthis._register(dataSource.getOriginalEditor().onDidLayoutChange((layoutInfo: EditorLayoutInfo) => {\r\n\t\t\tif (this._decorationsLeft !== layoutInfo.decorationsLeft) {\r\n\t\t\t\tthis._decorationsLeft = layoutInfo.decorationsLeft;\r\n\t\t\t\tdataSource.relayoutEditors();\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\tpublic setEnableSplitViewResizing(enableSplitViewResizing: boolean): void {\r\n\t\t// Nothing to do..\r\n\t}\r\n\r\n\tprotected _getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], renderIndicators: boolean): IEditorsZones {\r\n\t\tconst originalEditor = this._dataSource.getOriginalEditor();\r\n\t\tconst modifiedEditor = this._dataSource.getModifiedEditor();\r\n\t\tconst computer = new InlineViewZonesComputer(lineChanges, originalForeignVZ, modifiedForeignVZ, originalEditor, modifiedEditor, renderIndicators);\r\n\t\treturn computer.getViewZones();\r\n\t}\r\n\r\n\tprotected _getOriginalEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean): IEditorDiffDecorations {\r\n\t\tconst overviewZoneColor = String(this._removeColor);\r\n\r\n\t\tconst result: IEditorDiffDecorations = {\r\n\t\t\tdecorations: [],\r\n\t\t\toverviewZones: []\r\n\t\t};\r\n\r\n\t\tconst originalEditor = this._dataSource.getOriginalEditor();\r\n\t\tconst originalModel = originalEditor.getModel()!;\r\n\t\tconst originalViewModel = originalEditor._getViewModel()!;\r\n\r\n\t\tfor (const lineChange of lineChanges) {\r\n\r\n\t\t\t// Add overview zones in the overview ruler\r\n\t\t\tif (isChangeOrDelete(lineChange)) {\r\n\t\t\t\tresult.decorations.push({\r\n\t\t\t\t\trange: new Range(lineChange.originalStartLineNumber, 1, lineChange.originalEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER),\r\n\t\t\t\t\toptions: DECORATIONS.lineDeleteMargin\r\n\t\t\t\t});\r\n\r\n\t\t\t\tconst viewRange = getViewRange(originalModel, originalViewModel, lineChange.originalStartLineNumber, lineChange.originalEndLineNumber);\r\n\t\t\t\tresult.overviewZones.push(new OverviewRulerZone(viewRange.startLineNumber, viewRange.endLineNumber, overviewZoneColor));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprotected _getModifiedEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean): IEditorDiffDecorations {\r\n\t\tconst modifiedEditor = this._dataSource.getModifiedEditor();\r\n\t\tconst overviewZoneColor = String(this._insertColor);\r\n\r\n\t\tconst result: IEditorDiffDecorations = {\r\n\t\t\tdecorations: [],\r\n\t\t\toverviewZones: []\r\n\t\t};\r\n\r\n\t\tconst modifiedModel = modifiedEditor.getModel()!;\r\n\t\tconst modifiedViewModel = modifiedEditor._getViewModel()!;\r\n\r\n\t\tfor (const lineChange of lineChanges) {\r\n\r\n\t\t\t// Add decorations & overview zones\r\n\t\t\tif (isChangeOrInsert(lineChange)) {\r\n\t\t\t\tresult.decorations.push({\r\n\t\t\t\t\trange: new Range(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER),\r\n\t\t\t\t\toptions: (renderIndicators ? DECORATIONS.lineInsertWithSign : DECORATIONS.lineInsert)\r\n\t\t\t\t});\r\n\r\n\t\t\t\tconst viewRange = getViewRange(modifiedModel, modifiedViewModel, lineChange.modifiedStartLineNumber, lineChange.modifiedEndLineNumber);\r\n\t\t\t\tresult.overviewZones.push(new OverviewRulerZone(viewRange.startLineNumber, viewRange.endLineNumber, overviewZoneColor));\r\n\r\n\t\t\t\tif (lineChange.charChanges) {\r\n\t\t\t\t\tfor (const charChange of lineChange.charChanges) {\r\n\t\t\t\t\t\tif (isChangeOrInsert(charChange)) {\r\n\t\t\t\t\t\t\tif (ignoreTrimWhitespace) {\r\n\t\t\t\t\t\t\t\tfor (let lineNumber = charChange.modifiedStartLineNumber; lineNumber <= charChange.modifiedEndLineNumber; lineNumber++) {\r\n\t\t\t\t\t\t\t\t\tlet startColumn: number;\r\n\t\t\t\t\t\t\t\t\tlet endColumn: number;\r\n\t\t\t\t\t\t\t\t\tif (lineNumber === charChange.modifiedStartLineNumber) {\r\n\t\t\t\t\t\t\t\t\t\tstartColumn = charChange.modifiedStartColumn;\r\n\t\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\t\tstartColumn = modifiedModel.getLineFirstNonWhitespaceColumn(lineNumber);\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\tif (lineNumber === charChange.modifiedEndLineNumber) {\r\n\t\t\t\t\t\t\t\t\t\tendColumn = charChange.modifiedEndColumn;\r\n\t\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\t\tendColumn = modifiedModel.getLineLastNonWhitespaceColumn(lineNumber);\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\tresult.decorations.push(createDecoration(lineNumber, startColumn, lineNumber, endColumn, DECORATIONS.charInsert));\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\tresult.decorations.push(createDecoration(charChange.modifiedStartLineNumber, charChange.modifiedStartColumn, charChange.modifiedEndLineNumber, charChange.modifiedEndColumn, DECORATIONS.charInsert));\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tresult.decorations.push(createDecoration(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER, DECORATIONS.charInsertWholeLine));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic layout(): number {\r\n\t\t// An editor should not be smaller than 5px\r\n\t\treturn Math.max(5, this._decorationsLeft);\r\n\t}\r\n\r\n}\r\n\r\ninterface InlineModifiedViewZone extends IMyViewZone {\r\n\tshouldNotShrink: boolean;\r\n\tafterLineNumber: number;\r\n\theightInLines: number;\r\n\tminWidthInPx: number;\r\n\tdomNode: HTMLElement;\r\n\tmarginDomNode: HTMLElement;\r\n\tdiff: IDiffLinesChange;\r\n}\r\n\r\nclass InlineViewZonesComputer extends ViewZonesComputer {\r\n\r\n\tprivate readonly _originalModel: ITextModel;\r\n\tprivate readonly _renderIndicators: boolean;\r\n\tprivate readonly _pendingLineChange: editorCommon.ILineChange[];\r\n\tprivate readonly _pendingViewZones: InlineModifiedViewZone[];\r\n\tprivate readonly _lineBreaksComputer: ILineBreaksComputer;\r\n\r\n\tconstructor(\r\n\t\tlineChanges: editorCommon.ILineChange[],\r\n\t\toriginalForeignVZ: IEditorWhitespace[],\r\n\t\tmodifiedForeignVZ: IEditorWhitespace[],\r\n\t\toriginalEditor: CodeEditorWidget,\r\n\t\tmodifiedEditor: CodeEditorWidget,\r\n\t\trenderIndicators: boolean\r\n\t) {\r\n\t\tsuper(lineChanges, originalForeignVZ, modifiedForeignVZ, originalEditor, modifiedEditor);\r\n\t\tthis._originalModel = originalEditor.getModel()!;\r\n\t\tthis._renderIndicators = renderIndicators;\r\n\t\tthis._pendingLineChange = [];\r\n\t\tthis._pendingViewZones = [];\r\n\t\tthis._lineBreaksComputer = this._modifiedEditor._getViewModel()!.createLineBreaksComputer();\r\n\t}\r\n\r\n\tpublic getViewZones(): IEditorsZones {\r\n\t\tconst result = super.getViewZones();\r\n\t\tthis._finalize(result);\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprotected _createOriginalMarginDomNodeForModifiedForeignViewZoneInAddedRegion(): HTMLDivElement | null {\r\n\t\tconst result = document.createElement('div');\r\n\t\tresult.className = 'inline-added-margin-view-zone';\r\n\t\treturn result;\r\n\t}\r\n\r\n\tprotected _produceOriginalFromDiff(lineChange: editorCommon.ILineChange, lineChangeOriginalLength: number, lineChangeModifiedLength: number): IMyViewZone | null {\r\n\t\tconst marginDomNode = document.createElement('div');\r\n\t\tmarginDomNode.className = 'inline-added-margin-view-zone';\r\n\r\n\t\treturn {\r\n\t\t\tafterLineNumber: Math.max(lineChange.originalStartLineNumber, lineChange.originalEndLineNumber),\r\n\t\t\theightInLines: lineChangeModifiedLength,\r\n\t\t\tdomNode: document.createElement('div'),\r\n\t\t\tmarginDomNode: marginDomNode\r\n\t\t};\r\n\t}\r\n\r\n\tprotected _produceModifiedFromDiff(lineChange: editorCommon.ILineChange, lineChangeOriginalLength: number, lineChangeModifiedLength: number): IMyViewZone | null {\r\n\t\tconst domNode = document.createElement('div');\r\n\t\tdomNode.className = `view-lines line-delete ${MOUSE_CURSOR_TEXT_CSS_CLASS_NAME}`;\r\n\r\n\t\tconst marginDomNode = document.createElement('div');\r\n\t\tmarginDomNode.className = 'inline-deleted-margin-view-zone';\r\n\r\n\t\tconst viewZone: InlineModifiedViewZone = {\r\n\t\t\tshouldNotShrink: true,\r\n\t\t\tafterLineNumber: (lineChange.modifiedEndLineNumber === 0 ? lineChange.modifiedStartLineNumber : lineChange.modifiedStartLineNumber - 1),\r\n\t\t\theightInLines: lineChangeOriginalLength,\r\n\t\t\tminWidthInPx: 0,\r\n\t\t\tdomNode: domNode,\r\n\t\t\tmarginDomNode: marginDomNode,\r\n\t\t\tdiff: {\r\n\t\t\t\toriginalStartLineNumber: lineChange.originalStartLineNumber,\r\n\t\t\t\toriginalEndLineNumber: lineChange.originalEndLineNumber,\r\n\t\t\t\tmodifiedStartLineNumber: lineChange.modifiedStartLineNumber,\r\n\t\t\t\tmodifiedEndLineNumber: lineChange.modifiedEndLineNumber,\r\n\t\t\t\toriginalModel: this._originalModel,\r\n\t\t\t\tviewLineCounts: null,\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tfor (let lineNumber = lineChange.originalStartLineNumber; lineNumber <= lineChange.originalEndLineNumber; lineNumber++) {\r\n\t\t\tthis._lineBreaksComputer.addRequest(this._originalModel.getLineContent(lineNumber), null);\r\n\t\t}\r\n\r\n\t\tthis._pendingLineChange.push(lineChange);\r\n\t\tthis._pendingViewZones.push(viewZone);\r\n\r\n\t\treturn viewZone;\r\n\t}\r\n\r\n\tprivate _finalize(result: IEditorsZones): void {\r\n\t\tconst modifiedEditorOptions = this._modifiedEditor.getOptions();\r\n\t\tconst tabSize = this._modifiedEditor.getModel()!.getOptions().tabSize;\r\n\t\tconst fontInfo = modifiedEditorOptions.get(EditorOption.fontInfo);\r\n\t\tconst disableMonospaceOptimizations = modifiedEditorOptions.get(EditorOption.disableMonospaceOptimizations);\r\n\t\tconst typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth;\r\n\t\tconst scrollBeyondLastColumn = modifiedEditorOptions.get(EditorOption.scrollBeyondLastColumn);\r\n\t\tconst mightContainNonBasicASCII = this._originalModel.mightContainNonBasicASCII();\r\n\t\tconst mightContainRTL = this._originalModel.mightContainRTL();\r\n\t\tconst lineHeight = modifiedEditorOptions.get(EditorOption.lineHeight);\r\n\t\tconst layoutInfo = modifiedEditorOptions.get(EditorOption.layoutInfo);\r\n\t\tconst lineDecorationsWidth = layoutInfo.decorationsWidth;\r\n\t\tconst stopRenderingLineAfter = modifiedEditorOptions.get(EditorOption.stopRenderingLineAfter);\r\n\t\tconst renderWhitespace = modifiedEditorOptions.get(EditorOption.renderWhitespace);\r\n\t\tconst renderControlCharacters = modifiedEditorOptions.get(EditorOption.renderControlCharacters);\r\n\t\tconst fontLigatures = modifiedEditorOptions.get(EditorOption.fontLigatures);\r\n\r\n\t\tconst lineBreaks = this._lineBreaksComputer.finalize();\r\n\t\tlet lineBreakIndex = 0;\r\n\r\n\t\tfor (let i = 0; i < this._pendingLineChange.length; i++) {\r\n\t\t\tconst lineChange = this._pendingLineChange[i];\r\n\t\t\tconst viewZone = this._pendingViewZones[i];\r\n\t\t\tconst domNode = viewZone.domNode;\r\n\t\t\tConfiguration.applyFontInfoSlow(domNode, fontInfo);\r\n\r\n\t\t\tconst marginDomNode = viewZone.marginDomNode;\r\n\t\t\tConfiguration.applyFontInfoSlow(marginDomNode, fontInfo);\r\n\r\n\t\t\tconst decorations: InlineDecoration[] = [];\r\n\t\t\tif (lineChange.charChanges) {\r\n\t\t\t\tfor (const charChange of lineChange.charChanges) {\r\n\t\t\t\t\tif (isChangeOrDelete(charChange)) {\r\n\t\t\t\t\t\tdecorations.push(new InlineDecoration(\r\n\t\t\t\t\t\t\tnew Range(charChange.originalStartLineNumber, charChange.originalStartColumn, charChange.originalEndLineNumber, charChange.originalEndColumn),\r\n\t\t\t\t\t\t\t'char-delete',\r\n\t\t\t\t\t\t\tInlineDecorationType.Regular\r\n\t\t\t\t\t\t));\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tconst hasCharChanges = (decorations.length > 0);\r\n\r\n\t\t\tconst sb = createStringBuilder(10000);\r\n\t\t\tlet maxCharsPerLine = 0;\r\n\t\t\tlet renderedLineCount = 0;\r\n\t\t\tlet viewLineCounts: number[] | null = null;\r\n\t\t\tfor (let lineNumber = lineChange.originalStartLineNumber; lineNumber <= lineChange.originalEndLineNumber; lineNumber++) {\r\n\t\t\t\tconst lineIndex = lineNumber - lineChange.originalStartLineNumber;\r\n\t\t\t\tconst lineTokens = this._originalModel.getLineTokens(lineNumber);\r\n\t\t\t\tconst lineContent = lineTokens.getLineContent();\r\n\t\t\t\tconst lineBreakData = lineBreaks[lineBreakIndex++];\r\n\t\t\t\tconst actualDecorations = LineDecoration.filter(decorations, lineNumber, 1, lineContent.length + 1);\r\n\r\n\t\t\t\tif (lineBreakData) {\r\n\t\t\t\t\tlet lastBreakOffset = 0;\r\n\t\t\t\t\tfor (const breakOffset of lineBreakData.breakOffsets) {\r\n\t\t\t\t\t\tconst viewLineTokens = lineTokens.sliceAndInflate(lastBreakOffset, breakOffset, 0);\r\n\t\t\t\t\t\tconst viewLineContent = lineContent.substring(lastBreakOffset, breakOffset);\r\n\t\t\t\t\t\tmaxCharsPerLine = Math.max(maxCharsPerLine, this._renderOriginalLine(\r\n\t\t\t\t\t\t\trenderedLineCount++,\r\n\t\t\t\t\t\t\tviewLineContent,\r\n\t\t\t\t\t\t\tviewLineTokens,\r\n\t\t\t\t\t\t\tLineDecoration.extractWrapped(actualDecorations, lastBreakOffset, breakOffset),\r\n\t\t\t\t\t\t\thasCharChanges,\r\n\t\t\t\t\t\t\tmightContainNonBasicASCII,\r\n\t\t\t\t\t\t\tmightContainRTL,\r\n\t\t\t\t\t\t\tfontInfo,\r\n\t\t\t\t\t\t\tdisableMonospaceOptimizations,\r\n\t\t\t\t\t\t\tlineHeight,\r\n\t\t\t\t\t\t\tlineDecorationsWidth,\r\n\t\t\t\t\t\t\tstopRenderingLineAfter,\r\n\t\t\t\t\t\t\trenderWhitespace,\r\n\t\t\t\t\t\t\trenderControlCharacters,\r\n\t\t\t\t\t\t\tfontLigatures,\r\n\t\t\t\t\t\t\ttabSize,\r\n\t\t\t\t\t\t\tsb,\r\n\t\t\t\t\t\t\tmarginDomNode\r\n\t\t\t\t\t\t));\r\n\t\t\t\t\t\tlastBreakOffset = breakOffset;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (!viewLineCounts) {\r\n\t\t\t\t\t\tviewLineCounts = [];\r\n\t\t\t\t\t}\r\n\t\t\t\t\t// make sure all lines before this one have an entry in `viewLineCounts`\r\n\t\t\t\t\twhile (viewLineCounts.length < lineIndex) {\r\n\t\t\t\t\t\tviewLineCounts[viewLineCounts.length] = 1;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tviewLineCounts[lineIndex] = lineBreakData.breakOffsets.length;\r\n\t\t\t\t\tviewZone.heightInLines += (lineBreakData.breakOffsets.length - 1);\r\n\t\t\t\t\tconst marginDomNode2 = document.createElement('div');\r\n\t\t\t\t\tmarginDomNode2.className = 'line-delete';\r\n\t\t\t\t\tresult.original.push({\r\n\t\t\t\t\t\tafterLineNumber: lineNumber,\r\n\t\t\t\t\t\tafterColumn: 0,\r\n\t\t\t\t\t\theightInLines: lineBreakData.breakOffsets.length - 1,\r\n\t\t\t\t\t\tdomNode: createFakeLinesDiv(),\r\n\t\t\t\t\t\tmarginDomNode: marginDomNode2\r\n\t\t\t\t\t});\r\n\t\t\t\t} else {\r\n\t\t\t\t\tmaxCharsPerLine = Math.max(maxCharsPerLine, this._renderOriginalLine(\r\n\t\t\t\t\t\trenderedLineCount++,\r\n\t\t\t\t\t\tlineContent,\r\n\t\t\t\t\t\tlineTokens,\r\n\t\t\t\t\t\tactualDecorations,\r\n\t\t\t\t\t\thasCharChanges,\r\n\t\t\t\t\t\tmightContainNonBasicASCII,\r\n\t\t\t\t\t\tmightContainRTL,\r\n\t\t\t\t\t\tfontInfo,\r\n\t\t\t\t\t\tdisableMonospaceOptimizations,\r\n\t\t\t\t\t\tlineHeight,\r\n\t\t\t\t\t\tlineDecorationsWidth,\r\n\t\t\t\t\t\tstopRenderingLineAfter,\r\n\t\t\t\t\t\trenderWhitespace,\r\n\t\t\t\t\t\trenderControlCharacters,\r\n\t\t\t\t\t\tfontLigatures,\r\n\t\t\t\t\t\ttabSize,\r\n\t\t\t\t\t\tsb,\r\n\t\t\t\t\t\tmarginDomNode\r\n\t\t\t\t\t));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tmaxCharsPerLine += scrollBeyondLastColumn;\r\n\r\n\t\t\tconst html = sb.build();\r\n\t\t\tconst trustedhtml = ttPolicy ? ttPolicy.createHTML(html) : html;\r\n\t\t\tdomNode.innerHTML = trustedhtml as string;\r\n\t\t\tviewZone.minWidthInPx = (maxCharsPerLine * typicalHalfwidthCharacterWidth);\r\n\r\n\t\t\tif (viewLineCounts) {\r\n\t\t\t\t// make sure all lines have an entry in `viewLineCounts`\r\n\t\t\t\tconst cnt = lineChange.originalEndLineNumber - lineChange.originalStartLineNumber;\r\n\t\t\t\twhile (viewLineCounts.length <= cnt) {\r\n\t\t\t\t\tviewLineCounts[viewLineCounts.length] = 1;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tviewZone.diff.viewLineCounts = viewLineCounts;\r\n\t\t}\r\n\r\n\t\tresult.original.sort((a, b) => {\r\n\t\t\treturn a.afterLineNumber - b.afterLineNumber;\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _renderOriginalLine(\r\n\t\trenderedLineCount: number,\r\n\t\tlineContent: string,\r\n\t\tlineTokens: IViewLineTokens,\r\n\t\tdecorations: LineDecoration[],\r\n\t\thasCharChanges: boolean,\r\n\t\tmightContainNonBasicASCII: boolean,\r\n\t\tmightContainRTL: boolean,\r\n\t\tfontInfo: FontInfo,\r\n\t\tdisableMonospaceOptimizations: boolean,\r\n\t\tlineHeight: number,\r\n\t\tlineDecorationsWidth: number,\r\n\t\tstopRenderingLineAfter: number,\r\n\t\trenderWhitespace: 'selection' | 'none' | 'boundary' | 'trailing' | 'all',\r\n\t\trenderControlCharacters: boolean,\r\n\t\tfontLigatures: string,\r\n\t\ttabSize: number,\r\n\t\tsb: IStringBuilder,\r\n\t\tmarginDomNode: HTMLElement\r\n\t): number {\r\n\r\n\t\tsb.appendASCIIString('
    ');\r\n\r\n\t\tconst isBasicASCII = ViewLineRenderingData.isBasicASCII(lineContent, mightContainNonBasicASCII);\r\n\t\tconst containsRTL = ViewLineRenderingData.containsRTL(lineContent, isBasicASCII, mightContainRTL);\r\n\t\tconst output = renderViewLine(new RenderLineInput(\r\n\t\t\t(fontInfo.isMonospace && !disableMonospaceOptimizations),\r\n\t\t\tfontInfo.canUseHalfwidthRightwardsArrow,\r\n\t\t\tlineContent,\r\n\t\t\tfalse,\r\n\t\t\tisBasicASCII,\r\n\t\t\tcontainsRTL,\r\n\t\t\t0,\r\n\t\t\tlineTokens,\r\n\t\t\tdecorations,\r\n\t\t\ttabSize,\r\n\t\t\t0,\r\n\t\t\tfontInfo.spaceWidth,\r\n\t\t\tfontInfo.middotWidth,\r\n\t\t\tfontInfo.wsmiddotWidth,\r\n\t\t\tstopRenderingLineAfter,\r\n\t\t\trenderWhitespace,\r\n\t\t\trenderControlCharacters,\r\n\t\t\tfontLigatures !== EditorFontLigatures.OFF,\r\n\t\t\tnull // Send no selections, original line cannot be selected\r\n\t\t), sb);\r\n\r\n\t\tsb.appendASCIIString('
    ');\r\n\r\n\t\tif (this._renderIndicators) {\r\n\t\t\tconst marginElement = document.createElement('div');\r\n\t\t\tmarginElement.className = `delete-sign ${ThemeIcon.asClassName(diffRemoveIcon)}`;\r\n\t\t\tmarginElement.setAttribute('style', `position:absolute;top:${renderedLineCount * lineHeight}px;width:${lineDecorationsWidth}px;height:${lineHeight}px;right:0;`);\r\n\t\t\tmarginDomNode.appendChild(marginElement);\r\n\t\t}\r\n\r\n\t\tconst absoluteOffsets = output.characterMapping.getAbsoluteOffsets();\r\n\t\treturn absoluteOffsets.length > 0 ? absoluteOffsets[absoluteOffsets.length - 1] : 0;\r\n\t}\r\n}\r\n\r\nfunction validateDiffWordWrap(value: 'off' | 'on' | 'inherit' | undefined, defaultValue: 'off' | 'on' | 'inherit'): 'off' | 'on' | 'inherit' {\r\n\treturn validateStringSetOption<'off' | 'on' | 'inherit'>(value, defaultValue, ['off', 'on', 'inherit']);\r\n}\r\n\r\nfunction isChangeOrInsert(lineChange: editorCommon.IChange): boolean {\r\n\treturn lineChange.modifiedEndLineNumber > 0;\r\n}\r\n\r\nfunction isChangeOrDelete(lineChange: editorCommon.IChange): boolean {\r\n\treturn lineChange.originalEndLineNumber > 0;\r\n}\r\n\r\nfunction createFakeLinesDiv(): HTMLElement {\r\n\tconst r = document.createElement('div');\r\n\tr.className = 'diagonal-fill';\r\n\treturn r;\r\n}\r\n\r\nfunction getViewRange(model: ITextModel, viewModel: IViewModel, startLineNumber: number, endLineNumber: number): Range {\r\n\tconst lineCount = model.getLineCount();\r\n\tstartLineNumber = Math.min(lineCount, Math.max(1, startLineNumber));\r\n\tendLineNumber = Math.min(lineCount, Math.max(1, endLineNumber));\r\n\treturn viewModel.coordinatesConverter.convertModelRangeToViewRange(new Range(\r\n\t\tstartLineNumber, model.getLineMinColumn(startLineNumber),\r\n\t\tendLineNumber, model.getLineMaxColumn(endLineNumber)\r\n\t));\r\n}\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst added = theme.getColor(diffInserted);\r\n\tif (added) {\r\n\t\tcollector.addRule(`.monaco-editor .line-insert, .monaco-editor .char-insert { background-color: ${added}; }`);\r\n\t\tcollector.addRule(`.monaco-diff-editor .line-insert, .monaco-diff-editor .char-insert { background-color: ${added}; }`);\r\n\t\tcollector.addRule(`.monaco-editor .inline-added-margin-view-zone { background-color: ${added}; }`);\r\n\t}\r\n\r\n\tconst removed = theme.getColor(diffRemoved);\r\n\tif (removed) {\r\n\t\tcollector.addRule(`.monaco-editor .line-delete, .monaco-editor .char-delete { background-color: ${removed}; }`);\r\n\t\tcollector.addRule(`.monaco-diff-editor .line-delete, .monaco-diff-editor .char-delete { background-color: ${removed}; }`);\r\n\t\tcollector.addRule(`.monaco-editor .inline-deleted-margin-view-zone { background-color: ${removed}; }`);\r\n\t}\r\n\r\n\tconst addedOutline = theme.getColor(diffInsertedOutline);\r\n\tif (addedOutline) {\r\n\t\tcollector.addRule(`.monaco-editor .line-insert, .monaco-editor .char-insert { border: 1px ${theme.type === 'hc' ? 'dashed' : 'solid'} ${addedOutline}; }`);\r\n\t}\r\n\r\n\tconst removedOutline = theme.getColor(diffRemovedOutline);\r\n\tif (removedOutline) {\r\n\t\tcollector.addRule(`.monaco-editor .line-delete, .monaco-editor .char-delete { border: 1px ${theme.type === 'hc' ? 'dashed' : 'solid'} ${removedOutline}; }`);\r\n\t}\r\n\r\n\tconst shadow = theme.getColor(scrollbarShadow);\r\n\tif (shadow) {\r\n\t\tcollector.addRule(`.monaco-diff-editor.side-by-side .editor.modified { box-shadow: -6px 0 5px -5px ${shadow}; }`);\r\n\t}\r\n\r\n\tconst border = theme.getColor(diffBorder);\r\n\tif (border) {\r\n\t\tcollector.addRule(`.monaco-diff-editor.side-by-side .editor.modified { border-left: 1px solid ${border}; }`);\r\n\t}\r\n\r\n\tconst scrollbarSliderBackgroundColor = theme.getColor(scrollbarSliderBackground);\r\n\tif (scrollbarSliderBackgroundColor) {\r\n\t\tcollector.addRule(`\r\n\t\t\t.monaco-diff-editor .diffViewport {\r\n\t\t\t\tbackground: ${scrollbarSliderBackgroundColor};\r\n\t\t\t}\r\n\t\t`);\r\n\t}\r\n\r\n\tconst scrollbarSliderHoverBackgroundColor = theme.getColor(scrollbarSliderHoverBackground);\r\n\tif (scrollbarSliderHoverBackgroundColor) {\r\n\t\tcollector.addRule(`\r\n\t\t\t.monaco-diff-editor .diffViewport:hover {\r\n\t\t\t\tbackground: ${scrollbarSliderHoverBackgroundColor};\r\n\t\t\t}\r\n\t\t`);\r\n\t}\r\n\r\n\tconst scrollbarSliderActiveBackgroundColor = theme.getColor(scrollbarSliderActiveBackground);\r\n\tif (scrollbarSliderActiveBackgroundColor) {\r\n\t\tcollector.addRule(`\r\n\t\t\t.monaco-diff-editor .diffViewport:active {\r\n\t\t\t\tbackground: ${scrollbarSliderActiveBackgroundColor};\r\n\t\t\t}\r\n\t\t`);\r\n\t}\r\n\r\n\tconst diffDiagonalFillColor = theme.getColor(diffDiagonalFill);\r\n\tcollector.addRule(`\r\n\t.monaco-editor .diagonal-fill {\r\n\t\tbackground-image: linear-gradient(\r\n\t\t\t-45deg,\r\n\t\t\t${diffDiagonalFillColor} 12.5%,\r\n\t\t\t#0000 12.5%, #0000 50%,\r\n\t\t\t${diffDiagonalFillColor} 50%, ${diffDiagonalFillColor} 62.5%,\r\n\t\t\t#0000 62.5%, #0000 100%\r\n\t\t);\r\n\t\tbackground-size: 8px 8px;\r\n\t}\r\n\t`);\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./findWidget';\r\nimport * as nls from 'vs/nls';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { IMouseEvent } from 'vs/base/browser/mouseEvent';\r\nimport { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';\r\nimport { alert as alertFn } from 'vs/base/browser/ui/aria/aria';\r\nimport { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox';\r\nimport { FindInput, IFindInputStyles } from 'vs/base/browser/ui/findinput/findInput';\r\nimport { IMessage as InputBoxMessage } from 'vs/base/browser/ui/inputbox/inputBox';\r\nimport { ReplaceInput } from 'vs/base/browser/ui/findinput/replaceInput';\r\nimport { IVerticalSashLayoutProvider, ISashEvent, Orientation, Sash } from 'vs/base/browser/ui/sash/sash';\r\nimport { Widget } from 'vs/base/browser/ui/widget';\r\nimport { Delayer } from 'vs/base/common/async';\r\nimport { Color } from 'vs/base/common/color';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { toDisposable } from 'vs/base/common/lifecycle';\r\nimport * as platform from 'vs/base/common/platform';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, IViewZone, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';\r\nimport { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { CONTEXT_FIND_INPUT_FOCUSED, CONTEXT_REPLACE_INPUT_FOCUSED, FIND_IDS, MATCHES_LIMIT } from 'vs/editor/contrib/find/findModel';\r\nimport { FindReplaceState, FindReplaceStateChangedEvent } from 'vs/editor/contrib/find/findState';\r\nimport { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\r\nimport { contrastBorder, editorFindMatch, editorFindMatchBorder, editorFindMatchHighlight, editorFindMatchHighlightBorder, editorFindRangeHighlight, editorFindRangeHighlightBorder, editorWidgetBackground, editorWidgetBorder, editorWidgetResizeBorder, errorForeground, inputActiveOptionBorder, inputActiveOptionBackground, inputActiveOptionForeground, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow, editorWidgetForeground, focusBorder } from 'vs/platform/theme/common/colorRegistry';\r\nimport { IColorTheme, IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService';\r\nimport { ContextScopedFindInput, ContextScopedReplaceInput } from 'vs/platform/browser/contextScopedHistoryWidget';\r\nimport { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';\r\nimport { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';\r\nimport { INotificationService } from 'vs/platform/notification/common/notification';\r\nimport { Codicon } from 'vs/base/common/codicons';\r\nimport { registerIcon, widgetClose } from 'vs/platform/theme/common/iconRegistry';\r\n\r\nconst findSelectionIcon = registerIcon('find-selection', Codicon.selection, nls.localize('findSelectionIcon', 'Icon for \\'Find in Selection\\' in the editor find widget.'));\r\nconst findCollapsedIcon = registerIcon('find-collapsed', Codicon.chevronRight, nls.localize('findCollapsedIcon', 'Icon to indicate that the editor find widget is collapsed.'));\r\nconst findExpandedIcon = registerIcon('find-expanded', Codicon.chevronDown, nls.localize('findExpandedIcon', 'Icon to indicate that the editor find widget is expanded.'));\r\n\r\nexport const findReplaceIcon = registerIcon('find-replace', Codicon.replace, nls.localize('findReplaceIcon', 'Icon for \\'Replace\\' in the editor find widget.'));\r\nexport const findReplaceAllIcon = registerIcon('find-replace-all', Codicon.replaceAll, nls.localize('findReplaceAllIcon', 'Icon for \\'Replace All\\' in the editor find widget.'));\r\nexport const findPreviousMatchIcon = registerIcon('find-previous-match', Codicon.arrowUp, nls.localize('findPreviousMatchIcon', 'Icon for \\'Find Previous\\' in the editor find widget.'));\r\nexport const findNextMatchIcon = registerIcon('find-next-match', Codicon.arrowDown, nls.localize('findNextMatchIcon', 'Icon for \\'Find Next\\' in the editor find widget.'));\r\n\r\nexport interface IFindController {\r\n\treplace(): void;\r\n\treplaceAll(): void;\r\n\tgetGlobalBufferTerm(): Promise;\r\n}\r\n\r\nconst NLS_FIND_INPUT_LABEL = nls.localize('label.find', \"Find\");\r\nconst NLS_FIND_INPUT_PLACEHOLDER = nls.localize('placeholder.find', \"Find\");\r\nconst NLS_PREVIOUS_MATCH_BTN_LABEL = nls.localize('label.previousMatchButton', \"Previous match\");\r\nconst NLS_NEXT_MATCH_BTN_LABEL = nls.localize('label.nextMatchButton', \"Next match\");\r\nconst NLS_TOGGLE_SELECTION_FIND_TITLE = nls.localize('label.toggleSelectionFind', \"Find in selection\");\r\nconst NLS_CLOSE_BTN_LABEL = nls.localize('label.closeButton', \"Close\");\r\nconst NLS_REPLACE_INPUT_LABEL = nls.localize('label.replace', \"Replace\");\r\nconst NLS_REPLACE_INPUT_PLACEHOLDER = nls.localize('placeholder.replace', \"Replace\");\r\nconst NLS_REPLACE_BTN_LABEL = nls.localize('label.replaceButton', \"Replace\");\r\nconst NLS_REPLACE_ALL_BTN_LABEL = nls.localize('label.replaceAllButton', \"Replace All\");\r\nconst NLS_TOGGLE_REPLACE_MODE_BTN_LABEL = nls.localize('label.toggleReplaceButton', \"Toggle Replace mode\");\r\nconst NLS_MATCHES_COUNT_LIMIT_TITLE = nls.localize('title.matchesCountLimit', \"Only the first {0} results are highlighted, but all find operations work on the entire text.\", MATCHES_LIMIT);\r\nconst NLS_MATCHES_LOCATION = nls.localize('label.matchesLocation', \"{0} of {1}\");\r\nconst NLS_NO_RESULTS = nls.localize('label.noResults', \"No results\");\r\n\r\nconst FIND_WIDGET_INITIAL_WIDTH = 419;\r\nconst PART_WIDTH = 275;\r\nconst FIND_INPUT_AREA_WIDTH = PART_WIDTH - 54;\r\n\r\nlet MAX_MATCHES_COUNT_WIDTH = 69;\r\n// let FIND_ALL_CONTROLS_WIDTH = 17/** Find Input margin-left */ + (MAX_MATCHES_COUNT_WIDTH + 3 + 1) /** Match Results */ + 23 /** Button */ * 4 + 2/** sash */;\r\n\r\nconst FIND_INPUT_AREA_HEIGHT = 33; // The height of Find Widget when Replace Input is not visible.\r\nconst ctrlEnterReplaceAllWarningPromptedKey = 'ctrlEnterReplaceAll.windows.donotask';\r\n\r\nconst ctrlKeyMod = (platform.isMacintosh ? KeyMod.WinCtrl : KeyMod.CtrlCmd);\r\nexport class FindWidgetViewZone implements IViewZone {\r\n\tpublic readonly afterLineNumber: number;\r\n\tpublic heightInPx: number;\r\n\tpublic readonly suppressMouseDown: boolean;\r\n\tpublic readonly domNode: HTMLElement;\r\n\r\n\tconstructor(afterLineNumber: number) {\r\n\t\tthis.afterLineNumber = afterLineNumber;\r\n\r\n\t\tthis.heightInPx = FIND_INPUT_AREA_HEIGHT;\r\n\t\tthis.suppressMouseDown = false;\r\n\t\tthis.domNode = document.createElement('div');\r\n\t\tthis.domNode.className = 'dock-find-viewzone';\r\n\t}\r\n}\r\n\r\nfunction stopPropagationForMultiLineUpwards(event: IKeyboardEvent, value: string, textarea: HTMLTextAreaElement | null) {\r\n\tconst isMultiline = !!value.match(/\\n/);\r\n\tif (textarea && isMultiline && textarea.selectionStart > 0) {\r\n\t\tevent.stopPropagation();\r\n\t\treturn;\r\n\t}\r\n}\r\n\r\nfunction stopPropagationForMultiLineDownwards(event: IKeyboardEvent, value: string, textarea: HTMLTextAreaElement | null) {\r\n\tconst isMultiline = !!value.match(/\\n/);\r\n\tif (textarea && isMultiline && textarea.selectionEnd < textarea.value.length) {\r\n\t\tevent.stopPropagation();\r\n\t\treturn;\r\n\t}\r\n}\r\n\r\nexport class FindWidget extends Widget implements IOverlayWidget, IVerticalSashLayoutProvider {\r\n\tprivate static readonly ID = 'editor.contrib.findWidget';\r\n\tprivate readonly _codeEditor: ICodeEditor;\r\n\tprivate readonly _state: FindReplaceState;\r\n\tprivate readonly _controller: IFindController;\r\n\tprivate readonly _contextViewProvider: IContextViewProvider;\r\n\tprivate readonly _keybindingService: IKeybindingService;\r\n\tprivate readonly _contextKeyService: IContextKeyService;\r\n\tprivate readonly _storageService: IStorageService;\r\n\tprivate readonly _notificationService: INotificationService;\r\n\r\n\tprivate _domNode!: HTMLElement;\r\n\tprivate _cachedHeight: number | null = null;\r\n\tprivate _findInput!: FindInput;\r\n\tprivate _replaceInput!: ReplaceInput;\r\n\r\n\tprivate _toggleReplaceBtn!: SimpleButton;\r\n\tprivate _matchesCount!: HTMLElement;\r\n\tprivate _prevBtn!: SimpleButton;\r\n\tprivate _nextBtn!: SimpleButton;\r\n\tprivate _toggleSelectionFind!: Checkbox;\r\n\tprivate _closeBtn!: SimpleButton;\r\n\tprivate _replaceBtn!: SimpleButton;\r\n\tprivate _replaceAllBtn!: SimpleButton;\r\n\r\n\tprivate _isVisible: boolean;\r\n\tprivate _isReplaceVisible: boolean;\r\n\tprivate _ignoreChangeEvent: boolean;\r\n\tprivate _ctrlEnterReplaceAllWarningPrompted: boolean;\r\n\r\n\tprivate readonly _findFocusTracker: dom.IFocusTracker;\r\n\tprivate readonly _findInputFocused: IContextKey;\r\n\tprivate readonly _replaceFocusTracker: dom.IFocusTracker;\r\n\tprivate readonly _replaceInputFocused: IContextKey;\r\n\tprivate _viewZone?: FindWidgetViewZone;\r\n\tprivate _viewZoneId?: string;\r\n\r\n\tprivate _resizeSash!: Sash;\r\n\tprivate _resized!: boolean;\r\n\tprivate readonly _updateHistoryDelayer: Delayer;\r\n\r\n\tconstructor(\r\n\t\tcodeEditor: ICodeEditor,\r\n\t\tcontroller: IFindController,\r\n\t\tstate: FindReplaceState,\r\n\t\tcontextViewProvider: IContextViewProvider,\r\n\t\tkeybindingService: IKeybindingService,\r\n\t\tcontextKeyService: IContextKeyService,\r\n\t\tthemeService: IThemeService,\r\n\t\tstorageService: IStorageService,\r\n\t\tnotificationService: INotificationService,\r\n\t) {\r\n\t\tsuper();\r\n\t\tthis._codeEditor = codeEditor;\r\n\t\tthis._controller = controller;\r\n\t\tthis._state = state;\r\n\t\tthis._contextViewProvider = contextViewProvider;\r\n\t\tthis._keybindingService = keybindingService;\r\n\t\tthis._contextKeyService = contextKeyService;\r\n\t\tthis._storageService = storageService;\r\n\t\tthis._notificationService = notificationService;\r\n\r\n\t\tthis._ctrlEnterReplaceAllWarningPrompted = !!storageService.getBoolean(ctrlEnterReplaceAllWarningPromptedKey, StorageScope.GLOBAL);\r\n\r\n\t\tthis._isVisible = false;\r\n\t\tthis._isReplaceVisible = false;\r\n\t\tthis._ignoreChangeEvent = false;\r\n\r\n\t\tthis._updateHistoryDelayer = new Delayer(500);\r\n\t\tthis._register(toDisposable(() => this._updateHistoryDelayer.cancel()));\r\n\t\tthis._register(this._state.onFindReplaceStateChange((e) => this._onStateChanged(e)));\r\n\t\tthis._buildDomNode();\r\n\t\tthis._updateButtons();\r\n\t\tthis._tryUpdateWidgetWidth();\r\n\t\tthis._findInput.inputBox.layout();\r\n\r\n\t\tthis._register(this._codeEditor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => {\r\n\t\t\tif (e.hasChanged(EditorOption.readOnly)) {\r\n\t\t\t\tif (this._codeEditor.getOption(EditorOption.readOnly)) {\r\n\t\t\t\t\t// Hide replace part if editor becomes read only\r\n\t\t\t\t\tthis._state.change({ isReplaceRevealed: false }, false);\r\n\t\t\t\t}\r\n\t\t\t\tthis._updateButtons();\r\n\t\t\t}\r\n\t\t\tif (e.hasChanged(EditorOption.layoutInfo)) {\r\n\t\t\t\tthis._tryUpdateWidgetWidth();\r\n\t\t\t}\r\n\r\n\t\t\tif (e.hasChanged(EditorOption.accessibilitySupport)) {\r\n\t\t\t\tthis.updateAccessibilitySupport();\r\n\t\t\t}\r\n\r\n\t\t\tif (e.hasChanged(EditorOption.find)) {\r\n\t\t\t\tconst addExtraSpaceOnTop = this._codeEditor.getOption(EditorOption.find).addExtraSpaceOnTop;\r\n\t\t\t\tif (addExtraSpaceOnTop && !this._viewZone) {\r\n\t\t\t\t\tthis._viewZone = new FindWidgetViewZone(0);\r\n\t\t\t\t\tthis._showViewZone();\r\n\t\t\t\t}\r\n\t\t\t\tif (!addExtraSpaceOnTop && this._viewZone) {\r\n\t\t\t\t\tthis._removeViewZone();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis.updateAccessibilitySupport();\r\n\t\tthis._register(this._codeEditor.onDidChangeCursorSelection(() => {\r\n\t\t\tif (this._isVisible) {\r\n\t\t\t\tthis._updateToggleSelectionFindButton();\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._register(this._codeEditor.onDidFocusEditorWidget(async () => {\r\n\t\t\tif (this._isVisible) {\r\n\t\t\t\tlet globalBufferTerm = await this._controller.getGlobalBufferTerm();\r\n\t\t\t\tif (globalBufferTerm && globalBufferTerm !== this._state.searchString) {\r\n\t\t\t\t\tthis._state.change({ searchString: globalBufferTerm }, false);\r\n\t\t\t\t\tthis._findInput.select();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._findInputFocused = CONTEXT_FIND_INPUT_FOCUSED.bindTo(contextKeyService);\r\n\t\tthis._findFocusTracker = this._register(dom.trackFocus(this._findInput.inputBox.inputElement));\r\n\t\tthis._register(this._findFocusTracker.onDidFocus(() => {\r\n\t\t\tthis._findInputFocused.set(true);\r\n\t\t\tthis._updateSearchScope();\r\n\t\t}));\r\n\t\tthis._register(this._findFocusTracker.onDidBlur(() => {\r\n\t\t\tthis._findInputFocused.set(false);\r\n\t\t}));\r\n\r\n\t\tthis._replaceInputFocused = CONTEXT_REPLACE_INPUT_FOCUSED.bindTo(contextKeyService);\r\n\t\tthis._replaceFocusTracker = this._register(dom.trackFocus(this._replaceInput.inputBox.inputElement));\r\n\t\tthis._register(this._replaceFocusTracker.onDidFocus(() => {\r\n\t\t\tthis._replaceInputFocused.set(true);\r\n\t\t\tthis._updateSearchScope();\r\n\t\t}));\r\n\t\tthis._register(this._replaceFocusTracker.onDidBlur(() => {\r\n\t\t\tthis._replaceInputFocused.set(false);\r\n\t\t}));\r\n\r\n\t\tthis._codeEditor.addOverlayWidget(this);\r\n\t\tif (this._codeEditor.getOption(EditorOption.find).addExtraSpaceOnTop) {\r\n\t\t\tthis._viewZone = new FindWidgetViewZone(0); // Put it before the first line then users can scroll beyond the first line.\r\n\t\t}\r\n\r\n\t\tthis._applyTheme(themeService.getColorTheme());\r\n\t\tthis._register(themeService.onDidColorThemeChange(this._applyTheme.bind(this)));\r\n\r\n\t\tthis._register(this._codeEditor.onDidChangeModel(() => {\r\n\t\t\tif (!this._isVisible) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tthis._viewZoneId = undefined;\r\n\t\t}));\r\n\r\n\r\n\t\tthis._register(this._codeEditor.onDidScrollChange((e) => {\r\n\t\t\tif (e.scrollTopChanged) {\r\n\t\t\t\tthis._layoutViewZone();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\t// for other scroll changes, layout the viewzone in next tick to avoid ruining current rendering.\r\n\t\t\tsetTimeout(() => {\r\n\t\t\t\tthis._layoutViewZone();\r\n\t\t\t}, 0);\r\n\t\t}));\r\n\t}\r\n\r\n\t// ----- IOverlayWidget API\r\n\r\n\tpublic getId(): string {\r\n\t\treturn FindWidget.ID;\r\n\t}\r\n\r\n\tpublic getDomNode(): HTMLElement {\r\n\t\treturn this._domNode;\r\n\t}\r\n\r\n\tpublic getPosition(): IOverlayWidgetPosition | null {\r\n\t\tif (this._isVisible) {\r\n\t\t\treturn {\r\n\t\t\t\tpreference: OverlayWidgetPositionPreference.TOP_RIGHT_CORNER\r\n\t\t\t};\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\t// ----- React to state changes\r\n\r\n\tprivate _onStateChanged(e: FindReplaceStateChangedEvent): void {\r\n\t\tif (e.searchString) {\r\n\t\t\ttry {\r\n\t\t\t\tthis._ignoreChangeEvent = true;\r\n\t\t\t\tthis._findInput.setValue(this._state.searchString);\r\n\t\t\t} finally {\r\n\t\t\t\tthis._ignoreChangeEvent = false;\r\n\t\t\t}\r\n\t\t\tthis._updateButtons();\r\n\t\t}\r\n\t\tif (e.replaceString) {\r\n\t\t\tthis._replaceInput.inputBox.value = this._state.replaceString;\r\n\t\t}\r\n\t\tif (e.isRevealed) {\r\n\t\t\tif (this._state.isRevealed) {\r\n\t\t\t\tthis._reveal();\r\n\t\t\t} else {\r\n\t\t\t\tthis._hide(true);\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (e.isReplaceRevealed) {\r\n\t\t\tif (this._state.isReplaceRevealed) {\r\n\t\t\t\tif (!this._codeEditor.getOption(EditorOption.readOnly) && !this._isReplaceVisible) {\r\n\t\t\t\t\tthis._isReplaceVisible = true;\r\n\t\t\t\t\tthis._replaceInput.width = dom.getTotalWidth(this._findInput.domNode);\r\n\t\t\t\t\tthis._updateButtons();\r\n\t\t\t\t\tthis._replaceInput.inputBox.layout();\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tif (this._isReplaceVisible) {\r\n\t\t\t\t\tthis._isReplaceVisible = false;\r\n\t\t\t\t\tthis._updateButtons();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tif ((e.isRevealed || e.isReplaceRevealed) && (this._state.isRevealed || this._state.isReplaceRevealed)) {\r\n\t\t\tif (this._tryUpdateHeight()) {\r\n\t\t\t\tthis._showViewZone();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (e.isRegex) {\r\n\t\t\tthis._findInput.setRegex(this._state.isRegex);\r\n\t\t}\r\n\t\tif (e.wholeWord) {\r\n\t\t\tthis._findInput.setWholeWords(this._state.wholeWord);\r\n\t\t}\r\n\t\tif (e.matchCase) {\r\n\t\t\tthis._findInput.setCaseSensitive(this._state.matchCase);\r\n\t\t}\r\n\t\tif (e.preserveCase) {\r\n\t\t\tthis._replaceInput.setPreserveCase(this._state.preserveCase);\r\n\t\t}\r\n\t\tif (e.searchScope) {\r\n\t\t\tif (this._state.searchScope) {\r\n\t\t\t\tthis._toggleSelectionFind.checked = true;\r\n\t\t\t} else {\r\n\t\t\t\tthis._toggleSelectionFind.checked = false;\r\n\t\t\t}\r\n\t\t\tthis._updateToggleSelectionFindButton();\r\n\t\t}\r\n\t\tif (e.searchString || e.matchesCount || e.matchesPosition) {\r\n\t\t\tlet showRedOutline = (this._state.searchString.length > 0 && this._state.matchesCount === 0);\r\n\t\t\tthis._domNode.classList.toggle('no-results', showRedOutline);\r\n\r\n\t\t\tthis._updateMatchesCount();\r\n\t\t\tthis._updateButtons();\r\n\t\t}\r\n\t\tif (e.searchString || e.currentMatch) {\r\n\t\t\tthis._layoutViewZone();\r\n\t\t}\r\n\t\tif (e.updateHistory) {\r\n\t\t\tthis._delayedUpdateHistory();\r\n\t\t}\r\n\t\tif (e.loop) {\r\n\t\t\tthis._updateButtons();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _delayedUpdateHistory() {\r\n\t\tthis._updateHistoryDelayer.trigger(this._updateHistory.bind(this)).then(undefined, onUnexpectedError);\r\n\t}\r\n\r\n\tprivate _updateHistory() {\r\n\t\tif (this._state.searchString) {\r\n\t\t\tthis._findInput.inputBox.addToHistory();\r\n\t\t}\r\n\t\tif (this._state.replaceString) {\r\n\t\t\tthis._replaceInput.inputBox.addToHistory();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _updateMatchesCount(): void {\r\n\t\tthis._matchesCount.style.minWidth = MAX_MATCHES_COUNT_WIDTH + 'px';\r\n\t\tif (this._state.matchesCount >= MATCHES_LIMIT) {\r\n\t\t\tthis._matchesCount.title = NLS_MATCHES_COUNT_LIMIT_TITLE;\r\n\t\t} else {\r\n\t\t\tthis._matchesCount.title = '';\r\n\t\t}\r\n\r\n\t\t// remove previous content\r\n\t\tif (this._matchesCount.firstChild) {\r\n\t\t\tthis._matchesCount.removeChild(this._matchesCount.firstChild);\r\n\t\t}\r\n\r\n\t\tlet label: string;\r\n\t\tif (this._state.matchesCount > 0) {\r\n\t\t\tlet matchesCount: string = String(this._state.matchesCount);\r\n\t\t\tif (this._state.matchesCount >= MATCHES_LIMIT) {\r\n\t\t\t\tmatchesCount += '+';\r\n\t\t\t}\r\n\t\t\tlet matchesPosition: string = String(this._state.matchesPosition);\r\n\t\t\tif (matchesPosition === '0') {\r\n\t\t\t\tmatchesPosition = '?';\r\n\t\t\t}\r\n\t\t\tlabel = strings.format(NLS_MATCHES_LOCATION, matchesPosition, matchesCount);\r\n\t\t} else {\r\n\t\t\tlabel = NLS_NO_RESULTS;\r\n\t\t}\r\n\r\n\t\tthis._matchesCount.appendChild(document.createTextNode(label));\r\n\r\n\t\talertFn(this._getAriaLabel(label, this._state.currentMatch, this._state.searchString));\r\n\t\tMAX_MATCHES_COUNT_WIDTH = Math.max(MAX_MATCHES_COUNT_WIDTH, this._matchesCount.clientWidth);\r\n\t}\r\n\r\n\t// ----- actions\r\n\r\n\tprivate _getAriaLabel(label: string, currentMatch: Range | null, searchString: string): string {\r\n\t\tif (label === NLS_NO_RESULTS) {\r\n\t\t\treturn searchString === ''\r\n\t\t\t\t? nls.localize('ariaSearchNoResultEmpty', \"{0} found\", label)\r\n\t\t\t\t: nls.localize('ariaSearchNoResult', \"{0} found for '{1}'\", label, searchString);\r\n\t\t}\r\n\t\tif (currentMatch) {\r\n\t\t\tconst ariaLabel = nls.localize('ariaSearchNoResultWithLineNum', \"{0} found for '{1}', at {2}\", label, searchString, currentMatch.startLineNumber + ':' + currentMatch.startColumn);\r\n\t\t\tconst model = this._codeEditor.getModel();\r\n\t\t\tif (model && (currentMatch.startLineNumber <= model.getLineCount()) && (currentMatch.startLineNumber >= 1)) {\r\n\t\t\t\tconst lineContent = model.getLineContent(currentMatch.startLineNumber);\r\n\t\t\t\treturn `${lineContent}, ${ariaLabel}`;\r\n\t\t\t}\r\n\r\n\t\t\treturn ariaLabel;\r\n\t\t}\r\n\r\n\t\treturn nls.localize('ariaSearchNoResultWithLineNumNoCurrentMatch', \"{0} found for '{1}'\", label, searchString);\r\n\t}\r\n\r\n\t/**\r\n\t * If 'selection find' is ON we should not disable the button (its function is to cancel 'selection find').\r\n\t * If 'selection find' is OFF we enable the button only if there is a selection.\r\n\t */\r\n\tprivate _updateToggleSelectionFindButton(): void {\r\n\t\tlet selection = this._codeEditor.getSelection();\r\n\t\tlet isSelection = selection ? (selection.startLineNumber !== selection.endLineNumber || selection.startColumn !== selection.endColumn) : false;\r\n\t\tlet isChecked = this._toggleSelectionFind.checked;\r\n\r\n\t\tif (this._isVisible && (isChecked || isSelection)) {\r\n\t\t\tthis._toggleSelectionFind.enable();\r\n\t\t} else {\r\n\t\t\tthis._toggleSelectionFind.disable();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _updateButtons(): void {\r\n\t\tthis._findInput.setEnabled(this._isVisible);\r\n\t\tthis._replaceInput.setEnabled(this._isVisible && this._isReplaceVisible);\r\n\t\tthis._updateToggleSelectionFindButton();\r\n\t\tthis._closeBtn.setEnabled(this._isVisible);\r\n\r\n\t\tlet findInputIsNonEmpty = (this._state.searchString.length > 0);\r\n\t\tlet matchesCount = this._state.matchesCount ? true : false;\r\n\t\tthis._prevBtn.setEnabled(this._isVisible && findInputIsNonEmpty && matchesCount && this._state.canNavigateBack());\r\n\t\tthis._nextBtn.setEnabled(this._isVisible && findInputIsNonEmpty && matchesCount && this._state.canNavigateForward());\r\n\t\tthis._replaceBtn.setEnabled(this._isVisible && this._isReplaceVisible && findInputIsNonEmpty);\r\n\t\tthis._replaceAllBtn.setEnabled(this._isVisible && this._isReplaceVisible && findInputIsNonEmpty);\r\n\r\n\t\tthis._domNode.classList.toggle('replaceToggled', this._isReplaceVisible);\r\n\t\tthis._toggleReplaceBtn.setExpanded(this._isReplaceVisible);\r\n\r\n\t\tlet canReplace = !this._codeEditor.getOption(EditorOption.readOnly);\r\n\t\tthis._toggleReplaceBtn.setEnabled(this._isVisible && canReplace);\r\n\t}\r\n\r\n\tprivate _revealTimeouts: any[] = [];\r\n\r\n\tprivate _reveal(): void {\r\n\t\tthis._revealTimeouts.forEach(e => {\r\n\t\t\tclearTimeout(e);\r\n\t\t});\r\n\r\n\t\tthis._revealTimeouts = [];\r\n\r\n\t\tif (!this._isVisible) {\r\n\t\t\tthis._isVisible = true;\r\n\r\n\t\t\tconst selection = this._codeEditor.getSelection();\r\n\r\n\t\t\tswitch (this._codeEditor.getOption(EditorOption.find).autoFindInSelection) {\r\n\t\t\t\tcase 'always':\r\n\t\t\t\t\tthis._toggleSelectionFind.checked = true;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'never':\r\n\t\t\t\t\tthis._toggleSelectionFind.checked = false;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'multiline':\r\n\t\t\t\t\tconst isSelectionMultipleLine = !!selection && selection.startLineNumber !== selection.endLineNumber;\r\n\t\t\t\t\tthis._toggleSelectionFind.checked = isSelectionMultipleLine;\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tdefault:\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tthis._tryUpdateWidgetWidth();\r\n\t\t\tthis._updateButtons();\r\n\r\n\t\t\tthis._revealTimeouts.push(setTimeout(() => {\r\n\t\t\t\tthis._domNode.classList.add('visible');\r\n\t\t\t\tthis._domNode.setAttribute('aria-hidden', 'false');\r\n\t\t\t}, 0));\r\n\r\n\t\t\t// validate query again as it's being dismissed when we hide the find widget.\r\n\t\t\tthis._revealTimeouts.push(setTimeout(() => {\r\n\t\t\t\tthis._findInput.validate();\r\n\t\t\t}, 200));\r\n\r\n\t\t\tthis._codeEditor.layoutOverlayWidget(this);\r\n\r\n\t\t\tlet adjustEditorScrollTop = true;\r\n\t\t\tif (this._codeEditor.getOption(EditorOption.find).seedSearchStringFromSelection && selection) {\r\n\t\t\t\tconst domNode = this._codeEditor.getDomNode();\r\n\t\t\t\tif (domNode) {\r\n\t\t\t\t\tconst editorCoords = dom.getDomNodePagePosition(domNode);\r\n\t\t\t\t\tconst startCoords = this._codeEditor.getScrolledVisiblePosition(selection.getStartPosition());\r\n\t\t\t\t\tconst startLeft = editorCoords.left + (startCoords ? startCoords.left : 0);\r\n\t\t\t\t\tconst startTop = startCoords ? startCoords.top : 0;\r\n\r\n\t\t\t\t\tif (this._viewZone && startTop < this._viewZone.heightInPx) {\r\n\t\t\t\t\t\tif (selection.endLineNumber > selection.startLineNumber) {\r\n\t\t\t\t\t\t\tadjustEditorScrollTop = false;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tconst leftOfFindWidget = dom.getTopLeftOffset(this._domNode).left;\r\n\t\t\t\t\t\tif (startLeft > leftOfFindWidget) {\r\n\t\t\t\t\t\t\tadjustEditorScrollTop = false;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tconst endCoords = this._codeEditor.getScrolledVisiblePosition(selection.getEndPosition());\r\n\t\t\t\t\t\tconst endLeft = editorCoords.left + (endCoords ? endCoords.left : 0);\r\n\t\t\t\t\t\tif (endLeft > leftOfFindWidget) {\r\n\t\t\t\t\t\t\tadjustEditorScrollTop = false;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tthis._showViewZone(adjustEditorScrollTop);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _hide(focusTheEditor: boolean): void {\r\n\t\tthis._revealTimeouts.forEach(e => {\r\n\t\t\tclearTimeout(e);\r\n\t\t});\r\n\r\n\t\tthis._revealTimeouts = [];\r\n\r\n\t\tif (this._isVisible) {\r\n\t\t\tthis._isVisible = false;\r\n\r\n\t\t\tthis._updateButtons();\r\n\r\n\t\t\tthis._domNode.classList.remove('visible');\r\n\t\t\tthis._domNode.setAttribute('aria-hidden', 'true');\r\n\t\t\tthis._findInput.clearMessage();\r\n\t\t\tif (focusTheEditor) {\r\n\t\t\t\tthis._codeEditor.focus();\r\n\t\t\t}\r\n\t\t\tthis._codeEditor.layoutOverlayWidget(this);\r\n\t\t\tthis._removeViewZone();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _layoutViewZone(targetScrollTop?: number) {\r\n\t\tconst addExtraSpaceOnTop = this._codeEditor.getOption(EditorOption.find).addExtraSpaceOnTop;\r\n\r\n\t\tif (!addExtraSpaceOnTop) {\r\n\t\t\tthis._removeViewZone();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!this._isVisible) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst viewZone = this._viewZone;\r\n\t\tif (this._viewZoneId !== undefined || !viewZone) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._codeEditor.changeViewZones((accessor) => {\r\n\t\t\tviewZone.heightInPx = this._getHeight();\r\n\t\t\tthis._viewZoneId = accessor.addZone(viewZone);\r\n\t\t\t// scroll top adjust to make sure the editor doesn't scroll when adding viewzone at the beginning.\r\n\t\t\tthis._codeEditor.setScrollTop(targetScrollTop || this._codeEditor.getScrollTop() + viewZone.heightInPx);\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _showViewZone(adjustScroll: boolean = true) {\r\n\t\tif (!this._isVisible) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst addExtraSpaceOnTop = this._codeEditor.getOption(EditorOption.find).addExtraSpaceOnTop;\r\n\r\n\t\tif (!addExtraSpaceOnTop) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this._viewZone === undefined) {\r\n\t\t\tthis._viewZone = new FindWidgetViewZone(0);\r\n\t\t}\r\n\r\n\t\tconst viewZone = this._viewZone;\r\n\r\n\t\tthis._codeEditor.changeViewZones((accessor) => {\r\n\t\t\tif (this._viewZoneId !== undefined) {\r\n\t\t\t\t// the view zone already exists, we need to update the height\r\n\t\t\t\tconst newHeight = this._getHeight();\r\n\t\t\t\tif (newHeight === viewZone.heightInPx) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tlet scrollAdjustment = newHeight - viewZone.heightInPx;\r\n\t\t\t\tviewZone.heightInPx = newHeight;\r\n\t\t\t\taccessor.layoutZone(this._viewZoneId);\r\n\r\n\t\t\t\tif (adjustScroll) {\r\n\t\t\t\t\tthis._codeEditor.setScrollTop(this._codeEditor.getScrollTop() + scrollAdjustment);\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn;\r\n\t\t\t} else {\r\n\t\t\t\tlet scrollAdjustment = this._getHeight();\r\n\r\n\t\t\t\t// if the editor has top padding, factor that into the zone height\r\n\t\t\t\tscrollAdjustment -= this._codeEditor.getOption(EditorOption.padding).top;\r\n\t\t\t\tif (scrollAdjustment <= 0) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tviewZone.heightInPx = scrollAdjustment;\r\n\t\t\t\tthis._viewZoneId = accessor.addZone(viewZone);\r\n\r\n\t\t\t\tif (adjustScroll) {\r\n\t\t\t\t\tthis._codeEditor.setScrollTop(this._codeEditor.getScrollTop() + scrollAdjustment);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _removeViewZone() {\r\n\t\tthis._codeEditor.changeViewZones((accessor) => {\r\n\t\t\tif (this._viewZoneId !== undefined) {\r\n\t\t\t\taccessor.removeZone(this._viewZoneId);\r\n\t\t\t\tthis._viewZoneId = undefined;\r\n\t\t\t\tif (this._viewZone) {\r\n\t\t\t\t\tthis._codeEditor.setScrollTop(this._codeEditor.getScrollTop() - this._viewZone.heightInPx);\r\n\t\t\t\t\tthis._viewZone = undefined;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprivate _applyTheme(theme: IColorTheme) {\r\n\t\tlet inputStyles: IFindInputStyles = {\r\n\t\t\tinputActiveOptionBorder: theme.getColor(inputActiveOptionBorder),\r\n\t\t\tinputActiveOptionBackground: theme.getColor(inputActiveOptionBackground),\r\n\t\t\tinputActiveOptionForeground: theme.getColor(inputActiveOptionForeground),\r\n\t\t\tinputBackground: theme.getColor(inputBackground),\r\n\t\t\tinputForeground: theme.getColor(inputForeground),\r\n\t\t\tinputBorder: theme.getColor(inputBorder),\r\n\t\t\tinputValidationInfoBackground: theme.getColor(inputValidationInfoBackground),\r\n\t\t\tinputValidationInfoForeground: theme.getColor(inputValidationInfoForeground),\r\n\t\t\tinputValidationInfoBorder: theme.getColor(inputValidationInfoBorder),\r\n\t\t\tinputValidationWarningBackground: theme.getColor(inputValidationWarningBackground),\r\n\t\t\tinputValidationWarningForeground: theme.getColor(inputValidationWarningForeground),\r\n\t\t\tinputValidationWarningBorder: theme.getColor(inputValidationWarningBorder),\r\n\t\t\tinputValidationErrorBackground: theme.getColor(inputValidationErrorBackground),\r\n\t\t\tinputValidationErrorForeground: theme.getColor(inputValidationErrorForeground),\r\n\t\t\tinputValidationErrorBorder: theme.getColor(inputValidationErrorBorder),\r\n\t\t};\r\n\t\tthis._findInput.style(inputStyles);\r\n\t\tthis._replaceInput.style(inputStyles);\r\n\t\tthis._toggleSelectionFind.style(inputStyles);\r\n\t}\r\n\r\n\tprivate _tryUpdateWidgetWidth() {\r\n\t\tif (!this._isVisible) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (!dom.isInDOM(this._domNode)) {\r\n\t\t\t// the widget is not in the DOM\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst layoutInfo = this._codeEditor.getLayoutInfo();\r\n\t\tconst editorContentWidth = layoutInfo.contentWidth;\r\n\r\n\t\tif (editorContentWidth <= 0) {\r\n\t\t\t// for example, diff view original editor\r\n\t\t\tthis._domNode.classList.add('hiddenEditor');\r\n\t\t\treturn;\r\n\t\t} else if (this._domNode.classList.contains('hiddenEditor')) {\r\n\t\t\tthis._domNode.classList.remove('hiddenEditor');\r\n\t\t}\r\n\r\n\t\tconst editorWidth = layoutInfo.width;\r\n\t\tconst minimapWidth = layoutInfo.minimap.minimapWidth;\r\n\t\tlet collapsedFindWidget = false;\r\n\t\tlet reducedFindWidget = false;\r\n\t\tlet narrowFindWidget = false;\r\n\r\n\t\tif (this._resized) {\r\n\t\t\tlet widgetWidth = dom.getTotalWidth(this._domNode);\r\n\r\n\t\t\tif (widgetWidth > FIND_WIDGET_INITIAL_WIDTH) {\r\n\t\t\t\t// as the widget is resized by users, we may need to change the max width of the widget as the editor width changes.\r\n\t\t\t\tthis._domNode.style.maxWidth = `${editorWidth - 28 - minimapWidth - 15}px`;\r\n\t\t\t\tthis._replaceInput.width = dom.getTotalWidth(this._findInput.domNode);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (FIND_WIDGET_INITIAL_WIDTH + 28 + minimapWidth >= editorWidth) {\r\n\t\t\treducedFindWidget = true;\r\n\t\t}\r\n\t\tif (FIND_WIDGET_INITIAL_WIDTH + 28 + minimapWidth - MAX_MATCHES_COUNT_WIDTH >= editorWidth) {\r\n\t\t\tnarrowFindWidget = true;\r\n\t\t}\r\n\t\tif (FIND_WIDGET_INITIAL_WIDTH + 28 + minimapWidth - MAX_MATCHES_COUNT_WIDTH >= editorWidth + 50) {\r\n\t\t\tcollapsedFindWidget = true;\r\n\t\t}\r\n\t\tthis._domNode.classList.toggle('collapsed-find-widget', collapsedFindWidget);\r\n\t\tthis._domNode.classList.toggle('narrow-find-widget', narrowFindWidget);\r\n\t\tthis._domNode.classList.toggle('reduced-find-widget', reducedFindWidget);\r\n\r\n\t\tif (!narrowFindWidget && !collapsedFindWidget) {\r\n\t\t\t// the minimal left offset of findwidget is 15px.\r\n\t\t\tthis._domNode.style.maxWidth = `${editorWidth - 28 - minimapWidth - 15}px`;\r\n\t\t}\r\n\r\n\t\tif (this._resized) {\r\n\t\t\tthis._findInput.inputBox.layout();\r\n\t\t\tlet findInputWidth = this._findInput.inputBox.element.clientWidth;\r\n\t\t\tif (findInputWidth > 0) {\r\n\t\t\t\tthis._replaceInput.width = findInputWidth;\r\n\t\t\t}\r\n\t\t} else if (this._isReplaceVisible) {\r\n\t\t\tthis._replaceInput.width = dom.getTotalWidth(this._findInput.domNode);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _getHeight(): number {\r\n\t\tlet totalheight = 0;\r\n\r\n\t\t// find input margin top\r\n\t\ttotalheight += 4;\r\n\r\n\t\t// find input height\r\n\t\ttotalheight += this._findInput.inputBox.height + 2 /** input box border */;\r\n\r\n\t\tif (this._isReplaceVisible) {\r\n\t\t\t// replace input margin\r\n\t\t\ttotalheight += 4;\r\n\r\n\t\t\ttotalheight += this._replaceInput.inputBox.height + 2 /** input box border */;\r\n\t\t}\r\n\r\n\t\t// margin bottom\r\n\t\ttotalheight += 4;\r\n\t\treturn totalheight;\r\n\t}\r\n\r\n\tprivate _tryUpdateHeight(): boolean {\r\n\t\tconst totalHeight = this._getHeight();\r\n\t\tif (this._cachedHeight !== null && this._cachedHeight === totalHeight) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tthis._cachedHeight = totalHeight;\r\n\t\tthis._domNode.style.height = `${totalHeight}px`;\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\t// ----- Public\r\n\r\n\tpublic focusFindInput(): void {\r\n\t\tthis._findInput.select();\r\n\t\t// Edge browser requires focus() in addition to select()\r\n\t\tthis._findInput.focus();\r\n\t}\r\n\r\n\tpublic focusReplaceInput(): void {\r\n\t\tthis._replaceInput.select();\r\n\t\t// Edge browser requires focus() in addition to select()\r\n\t\tthis._replaceInput.focus();\r\n\t}\r\n\r\n\tpublic highlightFindOptions(): void {\r\n\t\tthis._findInput.highlightFindOptions();\r\n\t}\r\n\r\n\tprivate _updateSearchScope(): void {\r\n\t\tif (!this._codeEditor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this._toggleSelectionFind.checked) {\r\n\t\t\tlet selections = this._codeEditor.getSelections();\r\n\r\n\t\t\tselections.map(selection => {\r\n\t\t\t\tif (selection.endColumn === 1 && selection.endLineNumber > selection.startLineNumber) {\r\n\t\t\t\t\tselection = selection.setEndPosition(\r\n\t\t\t\t\t\tselection.endLineNumber - 1,\r\n\t\t\t\t\t\tthis._codeEditor.getModel()!.getLineMaxColumn(selection.endLineNumber - 1)\r\n\t\t\t\t\t);\r\n\t\t\t\t}\r\n\t\t\t\tconst currentMatch = this._state.currentMatch;\r\n\t\t\t\tif (selection.startLineNumber !== selection.endLineNumber) {\r\n\t\t\t\t\tif (!Range.equalsRange(selection, currentMatch)) {\r\n\t\t\t\t\t\treturn selection;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\treturn null;\r\n\t\t\t}).filter(element => !!element);\r\n\r\n\t\t\tif (selections.length) {\r\n\t\t\t\tthis._state.change({ searchScope: selections as Range[] }, true);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _onFindInputMouseDown(e: IMouseEvent): void {\r\n\t\t// on linux, middle key does pasting.\r\n\t\tif (e.middleButton) {\r\n\t\t\te.stopPropagation();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _onFindInputKeyDown(e: IKeyboardEvent): void {\r\n\t\tif (e.equals(ctrlKeyMod | KeyCode.Enter)) {\r\n\t\t\tthis._findInput.inputBox.insertAtCursor('\\n');\r\n\t\t\te.preventDefault();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (e.equals(KeyCode.Tab)) {\r\n\t\t\tif (this._isReplaceVisible) {\r\n\t\t\t\tthis._replaceInput.focus();\r\n\t\t\t} else {\r\n\t\t\t\tthis._findInput.focusOnCaseSensitive();\r\n\t\t\t}\r\n\t\t\te.preventDefault();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (e.equals(KeyMod.CtrlCmd | KeyCode.DownArrow)) {\r\n\t\t\tthis._codeEditor.focus();\r\n\t\t\te.preventDefault();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (e.equals(KeyCode.UpArrow)) {\r\n\t\t\treturn stopPropagationForMultiLineUpwards(e, this._findInput.getValue(), this._findInput.domNode.querySelector('textarea'));\r\n\t\t}\r\n\r\n\t\tif (e.equals(KeyCode.DownArrow)) {\r\n\t\t\treturn stopPropagationForMultiLineDownwards(e, this._findInput.getValue(), this._findInput.domNode.querySelector('textarea'));\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _onReplaceInputKeyDown(e: IKeyboardEvent): void {\r\n\t\tif (e.equals(ctrlKeyMod | KeyCode.Enter)) {\r\n\t\t\tif (platform.isWindows && platform.isNative && !this._ctrlEnterReplaceAllWarningPrompted) {\r\n\t\t\t\t// this is the first time when users press Ctrl + Enter to replace all\r\n\t\t\t\tthis._notificationService.info(\r\n\t\t\t\t\tnls.localize('ctrlEnter.keybindingChanged',\r\n\t\t\t\t\t\t'Ctrl+Enter now inserts line break instead of replacing all. You can modify the keybinding for editor.action.replaceAll to override this behavior.')\r\n\t\t\t\t);\r\n\r\n\t\t\t\tthis._ctrlEnterReplaceAllWarningPrompted = true;\r\n\t\t\t\tthis._storageService.store(ctrlEnterReplaceAllWarningPromptedKey, true, StorageScope.GLOBAL, StorageTarget.USER);\r\n\r\n\t\t\t}\r\n\r\n\t\t\tthis._replaceInput.inputBox.insertAtCursor('\\n');\r\n\t\t\te.preventDefault();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (e.equals(KeyCode.Tab)) {\r\n\t\t\tthis._findInput.focusOnCaseSensitive();\r\n\t\t\te.preventDefault();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (e.equals(KeyMod.Shift | KeyCode.Tab)) {\r\n\t\t\tthis._findInput.focus();\r\n\t\t\te.preventDefault();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (e.equals(KeyMod.CtrlCmd | KeyCode.DownArrow)) {\r\n\t\t\tthis._codeEditor.focus();\r\n\t\t\te.preventDefault();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (e.equals(KeyCode.UpArrow)) {\r\n\t\t\treturn stopPropagationForMultiLineUpwards(e, this._replaceInput.inputBox.value, this._replaceInput.inputBox.element.querySelector('textarea'));\r\n\t\t}\r\n\r\n\t\tif (e.equals(KeyCode.DownArrow)) {\r\n\t\t\treturn stopPropagationForMultiLineDownwards(e, this._replaceInput.inputBox.value, this._replaceInput.inputBox.element.querySelector('textarea'));\r\n\t\t}\r\n\t}\r\n\r\n\t// ----- sash\r\n\tpublic getVerticalSashLeft(_sash: Sash): number {\r\n\t\treturn 0;\r\n\t}\r\n\t// ----- initialization\r\n\r\n\tprivate _keybindingLabelFor(actionId: string): string {\r\n\t\tlet kb = this._keybindingService.lookupKeybinding(actionId);\r\n\t\tif (!kb) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\treturn ` (${kb.getLabel()})`;\r\n\t}\r\n\r\n\tprivate _buildDomNode(): void {\r\n\t\tconst flexibleHeight = true;\r\n\t\tconst flexibleWidth = true;\r\n\t\t// Find input\r\n\t\tthis._findInput = this._register(new ContextScopedFindInput(null, this._contextViewProvider, {\r\n\t\t\twidth: FIND_INPUT_AREA_WIDTH,\r\n\t\t\tlabel: NLS_FIND_INPUT_LABEL,\r\n\t\t\tplaceholder: NLS_FIND_INPUT_PLACEHOLDER,\r\n\t\t\tappendCaseSensitiveLabel: this._keybindingLabelFor(FIND_IDS.ToggleCaseSensitiveCommand),\r\n\t\t\tappendWholeWordsLabel: this._keybindingLabelFor(FIND_IDS.ToggleWholeWordCommand),\r\n\t\t\tappendRegexLabel: this._keybindingLabelFor(FIND_IDS.ToggleRegexCommand),\r\n\t\t\tvalidation: (value: string): InputBoxMessage | null => {\r\n\t\t\t\tif (value.length === 0 || !this._findInput.getRegex()) {\r\n\t\t\t\t\treturn null;\r\n\t\t\t\t}\r\n\t\t\t\ttry {\r\n\t\t\t\t\t// use `g` and `u` which are also used by the TextModel search\r\n\t\t\t\t\tnew RegExp(value, 'gu');\r\n\t\t\t\t\treturn null;\r\n\t\t\t\t} catch (e) {\r\n\t\t\t\t\treturn { content: e.message };\r\n\t\t\t\t}\r\n\t\t\t},\r\n\t\t\tflexibleHeight,\r\n\t\t\tflexibleWidth,\r\n\t\t\tflexibleMaxHeight: 118\r\n\t\t}, this._contextKeyService, true));\r\n\t\tthis._findInput.setRegex(!!this._state.isRegex);\r\n\t\tthis._findInput.setCaseSensitive(!!this._state.matchCase);\r\n\t\tthis._findInput.setWholeWords(!!this._state.wholeWord);\r\n\t\tthis._register(this._findInput.onKeyDown((e) => this._onFindInputKeyDown(e)));\r\n\t\tthis._register(this._findInput.inputBox.onDidChange(() => {\r\n\t\t\tif (this._ignoreChangeEvent) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tthis._state.change({ searchString: this._findInput.getValue() }, true);\r\n\t\t}));\r\n\t\tthis._register(this._findInput.onDidOptionChange(() => {\r\n\t\t\tthis._state.change({\r\n\t\t\t\tisRegex: this._findInput.getRegex(),\r\n\t\t\t\twholeWord: this._findInput.getWholeWords(),\r\n\t\t\t\tmatchCase: this._findInput.getCaseSensitive()\r\n\t\t\t}, true);\r\n\t\t}));\r\n\t\tthis._register(this._findInput.onCaseSensitiveKeyDown((e) => {\r\n\t\t\tif (e.equals(KeyMod.Shift | KeyCode.Tab)) {\r\n\t\t\t\tif (this._isReplaceVisible) {\r\n\t\t\t\t\tthis._replaceInput.focus();\r\n\t\t\t\t\te.preventDefault();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._register(this._findInput.onRegexKeyDown((e) => {\r\n\t\t\tif (e.equals(KeyCode.Tab)) {\r\n\t\t\t\tif (this._isReplaceVisible) {\r\n\t\t\t\t\tthis._replaceInput.focusOnPreserve();\r\n\t\t\t\t\te.preventDefault();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._register(this._findInput.inputBox.onDidHeightChange((e) => {\r\n\t\t\tif (this._tryUpdateHeight()) {\r\n\t\t\t\tthis._showViewZone();\r\n\t\t\t}\r\n\t\t}));\r\n\t\tif (platform.isLinux) {\r\n\t\t\tthis._register(this._findInput.onMouseDown((e) => this._onFindInputMouseDown(e)));\r\n\t\t}\r\n\r\n\t\tthis._matchesCount = document.createElement('div');\r\n\t\tthis._matchesCount.className = 'matchesCount';\r\n\t\tthis._updateMatchesCount();\r\n\r\n\t\t// Previous button\r\n\t\tthis._prevBtn = this._register(new SimpleButton({\r\n\t\t\tlabel: NLS_PREVIOUS_MATCH_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.PreviousMatchFindAction),\r\n\t\t\ticon: findPreviousMatchIcon,\r\n\t\t\tonTrigger: () => {\r\n\t\t\t\tthis._codeEditor.getAction(FIND_IDS.PreviousMatchFindAction).run().then(undefined, onUnexpectedError);\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\t// Next button\r\n\t\tthis._nextBtn = this._register(new SimpleButton({\r\n\t\t\tlabel: NLS_NEXT_MATCH_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.NextMatchFindAction),\r\n\t\t\ticon: findNextMatchIcon,\r\n\t\t\tonTrigger: () => {\r\n\t\t\t\tthis._codeEditor.getAction(FIND_IDS.NextMatchFindAction).run().then(undefined, onUnexpectedError);\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tlet findPart = document.createElement('div');\r\n\t\tfindPart.className = 'find-part';\r\n\t\tfindPart.appendChild(this._findInput.domNode);\r\n\t\tconst actionsContainer = document.createElement('div');\r\n\t\tactionsContainer.className = 'find-actions';\r\n\t\tfindPart.appendChild(actionsContainer);\r\n\t\tactionsContainer.appendChild(this._matchesCount);\r\n\t\tactionsContainer.appendChild(this._prevBtn.domNode);\r\n\t\tactionsContainer.appendChild(this._nextBtn.domNode);\r\n\r\n\t\t// Toggle selection button\r\n\t\tthis._toggleSelectionFind = this._register(new Checkbox({\r\n\t\t\ticon: findSelectionIcon,\r\n\t\t\ttitle: NLS_TOGGLE_SELECTION_FIND_TITLE + this._keybindingLabelFor(FIND_IDS.ToggleSearchScopeCommand),\r\n\t\t\tisChecked: false\r\n\t\t}));\r\n\r\n\t\tthis._register(this._toggleSelectionFind.onChange(() => {\r\n\t\t\tif (this._toggleSelectionFind.checked) {\r\n\t\t\t\tif (this._codeEditor.hasModel()) {\r\n\t\t\t\t\tlet selections = this._codeEditor.getSelections();\r\n\t\t\t\t\tselections.map(selection => {\r\n\t\t\t\t\t\tif (selection.endColumn === 1 && selection.endLineNumber > selection.startLineNumber) {\r\n\t\t\t\t\t\t\tselection = selection.setEndPosition(selection.endLineNumber - 1, this._codeEditor.getModel()!.getLineMaxColumn(selection.endLineNumber - 1));\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (!selection.isEmpty()) {\r\n\t\t\t\t\t\t\treturn selection;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\treturn null;\r\n\t\t\t\t\t}).filter(element => !!element);\r\n\r\n\t\t\t\t\tif (selections.length) {\r\n\t\t\t\t\t\tthis._state.change({ searchScope: selections as Range[] }, true);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tthis._state.change({ searchScope: null }, true);\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tactionsContainer.appendChild(this._toggleSelectionFind.domNode);\r\n\r\n\t\t// Close button\r\n\t\tthis._closeBtn = this._register(new SimpleButton({\r\n\t\t\tlabel: NLS_CLOSE_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.CloseFindWidgetCommand),\r\n\t\t\ticon: widgetClose,\r\n\t\t\tonTrigger: () => {\r\n\t\t\t\tthis._state.change({ isRevealed: false, searchScope: null }, false);\r\n\t\t\t},\r\n\t\t\tonKeyDown: (e) => {\r\n\t\t\t\tif (e.equals(KeyCode.Tab)) {\r\n\t\t\t\t\tif (this._isReplaceVisible) {\r\n\t\t\t\t\t\tif (this._replaceBtn.isEnabled()) {\r\n\t\t\t\t\t\t\tthis._replaceBtn.focus();\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tthis._codeEditor.focus();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\te.preventDefault();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tactionsContainer.appendChild(this._closeBtn.domNode);\r\n\r\n\t\t// Replace input\r\n\t\tthis._replaceInput = this._register(new ContextScopedReplaceInput(null, undefined, {\r\n\t\t\tlabel: NLS_REPLACE_INPUT_LABEL,\r\n\t\t\tplaceholder: NLS_REPLACE_INPUT_PLACEHOLDER,\r\n\t\t\tappendPreserveCaseLabel: this._keybindingLabelFor(FIND_IDS.TogglePreserveCaseCommand),\r\n\t\t\thistory: [],\r\n\t\t\tflexibleHeight,\r\n\t\t\tflexibleWidth,\r\n\t\t\tflexibleMaxHeight: 118\r\n\t\t}, this._contextKeyService, true));\r\n\t\tthis._replaceInput.setPreserveCase(!!this._state.preserveCase);\r\n\t\tthis._register(this._replaceInput.onKeyDown((e) => this._onReplaceInputKeyDown(e)));\r\n\t\tthis._register(this._replaceInput.inputBox.onDidChange(() => {\r\n\t\t\tthis._state.change({ replaceString: this._replaceInput.inputBox.value }, false);\r\n\t\t}));\r\n\t\tthis._register(this._replaceInput.inputBox.onDidHeightChange((e) => {\r\n\t\t\tif (this._isReplaceVisible && this._tryUpdateHeight()) {\r\n\t\t\t\tthis._showViewZone();\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._register(this._replaceInput.onDidOptionChange(() => {\r\n\t\t\tthis._state.change({\r\n\t\t\t\tpreserveCase: this._replaceInput.getPreserveCase()\r\n\t\t\t}, true);\r\n\t\t}));\r\n\t\tthis._register(this._replaceInput.onPreserveCaseKeyDown((e) => {\r\n\t\t\tif (e.equals(KeyCode.Tab)) {\r\n\t\t\t\tif (this._prevBtn.isEnabled()) {\r\n\t\t\t\t\tthis._prevBtn.focus();\r\n\t\t\t\t} else if (this._nextBtn.isEnabled()) {\r\n\t\t\t\t\tthis._nextBtn.focus();\r\n\t\t\t\t} else if (this._toggleSelectionFind.enabled) {\r\n\t\t\t\t\tthis._toggleSelectionFind.focus();\r\n\t\t\t\t} else if (this._closeBtn.isEnabled()) {\r\n\t\t\t\t\tthis._closeBtn.focus();\r\n\t\t\t\t}\r\n\r\n\t\t\t\te.preventDefault();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\t// Replace one button\r\n\t\tthis._replaceBtn = this._register(new SimpleButton({\r\n\t\t\tlabel: NLS_REPLACE_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.ReplaceOneAction),\r\n\t\t\ticon: findReplaceIcon,\r\n\t\t\tonTrigger: () => {\r\n\t\t\t\tthis._controller.replace();\r\n\t\t\t},\r\n\t\t\tonKeyDown: (e) => {\r\n\t\t\t\tif (e.equals(KeyMod.Shift | KeyCode.Tab)) {\r\n\t\t\t\t\tthis._closeBtn.focus();\r\n\t\t\t\t\te.preventDefault();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\t// Replace all button\r\n\t\tthis._replaceAllBtn = this._register(new SimpleButton({\r\n\t\t\tlabel: NLS_REPLACE_ALL_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.ReplaceAllAction),\r\n\t\t\ticon: findReplaceAllIcon,\r\n\t\t\tonTrigger: () => {\r\n\t\t\t\tthis._controller.replaceAll();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tlet replacePart = document.createElement('div');\r\n\t\treplacePart.className = 'replace-part';\r\n\t\treplacePart.appendChild(this._replaceInput.domNode);\r\n\r\n\t\tconst replaceActionsContainer = document.createElement('div');\r\n\t\treplaceActionsContainer.className = 'replace-actions';\r\n\t\treplacePart.appendChild(replaceActionsContainer);\r\n\r\n\t\treplaceActionsContainer.appendChild(this._replaceBtn.domNode);\r\n\t\treplaceActionsContainer.appendChild(this._replaceAllBtn.domNode);\r\n\r\n\t\t// Toggle replace button\r\n\t\tthis._toggleReplaceBtn = this._register(new SimpleButton({\r\n\t\t\tlabel: NLS_TOGGLE_REPLACE_MODE_BTN_LABEL,\r\n\t\t\tclassName: 'codicon toggle left',\r\n\t\t\tonTrigger: () => {\r\n\t\t\t\tthis._state.change({ isReplaceRevealed: !this._isReplaceVisible }, false);\r\n\t\t\t\tif (this._isReplaceVisible) {\r\n\t\t\t\t\tthis._replaceInput.width = dom.getTotalWidth(this._findInput.domNode);\r\n\t\t\t\t\tthis._replaceInput.inputBox.layout();\r\n\t\t\t\t}\r\n\t\t\t\tthis._showViewZone();\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._toggleReplaceBtn.setExpanded(this._isReplaceVisible);\r\n\r\n\t\t// Widget\r\n\t\tthis._domNode = document.createElement('div');\r\n\t\tthis._domNode.className = 'editor-widget find-widget';\r\n\t\tthis._domNode.setAttribute('aria-hidden', 'true');\r\n\t\t// We need to set this explicitly, otherwise on IE11, the width inheritence of flex doesn't work.\r\n\t\tthis._domNode.style.width = `${FIND_WIDGET_INITIAL_WIDTH}px`;\r\n\r\n\t\tthis._domNode.appendChild(this._toggleReplaceBtn.domNode);\r\n\t\tthis._domNode.appendChild(findPart);\r\n\t\tthis._domNode.appendChild(replacePart);\r\n\r\n\t\tthis._resizeSash = new Sash(this._domNode, this, { orientation: Orientation.VERTICAL, size: 2 });\r\n\t\tthis._resized = false;\r\n\t\tlet originalWidth = FIND_WIDGET_INITIAL_WIDTH;\r\n\r\n\t\tthis._register(this._resizeSash.onDidStart(() => {\r\n\t\t\toriginalWidth = dom.getTotalWidth(this._domNode);\r\n\t\t}));\r\n\r\n\t\tthis._register(this._resizeSash.onDidChange((evt: ISashEvent) => {\r\n\t\t\tthis._resized = true;\r\n\t\t\tlet width = originalWidth + evt.startX - evt.currentX;\r\n\r\n\t\t\tif (width < FIND_WIDGET_INITIAL_WIDTH) {\r\n\t\t\t\t// narrow down the find widget should be handled by CSS.\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst maxWidth = parseFloat(dom.getComputedStyle(this._domNode).maxWidth!) || 0;\r\n\t\t\tif (width > maxWidth) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tthis._domNode.style.width = `${width}px`;\r\n\t\t\tif (this._isReplaceVisible) {\r\n\t\t\t\tthis._replaceInput.width = dom.getTotalWidth(this._findInput.domNode);\r\n\t\t\t}\r\n\r\n\t\t\tthis._findInput.inputBox.layout();\r\n\t\t\tthis._tryUpdateHeight();\r\n\t\t}));\r\n\r\n\t\tthis._register(this._resizeSash.onDidReset(() => {\r\n\t\t\t// users double click on the sash\r\n\t\t\tconst currentWidth = dom.getTotalWidth(this._domNode);\r\n\r\n\t\t\tif (currentWidth < FIND_WIDGET_INITIAL_WIDTH) {\r\n\t\t\t\t// The editor is narrow and the width of the find widget is controlled fully by CSS.\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tlet width = FIND_WIDGET_INITIAL_WIDTH;\r\n\r\n\t\t\tif (!this._resized || currentWidth === FIND_WIDGET_INITIAL_WIDTH) {\r\n\t\t\t\t// 1. never resized before, double click should maximizes it\r\n\t\t\t\t// 2. users resized it already but its width is the same as default\r\n\t\t\t\tconst layoutInfo = this._codeEditor.getLayoutInfo();\r\n\t\t\t\twidth = layoutInfo.width - 28 - layoutInfo.minimap.minimapWidth - 15;\r\n\t\t\t\tthis._resized = true;\r\n\t\t\t} else {\r\n\t\t\t\t/**\r\n\t\t\t\t * no op, the find widget should be shrinked to its default size.\r\n\t\t\t\t */\r\n\t\t\t}\r\n\r\n\r\n\t\t\tthis._domNode.style.width = `${width}px`;\r\n\t\t\tif (this._isReplaceVisible) {\r\n\t\t\t\tthis._replaceInput.width = dom.getTotalWidth(this._findInput.domNode);\r\n\t\t\t}\r\n\r\n\t\t\tthis._findInput.inputBox.layout();\r\n\t\t}));\r\n\t}\r\n\r\n\tprivate updateAccessibilitySupport(): void {\r\n\t\tconst value = this._codeEditor.getOption(EditorOption.accessibilitySupport);\r\n\t\tthis._findInput.setFocusInputOnOptionClick(value !== AccessibilitySupport.Enabled);\r\n\t}\r\n}\r\n\r\nexport interface ISimpleButtonOpts {\r\n\treadonly label: string;\r\n\treadonly className?: string;\r\n\treadonly icon?: ThemeIcon;\r\n\treadonly onTrigger: () => void;\r\n\treadonly onKeyDown?: (e: IKeyboardEvent) => void;\r\n}\r\n\r\nexport class SimpleButton extends Widget {\r\n\r\n\tprivate readonly _opts: ISimpleButtonOpts;\r\n\tprivate readonly _domNode: HTMLElement;\r\n\r\n\tconstructor(opts: ISimpleButtonOpts) {\r\n\t\tsuper();\r\n\t\tthis._opts = opts;\r\n\r\n\t\tlet className = 'button';\r\n\t\tif (this._opts.className) {\r\n\t\t\tclassName = className + ' ' + this._opts.className;\r\n\t\t}\r\n\t\tif (this._opts.icon) {\r\n\t\t\tclassName = className + ' ' + ThemeIcon.asClassName(this._opts.icon);\r\n\t\t}\r\n\r\n\t\tthis._domNode = document.createElement('div');\r\n\t\tthis._domNode.title = this._opts.label;\r\n\t\tthis._domNode.tabIndex = 0;\r\n\t\tthis._domNode.className = className;\r\n\t\tthis._domNode.setAttribute('role', 'button');\r\n\t\tthis._domNode.setAttribute('aria-label', this._opts.label);\r\n\r\n\t\tthis.onclick(this._domNode, (e) => {\r\n\t\t\tthis._opts.onTrigger();\r\n\t\t\te.preventDefault();\r\n\t\t});\r\n\r\n\t\tthis.onkeydown(this._domNode, (e) => {\r\n\t\t\tif (e.equals(KeyCode.Space) || e.equals(KeyCode.Enter)) {\r\n\t\t\t\tthis._opts.onTrigger();\r\n\t\t\t\te.preventDefault();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (this._opts.onKeyDown) {\r\n\t\t\t\tthis._opts.onKeyDown(e);\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic get domNode(): HTMLElement {\r\n\t\treturn this._domNode;\r\n\t}\r\n\r\n\tpublic isEnabled(): boolean {\r\n\t\treturn (this._domNode.tabIndex >= 0);\r\n\t}\r\n\r\n\tpublic focus(): void {\r\n\t\tthis._domNode.focus();\r\n\t}\r\n\r\n\tpublic setEnabled(enabled: boolean): void {\r\n\t\tthis._domNode.classList.toggle('disabled', !enabled);\r\n\t\tthis._domNode.setAttribute('aria-disabled', String(!enabled));\r\n\t\tthis._domNode.tabIndex = enabled ? 0 : -1;\r\n\t}\r\n\r\n\tpublic setExpanded(expanded: boolean): void {\r\n\t\tthis._domNode.setAttribute('aria-expanded', String(!!expanded));\r\n\t\tif (expanded) {\r\n\t\t\tthis._domNode.classList.remove(...ThemeIcon.asClassNameArray(findCollapsedIcon));\r\n\t\t\tthis._domNode.classList.add(...ThemeIcon.asClassNameArray(findExpandedIcon));\r\n\t\t} else {\r\n\t\t\tthis._domNode.classList.remove(...ThemeIcon.asClassNameArray(findExpandedIcon));\r\n\t\t\tthis._domNode.classList.add(...ThemeIcon.asClassNameArray(findCollapsedIcon));\r\n\t\t}\r\n\t}\r\n}\r\n\r\n// theming\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst addBackgroundColorRule = (selector: string, color: Color | undefined): void => {\r\n\t\tif (color) {\r\n\t\t\tcollector.addRule(`.monaco-editor ${selector} { background-color: ${color}; }`);\r\n\t\t}\r\n\t};\r\n\r\n\taddBackgroundColorRule('.findMatch', theme.getColor(editorFindMatchHighlight));\r\n\taddBackgroundColorRule('.currentFindMatch', theme.getColor(editorFindMatch));\r\n\taddBackgroundColorRule('.findScope', theme.getColor(editorFindRangeHighlight));\r\n\r\n\tconst widgetBackground = theme.getColor(editorWidgetBackground);\r\n\taddBackgroundColorRule('.find-widget', widgetBackground);\r\n\r\n\tconst widgetShadowColor = theme.getColor(widgetShadow);\r\n\tif (widgetShadowColor) {\r\n\t\tcollector.addRule(`.monaco-editor .find-widget { box-shadow: 0 0 8px 2px ${widgetShadowColor}; }`);\r\n\t}\r\n\r\n\tconst findMatchHighlightBorder = theme.getColor(editorFindMatchHighlightBorder);\r\n\tif (findMatchHighlightBorder) {\r\n\t\tcollector.addRule(`.monaco-editor .findMatch { border: 1px ${theme.type === 'hc' ? 'dotted' : 'solid'} ${findMatchHighlightBorder}; box-sizing: border-box; }`);\r\n\t}\r\n\r\n\tconst findMatchBorder = theme.getColor(editorFindMatchBorder);\r\n\tif (findMatchBorder) {\r\n\t\tcollector.addRule(`.monaco-editor .currentFindMatch { border: 2px solid ${findMatchBorder}; padding: 1px; box-sizing: border-box; }`);\r\n\t}\r\n\r\n\tconst findRangeHighlightBorder = theme.getColor(editorFindRangeHighlightBorder);\r\n\tif (findRangeHighlightBorder) {\r\n\t\tcollector.addRule(`.monaco-editor .findScope { border: 1px ${theme.type === 'hc' ? 'dashed' : 'solid'} ${findRangeHighlightBorder}; }`);\r\n\t}\r\n\r\n\tconst hcBorder = theme.getColor(contrastBorder);\r\n\tif (hcBorder) {\r\n\t\tcollector.addRule(`.monaco-editor .find-widget { border: 1px solid ${hcBorder}; }`);\r\n\t}\r\n\r\n\tconst foreground = theme.getColor(editorWidgetForeground);\r\n\tif (foreground) {\r\n\t\tcollector.addRule(`.monaco-editor .find-widget { color: ${foreground}; }`);\r\n\t}\r\n\r\n\tconst error = theme.getColor(errorForeground);\r\n\tif (error) {\r\n\t\tcollector.addRule(`.monaco-editor .find-widget.no-results .matchesCount { color: ${error}; }`);\r\n\t}\r\n\r\n\tconst resizeBorderBackground = theme.getColor(editorWidgetResizeBorder);\r\n\tif (resizeBorderBackground) {\r\n\t\tcollector.addRule(`.monaco-editor .find-widget .monaco-sash { background-color: ${resizeBorderBackground}; }`);\r\n\t} else {\r\n\t\tconst border = theme.getColor(editorWidgetBorder);\r\n\t\tif (border) {\r\n\t\t\tcollector.addRule(`.monaco-editor .find-widget .monaco-sash { background-color: ${border}; }`);\r\n\t\t}\r\n\t}\r\n\r\n\t// This rule is used to override the outline color for synthetic-focus find input.\r\n\tconst focusOutline = theme.getColor(focusBorder);\r\n\tif (focusOutline) {\r\n\t\tcollector.addRule(`.monaco-editor .find-widget .monaco-inputbox.synthetic-focus { outline-color: ${focusOutline}; }`);\r\n\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { Delayer } from 'vs/base/common/async';\r\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport * as strings from 'vs/base/common/strings';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction, EditorCommand, ServicesAccessor, registerEditorAction, registerEditorCommand, registerEditorContribution, MultiEditorAction, registerMultiEditorAction } from 'vs/editor/browser/editorExtensions';\r\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { CONTEXT_FIND_INPUT_FOCUSED, CONTEXT_FIND_WIDGET_VISIBLE, FIND_IDS, FindModelBoundToEditorModel, ToggleCaseSensitiveKeybinding, TogglePreserveCaseKeybinding, ToggleRegexKeybinding, ToggleSearchScopeKeybinding, ToggleWholeWordKeybinding, CONTEXT_REPLACE_INPUT_FOCUSED } from 'vs/editor/contrib/find/findModel';\r\nimport { FindOptionsWidget } from 'vs/editor/contrib/find/findOptionsWidget';\r\nimport { FindReplaceState, FindReplaceStateChangedEvent, INewFindReplaceState } from 'vs/editor/contrib/find/findState';\r\nimport { FindWidget, IFindController } from 'vs/editor/contrib/find/findWidget';\r\nimport { MenuId } from 'vs/platform/actions/common/actions';\r\nimport { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';\r\nimport { IContextKey, IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IContextViewService } from 'vs/platform/contextview/browser/contextView';\r\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';\r\nimport { IThemeService } from 'vs/platform/theme/common/themeService';\r\nimport { INotificationService } from 'vs/platform/notification/common/notification';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\n\r\nconst SEARCH_STRING_MAX_LENGTH = 524288;\r\n\r\nexport function getSelectionSearchString(editor: ICodeEditor, seedSearchStringFromSelection: 'single' | 'multiple' = 'single'): string | null {\r\n\tif (!editor.hasModel()) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\tconst selection = editor.getSelection();\r\n\t// if selection spans multiple lines, default search string to empty\r\n\r\n\tif ((seedSearchStringFromSelection === 'single' && selection.startLineNumber === selection.endLineNumber)\r\n\t\t|| seedSearchStringFromSelection === 'multiple') {\r\n\t\tif (selection.isEmpty()) {\r\n\t\t\tconst wordAtPosition = editor.getConfiguredWordAtPosition(selection.getStartPosition());\r\n\t\t\tif (wordAtPosition) {\r\n\t\t\t\treturn wordAtPosition.word;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tif (editor.getModel().getValueLengthInRange(selection) < SEARCH_STRING_MAX_LENGTH) {\r\n\t\t\t\treturn editor.getModel().getValueInRange(selection);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\treturn null;\r\n}\r\n\r\nexport const enum FindStartFocusAction {\r\n\tNoFocusChange,\r\n\tFocusFindInput,\r\n\tFocusReplaceInput\r\n}\r\n\r\nexport interface IFindStartOptions {\r\n\tforceRevealReplace: boolean;\r\n\tseedSearchStringFromSelection: 'none' | 'single' | 'multiple';\r\n\tseedSearchStringFromGlobalClipboard: boolean;\r\n\tshouldFocus: FindStartFocusAction;\r\n\tshouldAnimate: boolean;\r\n\tupdateSearchScope: boolean;\r\n\tloop: boolean;\r\n}\r\n\r\nexport class CommonFindController extends Disposable implements IEditorContribution {\r\n\r\n\tpublic static readonly ID = 'editor.contrib.findController';\r\n\r\n\tprotected _editor: ICodeEditor;\r\n\tprivate readonly _findWidgetVisible: IContextKey;\r\n\tprotected _state: FindReplaceState;\r\n\tprotected _updateHistoryDelayer: Delayer;\r\n\tprivate _model: FindModelBoundToEditorModel | null;\r\n\tprotected readonly _storageService: IStorageService;\r\n\tprivate readonly _clipboardService: IClipboardService;\r\n\tprotected readonly _contextKeyService: IContextKeyService;\r\n\r\n\tget editor() {\r\n\t\treturn this._editor;\r\n\t}\r\n\r\n\tpublic static get(editor: ICodeEditor): CommonFindController {\r\n\t\treturn editor.getContribution(CommonFindController.ID);\r\n\t}\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\r\n\t\t@IStorageService storageService: IStorageService,\r\n\t\t@IClipboardService clipboardService: IClipboardService\r\n\t) {\r\n\t\tsuper();\r\n\t\tthis._editor = editor;\r\n\t\tthis._findWidgetVisible = CONTEXT_FIND_WIDGET_VISIBLE.bindTo(contextKeyService);\r\n\t\tthis._contextKeyService = contextKeyService;\r\n\t\tthis._storageService = storageService;\r\n\t\tthis._clipboardService = clipboardService;\r\n\r\n\t\tthis._updateHistoryDelayer = new Delayer(500);\r\n\t\tthis._state = this._register(new FindReplaceState());\r\n\t\tthis.loadQueryState();\r\n\t\tthis._register(this._state.onFindReplaceStateChange((e) => this._onStateChanged(e)));\r\n\r\n\t\tthis._model = null;\r\n\r\n\t\tthis._register(this._editor.onDidChangeModel(() => {\r\n\t\t\tlet shouldRestartFind = (this._editor.getModel() && this._state.isRevealed);\r\n\r\n\t\t\tthis.disposeModel();\r\n\r\n\t\t\tthis._state.change({\r\n\t\t\t\tsearchScope: null,\r\n\t\t\t\tmatchCase: this._storageService.getBoolean('editor.matchCase', StorageScope.WORKSPACE, false),\r\n\t\t\t\twholeWord: this._storageService.getBoolean('editor.wholeWord', StorageScope.WORKSPACE, false),\r\n\t\t\t\tisRegex: this._storageService.getBoolean('editor.isRegex', StorageScope.WORKSPACE, false),\r\n\t\t\t\tpreserveCase: this._storageService.getBoolean('editor.preserveCase', StorageScope.WORKSPACE, false)\r\n\t\t\t}, false);\r\n\r\n\t\t\tif (shouldRestartFind) {\r\n\t\t\t\tthis._start({\r\n\t\t\t\t\tforceRevealReplace: false,\r\n\t\t\t\t\tseedSearchStringFromSelection: 'none',\r\n\t\t\t\t\tseedSearchStringFromGlobalClipboard: false,\r\n\t\t\t\t\tshouldFocus: FindStartFocusAction.NoFocusChange,\r\n\t\t\t\t\tshouldAnimate: false,\r\n\t\t\t\t\tupdateSearchScope: false,\r\n\t\t\t\t\tloop: this._editor.getOption(EditorOption.find).loop\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis.disposeModel();\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tprivate disposeModel(): void {\r\n\t\tif (this._model) {\r\n\t\t\tthis._model.dispose();\r\n\t\t\tthis._model = null;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _onStateChanged(e: FindReplaceStateChangedEvent): void {\r\n\t\tthis.saveQueryState(e);\r\n\r\n\t\tif (e.isRevealed) {\r\n\t\t\tif (this._state.isRevealed) {\r\n\t\t\t\tthis._findWidgetVisible.set(true);\r\n\t\t\t} else {\r\n\t\t\t\tthis._findWidgetVisible.reset();\r\n\t\t\t\tthis.disposeModel();\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (e.searchString) {\r\n\t\t\tthis.setGlobalBufferTerm(this._state.searchString);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate saveQueryState(e: FindReplaceStateChangedEvent) {\r\n\t\tif (e.isRegex) {\r\n\t\t\tthis._storageService.store('editor.isRegex', this._state.actualIsRegex, StorageScope.WORKSPACE, StorageTarget.USER);\r\n\t\t}\r\n\t\tif (e.wholeWord) {\r\n\t\t\tthis._storageService.store('editor.wholeWord', this._state.actualWholeWord, StorageScope.WORKSPACE, StorageTarget.USER);\r\n\t\t}\r\n\t\tif (e.matchCase) {\r\n\t\t\tthis._storageService.store('editor.matchCase', this._state.actualMatchCase, StorageScope.WORKSPACE, StorageTarget.USER);\r\n\t\t}\r\n\t\tif (e.preserveCase) {\r\n\t\t\tthis._storageService.store('editor.preserveCase', this._state.actualPreserveCase, StorageScope.WORKSPACE, StorageTarget.USER);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate loadQueryState() {\r\n\t\tthis._state.change({\r\n\t\t\tmatchCase: this._storageService.getBoolean('editor.matchCase', StorageScope.WORKSPACE, this._state.matchCase),\r\n\t\t\twholeWord: this._storageService.getBoolean('editor.wholeWord', StorageScope.WORKSPACE, this._state.wholeWord),\r\n\t\t\tisRegex: this._storageService.getBoolean('editor.isRegex', StorageScope.WORKSPACE, this._state.isRegex),\r\n\t\t\tpreserveCase: this._storageService.getBoolean('editor.preserveCase', StorageScope.WORKSPACE, this._state.preserveCase)\r\n\t\t}, false);\r\n\t}\r\n\r\n\tpublic isFindInputFocused(): boolean {\r\n\t\treturn !!CONTEXT_FIND_INPUT_FOCUSED.getValue(this._contextKeyService);\r\n\t}\r\n\r\n\tpublic getState(): FindReplaceState {\r\n\t\treturn this._state;\r\n\t}\r\n\r\n\tpublic closeFindWidget(): void {\r\n\t\tthis._state.change({\r\n\t\t\tisRevealed: false,\r\n\t\t\tsearchScope: null\r\n\t\t}, false);\r\n\t\tthis._editor.focus();\r\n\t}\r\n\r\n\tpublic toggleCaseSensitive(): void {\r\n\t\tthis._state.change({ matchCase: !this._state.matchCase }, false);\r\n\t\tif (!this._state.isRevealed) {\r\n\t\t\tthis.highlightFindOptions();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic toggleWholeWords(): void {\r\n\t\tthis._state.change({ wholeWord: !this._state.wholeWord }, false);\r\n\t\tif (!this._state.isRevealed) {\r\n\t\t\tthis.highlightFindOptions();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic toggleRegex(): void {\r\n\t\tthis._state.change({ isRegex: !this._state.isRegex }, false);\r\n\t\tif (!this._state.isRevealed) {\r\n\t\t\tthis.highlightFindOptions();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic togglePreserveCase(): void {\r\n\t\tthis._state.change({ preserveCase: !this._state.preserveCase }, false);\r\n\t\tif (!this._state.isRevealed) {\r\n\t\t\tthis.highlightFindOptions();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic toggleSearchScope(): void {\r\n\t\tif (this._state.searchScope) {\r\n\t\t\tthis._state.change({ searchScope: null }, true);\r\n\t\t} else {\r\n\t\t\tif (this._editor.hasModel()) {\r\n\t\t\t\tlet selections = this._editor.getSelections();\r\n\t\t\t\tselections.map(selection => {\r\n\t\t\t\t\tif (selection.endColumn === 1 && selection.endLineNumber > selection.startLineNumber) {\r\n\t\t\t\t\t\tselection = selection.setEndPosition(\r\n\t\t\t\t\t\t\tselection.endLineNumber - 1,\r\n\t\t\t\t\t\t\tthis._editor.getModel()!.getLineMaxColumn(selection.endLineNumber - 1)\r\n\t\t\t\t\t\t);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (!selection.isEmpty()) {\r\n\t\t\t\t\t\treturn selection;\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn null;\r\n\t\t\t\t}).filter(element => !!element);\r\n\r\n\t\t\t\tif (selections.length) {\r\n\t\t\t\t\tthis._state.change({ searchScope: selections }, true);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic setSearchString(searchString: string): void {\r\n\t\tif (this._state.isRegex) {\r\n\t\t\tsearchString = strings.escapeRegExpCharacters(searchString);\r\n\t\t}\r\n\t\tthis._state.change({ searchString: searchString }, false);\r\n\t}\r\n\r\n\tpublic highlightFindOptions(ignoreWhenVisible: boolean = false): void {\r\n\t\t// overwritten in subclass\r\n\t}\r\n\r\n\tprotected async _start(opts: IFindStartOptions): Promise {\r\n\t\tthis.disposeModel();\r\n\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\t// cannot do anything with an editor that doesn't have a model...\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet stateChanges: INewFindReplaceState = {\r\n\t\t\tisRevealed: true\r\n\t\t};\r\n\r\n\t\tif (opts.seedSearchStringFromSelection === 'single') {\r\n\t\t\tlet selectionSearchString = getSelectionSearchString(this._editor, opts.seedSearchStringFromSelection);\r\n\t\t\tif (selectionSearchString) {\r\n\t\t\t\tif (this._state.isRegex) {\r\n\t\t\t\t\tstateChanges.searchString = strings.escapeRegExpCharacters(selectionSearchString);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tstateChanges.searchString = selectionSearchString;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else if (opts.seedSearchStringFromSelection === 'multiple' && !opts.updateSearchScope) {\r\n\t\t\tlet selectionSearchString = getSelectionSearchString(this._editor, opts.seedSearchStringFromSelection);\r\n\t\t\tif (selectionSearchString) {\r\n\t\t\t\tstateChanges.searchString = selectionSearchString;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!stateChanges.searchString && opts.seedSearchStringFromGlobalClipboard) {\r\n\t\t\tlet selectionSearchString = await this.getGlobalBufferTerm();\r\n\r\n\t\t\tif (!this._editor.hasModel()) {\r\n\t\t\t\t// the editor has lost its model in the meantime\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (selectionSearchString) {\r\n\t\t\t\tstateChanges.searchString = selectionSearchString;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Overwrite isReplaceRevealed\r\n\t\tif (opts.forceRevealReplace) {\r\n\t\t\tstateChanges.isReplaceRevealed = true;\r\n\t\t} else if (!this._findWidgetVisible.get()) {\r\n\t\t\tstateChanges.isReplaceRevealed = false;\r\n\t\t}\r\n\r\n\t\tif (opts.updateSearchScope) {\r\n\t\t\tlet currentSelections = this._editor.getSelections();\r\n\t\t\tif (currentSelections.some(selection => !selection.isEmpty())) {\r\n\t\t\t\tstateChanges.searchScope = currentSelections;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tstateChanges.loop = opts.loop;\r\n\r\n\t\tthis._state.change(stateChanges, false);\r\n\r\n\t\tif (!this._model) {\r\n\t\t\tthis._model = new FindModelBoundToEditorModel(this._editor, this._state);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic start(opts: IFindStartOptions): Promise {\r\n\t\treturn this._start(opts);\r\n\t}\r\n\r\n\tpublic moveToNextMatch(): boolean {\r\n\t\tif (this._model) {\r\n\t\t\tthis._model.moveToNextMatch();\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic moveToPrevMatch(): boolean {\r\n\t\tif (this._model) {\r\n\t\t\tthis._model.moveToPrevMatch();\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic replace(): boolean {\r\n\t\tif (this._model) {\r\n\t\t\tthis._model.replace();\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic replaceAll(): boolean {\r\n\t\tif (this._model) {\r\n\t\t\tthis._model.replaceAll();\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic selectAllMatches(): boolean {\r\n\t\tif (this._model) {\r\n\t\t\tthis._model.selectAllMatches();\r\n\t\t\tthis._editor.focus();\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tpublic async getGlobalBufferTerm(): Promise {\r\n\t\tif (this._editor.getOption(EditorOption.find).globalFindClipboard\r\n\t\t\t&& this._editor.hasModel()\r\n\t\t\t&& !this._editor.getModel().isTooLargeForSyncing()\r\n\t\t) {\r\n\t\t\treturn this._clipboardService.readFindText();\r\n\t\t}\r\n\t\treturn '';\r\n\t}\r\n\r\n\tpublic setGlobalBufferTerm(text: string): void {\r\n\t\tif (this._editor.getOption(EditorOption.find).globalFindClipboard\r\n\t\t\t&& this._editor.hasModel()\r\n\t\t\t&& !this._editor.getModel().isTooLargeForSyncing()\r\n\t\t) {\r\n\t\t\t// intentionally not awaited\r\n\t\t\tthis._clipboardService.writeFindText(text);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class FindController extends CommonFindController implements IFindController {\r\n\r\n\tprivate _widget: FindWidget | null;\r\n\tprivate _findOptionsWidget: FindOptionsWidget | null;\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor,\r\n\t\t@IContextViewService private readonly _contextViewService: IContextViewService,\r\n\t\t@IContextKeyService _contextKeyService: IContextKeyService,\r\n\t\t@IKeybindingService private readonly _keybindingService: IKeybindingService,\r\n\t\t@IThemeService private readonly _themeService: IThemeService,\r\n\t\t@INotificationService private readonly _notificationService: INotificationService,\r\n\t\t@IStorageService _storageService: IStorageService,\r\n\t\t@IClipboardService clipboardService: IClipboardService,\r\n\t) {\r\n\t\tsuper(editor, _contextKeyService, _storageService, clipboardService);\r\n\t\tthis._widget = null;\r\n\t\tthis._findOptionsWidget = null;\r\n\t}\r\n\r\n\tprotected async _start(opts: IFindStartOptions): Promise {\r\n\t\tif (!this._widget) {\r\n\t\t\tthis._createFindWidget();\r\n\t\t}\r\n\r\n\t\tconst selection = this._editor.getSelection();\r\n\t\tlet updateSearchScope = false;\r\n\r\n\t\tswitch (this._editor.getOption(EditorOption.find).autoFindInSelection) {\r\n\t\t\tcase 'always':\r\n\t\t\t\tupdateSearchScope = true;\r\n\t\t\t\tbreak;\r\n\t\t\tcase 'never':\r\n\t\t\t\tupdateSearchScope = false;\r\n\t\t\t\tbreak;\r\n\t\t\tcase 'multiline':\r\n\t\t\t\tconst isSelectionMultipleLine = !!selection && selection.startLineNumber !== selection.endLineNumber;\r\n\t\t\t\tupdateSearchScope = isSelectionMultipleLine;\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tdefault:\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\topts.updateSearchScope = updateSearchScope;\r\n\r\n\t\tawait super._start(opts);\r\n\r\n\t\tif (this._widget) {\r\n\t\t\tif (opts.shouldFocus === FindStartFocusAction.FocusReplaceInput) {\r\n\t\t\t\tthis._widget.focusReplaceInput();\r\n\t\t\t} else if (opts.shouldFocus === FindStartFocusAction.FocusFindInput) {\r\n\t\t\t\tthis._widget.focusFindInput();\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic highlightFindOptions(ignoreWhenVisible: boolean = false): void {\r\n\t\tif (!this._widget) {\r\n\t\t\tthis._createFindWidget();\r\n\t\t}\r\n\t\tif (this._state.isRevealed && !ignoreWhenVisible) {\r\n\t\t\tthis._widget!.highlightFindOptions();\r\n\t\t} else {\r\n\t\t\tthis._findOptionsWidget!.highlightFindOptions();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _createFindWidget() {\r\n\t\tthis._widget = this._register(new FindWidget(this._editor, this, this._state, this._contextViewService, this._keybindingService, this._contextKeyService, this._themeService, this._storageService, this._notificationService));\r\n\t\tthis._findOptionsWidget = this._register(new FindOptionsWidget(this._editor, this._state, this._keybindingService, this._themeService));\r\n\t}\r\n}\r\n\r\nexport class StartFindAction extends MultiEditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: FIND_IDS.StartFindAction,\r\n\t\t\tlabel: nls.localize('startFindAction', \"Find\"),\r\n\t\t\talias: 'Find',\r\n\t\t\tprecondition: ContextKeyExpr.or(ContextKeyExpr.has('editorFocus'), ContextKeyExpr.has('editorIsOpen')),\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: null,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.KEY_F,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tmenuOpts: {\r\n\t\t\t\tmenuId: MenuId.MenubarEditMenu,\r\n\t\t\t\tgroup: '3_find',\r\n\t\t\t\ttitle: nls.localize({ key: 'miFind', comment: ['&& denotes a mnemonic'] }, \"&&Find\"),\r\n\t\t\t\torder: 1\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic async run(accessor: ServicesAccessor | null, editor: ICodeEditor): Promise {\r\n\t\tlet controller = CommonFindController.get(editor);\r\n\t\tif (controller) {\r\n\t\t\tawait controller.start({\r\n\t\t\t\tforceRevealReplace: false,\r\n\t\t\t\tseedSearchStringFromSelection: editor.getOption(EditorOption.find).seedSearchStringFromSelection ? 'single' : 'none',\r\n\t\t\t\tseedSearchStringFromGlobalClipboard: editor.getOption(EditorOption.find).globalFindClipboard,\r\n\t\t\t\tshouldFocus: FindStartFocusAction.FocusFindInput,\r\n\t\t\t\tshouldAnimate: true,\r\n\t\t\t\tupdateSearchScope: false,\r\n\t\t\t\tloop: editor.getOption(EditorOption.find).loop\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class StartFindWithSelectionAction extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: FIND_IDS.StartFindWithSelection,\r\n\t\t\tlabel: nls.localize('startFindWithSelectionAction', \"Find With Selection\"),\r\n\t\t\talias: 'Find With Selection',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: null,\r\n\t\t\t\tprimary: 0,\r\n\t\t\t\tmac: {\r\n\t\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.KEY_E,\r\n\t\t\t\t},\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic async run(accessor: ServicesAccessor | null, editor: ICodeEditor): Promise {\r\n\t\tlet controller = CommonFindController.get(editor);\r\n\t\tif (controller) {\r\n\t\t\tawait controller.start({\r\n\t\t\t\tforceRevealReplace: false,\r\n\t\t\t\tseedSearchStringFromSelection: 'multiple',\r\n\t\t\t\tseedSearchStringFromGlobalClipboard: false,\r\n\t\t\t\tshouldFocus: FindStartFocusAction.NoFocusChange,\r\n\t\t\t\tshouldAnimate: true,\r\n\t\t\t\tupdateSearchScope: false,\r\n\t\t\t\tloop: editor.getOption(EditorOption.find).loop\r\n\t\t\t});\r\n\r\n\t\t\tcontroller.setGlobalBufferTerm(controller.getState().searchString);\r\n\t\t}\r\n\t}\r\n}\r\nexport abstract class MatchFindAction extends EditorAction {\r\n\tpublic async run(accessor: ServicesAccessor | null, editor: ICodeEditor): Promise {\r\n\t\tlet controller = CommonFindController.get(editor);\r\n\t\tif (controller && !this._run(controller)) {\r\n\t\t\tawait controller.start({\r\n\t\t\t\tforceRevealReplace: false,\r\n\t\t\t\tseedSearchStringFromSelection: (controller.getState().searchString.length === 0) && editor.getOption(EditorOption.find).seedSearchStringFromSelection ? 'single' : 'none',\r\n\t\t\t\tseedSearchStringFromGlobalClipboard: true,\r\n\t\t\t\tshouldFocus: FindStartFocusAction.NoFocusChange,\r\n\t\t\t\tshouldAnimate: true,\r\n\t\t\t\tupdateSearchScope: false,\r\n\t\t\t\tloop: editor.getOption(EditorOption.find).loop\r\n\t\t\t});\r\n\t\t\tthis._run(controller);\r\n\t\t}\r\n\t}\r\n\r\n\tprotected abstract _run(controller: CommonFindController): boolean;\r\n}\r\n\r\nexport class NextMatchFindAction extends MatchFindAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: FIND_IDS.NextMatchFindAction,\r\n\t\t\tlabel: nls.localize('findNextMatchAction', \"Find Next\"),\r\n\t\t\talias: 'Find Next',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.focus,\r\n\t\t\t\tprimary: KeyCode.F3,\r\n\t\t\t\tmac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_G, secondary: [KeyCode.F3] },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprotected _run(controller: CommonFindController): boolean {\r\n\t\tconst result = controller.moveToNextMatch();\r\n\t\tif (result) {\r\n\t\t\tcontroller.editor.pushUndoStop();\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\nexport class NextMatchFindAction2 extends MatchFindAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: FIND_IDS.NextMatchFindAction,\r\n\t\t\tlabel: nls.localize('findNextMatchAction', \"Find Next\"),\r\n\t\t\talias: 'Find Next',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: ContextKeyExpr.and(EditorContextKeys.focus, CONTEXT_FIND_INPUT_FOCUSED),\r\n\t\t\t\tprimary: KeyCode.Enter,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprotected _run(controller: CommonFindController): boolean {\r\n\t\tconst result = controller.moveToNextMatch();\r\n\t\tif (result) {\r\n\t\t\tcontroller.editor.pushUndoStop();\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\nexport class PreviousMatchFindAction extends MatchFindAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: FIND_IDS.PreviousMatchFindAction,\r\n\t\t\tlabel: nls.localize('findPreviousMatchAction', \"Find Previous\"),\r\n\t\t\talias: 'Find Previous',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.focus,\r\n\t\t\t\tprimary: KeyMod.Shift | KeyCode.F3,\r\n\t\t\t\tmac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G, secondary: [KeyMod.Shift | KeyCode.F3] },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprotected _run(controller: CommonFindController): boolean {\r\n\t\treturn controller.moveToPrevMatch();\r\n\t}\r\n}\r\n\r\nexport class PreviousMatchFindAction2 extends MatchFindAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: FIND_IDS.PreviousMatchFindAction,\r\n\t\t\tlabel: nls.localize('findPreviousMatchAction', \"Find Previous\"),\r\n\t\t\talias: 'Find Previous',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: ContextKeyExpr.and(EditorContextKeys.focus, CONTEXT_FIND_INPUT_FOCUSED),\r\n\t\t\t\tprimary: KeyMod.Shift | KeyCode.Enter,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprotected _run(controller: CommonFindController): boolean {\r\n\t\treturn controller.moveToPrevMatch();\r\n\t}\r\n}\r\n\r\nexport abstract class SelectionMatchFindAction extends EditorAction {\r\n\tpublic async run(accessor: ServicesAccessor | null, editor: ICodeEditor): Promise {\r\n\t\tlet controller = CommonFindController.get(editor);\r\n\t\tif (!controller) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tlet selectionSearchString = getSelectionSearchString(editor);\r\n\t\tif (selectionSearchString) {\r\n\t\t\tcontroller.setSearchString(selectionSearchString);\r\n\t\t}\r\n\t\tif (!this._run(controller)) {\r\n\t\t\tawait controller.start({\r\n\t\t\t\tforceRevealReplace: false,\r\n\t\t\t\tseedSearchStringFromSelection: editor.getOption(EditorOption.find).seedSearchStringFromSelection ? 'single' : 'none',\r\n\t\t\t\tseedSearchStringFromGlobalClipboard: false,\r\n\t\t\t\tshouldFocus: FindStartFocusAction.NoFocusChange,\r\n\t\t\t\tshouldAnimate: true,\r\n\t\t\t\tupdateSearchScope: false,\r\n\t\t\t\tloop: editor.getOption(EditorOption.find).loop\r\n\t\t\t});\r\n\t\t\tthis._run(controller);\r\n\t\t}\r\n\t}\r\n\r\n\tprotected abstract _run(controller: CommonFindController): boolean;\r\n}\r\n\r\nexport class NextSelectionMatchFindAction extends SelectionMatchFindAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: FIND_IDS.NextSelectionMatchFindAction,\r\n\t\t\tlabel: nls.localize('nextSelectionMatchFindAction', \"Find Next Selection\"),\r\n\t\t\talias: 'Find Next Selection',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.focus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.F3,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprotected _run(controller: CommonFindController): boolean {\r\n\t\treturn controller.moveToNextMatch();\r\n\t}\r\n}\r\n\r\nexport class PreviousSelectionMatchFindAction extends SelectionMatchFindAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: FIND_IDS.PreviousSelectionMatchFindAction,\r\n\t\t\tlabel: nls.localize('previousSelectionMatchFindAction', \"Find Previous Selection\"),\r\n\t\t\talias: 'Find Previous Selection',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.focus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.F3,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprotected _run(controller: CommonFindController): boolean {\r\n\t\treturn controller.moveToPrevMatch();\r\n\t}\r\n}\r\n\r\nexport class StartFindReplaceAction extends MultiEditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: FIND_IDS.StartFindReplaceAction,\r\n\t\t\tlabel: nls.localize('startReplace', \"Replace\"),\r\n\t\t\talias: 'Replace',\r\n\t\t\tprecondition: ContextKeyExpr.or(ContextKeyExpr.has('editorFocus'), ContextKeyExpr.has('editorIsOpen')),\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: null,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.KEY_H,\r\n\t\t\t\tmac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_F },\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tmenuOpts: {\r\n\t\t\t\tmenuId: MenuId.MenubarEditMenu,\r\n\t\t\t\tgroup: '3_find',\r\n\t\t\t\ttitle: nls.localize({ key: 'miReplace', comment: ['&& denotes a mnemonic'] }, \"&&Replace\"),\r\n\t\t\t\torder: 2\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic async run(accessor: ServicesAccessor | null, editor: ICodeEditor): Promise {\r\n\t\tif (!editor.hasModel() || editor.getOption(EditorOption.readOnly)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet controller = CommonFindController.get(editor);\r\n\t\tlet currentSelection = editor.getSelection();\r\n\t\tlet findInputFocused = controller.isFindInputFocused();\r\n\t\t// we only seed search string from selection when the current selection is single line and not empty,\r\n\t\t// + the find input is not focused\r\n\t\tlet seedSearchStringFromSelection = !currentSelection.isEmpty()\r\n\t\t\t&& currentSelection.startLineNumber === currentSelection.endLineNumber && editor.getOption(EditorOption.find).seedSearchStringFromSelection\r\n\t\t\t&& !findInputFocused;\r\n\t\t/*\r\n\t\t * if the existing search string in find widget is empty and we don't seed search string from selection, it means the Find Input is still empty, so we should focus the Find Input instead of Replace Input.\r\n\r\n\t\t * findInputFocused true -> seedSearchStringFromSelection false, FocusReplaceInput\r\n\t\t * findInputFocused false, seedSearchStringFromSelection true FocusReplaceInput\r\n\t\t * findInputFocused false seedSearchStringFromSelection false FocusFindInput\r\n\t\t */\r\n\t\tlet shouldFocus = (findInputFocused || seedSearchStringFromSelection) ?\r\n\t\t\tFindStartFocusAction.FocusReplaceInput : FindStartFocusAction.FocusFindInput;\r\n\r\n\r\n\t\tif (controller) {\r\n\t\t\tawait controller.start({\r\n\t\t\t\tforceRevealReplace: true,\r\n\t\t\t\tseedSearchStringFromSelection: seedSearchStringFromSelection ? 'single' : 'none',\r\n\t\t\t\tseedSearchStringFromGlobalClipboard: editor.getOption(EditorOption.find).seedSearchStringFromSelection,\r\n\t\t\t\tshouldFocus: shouldFocus,\r\n\t\t\t\tshouldAnimate: true,\r\n\t\t\t\tupdateSearchScope: false,\r\n\t\t\t\tloop: editor.getOption(EditorOption.find).loop\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(CommonFindController.ID, FindController);\r\n\r\nexport const EditorStartFindAction = new StartFindAction();\r\nregisterMultiEditorAction(EditorStartFindAction);\r\nregisterEditorAction(StartFindWithSelectionAction);\r\nregisterEditorAction(NextMatchFindAction);\r\nregisterEditorAction(NextMatchFindAction2);\r\nregisterEditorAction(PreviousMatchFindAction);\r\nregisterEditorAction(PreviousMatchFindAction2);\r\nregisterEditorAction(NextSelectionMatchFindAction);\r\nregisterEditorAction(PreviousSelectionMatchFindAction);\r\nexport const EditorStartFindReplaceAction = new StartFindReplaceAction();\r\nregisterMultiEditorAction(EditorStartFindReplaceAction);\r\n\r\nconst FindCommand = EditorCommand.bindToContribution(CommonFindController.get);\r\n\r\nregisterEditorCommand(new FindCommand({\r\n\tid: FIND_IDS.CloseFindWidgetCommand,\r\n\tprecondition: CONTEXT_FIND_WIDGET_VISIBLE,\r\n\thandler: x => x.closeFindWidget(),\r\n\tkbOpts: {\r\n\t\tweight: KeybindingWeight.EditorContrib + 5,\r\n\t\tkbExpr: ContextKeyExpr.and(EditorContextKeys.focus, ContextKeyExpr.not('isComposing')),\r\n\t\tprimary: KeyCode.Escape,\r\n\t\tsecondary: [KeyMod.Shift | KeyCode.Escape]\r\n\t}\r\n}));\r\n\r\nregisterEditorCommand(new FindCommand({\r\n\tid: FIND_IDS.ToggleCaseSensitiveCommand,\r\n\tprecondition: undefined,\r\n\thandler: x => x.toggleCaseSensitive(),\r\n\tkbOpts: {\r\n\t\tweight: KeybindingWeight.EditorContrib + 5,\r\n\t\tkbExpr: EditorContextKeys.focus,\r\n\t\tprimary: ToggleCaseSensitiveKeybinding.primary,\r\n\t\tmac: ToggleCaseSensitiveKeybinding.mac,\r\n\t\twin: ToggleCaseSensitiveKeybinding.win,\r\n\t\tlinux: ToggleCaseSensitiveKeybinding.linux\r\n\t}\r\n}));\r\n\r\nregisterEditorCommand(new FindCommand({\r\n\tid: FIND_IDS.ToggleWholeWordCommand,\r\n\tprecondition: undefined,\r\n\thandler: x => x.toggleWholeWords(),\r\n\tkbOpts: {\r\n\t\tweight: KeybindingWeight.EditorContrib + 5,\r\n\t\tkbExpr: EditorContextKeys.focus,\r\n\t\tprimary: ToggleWholeWordKeybinding.primary,\r\n\t\tmac: ToggleWholeWordKeybinding.mac,\r\n\t\twin: ToggleWholeWordKeybinding.win,\r\n\t\tlinux: ToggleWholeWordKeybinding.linux\r\n\t}\r\n}));\r\n\r\nregisterEditorCommand(new FindCommand({\r\n\tid: FIND_IDS.ToggleRegexCommand,\r\n\tprecondition: undefined,\r\n\thandler: x => x.toggleRegex(),\r\n\tkbOpts: {\r\n\t\tweight: KeybindingWeight.EditorContrib + 5,\r\n\t\tkbExpr: EditorContextKeys.focus,\r\n\t\tprimary: ToggleRegexKeybinding.primary,\r\n\t\tmac: ToggleRegexKeybinding.mac,\r\n\t\twin: ToggleRegexKeybinding.win,\r\n\t\tlinux: ToggleRegexKeybinding.linux\r\n\t}\r\n}));\r\n\r\nregisterEditorCommand(new FindCommand({\r\n\tid: FIND_IDS.ToggleSearchScopeCommand,\r\n\tprecondition: undefined,\r\n\thandler: x => x.toggleSearchScope(),\r\n\tkbOpts: {\r\n\t\tweight: KeybindingWeight.EditorContrib + 5,\r\n\t\tkbExpr: EditorContextKeys.focus,\r\n\t\tprimary: ToggleSearchScopeKeybinding.primary,\r\n\t\tmac: ToggleSearchScopeKeybinding.mac,\r\n\t\twin: ToggleSearchScopeKeybinding.win,\r\n\t\tlinux: ToggleSearchScopeKeybinding.linux\r\n\t}\r\n}));\r\n\r\nregisterEditorCommand(new FindCommand({\r\n\tid: FIND_IDS.TogglePreserveCaseCommand,\r\n\tprecondition: undefined,\r\n\thandler: x => x.togglePreserveCase(),\r\n\tkbOpts: {\r\n\t\tweight: KeybindingWeight.EditorContrib + 5,\r\n\t\tkbExpr: EditorContextKeys.focus,\r\n\t\tprimary: TogglePreserveCaseKeybinding.primary,\r\n\t\tmac: TogglePreserveCaseKeybinding.mac,\r\n\t\twin: TogglePreserveCaseKeybinding.win,\r\n\t\tlinux: TogglePreserveCaseKeybinding.linux\r\n\t}\r\n}));\r\n\r\nregisterEditorCommand(new FindCommand({\r\n\tid: FIND_IDS.ReplaceOneAction,\r\n\tprecondition: CONTEXT_FIND_WIDGET_VISIBLE,\r\n\thandler: x => x.replace(),\r\n\tkbOpts: {\r\n\t\tweight: KeybindingWeight.EditorContrib + 5,\r\n\t\tkbExpr: EditorContextKeys.focus,\r\n\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_1\r\n\t}\r\n}));\r\n\r\nregisterEditorCommand(new FindCommand({\r\n\tid: FIND_IDS.ReplaceOneAction,\r\n\tprecondition: CONTEXT_FIND_WIDGET_VISIBLE,\r\n\thandler: x => x.replace(),\r\n\tkbOpts: {\r\n\t\tweight: KeybindingWeight.EditorContrib + 5,\r\n\t\tkbExpr: ContextKeyExpr.and(EditorContextKeys.focus, CONTEXT_REPLACE_INPUT_FOCUSED),\r\n\t\tprimary: KeyCode.Enter\r\n\t}\r\n}));\r\n\r\nregisterEditorCommand(new FindCommand({\r\n\tid: FIND_IDS.ReplaceAllAction,\r\n\tprecondition: CONTEXT_FIND_WIDGET_VISIBLE,\r\n\thandler: x => x.replaceAll(),\r\n\tkbOpts: {\r\n\t\tweight: KeybindingWeight.EditorContrib + 5,\r\n\t\tkbExpr: EditorContextKeys.focus,\r\n\t\tprimary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Enter\r\n\t}\r\n}));\r\n\r\nregisterEditorCommand(new FindCommand({\r\n\tid: FIND_IDS.ReplaceAllAction,\r\n\tprecondition: CONTEXT_FIND_WIDGET_VISIBLE,\r\n\thandler: x => x.replaceAll(),\r\n\tkbOpts: {\r\n\t\tweight: KeybindingWeight.EditorContrib + 5,\r\n\t\tkbExpr: ContextKeyExpr.and(EditorContextKeys.focus, CONTEXT_REPLACE_INPUT_FOCUSED),\r\n\t\tprimary: undefined,\r\n\t\tmac: {\r\n\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.Enter,\r\n\t\t}\r\n\t}\r\n}));\r\n\r\nregisterEditorCommand(new FindCommand({\r\n\tid: FIND_IDS.SelectAllMatchesAction,\r\n\tprecondition: CONTEXT_FIND_WIDGET_VISIBLE,\r\n\thandler: x => x.selectAllMatches(),\r\n\tkbOpts: {\r\n\t\tweight: KeybindingWeight.EditorContrib + 5,\r\n\t\tkbExpr: EditorContextKeys.focus,\r\n\t\tprimary: KeyMod.Alt | KeyCode.Enter\r\n\t}\r\n}));\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { TrackedRangeStickiness, IModelDeltaDecoration, IModelDecorationsChangeAccessor } from 'vs/editor/common/model';\r\nimport { ModelDecorationOptions } from 'vs/editor/common/model/textModel';\r\nimport { IDecorationProvider } from 'vs/editor/contrib/folding/foldingModel';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { Codicon } from 'vs/base/common/codicons';\r\nimport { localize } from 'vs/nls';\r\nimport { registerIcon } from 'vs/platform/theme/common/iconRegistry';\r\nimport { ThemeIcon } from 'vs/platform/theme/common/themeService';\r\n\r\nexport const foldingExpandedIcon = registerIcon('folding-expanded', Codicon.chevronDown, localize('foldingExpandedIcon', 'Icon for expanded ranges in the editor glyph margin.'));\r\nexport const foldingCollapsedIcon = registerIcon('folding-collapsed', Codicon.chevronRight, localize('foldingCollapsedIcon', 'Icon for collapsed ranges in the editor glyph margin.'));\r\nexport class FoldingDecorationProvider implements IDecorationProvider {\r\n\r\n\tprivate static readonly COLLAPSED_VISUAL_DECORATION = ModelDecorationOptions.register({\r\n\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,\r\n\t\tafterContentClassName: 'inline-folded',\r\n\t\tisWholeLine: true,\r\n\t\tfirstLineDecorationClassName: ThemeIcon.asClassName(foldingCollapsedIcon)\r\n\t});\r\n\r\n\tprivate static readonly COLLAPSED_HIGHLIGHTED_VISUAL_DECORATION = ModelDecorationOptions.register({\r\n\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,\r\n\t\tafterContentClassName: 'inline-folded',\r\n\t\tclassName: 'folded-background',\r\n\t\tisWholeLine: true,\r\n\t\tfirstLineDecorationClassName: ThemeIcon.asClassName(foldingCollapsedIcon)\r\n\t});\r\n\r\n\tprivate static readonly EXPANDED_AUTO_HIDE_VISUAL_DECORATION = ModelDecorationOptions.register({\r\n\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,\r\n\t\tisWholeLine: true,\r\n\t\tfirstLineDecorationClassName: ThemeIcon.asClassName(foldingExpandedIcon)\r\n\t});\r\n\r\n\tprivate static readonly EXPANDED_VISUAL_DECORATION = ModelDecorationOptions.register({\r\n\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,\r\n\t\tisWholeLine: true,\r\n\t\tfirstLineDecorationClassName: 'alwaysShowFoldIcons ' + ThemeIcon.asClassName(foldingExpandedIcon)\r\n\t});\r\n\r\n\tprivate static readonly HIDDEN_RANGE_DECORATION = ModelDecorationOptions.register({\r\n\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges\r\n\t});\r\n\r\n\tpublic autoHideFoldingControls: boolean = true;\r\n\r\n\tpublic showFoldingHighlights: boolean = true;\r\n\r\n\tconstructor(private readonly editor: ICodeEditor) {\r\n\t}\r\n\r\n\tgetDecorationOption(isCollapsed: boolean, isHidden: boolean): ModelDecorationOptions {\r\n\t\tif (isHidden) {\r\n\t\t\treturn FoldingDecorationProvider.HIDDEN_RANGE_DECORATION;\r\n\t\t}\r\n\t\tif (isCollapsed) {\r\n\t\t\treturn this.showFoldingHighlights ? FoldingDecorationProvider.COLLAPSED_HIGHLIGHTED_VISUAL_DECORATION : FoldingDecorationProvider.COLLAPSED_VISUAL_DECORATION;\r\n\t\t} else if (this.autoHideFoldingControls) {\r\n\t\t\treturn FoldingDecorationProvider.EXPANDED_AUTO_HIDE_VISUAL_DECORATION;\r\n\t\t} else {\r\n\t\t\treturn FoldingDecorationProvider.EXPANDED_VISUAL_DECORATION;\r\n\t\t}\r\n\t}\r\n\r\n\tdeltaDecorations(oldDecorations: string[], newDecorations: IModelDeltaDecoration[]): string[] {\r\n\t\treturn this.editor.deltaDecorations(oldDecorations, newDecorations);\r\n\t}\r\n\r\n\tchangeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => T): T {\r\n\t\treturn this.editor.changeDecorations(callback);\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport 'vs/css!./folding';\r\nimport * as nls from 'vs/nls';\r\nimport * as types from 'vs/base/common/types';\r\nimport { escapeRegExpCharacters } from 'vs/base/common/strings';\r\nimport { RunOnceScheduler, Delayer, CancelablePromise, createCancelablePromise } from 'vs/base/common/async';\r\nimport { KeyCode, KeyMod, KeyChord } from 'vs/base/common/keyCodes';\r\nimport { Disposable, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { ScrollType, IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { ITextModel } from 'vs/editor/common/model';\r\nimport { registerEditorAction, registerEditorContribution, ServicesAccessor, EditorAction, registerInstantiatedEditorAction } from 'vs/editor/browser/editorExtensions';\r\nimport { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';\r\nimport { FoldingModel, setCollapseStateAtLevel, CollapseMemento, setCollapseStateLevelsDown, setCollapseStateLevelsUp, setCollapseStateForMatchingLines, setCollapseStateForType, toggleCollapseState, setCollapseStateUp } from 'vs/editor/contrib/folding/foldingModel';\r\nimport { FoldingDecorationProvider, foldingCollapsedIcon, foldingExpandedIcon } from './foldingDecorations';\r\nimport { FoldingRegions, FoldingRegion } from './foldingRanges';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { IMarginData, IEmptyContentData } from 'vs/editor/browser/controller/mouseTarget';\r\nimport { HiddenRangeModel } from 'vs/editor/contrib/folding/hiddenRangeModel';\r\nimport { IRange } from 'vs/editor/common/core/range';\r\nimport { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';\r\nimport { IndentRangeProvider } from 'vs/editor/contrib/folding/indentRangeProvider';\r\nimport { IPosition } from 'vs/editor/common/core/position';\r\nimport { FoldingRangeProviderRegistry, FoldingRangeKind } from 'vs/editor/common/modes';\r\nimport { SyntaxRangeProvider, ID_SYNTAX_PROVIDER } from './syntaxRangeProvider';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { InitializingRangeProvider, ID_INIT_PROVIDER } from 'vs/editor/contrib/folding/intializingRangeProvider';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\r\nimport { registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService';\r\nimport { registerColor, editorSelectionBackground, transparent, iconForeground } from 'vs/platform/theme/common/colorRegistry';\r\n\r\nconst CONTEXT_FOLDING_ENABLED = new RawContextKey('foldingEnabled', false);\r\n\r\nexport interface RangeProvider {\r\n\treadonly id: string;\r\n\tcompute(cancelationToken: CancellationToken): Promise;\r\n\tdispose(): void;\r\n}\r\n\r\ninterface FoldingStateMemento {\r\n\tcollapsedRegions?: CollapseMemento;\r\n\tlineCount?: number;\r\n\tprovider?: string;\r\n}\r\n\r\nexport class FoldingController extends Disposable implements IEditorContribution {\r\n\r\n\tpublic static ID = 'editor.contrib.folding';\r\n\r\n\tpublic static get(editor: ICodeEditor): FoldingController {\r\n\t\treturn editor.getContribution(FoldingController.ID);\r\n\t}\r\n\r\n\tprivate readonly editor: ICodeEditor;\r\n\tprivate _isEnabled: boolean;\r\n\tprivate _useFoldingProviders: boolean;\r\n\tprivate _unfoldOnClickAfterEndOfLine: boolean;\r\n\tprivate _restoringViewState: boolean;\r\n\r\n\tprivate readonly foldingDecorationProvider: FoldingDecorationProvider;\r\n\r\n\tprivate foldingModel: FoldingModel | null;\r\n\tprivate hiddenRangeModel: HiddenRangeModel | null;\r\n\r\n\tprivate rangeProvider: RangeProvider | null;\r\n\tprivate foldingRegionPromise: CancelablePromise | null;\r\n\r\n\tprivate foldingStateMemento: FoldingStateMemento | null;\r\n\r\n\tprivate foldingModelPromise: Promise | null;\r\n\tprivate updateScheduler: Delayer | null;\r\n\r\n\tprivate foldingEnabled: IContextKey;\r\n\tprivate cursorChangedScheduler: RunOnceScheduler | null;\r\n\r\n\tprivate readonly localToDispose = this._register(new DisposableStore());\r\n\tprivate mouseDownInfo: { lineNumber: number, iconClicked: boolean } | null;\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor,\r\n\t\t@IContextKeyService private readonly contextKeyService: IContextKeyService\r\n\t) {\r\n\t\tsuper();\r\n\t\tthis.editor = editor;\r\n\t\tconst options = this.editor.getOptions();\r\n\t\tthis._isEnabled = options.get(EditorOption.folding);\r\n\t\tthis._useFoldingProviders = options.get(EditorOption.foldingStrategy) !== 'indentation';\r\n\t\tthis._unfoldOnClickAfterEndOfLine = options.get(EditorOption.unfoldOnClickAfterEndOfLine);\r\n\t\tthis._restoringViewState = false;\r\n\r\n\t\tthis.foldingModel = null;\r\n\t\tthis.hiddenRangeModel = null;\r\n\t\tthis.rangeProvider = null;\r\n\t\tthis.foldingRegionPromise = null;\r\n\t\tthis.foldingStateMemento = null;\r\n\t\tthis.foldingModelPromise = null;\r\n\t\tthis.updateScheduler = null;\r\n\t\tthis.cursorChangedScheduler = null;\r\n\t\tthis.mouseDownInfo = null;\r\n\r\n\t\tthis.foldingDecorationProvider = new FoldingDecorationProvider(editor);\r\n\t\tthis.foldingDecorationProvider.autoHideFoldingControls = options.get(EditorOption.showFoldingControls) === 'mouseover';\r\n\t\tthis.foldingDecorationProvider.showFoldingHighlights = options.get(EditorOption.foldingHighlight);\r\n\t\tthis.foldingEnabled = CONTEXT_FOLDING_ENABLED.bindTo(this.contextKeyService);\r\n\t\tthis.foldingEnabled.set(this._isEnabled);\r\n\r\n\t\tthis._register(this.editor.onDidChangeModel(() => this.onModelChanged()));\r\n\r\n\t\tthis._register(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => {\r\n\t\t\tif (e.hasChanged(EditorOption.folding)) {\r\n\t\t\t\tthis._isEnabled = this.editor.getOptions().get(EditorOption.folding);\r\n\t\t\t\tthis.foldingEnabled.set(this._isEnabled);\r\n\t\t\t\tthis.onModelChanged();\r\n\t\t\t}\r\n\t\t\tif (e.hasChanged(EditorOption.showFoldingControls) || e.hasChanged(EditorOption.foldingHighlight)) {\r\n\t\t\t\tconst options = this.editor.getOptions();\r\n\t\t\t\tthis.foldingDecorationProvider.autoHideFoldingControls = options.get(EditorOption.showFoldingControls) === 'mouseover';\r\n\t\t\t\tthis.foldingDecorationProvider.showFoldingHighlights = options.get(EditorOption.foldingHighlight);\r\n\t\t\t\tthis.onModelContentChanged();\r\n\t\t\t}\r\n\t\t\tif (e.hasChanged(EditorOption.foldingStrategy)) {\r\n\t\t\t\tthis._useFoldingProviders = this.editor.getOptions().get(EditorOption.foldingStrategy) !== 'indentation';\r\n\t\t\t\tthis.onFoldingStrategyChanged();\r\n\t\t\t}\r\n\t\t\tif (e.hasChanged(EditorOption.unfoldOnClickAfterEndOfLine)) {\r\n\t\t\t\tthis._unfoldOnClickAfterEndOfLine = this.editor.getOptions().get(EditorOption.unfoldOnClickAfterEndOfLine);\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis.onModelChanged();\r\n\t}\r\n\r\n\t/**\r\n\t * Store view state.\r\n\t */\r\n\tpublic saveViewState(): FoldingStateMemento | undefined {\r\n\t\tlet model = this.editor.getModel();\r\n\t\tif (!model || !this._isEnabled || model.isTooLargeForTokenization()) {\r\n\t\t\treturn {};\r\n\t\t}\r\n\t\tif (this.foldingModel) { // disposed ?\r\n\t\t\tlet collapsedRegions = this.foldingModel.isInitialized ? this.foldingModel.getMemento() : this.hiddenRangeModel!.getMemento();\r\n\t\t\tlet provider = this.rangeProvider ? this.rangeProvider.id : undefined;\r\n\t\t\treturn { collapsedRegions, lineCount: model.getLineCount(), provider };\r\n\t\t}\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\t/**\r\n\t * Restore view state.\r\n\t */\r\n\tpublic restoreViewState(state: FoldingStateMemento): void {\r\n\t\tlet model = this.editor.getModel();\r\n\t\tif (!model || !this._isEnabled || model.isTooLargeForTokenization() || !this.hiddenRangeModel) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (!state || !state.collapsedRegions || state.lineCount !== model.getLineCount()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (state.provider === ID_SYNTAX_PROVIDER || state.provider === ID_INIT_PROVIDER) {\r\n\t\t\tthis.foldingStateMemento = state;\r\n\t\t}\r\n\r\n\t\tconst collapsedRegions = state.collapsedRegions;\r\n\r\n\t\t// set the hidden ranges right away, before waiting for the folding model.\r\n\t\tif (this.hiddenRangeModel.applyMemento(collapsedRegions)) {\r\n\t\t\tconst foldingModel = this.getFoldingModel();\r\n\t\t\tif (foldingModel) {\r\n\t\t\t\tfoldingModel.then(foldingModel => {\r\n\t\t\t\t\tif (foldingModel) {\r\n\t\t\t\t\t\tthis._restoringViewState = true;\r\n\t\t\t\t\t\ttry {\r\n\t\t\t\t\t\t\tfoldingModel.applyMemento(collapsedRegions);\r\n\t\t\t\t\t\t} finally {\r\n\t\t\t\t\t\t\tthis._restoringViewState = false;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}).then(undefined, onUnexpectedError);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate onModelChanged(): void {\r\n\t\tthis.localToDispose.clear();\r\n\r\n\t\tlet model = this.editor.getModel();\r\n\t\tif (!this._isEnabled || !model || model.isTooLargeForTokenization()) {\r\n\t\t\t// huge files get no view model, so they cannot support hidden areas\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.foldingModel = new FoldingModel(model, this.foldingDecorationProvider);\r\n\t\tthis.localToDispose.add(this.foldingModel);\r\n\r\n\t\tthis.hiddenRangeModel = new HiddenRangeModel(this.foldingModel);\r\n\t\tthis.localToDispose.add(this.hiddenRangeModel);\r\n\t\tthis.localToDispose.add(this.hiddenRangeModel.onDidChange(hr => this.onHiddenRangesChanges(hr)));\r\n\r\n\t\tthis.updateScheduler = new Delayer(200);\r\n\r\n\t\tthis.cursorChangedScheduler = new RunOnceScheduler(() => this.revealCursor(), 200);\r\n\t\tthis.localToDispose.add(this.cursorChangedScheduler);\r\n\t\tthis.localToDispose.add(FoldingRangeProviderRegistry.onDidChange(() => this.onFoldingStrategyChanged()));\r\n\t\tthis.localToDispose.add(this.editor.onDidChangeModelLanguageConfiguration(() => this.onFoldingStrategyChanged())); // covers model language changes as well\r\n\t\tthis.localToDispose.add(this.editor.onDidChangeModelContent(() => this.onModelContentChanged()));\r\n\t\tthis.localToDispose.add(this.editor.onDidChangeCursorPosition(() => this.onCursorPositionChanged()));\r\n\t\tthis.localToDispose.add(this.editor.onMouseDown(e => this.onEditorMouseDown(e)));\r\n\t\tthis.localToDispose.add(this.editor.onMouseUp(e => this.onEditorMouseUp(e)));\r\n\t\tthis.localToDispose.add({\r\n\t\t\tdispose: () => {\r\n\t\t\t\tif (this.foldingRegionPromise) {\r\n\t\t\t\t\tthis.foldingRegionPromise.cancel();\r\n\t\t\t\t\tthis.foldingRegionPromise = null;\r\n\t\t\t\t}\r\n\t\t\t\tif (this.updateScheduler) {\r\n\t\t\t\t\tthis.updateScheduler.cancel();\r\n\t\t\t\t}\r\n\t\t\t\tthis.updateScheduler = null;\r\n\t\t\t\tthis.foldingModel = null;\r\n\t\t\t\tthis.foldingModelPromise = null;\r\n\t\t\t\tthis.hiddenRangeModel = null;\r\n\t\t\t\tthis.cursorChangedScheduler = null;\r\n\t\t\t\tthis.foldingStateMemento = null;\r\n\t\t\t\tif (this.rangeProvider) {\r\n\t\t\t\t\tthis.rangeProvider.dispose();\r\n\t\t\t\t}\r\n\t\t\t\tthis.rangeProvider = null;\r\n\t\t\t}\r\n\t\t});\r\n\t\tthis.onModelContentChanged();\r\n\t}\r\n\r\n\tprivate onFoldingStrategyChanged() {\r\n\t\tif (this.rangeProvider) {\r\n\t\t\tthis.rangeProvider.dispose();\r\n\t\t}\r\n\t\tthis.rangeProvider = null;\r\n\t\tthis.onModelContentChanged();\r\n\t}\r\n\r\n\tprivate getRangeProvider(editorModel: ITextModel): RangeProvider {\r\n\t\tif (this.rangeProvider) {\r\n\t\t\treturn this.rangeProvider;\r\n\t\t}\r\n\t\tthis.rangeProvider = new IndentRangeProvider(editorModel); // fallback\r\n\r\n\r\n\t\tif (this._useFoldingProviders && this.foldingModel) {\r\n\t\t\tlet foldingProviders = FoldingRangeProviderRegistry.ordered(this.foldingModel.textModel);\r\n\t\t\tif (foldingProviders.length === 0 && this.foldingStateMemento && this.foldingStateMemento.collapsedRegions) {\r\n\t\t\t\tconst rangeProvider = this.rangeProvider = new InitializingRangeProvider(editorModel, this.foldingStateMemento.collapsedRegions, () => {\r\n\t\t\t\t\t// if after 30 the InitializingRangeProvider is still not replaced, force a refresh\r\n\t\t\t\t\tthis.foldingStateMemento = null;\r\n\t\t\t\t\tthis.onFoldingStrategyChanged();\r\n\t\t\t\t}, 30000);\r\n\t\t\t\treturn rangeProvider; // keep memento in case there are still no foldingProviders on the next request.\r\n\t\t\t} else if (foldingProviders.length > 0) {\r\n\t\t\t\tthis.rangeProvider = new SyntaxRangeProvider(editorModel, foldingProviders, () => this.onModelContentChanged());\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis.foldingStateMemento = null;\r\n\t\treturn this.rangeProvider;\r\n\t}\r\n\r\n\tpublic getFoldingModel() {\r\n\t\treturn this.foldingModelPromise;\r\n\t}\r\n\r\n\tprivate onModelContentChanged() {\r\n\t\tif (this.updateScheduler) {\r\n\t\t\tif (this.foldingRegionPromise) {\r\n\t\t\t\tthis.foldingRegionPromise.cancel();\r\n\t\t\t\tthis.foldingRegionPromise = null;\r\n\t\t\t}\r\n\t\t\tthis.foldingModelPromise = this.updateScheduler.trigger(() => {\r\n\t\t\t\tconst foldingModel = this.foldingModel;\r\n\t\t\t\tif (!foldingModel) { // null if editor has been disposed, or folding turned off\r\n\t\t\t\t\treturn null;\r\n\t\t\t\t}\r\n\t\t\t\tlet foldingRegionPromise = this.foldingRegionPromise = createCancelablePromise(token => this.getRangeProvider(foldingModel.textModel).compute(token));\r\n\t\t\t\treturn foldingRegionPromise.then(foldingRanges => {\r\n\t\t\t\t\tif (foldingRanges && foldingRegionPromise === this.foldingRegionPromise) { // new request or cancelled in the meantime?\r\n\t\t\t\t\t\t// some cursors might have moved into hidden regions, make sure they are in expanded regions\r\n\t\t\t\t\t\tlet selections = this.editor.getSelections();\r\n\t\t\t\t\t\tlet selectionLineNumbers = selections ? selections.map(s => s.startLineNumber) : [];\r\n\t\t\t\t\t\tfoldingModel.update(foldingRanges, selectionLineNumbers);\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn foldingModel;\r\n\t\t\t\t});\r\n\t\t\t}).then(undefined, (err) => {\r\n\t\t\t\tonUnexpectedError(err);\r\n\t\t\t\treturn null;\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tprivate onHiddenRangesChanges(hiddenRanges: IRange[]) {\r\n\t\tif (this.hiddenRangeModel && hiddenRanges.length && !this._restoringViewState) {\r\n\t\t\tlet selections = this.editor.getSelections();\r\n\t\t\tif (selections) {\r\n\t\t\t\tif (this.hiddenRangeModel.adjustSelections(selections)) {\r\n\t\t\t\t\tthis.editor.setSelections(selections);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis.editor.setHiddenAreas(hiddenRanges);\r\n\t}\r\n\r\n\tprivate onCursorPositionChanged() {\r\n\t\tif (this.hiddenRangeModel && this.hiddenRangeModel.hasRanges()) {\r\n\t\t\tthis.cursorChangedScheduler!.schedule();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate revealCursor() {\r\n\t\tconst foldingModel = this.getFoldingModel();\r\n\t\tif (!foldingModel) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tfoldingModel.then(foldingModel => { // null is returned if folding got disabled in the meantime\r\n\t\t\tif (foldingModel) {\r\n\t\t\t\tlet selections = this.editor.getSelections();\r\n\t\t\t\tif (selections && selections.length > 0) {\r\n\t\t\t\t\tlet toToggle: FoldingRegion[] = [];\r\n\t\t\t\t\tfor (let selection of selections) {\r\n\t\t\t\t\t\tlet lineNumber = selection.selectionStartLineNumber;\r\n\t\t\t\t\t\tif (this.hiddenRangeModel && this.hiddenRangeModel.isHidden(lineNumber)) {\r\n\t\t\t\t\t\t\ttoToggle.push(...foldingModel.getAllRegionsAtLine(lineNumber, r => r.isCollapsed && lineNumber > r.startLineNumber));\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (toToggle.length) {\r\n\t\t\t\t\t\tfoldingModel.toggleCollapseState(toToggle);\r\n\t\t\t\t\t\tthis.reveal(selections[0].getPosition());\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}).then(undefined, onUnexpectedError);\r\n\r\n\t}\r\n\r\n\tprivate onEditorMouseDown(e: IEditorMouseEvent): void {\r\n\t\tthis.mouseDownInfo = null;\r\n\r\n\r\n\t\tif (!this.hiddenRangeModel || !e.target || !e.target.range) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (!e.event.leftButton && !e.event.middleButton) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst range = e.target.range;\r\n\t\tlet iconClicked = false;\r\n\t\tswitch (e.target.type) {\r\n\t\t\tcase MouseTargetType.GUTTER_LINE_DECORATIONS:\r\n\t\t\t\tconst data = e.target.detail as IMarginData;\r\n\t\t\t\tconst offsetLeftInGutter = (e.target.element as HTMLElement).offsetLeft;\r\n\t\t\t\tconst gutterOffsetX = data.offsetX - offsetLeftInGutter;\r\n\r\n\t\t\t\t// const gutterOffsetX = data.offsetX - data.glyphMarginWidth - data.lineNumbersWidth - data.glyphMarginLeft;\r\n\r\n\t\t\t\t// TODO@joao TODO@alex TODO@martin this is such that we don't collide with dirty diff\r\n\t\t\t\tif (gutterOffsetX < 5) { // the whitespace between the border and the real folding icon border is 5px\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\ticonClicked = true;\r\n\t\t\t\tbreak;\r\n\t\t\tcase MouseTargetType.CONTENT_EMPTY: {\r\n\t\t\t\tif (this._unfoldOnClickAfterEndOfLine && this.hiddenRangeModel.hasRanges()) {\r\n\t\t\t\t\tconst data = e.target.detail as IEmptyContentData;\r\n\t\t\t\t\tif (!data.isAfterLines) {\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tcase MouseTargetType.CONTENT_TEXT: {\r\n\t\t\t\tif (this.hiddenRangeModel.hasRanges()) {\r\n\t\t\t\t\tlet model = this.editor.getModel();\r\n\t\t\t\t\tif (model && range.startColumn === model.getLineMaxColumn(range.startLineNumber)) {\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tdefault:\r\n\t\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.mouseDownInfo = { lineNumber: range.startLineNumber, iconClicked };\r\n\t}\r\n\r\n\tprivate onEditorMouseUp(e: IEditorMouseEvent): void {\r\n\t\tconst foldingModel = this.getFoldingModel();\r\n\t\tif (!foldingModel || !this.mouseDownInfo || !e.target) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tlet lineNumber = this.mouseDownInfo.lineNumber;\r\n\t\tlet iconClicked = this.mouseDownInfo.iconClicked;\r\n\r\n\t\tlet range = e.target.range;\r\n\t\tif (!range || range.startLineNumber !== lineNumber) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (iconClicked) {\r\n\t\t\tif (e.target.type !== MouseTargetType.GUTTER_LINE_DECORATIONS) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tlet model = this.editor.getModel();\r\n\t\t\tif (!model || range.startColumn !== model.getLineMaxColumn(lineNumber)) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tfoldingModel.then(foldingModel => {\r\n\t\t\tif (foldingModel) {\r\n\t\t\t\tlet region = foldingModel.getRegionAtLine(lineNumber);\r\n\t\t\t\tif (region && region.startLineNumber === lineNumber) {\r\n\t\t\t\t\tlet isCollapsed = region.isCollapsed;\r\n\t\t\t\t\tif (iconClicked || isCollapsed) {\r\n\t\t\t\t\t\tlet toToggle = [];\r\n\t\t\t\t\t\tlet recursive = e.event.middleButton || e.event.shiftKey;\r\n\t\t\t\t\t\tif (recursive) {\r\n\t\t\t\t\t\t\tfor (const r of foldingModel.getRegionsInside(region)) {\r\n\t\t\t\t\t\t\t\tif (r.isCollapsed === isCollapsed) {\r\n\t\t\t\t\t\t\t\t\ttoToggle.push(r);\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\t// when recursive, first only collapse all children. If all are already folded or there are no children, also fold parent.\r\n\t\t\t\t\t\tif (isCollapsed || !recursive || toToggle.length === 0) {\r\n\t\t\t\t\t\t\ttoToggle.push(region);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tfoldingModel.toggleCollapseState(toToggle);\r\n\t\t\t\t\t\tthis.reveal({ lineNumber, column: 1 });\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}).then(undefined, onUnexpectedError);\r\n\t}\r\n\r\n\tpublic reveal(position: IPosition): void {\r\n\t\tthis.editor.revealPositionInCenterIfOutsideViewport(position, ScrollType.Smooth);\r\n\t}\r\n}\r\n\r\nabstract class FoldingAction extends EditorAction {\r\n\r\n\tabstract invoke(foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor, args: T): void;\r\n\r\n\tpublic runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: T): void | Promise {\r\n\t\tlet foldingController = FoldingController.get(editor);\r\n\t\tif (!foldingController) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tlet foldingModelPromise = foldingController.getFoldingModel();\r\n\t\tif (foldingModelPromise) {\r\n\t\t\tthis.reportTelemetry(accessor, editor);\r\n\t\t\treturn foldingModelPromise.then(foldingModel => {\r\n\t\t\t\tif (foldingModel) {\r\n\t\t\t\t\tthis.invoke(foldingController, foldingModel, editor, args);\r\n\t\t\t\t\tconst selection = editor.getSelection();\r\n\t\t\t\t\tif (selection) {\r\n\t\t\t\t\t\tfoldingController.reveal(selection.getStartPosition());\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tprotected getSelectedLines(editor: ICodeEditor) {\r\n\t\tlet selections = editor.getSelections();\r\n\t\treturn selections ? selections.map(s => s.startLineNumber) : [];\r\n\t}\r\n\r\n\tprotected getLineNumbers(args: FoldingArguments, editor: ICodeEditor) {\r\n\t\tif (args && args.selectionLines) {\r\n\t\t\treturn args.selectionLines.map(l => l + 1); // to 0-bases line numbers\r\n\t\t}\r\n\t\treturn this.getSelectedLines(editor);\r\n\t}\r\n\r\n\tpublic run(_accessor: ServicesAccessor, _editor: ICodeEditor): void {\r\n\t}\r\n}\r\n\r\ninterface FoldingArguments {\r\n\tlevels?: number;\r\n\tdirection?: 'up' | 'down';\r\n\tselectionLines?: number[];\r\n}\r\n\r\nfunction foldingArgumentsConstraint(args: any) {\r\n\tif (!types.isUndefined(args)) {\r\n\t\tif (!types.isObject(args)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tconst foldingArgs: FoldingArguments = args;\r\n\t\tif (!types.isUndefined(foldingArgs.levels) && !types.isNumber(foldingArgs.levels)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (!types.isUndefined(foldingArgs.direction) && !types.isString(foldingArgs.direction)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tif (!types.isUndefined(foldingArgs.selectionLines) && (!types.isArray(foldingArgs.selectionLines) || !foldingArgs.selectionLines.every(types.isNumber))) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n\treturn true;\r\n}\r\n\r\nclass UnfoldAction extends FoldingAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.unfold',\r\n\t\t\tlabel: nls.localize('unfoldAction.label', \"Unfold\"),\r\n\t\t\talias: 'Unfold',\r\n\t\t\tprecondition: CONTEXT_FOLDING_ENABLED,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_CLOSE_SQUARE_BRACKET,\r\n\t\t\t\tmac: {\r\n\t\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.US_CLOSE_SQUARE_BRACKET\r\n\t\t\t\t},\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tdescription: {\r\n\t\t\t\tdescription: 'Unfold the content in the editor',\r\n\t\t\t\targs: [\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tname: 'Unfold editor argument',\r\n\t\t\t\t\t\tdescription: `Property-value pairs that can be passed through this argument:\r\n\t\t\t\t\t\t* 'levels': Number of levels to unfold. If not set, defaults to 1.\r\n\t\t\t\t\t\t* 'direction': If 'up', unfold given number of levels up otherwise unfolds down.\r\n\t\t\t\t\t\t* 'selectionLines': The start lines (0-based) of the editor selections to apply the unfold action to. If not set, the active selection(s) will be used.\r\n\t\t\t\t\t\t`,\r\n\t\t\t\t\t\tconstraint: foldingArgumentsConstraint,\r\n\t\t\t\t\t\tschema: {\r\n\t\t\t\t\t\t\t'type': 'object',\r\n\t\t\t\t\t\t\t'properties': {\r\n\t\t\t\t\t\t\t\t'levels': {\r\n\t\t\t\t\t\t\t\t\t'type': 'number',\r\n\t\t\t\t\t\t\t\t\t'default': 1\r\n\t\t\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\t\t'direction': {\r\n\t\t\t\t\t\t\t\t\t'type': 'string',\r\n\t\t\t\t\t\t\t\t\t'enum': ['up', 'down'],\r\n\t\t\t\t\t\t\t\t\t'default': 'down'\r\n\t\t\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\t\t'selectionLines': {\r\n\t\t\t\t\t\t\t\t\t'type': 'array',\r\n\t\t\t\t\t\t\t\t\t'items': {\r\n\t\t\t\t\t\t\t\t\t\t'type': 'number'\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t]\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tinvoke(_foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor, args: FoldingArguments): void {\r\n\t\tlet levels = args && args.levels || 1;\r\n\t\tlet lineNumbers = this.getLineNumbers(args, editor);\r\n\t\tif (args && args.direction === 'up') {\r\n\t\t\tsetCollapseStateLevelsUp(foldingModel, false, levels, lineNumbers);\r\n\t\t} else {\r\n\t\t\tsetCollapseStateLevelsDown(foldingModel, false, levels, lineNumbers);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass UnFoldRecursivelyAction extends FoldingAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.unfoldRecursively',\r\n\t\t\tlabel: nls.localize('unFoldRecursivelyAction.label', \"Unfold Recursively\"),\r\n\t\t\talias: 'Unfold Recursively',\r\n\t\t\tprecondition: CONTEXT_FOLDING_ENABLED,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.US_CLOSE_SQUARE_BRACKET),\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tinvoke(_foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor, _args: any): void {\r\n\t\tsetCollapseStateLevelsDown(foldingModel, false, Number.MAX_VALUE, this.getSelectedLines(editor));\r\n\t}\r\n}\r\n\r\nclass FoldAction extends FoldingAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.fold',\r\n\t\t\tlabel: nls.localize('foldAction.label', \"Fold\"),\r\n\t\t\talias: 'Fold',\r\n\t\t\tprecondition: CONTEXT_FOLDING_ENABLED,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_OPEN_SQUARE_BRACKET,\r\n\t\t\t\tmac: {\r\n\t\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.US_OPEN_SQUARE_BRACKET\r\n\t\t\t\t},\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tdescription: {\r\n\t\t\t\tdescription: 'Fold the content in the editor',\r\n\t\t\t\targs: [\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tname: 'Fold editor argument',\r\n\t\t\t\t\t\tdescription: `Property-value pairs that can be passed through this argument:\r\n\t\t\t\t\t\t\t* 'levels': Number of levels to fold.\r\n\t\t\t\t\t\t\t* 'direction': If 'up', folds given number of levels up otherwise folds down.\r\n\t\t\t\t\t\t\t* 'selectionLines': The start lines (0-based) of the editor selections to apply the fold action to. If not set, the active selection(s) will be used.\r\n\t\t\t\t\t\t\tIf no levels or direction is set, folds the region at the locations or if already collapsed, the first uncollapsed parent instead.\r\n\t\t\t\t\t\t`,\r\n\t\t\t\t\t\tconstraint: foldingArgumentsConstraint,\r\n\t\t\t\t\t\tschema: {\r\n\t\t\t\t\t\t\t'type': 'object',\r\n\t\t\t\t\t\t\t'properties': {\r\n\t\t\t\t\t\t\t\t'levels': {\r\n\t\t\t\t\t\t\t\t\t'type': 'number',\r\n\t\t\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\t\t'direction': {\r\n\t\t\t\t\t\t\t\t\t'type': 'string',\r\n\t\t\t\t\t\t\t\t\t'enum': ['up', 'down'],\r\n\t\t\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\t\t'selectionLines': {\r\n\t\t\t\t\t\t\t\t\t'type': 'array',\r\n\t\t\t\t\t\t\t\t\t'items': {\r\n\t\t\t\t\t\t\t\t\t\t'type': 'number'\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t]\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tinvoke(_foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor, args: FoldingArguments): void {\r\n\t\tlet lineNumbers = this.getLineNumbers(args, editor);\r\n\r\n\t\tconst levels = args && args.levels;\r\n\t\tconst direction = args && args.direction;\r\n\r\n\t\tif (typeof levels !== 'number' && typeof direction !== 'string') {\r\n\t\t\t// fold the region at the location or if already collapsed, the first uncollapsed parent instead.\r\n\t\t\tsetCollapseStateUp(foldingModel, true, lineNumbers);\r\n\t\t} else {\r\n\t\t\tif (direction === 'up') {\r\n\t\t\t\tsetCollapseStateLevelsUp(foldingModel, true, levels || 1, lineNumbers);\r\n\t\t\t} else {\r\n\t\t\t\tsetCollapseStateLevelsDown(foldingModel, true, levels || 1, lineNumbers);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\n\r\nclass ToggleFoldAction extends FoldingAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.toggleFold',\r\n\t\t\tlabel: nls.localize('toggleFoldAction.label', \"Toggle Fold\"),\r\n\t\t\talias: 'Toggle Fold',\r\n\t\t\tprecondition: CONTEXT_FOLDING_ENABLED,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_L),\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tinvoke(_foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor): void {\r\n\t\tlet selectedLines = this.getSelectedLines(editor);\r\n\t\ttoggleCollapseState(foldingModel, 1, selectedLines);\r\n\t}\r\n}\r\n\r\n\r\nclass FoldRecursivelyAction extends FoldingAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.foldRecursively',\r\n\t\t\tlabel: nls.localize('foldRecursivelyAction.label', \"Fold Recursively\"),\r\n\t\t\talias: 'Fold Recursively',\r\n\t\t\tprecondition: CONTEXT_FOLDING_ENABLED,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.US_OPEN_SQUARE_BRACKET),\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tinvoke(_foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor): void {\r\n\t\tlet selectedLines = this.getSelectedLines(editor);\r\n\t\tsetCollapseStateLevelsDown(foldingModel, true, Number.MAX_VALUE, selectedLines);\r\n\t}\r\n}\r\n\r\nclass FoldAllBlockCommentsAction extends FoldingAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.foldAllBlockComments',\r\n\t\t\tlabel: nls.localize('foldAllBlockComments.label', \"Fold All Block Comments\"),\r\n\t\t\talias: 'Fold All Block Comments',\r\n\t\t\tprecondition: CONTEXT_FOLDING_ENABLED,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.US_SLASH),\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tinvoke(_foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor): void {\r\n\t\tif (foldingModel.regions.hasTypes()) {\r\n\t\t\tsetCollapseStateForType(foldingModel, FoldingRangeKind.Comment.value, true);\r\n\t\t} else {\r\n\t\t\tconst editorModel = editor.getModel();\r\n\t\t\tif (!editorModel) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tlet comments = LanguageConfigurationRegistry.getComments(editorModel.getLanguageIdentifier().id);\r\n\t\t\tif (comments && comments.blockCommentStartToken) {\r\n\t\t\t\tlet regExp = new RegExp('^\\\\s*' + escapeRegExpCharacters(comments.blockCommentStartToken));\r\n\t\t\t\tsetCollapseStateForMatchingLines(foldingModel, regExp, true);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass FoldAllRegionsAction extends FoldingAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.foldAllMarkerRegions',\r\n\t\t\tlabel: nls.localize('foldAllMarkerRegions.label', \"Fold All Regions\"),\r\n\t\t\talias: 'Fold All Regions',\r\n\t\t\tprecondition: CONTEXT_FOLDING_ENABLED,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_8),\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tinvoke(_foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor): void {\r\n\t\tif (foldingModel.regions.hasTypes()) {\r\n\t\t\tsetCollapseStateForType(foldingModel, FoldingRangeKind.Region.value, true);\r\n\t\t} else {\r\n\t\t\tconst editorModel = editor.getModel();\r\n\t\t\tif (!editorModel) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tlet foldingRules = LanguageConfigurationRegistry.getFoldingRules(editorModel.getLanguageIdentifier().id);\r\n\t\t\tif (foldingRules && foldingRules.markers && foldingRules.markers.start) {\r\n\t\t\t\tlet regExp = new RegExp(foldingRules.markers.start);\r\n\t\t\t\tsetCollapseStateForMatchingLines(foldingModel, regExp, true);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass UnfoldAllRegionsAction extends FoldingAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.unfoldAllMarkerRegions',\r\n\t\t\tlabel: nls.localize('unfoldAllMarkerRegions.label', \"Unfold All Regions\"),\r\n\t\t\talias: 'Unfold All Regions',\r\n\t\t\tprecondition: CONTEXT_FOLDING_ENABLED,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_9),\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tinvoke(_foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor): void {\r\n\t\tif (foldingModel.regions.hasTypes()) {\r\n\t\t\tsetCollapseStateForType(foldingModel, FoldingRangeKind.Region.value, false);\r\n\t\t} else {\r\n\t\t\tconst editorModel = editor.getModel();\r\n\t\t\tif (!editorModel) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tlet foldingRules = LanguageConfigurationRegistry.getFoldingRules(editorModel.getLanguageIdentifier().id);\r\n\t\t\tif (foldingRules && foldingRules.markers && foldingRules.markers.start) {\r\n\t\t\t\tlet regExp = new RegExp(foldingRules.markers.start);\r\n\t\t\t\tsetCollapseStateForMatchingLines(foldingModel, regExp, false);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass FoldAllAction extends FoldingAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.foldAll',\r\n\t\t\tlabel: nls.localize('foldAllAction.label', \"Fold All\"),\r\n\t\t\talias: 'Fold All',\r\n\t\t\tprecondition: CONTEXT_FOLDING_ENABLED,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_0),\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tinvoke(_foldingController: FoldingController, foldingModel: FoldingModel, _editor: ICodeEditor): void {\r\n\t\tsetCollapseStateLevelsDown(foldingModel, true);\r\n\t}\r\n}\r\n\r\nclass UnfoldAllAction extends FoldingAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.unfoldAll',\r\n\t\t\tlabel: nls.localize('unfoldAllAction.label', \"Unfold All\"),\r\n\t\t\talias: 'Unfold All',\r\n\t\t\tprecondition: CONTEXT_FOLDING_ENABLED,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_J),\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tinvoke(_foldingController: FoldingController, foldingModel: FoldingModel, _editor: ICodeEditor): void {\r\n\t\tsetCollapseStateLevelsDown(foldingModel, false);\r\n\t}\r\n}\r\n\r\nclass FoldLevelAction extends FoldingAction {\r\n\tprivate static readonly ID_PREFIX = 'editor.foldLevel';\r\n\tpublic static readonly ID = (level: number) => FoldLevelAction.ID_PREFIX + level;\r\n\r\n\tprivate getFoldingLevel() {\r\n\t\treturn parseInt(this.id.substr(FoldLevelAction.ID_PREFIX.length));\r\n\t}\r\n\r\n\tinvoke(_foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor): void {\r\n\t\tsetCollapseStateAtLevel(foldingModel, this.getFoldingLevel(), true, this.getSelectedLines(editor));\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(FoldingController.ID, FoldingController);\r\nregisterEditorAction(UnfoldAction);\r\nregisterEditorAction(UnFoldRecursivelyAction);\r\nregisterEditorAction(FoldAction);\r\nregisterEditorAction(FoldRecursivelyAction);\r\nregisterEditorAction(FoldAllAction);\r\nregisterEditorAction(UnfoldAllAction);\r\nregisterEditorAction(FoldAllBlockCommentsAction);\r\nregisterEditorAction(FoldAllRegionsAction);\r\nregisterEditorAction(UnfoldAllRegionsAction);\r\nregisterEditorAction(ToggleFoldAction);\r\n\r\nfor (let i = 1; i <= 7; i++) {\r\n\tregisterInstantiatedEditorAction(\r\n\t\tnew FoldLevelAction({\r\n\t\t\tid: FoldLevelAction.ID(i),\r\n\t\t\tlabel: nls.localize('foldLevelAction.label', \"Fold Level {0}\", i),\r\n\t\t\talias: `Fold Level ${i}`,\r\n\t\t\tprecondition: CONTEXT_FOLDING_ENABLED,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | (KeyCode.KEY_0 + i)),\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t})\r\n\t);\r\n}\r\n\r\nexport const foldBackgroundBackground = registerColor('editor.foldBackground', { light: transparent(editorSelectionBackground, 0.3), dark: transparent(editorSelectionBackground, 0.3), hc: null }, nls.localize('foldBackgroundBackground', \"Background color behind folded ranges. The color must not be opaque so as not to hide underlying decorations.\"), true);\r\nexport const editorFoldForeground = registerColor('editorGutter.foldingControlForeground', { dark: iconForeground, light: iconForeground, hc: iconForeground }, nls.localize('editorGutter.foldingControlForeground', 'Color of the folding control in the editor gutter.'));\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst foldBackground = theme.getColor(foldBackgroundBackground);\r\n\tif (foldBackground) {\r\n\t\tcollector.addRule(`.monaco-editor .folded-background { background-color: ${foldBackground}; }`);\r\n\t}\r\n\r\n\tconst editorFoldColor = theme.getColor(editorFoldForeground);\r\n\tif (editorFoldColor) {\r\n\t\tcollector.addRule(`\r\n\t\t.monaco-editor .cldr${ThemeIcon.asCSSSelector(foldingExpandedIcon)},\r\n\t\t.monaco-editor .cldr${ThemeIcon.asCSSSelector(foldingCollapsedIcon)} {\r\n\t\t\tcolor: ${editorFoldColor} !important;\r\n\t\t}\r\n\t\t`);\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IMarker } from 'vs/platform/markers/common/markers';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { registerEditorAction, registerEditorContribution, ServicesAccessor, IActionOptions, EditorAction, EditorCommand, registerEditorCommand } from 'vs/editor/browser/editorExtensions';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { MarkerNavigationWidget } from './gotoErrorWidget';\r\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\r\nimport { MenuId } from 'vs/platform/actions/common/actions';\r\nimport { TextEditorSelectionRevealType } from 'vs/platform/editor/common/editor';\r\nimport { Codicon } from 'vs/base/common/codicons';\r\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IMarkerNavigationService, MarkerList } from 'vs/editor/contrib/gotoError/markerNavigationService';\r\nimport { registerIcon } from 'vs/platform/theme/common/iconRegistry';\r\n\r\nexport class MarkerController implements IEditorContribution {\r\n\r\n\tstatic readonly ID = 'editor.contrib.markerController';\r\n\r\n\tstatic get(editor: ICodeEditor): MarkerController {\r\n\t\treturn editor.getContribution(MarkerController.ID);\r\n\t}\r\n\r\n\tprivate readonly _editor: ICodeEditor;\r\n\r\n\tprivate readonly _widgetVisible: IContextKey;\r\n\tprivate readonly _sessionDispoables = new DisposableStore();\r\n\r\n\tprivate _model?: MarkerList;\r\n\tprivate _widget?: MarkerNavigationWidget;\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor,\r\n\t\t@IMarkerNavigationService private readonly _markerNavigationService: IMarkerNavigationService,\r\n\t\t@IContextKeyService private readonly _contextKeyService: IContextKeyService,\r\n\t\t@ICodeEditorService private readonly _editorService: ICodeEditorService,\r\n\t\t@IInstantiationService private readonly _instantiationService: IInstantiationService,\r\n\t) {\r\n\t\tthis._editor = editor;\r\n\t\tthis._widgetVisible = CONTEXT_MARKERS_NAVIGATION_VISIBLE.bindTo(this._contextKeyService);\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis._cleanUp();\r\n\t\tthis._sessionDispoables.dispose();\r\n\t}\r\n\r\n\tprivate _cleanUp(): void {\r\n\t\tthis._widgetVisible.reset();\r\n\t\tthis._sessionDispoables.clear();\r\n\t\tthis._widget = undefined;\r\n\t\tthis._model = undefined;\r\n\t}\r\n\r\n\tprivate _getOrCreateModel(uri: URI | undefined): MarkerList {\r\n\r\n\t\tif (this._model && this._model.matches(uri)) {\r\n\t\t\treturn this._model;\r\n\t\t}\r\n\t\tlet reusePosition = false;\r\n\t\tif (this._model) {\r\n\t\t\treusePosition = true;\r\n\t\t\tthis._cleanUp();\r\n\t\t}\r\n\r\n\t\tthis._model = this._markerNavigationService.getMarkerList(uri);\r\n\t\tif (reusePosition) {\r\n\t\t\tthis._model.move(true, this._editor.getModel()!, this._editor.getPosition()!);\r\n\t\t}\r\n\r\n\t\tthis._widget = this._instantiationService.createInstance(MarkerNavigationWidget, this._editor);\r\n\t\tthis._widget.onDidClose(() => this.close(), this, this._sessionDispoables);\r\n\t\tthis._widgetVisible.set(true);\r\n\r\n\t\tthis._sessionDispoables.add(this._model);\r\n\t\tthis._sessionDispoables.add(this._widget);\r\n\r\n\t\t// follow cursor\r\n\t\tthis._sessionDispoables.add(this._editor.onDidChangeCursorPosition(e => {\r\n\t\t\tif (!this._model?.selected || !Range.containsPosition(this._model?.selected.marker, e.position)) {\r\n\t\t\t\tthis._model?.resetIndex();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\t// update markers\r\n\t\tthis._sessionDispoables.add(this._model.onDidChange(() => {\r\n\t\t\tif (!this._widget || !this._widget.position || !this._model) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tconst info = this._model.find(this._editor.getModel()!.uri, this._widget!.position!);\r\n\t\t\tif (info) {\r\n\t\t\t\tthis._widget.updateMarker(info.marker);\r\n\t\t\t} else {\r\n\t\t\t\tthis._widget.showStale();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\t// open related\r\n\t\tthis._sessionDispoables.add(this._widget.onDidSelectRelatedInformation(related => {\r\n\t\t\tthis._editorService.openCodeEditor({\r\n\t\t\t\tresource: related.resource,\r\n\t\t\t\toptions: { pinned: true, revealIfOpened: true, selection: Range.lift(related).collapseToStart() }\r\n\t\t\t}, this._editor);\r\n\t\t\tthis.close(false);\r\n\t\t}));\r\n\t\tthis._sessionDispoables.add(this._editor.onDidChangeModel(() => this._cleanUp()));\r\n\r\n\t\treturn this._model;\r\n\t}\r\n\r\n\tclose(focusEditor: boolean = true): void {\r\n\t\tthis._cleanUp();\r\n\t\tif (focusEditor) {\r\n\t\t\tthis._editor.focus();\r\n\t\t}\r\n\t}\r\n\r\n\tshowAtMarker(marker: IMarker): void {\r\n\t\tif (this._editor.hasModel()) {\r\n\t\t\tconst model = this._getOrCreateModel(this._editor.getModel().uri);\r\n\t\t\tmodel.resetIndex();\r\n\t\t\tmodel.move(true, this._editor.getModel(), new Position(marker.startLineNumber, marker.startColumn));\r\n\t\t\tif (model.selected) {\r\n\t\t\t\tthis._widget!.showAtMarker(model.selected.marker, model.selected.index, model.selected.total);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tasync nagivate(next: boolean, multiFile: boolean) {\r\n\t\tif (this._editor.hasModel()) {\r\n\t\t\tconst model = this._getOrCreateModel(multiFile ? undefined : this._editor.getModel().uri);\r\n\t\t\tmodel.move(next, this._editor.getModel(), this._editor.getPosition());\r\n\t\t\tif (!model.selected) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tif (model.selected.marker.resource.toString() !== this._editor.getModel().uri.toString()) {\r\n\t\t\t\t// show in different editor\r\n\t\t\t\tthis._cleanUp();\r\n\t\t\t\tconst otherEditor = await this._editorService.openCodeEditor({\r\n\t\t\t\t\tresource: model.selected.marker.resource,\r\n\t\t\t\t\toptions: { pinned: false, revealIfOpened: true, selectionRevealType: TextEditorSelectionRevealType.NearTop, selection: model.selected.marker }\r\n\t\t\t\t}, this._editor);\r\n\r\n\t\t\t\tif (otherEditor) {\r\n\t\t\t\t\tMarkerController.get(otherEditor).close();\r\n\t\t\t\t\tMarkerController.get(otherEditor).nagivate(next, multiFile);\r\n\t\t\t\t}\r\n\r\n\t\t\t} else {\r\n\t\t\t\t// show in this editor\r\n\t\t\t\tthis._widget!.showAtMarker(model.selected.marker, model.selected.index, model.selected.total);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass MarkerNavigationAction extends EditorAction {\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _next: boolean,\r\n\t\tprivate readonly _multiFile: boolean,\r\n\t\topts: IActionOptions\r\n\t) {\r\n\t\tsuper(opts);\r\n\t}\r\n\r\n\tasync run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise {\r\n\t\tif (editor.hasModel()) {\r\n\t\t\tMarkerController.get(editor).nagivate(this._next, this._multiFile);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class NextMarkerAction extends MarkerNavigationAction {\r\n\tstatic ID: string = 'editor.action.marker.next';\r\n\tstatic LABEL: string = nls.localize('markerAction.next.label', \"Go to Next Problem (Error, Warning, Info)\");\r\n\tconstructor() {\r\n\t\tsuper(true, false, {\r\n\t\t\tid: NextMarkerAction.ID,\r\n\t\t\tlabel: NextMarkerAction.LABEL,\r\n\t\t\talias: 'Go to Next Problem (Error, Warning, Info)',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.focus,\r\n\t\t\t\tprimary: KeyMod.Alt | KeyCode.F8,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tmenuOpts: {\r\n\t\t\t\tmenuId: MarkerNavigationWidget.TitleMenu,\r\n\t\t\t\ttitle: NextMarkerAction.LABEL,\r\n\t\t\t\ticon: registerIcon('marker-navigation-next', Codicon.chevronDown, nls.localize('nextMarkerIcon', 'Icon for goto next marker.')),\r\n\t\t\t\tgroup: 'navigation',\r\n\t\t\t\torder: 1\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n\r\nclass PrevMarkerAction extends MarkerNavigationAction {\r\n\tstatic ID: string = 'editor.action.marker.prev';\r\n\tstatic LABEL: string = nls.localize('markerAction.previous.label', \"Go to Previous Problem (Error, Warning, Info)\");\r\n\tconstructor() {\r\n\t\tsuper(false, false, {\r\n\t\t\tid: PrevMarkerAction.ID,\r\n\t\t\tlabel: PrevMarkerAction.LABEL,\r\n\t\t\talias: 'Go to Previous Problem (Error, Warning, Info)',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.focus,\r\n\t\t\t\tprimary: KeyMod.Shift | KeyMod.Alt | KeyCode.F8,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tmenuOpts: {\r\n\t\t\t\tmenuId: MarkerNavigationWidget.TitleMenu,\r\n\t\t\t\ttitle: NextMarkerAction.LABEL,\r\n\t\t\t\ticon: registerIcon('marker-navigation-previous', Codicon.chevronUp, nls.localize('previousMarkerIcon', 'Icon for goto previous marker.')),\r\n\t\t\t\tgroup: 'navigation',\r\n\t\t\t\torder: 2\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n\r\nclass NextMarkerInFilesAction extends MarkerNavigationAction {\r\n\tconstructor() {\r\n\t\tsuper(true, true, {\r\n\t\t\tid: 'editor.action.marker.nextInFiles',\r\n\t\t\tlabel: nls.localize('markerAction.nextInFiles.label', \"Go to Next Problem in Files (Error, Warning, Info)\"),\r\n\t\t\talias: 'Go to Next Problem in Files (Error, Warning, Info)',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.focus,\r\n\t\t\t\tprimary: KeyCode.F8,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tmenuOpts: {\r\n\t\t\t\tmenuId: MenuId.MenubarGoMenu,\r\n\t\t\t\ttitle: nls.localize({ key: 'miGotoNextProblem', comment: ['&& denotes a mnemonic'] }, \"Next &&Problem\"),\r\n\t\t\t\tgroup: '6_problem_nav',\r\n\t\t\t\torder: 1\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n\r\nclass PrevMarkerInFilesAction extends MarkerNavigationAction {\r\n\tconstructor() {\r\n\t\tsuper(false, true, {\r\n\t\t\tid: 'editor.action.marker.prevInFiles',\r\n\t\t\tlabel: nls.localize('markerAction.previousInFiles.label', \"Go to Previous Problem in Files (Error, Warning, Info)\"),\r\n\t\t\talias: 'Go to Previous Problem in Files (Error, Warning, Info)',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.focus,\r\n\t\t\t\tprimary: KeyMod.Shift | KeyCode.F8,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tmenuOpts: {\r\n\t\t\t\tmenuId: MenuId.MenubarGoMenu,\r\n\t\t\t\ttitle: nls.localize({ key: 'miGotoPreviousProblem', comment: ['&& denotes a mnemonic'] }, \"Previous &&Problem\"),\r\n\t\t\t\tgroup: '6_problem_nav',\r\n\t\t\t\torder: 2\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(MarkerController.ID, MarkerController);\r\nregisterEditorAction(NextMarkerAction);\r\nregisterEditorAction(PrevMarkerAction);\r\nregisterEditorAction(NextMarkerInFilesAction);\r\nregisterEditorAction(PrevMarkerInFilesAction);\r\n\r\nconst CONTEXT_MARKERS_NAVIGATION_VISIBLE = new RawContextKey('markersNavigationVisible', false);\r\n\r\nconst MarkerCommand = EditorCommand.bindToContribution(MarkerController.get);\r\n\r\nregisterEditorCommand(new MarkerCommand({\r\n\tid: 'closeMarkersNavigation',\r\n\tprecondition: CONTEXT_MARKERS_NAVIGATION_VISIBLE,\r\n\thandler: x => x.close(),\r\n\tkbOpts: {\r\n\t\tweight: KeybindingWeight.EditorContrib + 50,\r\n\t\tkbExpr: EditorContextKeys.focus,\r\n\t\tprimary: KeyCode.Escape,\r\n\t\tsecondary: [KeyMod.Shift | KeyCode.Escape]\r\n\t}\r\n}));\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { IDisposable, toDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { CodeActionTriggerType } from 'vs/editor/common/modes';\r\nimport { isNonEmptyArray } from 'vs/base/common/arrays';\r\nimport { IMarker, IMarkerData, MarkerSeverity } from 'vs/platform/markers/common/markers';\r\nimport { basename } from 'vs/base/common/resources';\r\nimport { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService';\r\nimport { onUnexpectedError } from 'vs/base/common/errors';\r\nimport { IOpenerService } from 'vs/platform/opener/common/opener';\r\nimport { MarkerController, NextMarkerAction } from 'vs/editor/contrib/gotoError/gotoError';\r\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\r\nimport { CancelablePromise, createCancelablePromise, disposableTimeout } from 'vs/base/common/async';\r\nimport { getCodeActions, CodeActionSet } from 'vs/editor/contrib/codeAction/codeAction';\r\nimport { QuickFixAction, QuickFixController } from 'vs/editor/contrib/codeAction/codeActionCommands';\r\nimport { CodeActionKind, CodeActionTrigger } from 'vs/editor/contrib/codeAction/types';\r\nimport { IModelDecoration } from 'vs/editor/common/model';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { Progress } from 'vs/platform/progress/common/progress';\r\nimport { ITextEditorOptions } from 'vs/platform/editor/common/editor';\r\nimport { renderHoverAction } from 'vs/base/browser/ui/hover/hoverWidget';\r\nimport { IEditorHover, IEditorHoverParticipant, IHoverPart } from 'vs/editor/contrib/hover/modesContentHover';\r\n\r\nconst $ = dom.$;\r\n\r\nexport class MarkerHover implements IHoverPart {\r\n\r\n\tconstructor(\r\n\t\tpublic readonly range: Range,\r\n\t\tpublic readonly marker: IMarker,\r\n\t) { }\r\n\r\n\tpublic equals(other: IHoverPart): boolean {\r\n\t\tif (other instanceof MarkerHover) {\r\n\t\t\treturn IMarkerData.makeKey(this.marker) === IMarkerData.makeKey(other.marker);\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\nconst markerCodeActionTrigger: CodeActionTrigger = {\r\n\ttype: CodeActionTriggerType.Manual,\r\n\tfilter: { include: CodeActionKind.QuickFix }\r\n};\r\n\r\nexport class MarkerHoverParticipant implements IEditorHoverParticipant {\r\n\r\n\tprivate recentMarkerCodeActionsInfo: { marker: IMarker, hasCodeActions: boolean } | undefined = undefined;\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _editor: ICodeEditor,\r\n\t\tprivate readonly _hover: IEditorHover,\r\n\t\t@IMarkerDecorationsService private readonly _markerDecorationsService: IMarkerDecorationsService,\r\n\t\t@IKeybindingService private readonly _keybindingService: IKeybindingService,\r\n\t\t@IOpenerService private readonly _openerService: IOpenerService,\r\n\t) { }\r\n\r\n\tpublic computeSync(hoverRange: Range, lineDecorations: IModelDecoration[]): MarkerHover[] {\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tconst model = this._editor.getModel();\r\n\t\tconst lineNumber = hoverRange.startLineNumber;\r\n\t\tconst maxColumn = model.getLineMaxColumn(lineNumber);\r\n\t\tconst result: MarkerHover[] = [];\r\n\t\tfor (const d of lineDecorations) {\r\n\t\t\tconst startColumn = (d.range.startLineNumber === lineNumber) ? d.range.startColumn : 1;\r\n\t\t\tconst endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn;\r\n\r\n\t\t\tconst marker = this._markerDecorationsService.getMarker(model.uri, d);\r\n\t\t\tif (!marker) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tconst range = new Range(hoverRange.startLineNumber, startColumn, hoverRange.startLineNumber, endColumn);\r\n\t\t\tresult.push(new MarkerHover(range, marker));\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic renderHoverParts(hoverParts: MarkerHover[], fragment: DocumentFragment): IDisposable {\r\n\t\tif (!hoverParts.length) {\r\n\t\t\treturn Disposable.None;\r\n\t\t}\r\n\t\tconst disposables = new DisposableStore();\r\n\t\thoverParts.forEach(msg => fragment.appendChild(this.renderMarkerHover(msg, disposables)));\r\n\t\tconst markerHoverForStatusbar = hoverParts.length === 1 ? hoverParts[0] : hoverParts.sort((a, b) => MarkerSeverity.compare(a.marker.severity, b.marker.severity))[0];\r\n\t\tfragment.appendChild(this.renderMarkerStatusbar(markerHoverForStatusbar, disposables));\r\n\t\treturn disposables;\r\n\t}\r\n\r\n\tprivate renderMarkerHover(markerHover: MarkerHover, disposables: DisposableStore): HTMLElement {\r\n\t\tconst hoverElement = $('div.hover-row');\r\n\t\tconst markerElement = dom.append(hoverElement, $('div.marker.hover-contents'));\r\n\t\tconst { source, message, code, relatedInformation } = markerHover.marker;\r\n\r\n\t\tthis._editor.applyFontInfo(markerElement);\r\n\t\tconst messageElement = dom.append(markerElement, $('span'));\r\n\t\tmessageElement.style.whiteSpace = 'pre-wrap';\r\n\t\tmessageElement.innerText = message;\r\n\r\n\t\tif (source || code) {\r\n\t\t\t// Code has link\r\n\t\t\tif (code && typeof code !== 'string') {\r\n\t\t\t\tconst sourceAndCodeElement = $('span');\r\n\t\t\t\tif (source) {\r\n\t\t\t\t\tconst sourceElement = dom.append(sourceAndCodeElement, $('span'));\r\n\t\t\t\t\tsourceElement.innerText = source;\r\n\t\t\t\t}\r\n\t\t\t\tconst codeLink = dom.append(sourceAndCodeElement, $('a.code-link'));\r\n\t\t\t\tcodeLink.setAttribute('href', code.target.toString());\r\n\r\n\t\t\t\tdisposables.add(dom.addDisposableListener(codeLink, 'click', (e) => {\r\n\t\t\t\t\tthis._openerService.open(code.target);\r\n\t\t\t\t\te.preventDefault();\r\n\t\t\t\t\te.stopPropagation();\r\n\t\t\t\t}));\r\n\r\n\t\t\t\tconst codeElement = dom.append(codeLink, $('span'));\r\n\t\t\t\tcodeElement.innerText = code.value;\r\n\r\n\t\t\t\tconst detailsElement = dom.append(markerElement, sourceAndCodeElement);\r\n\t\t\t\tdetailsElement.style.opacity = '0.6';\r\n\t\t\t\tdetailsElement.style.paddingLeft = '6px';\r\n\t\t\t} else {\r\n\t\t\t\tconst detailsElement = dom.append(markerElement, $('span'));\r\n\t\t\t\tdetailsElement.style.opacity = '0.6';\r\n\t\t\t\tdetailsElement.style.paddingLeft = '6px';\r\n\t\t\t\tdetailsElement.innerText = source && code ? `${source}(${code})` : source ? source : `(${code})`;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (isNonEmptyArray(relatedInformation)) {\r\n\t\t\tfor (const { message, resource, startLineNumber, startColumn } of relatedInformation) {\r\n\t\t\t\tconst relatedInfoContainer = dom.append(markerElement, $('div'));\r\n\t\t\t\trelatedInfoContainer.style.marginTop = '8px';\r\n\t\t\t\tconst a = dom.append(relatedInfoContainer, $('a'));\r\n\t\t\t\ta.innerText = `${basename(resource)}(${startLineNumber}, ${startColumn}): `;\r\n\t\t\t\ta.style.cursor = 'pointer';\r\n\t\t\t\tdisposables.add(dom.addDisposableListener(a, 'click', (e) => {\r\n\t\t\t\t\te.stopPropagation();\r\n\t\t\t\t\te.preventDefault();\r\n\t\t\t\t\tif (this._openerService) {\r\n\t\t\t\t\t\tthis._openerService.open(resource, {\r\n\t\t\t\t\t\t\tfromUserGesture: true,\r\n\t\t\t\t\t\t\teditorOptions: { selection: { startLineNumber, startColumn } }\r\n\t\t\t\t\t\t}).catch(onUnexpectedError);\r\n\t\t\t\t\t}\r\n\t\t\t\t}));\r\n\t\t\t\tconst messageElement = dom.append(relatedInfoContainer, $('span'));\r\n\t\t\t\tmessageElement.innerText = message;\r\n\t\t\t\tthis._editor.applyFontInfo(messageElement);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn hoverElement;\r\n\t}\r\n\r\n\tprivate renderMarkerStatusbar(markerHover: MarkerHover, disposables: DisposableStore): HTMLElement {\r\n\t\tconst hoverElement = $('div.hover-row.status-bar');\r\n\t\tconst actionsElement = dom.append(hoverElement, $('div.actions'));\r\n\t\tif (markerHover.marker.severity === MarkerSeverity.Error || markerHover.marker.severity === MarkerSeverity.Warning || markerHover.marker.severity === MarkerSeverity.Info) {\r\n\t\t\tdisposables.add(this.renderAction(actionsElement, {\r\n\t\t\t\tlabel: nls.localize('peek problem', \"Peek Problem\"),\r\n\t\t\t\tcommandId: NextMarkerAction.ID,\r\n\t\t\t\trun: () => {\r\n\t\t\t\t\tthis._hover.hide();\r\n\t\t\t\t\tMarkerController.get(this._editor).showAtMarker(markerHover.marker);\r\n\t\t\t\t\tthis._editor.focus();\r\n\t\t\t\t}\r\n\t\t\t}));\r\n\t\t}\r\n\r\n\t\tif (!this._editor.getOption(EditorOption.readOnly)) {\r\n\t\t\tconst quickfixPlaceholderElement = dom.append(actionsElement, $('div'));\r\n\t\t\tif (this.recentMarkerCodeActionsInfo) {\r\n\t\t\t\tif (IMarkerData.makeKey(this.recentMarkerCodeActionsInfo.marker) === IMarkerData.makeKey(markerHover.marker)) {\r\n\t\t\t\t\tif (!this.recentMarkerCodeActionsInfo.hasCodeActions) {\r\n\t\t\t\t\t\tquickfixPlaceholderElement.textContent = nls.localize('noQuickFixes', \"No quick fixes available\");\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis.recentMarkerCodeActionsInfo = undefined;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tconst updatePlaceholderDisposable = this.recentMarkerCodeActionsInfo && !this.recentMarkerCodeActionsInfo.hasCodeActions ? Disposable.None : disposables.add(disposableTimeout(() => quickfixPlaceholderElement.textContent = nls.localize('checkingForQuickFixes', \"Checking for quick fixes...\"), 200));\r\n\t\t\tif (!quickfixPlaceholderElement.textContent) {\r\n\t\t\t\t// Have some content in here to avoid flickering\r\n\t\t\t\tquickfixPlaceholderElement.textContent = String.fromCharCode(0xA0); //  \r\n\t\t\t}\r\n\t\t\tconst codeActionsPromise = this.getCodeActions(markerHover.marker);\r\n\t\t\tdisposables.add(toDisposable(() => codeActionsPromise.cancel()));\r\n\t\t\tcodeActionsPromise.then(actions => {\r\n\t\t\t\tupdatePlaceholderDisposable.dispose();\r\n\t\t\t\tthis.recentMarkerCodeActionsInfo = { marker: markerHover.marker, hasCodeActions: actions.validActions.length > 0 };\r\n\r\n\t\t\t\tif (!this.recentMarkerCodeActionsInfo.hasCodeActions) {\r\n\t\t\t\t\tactions.dispose();\r\n\t\t\t\t\tquickfixPlaceholderElement.textContent = nls.localize('noQuickFixes', \"No quick fixes available\");\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\tquickfixPlaceholderElement.style.display = 'none';\r\n\r\n\t\t\t\tlet showing = false;\r\n\t\t\t\tdisposables.add(toDisposable(() => {\r\n\t\t\t\t\tif (!showing) {\r\n\t\t\t\t\t\tactions.dispose();\r\n\t\t\t\t\t}\r\n\t\t\t\t}));\r\n\r\n\t\t\t\tdisposables.add(this.renderAction(actionsElement, {\r\n\t\t\t\t\tlabel: nls.localize('quick fixes', \"Quick Fix...\"),\r\n\t\t\t\t\tcommandId: QuickFixAction.Id,\r\n\t\t\t\t\trun: (target) => {\r\n\t\t\t\t\t\tshowing = true;\r\n\t\t\t\t\t\tconst controller = QuickFixController.get(this._editor);\r\n\t\t\t\t\t\tconst elementPosition = dom.getDomNodePagePosition(target);\r\n\t\t\t\t\t\t// Hide the hover pre-emptively, otherwise the editor can close the code actions\r\n\t\t\t\t\t\t// context menu as well when using keyboard navigation\r\n\t\t\t\t\t\tthis._hover.hide();\r\n\t\t\t\t\t\tcontroller.showCodeActions(markerCodeActionTrigger, actions, {\r\n\t\t\t\t\t\t\tx: elementPosition.left + 6,\r\n\t\t\t\t\t\t\ty: elementPosition.top + elementPosition.height + 6\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t}\r\n\t\t\t\t}));\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\treturn hoverElement;\r\n\t}\r\n\r\n\tprivate renderAction(parent: HTMLElement, actionOptions: { label: string, iconClass?: string, run: (target: HTMLElement) => void, commandId: string }): IDisposable {\r\n\t\tconst keybinding = this._keybindingService.lookupKeybinding(actionOptions.commandId);\r\n\t\tconst keybindingLabel = keybinding ? keybinding.getLabel() : null;\r\n\t\treturn renderHoverAction(parent, actionOptions, keybindingLabel);\r\n\t}\r\n\r\n\tprivate getCodeActions(marker: IMarker): CancelablePromise {\r\n\t\treturn createCancelablePromise(cancellationToken => {\r\n\t\t\treturn getCodeActions(\r\n\t\t\t\tthis._editor.getModel()!,\r\n\t\t\t\tnew Range(marker.startLineNumber, marker.startColumn, marker.endLineNumber, marker.endColumn),\r\n\t\t\t\tmarkerCodeActionTrigger,\r\n\t\t\t\tProgress.None,\r\n\t\t\t\tcancellationToken);\r\n\t\t});\r\n\t}\r\n}\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { CancellationToken } from 'vs/base/common/cancellation';\r\nimport { Color, RGBA } from 'vs/base/common/color';\r\nimport { IDisposable, DisposableStore, combinedDisposable } from 'vs/base/common/lifecycle';\r\nimport { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';\r\nimport { Position } from 'vs/editor/common/core/position';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { ModelDecorationOptions } from 'vs/editor/common/model/textModel';\r\nimport { DocumentColorProvider, IColor, TokenizationRegistry } from 'vs/editor/common/modes';\r\nimport { getColorPresentations } from 'vs/editor/contrib/colorPicker/color';\r\nimport { ColorDetector } from 'vs/editor/contrib/colorPicker/colorDetector';\r\nimport { ColorPickerModel } from 'vs/editor/contrib/colorPicker/colorPickerModel';\r\nimport { ColorPickerWidget } from 'vs/editor/contrib/colorPicker/colorPickerWidget';\r\nimport { HoverOperation, HoverStartMode, IHoverComputer } from 'vs/editor/contrib/hover/hoverOperation';\r\nimport { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';\r\nimport { coalesce } from 'vs/base/common/arrays';\r\nimport { IIdentifiedSingleEditOperation, IModelDecoration, TrackedRangeStickiness } from 'vs/editor/common/model';\r\nimport { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { Constants } from 'vs/base/common/uint';\r\nimport { textLinkForeground } from 'vs/platform/theme/common/colorRegistry';\r\nimport { IContextKey } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\r\nimport { Widget } from 'vs/base/browser/ui/widget';\r\nimport { KeyCode } from 'vs/base/common/keyCodes';\r\nimport { HoverWidget } from 'vs/base/browser/ui/hover/hoverWidget';\r\nimport { MarkerHover, MarkerHoverParticipant } from 'vs/editor/contrib/hover/markerHoverParticipant';\r\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\r\nimport { MarkdownHover, MarkdownHoverParticipant } from 'vs/editor/contrib/hover/markdownHoverParticipant';\r\n\r\nexport interface IHoverPart {\r\n\treadonly range: Range;\r\n\tequals(other: IHoverPart): boolean;\r\n}\r\n\r\nexport interface IEditorHover {\r\n\thide(): void;\r\n\tonContentsChanged(): void;\r\n}\r\n\r\nexport interface IEditorHoverParticipant {\r\n\tcomputeSync(hoverRange: Range, lineDecorations: IModelDecoration[]): T[];\r\n\trenderHoverParts(hoverParts: T[], fragment: DocumentFragment): IDisposable;\r\n}\r\n\r\nclass ColorHover implements IHoverPart {\r\n\r\n\tconstructor(\r\n\t\tpublic readonly range: Range,\r\n\t\tpublic readonly color: IColor,\r\n\t\tpublic readonly provider: DocumentColorProvider\r\n\t) { }\r\n\r\n\tequals(other: IHoverPart): boolean {\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\nclass HoverPartInfo {\r\n\tconstructor(\r\n\t\tpublic readonly owner: IEditorHoverParticipant | null,\r\n\t\tpublic readonly data: IHoverPart\r\n\t) { }\r\n}\r\n\r\nclass ModesContentComputer implements IHoverComputer {\r\n\r\n\tprivate readonly _editor: ICodeEditor;\r\n\tprivate _result: HoverPartInfo[];\r\n\tprivate _range: Range | null;\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor,\r\n\t\tprivate readonly _markerHoverParticipant: IEditorHoverParticipant,\r\n\t\tprivate readonly _markdownHoverParticipant: MarkdownHoverParticipant\r\n\t) {\r\n\t\tthis._editor = editor;\r\n\t\tthis._result = [];\r\n\t\tthis._range = null;\r\n\t}\r\n\r\n\tpublic setRange(range: Range): void {\r\n\t\tthis._range = range;\r\n\t\tthis._result = [];\r\n\t}\r\n\r\n\tpublic clearResult(): void {\r\n\t\tthis._result = [];\r\n\t}\r\n\r\n\tpublic async computeAsync(token: CancellationToken): Promise {\r\n\t\tif (!this._editor.hasModel() || !this._range) {\r\n\t\t\treturn Promise.resolve([]);\r\n\t\t}\r\n\r\n\t\tconst markdownHovers = await this._markdownHoverParticipant.computeAsync(this._range, token);\r\n\t\treturn markdownHovers.map(h => new HoverPartInfo(this._markdownHoverParticipant, h));\r\n\t}\r\n\r\n\tpublic computeSync(): HoverPartInfo[] {\r\n\t\tif (!this._editor.hasModel() || !this._range) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tconst model = this._editor.getModel();\r\n\t\tconst hoverRange = this._range;\r\n\t\tconst lineNumber = hoverRange.startLineNumber;\r\n\r\n\t\tif (lineNumber > this._editor.getModel().getLineCount()) {\r\n\t\t\t// Illegal line number => no results\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tconst maxColumn = model.getLineMaxColumn(lineNumber);\r\n\t\tconst lineDecorations = this._editor.getLineDecorations(lineNumber).filter((d) => {\r\n\t\t\tconst startColumn = (d.range.startLineNumber === lineNumber) ? d.range.startColumn : 1;\r\n\t\t\tconst endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn;\r\n\t\t\tif (startColumn > hoverRange.startColumn || hoverRange.endColumn > endColumn) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t});\r\n\r\n\t\tlet result: HoverPartInfo[] = [];\r\n\r\n\t\tconst colorDetector = ColorDetector.get(this._editor);\r\n\t\tfor (const d of lineDecorations) {\r\n\t\t\tconst colorData = colorDetector.getColorData(d.range.getStartPosition());\r\n\t\t\tif (colorData) {\r\n\t\t\t\tconst { color, range } = colorData.colorInfo;\r\n\t\t\t\tresult.push(new HoverPartInfo(null, new ColorHover(Range.lift(range), color, colorData.provider)));\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst markdownHovers = this._markdownHoverParticipant.computeSync(this._range, lineDecorations);\r\n\t\tresult = result.concat(markdownHovers.map(h => new HoverPartInfo(this._markdownHoverParticipant, h)));\r\n\r\n\t\tconst markerHovers = this._markerHoverParticipant.computeSync(this._range, lineDecorations);\r\n\t\tresult = result.concat(markerHovers.map(h => new HoverPartInfo(this._markerHoverParticipant, h)));\r\n\r\n\t\treturn coalesce(result);\r\n\t}\r\n\r\n\tpublic onResult(result: HoverPartInfo[], isFromSynchronousComputation: boolean): void {\r\n\t\t// Always put synchronous messages before asynchronous ones\r\n\t\tif (isFromSynchronousComputation) {\r\n\t\t\tthis._result = result.concat(this._result);\r\n\t\t} else {\r\n\t\t\tthis._result = this._result.concat(result);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getResult(): HoverPartInfo[] {\r\n\t\treturn this._result.slice(0);\r\n\t}\r\n\r\n\tpublic getResultWithLoadingMessage(): HoverPartInfo[] {\r\n\t\tif (this._range) {\r\n\t\t\tconst loadingMessage = new HoverPartInfo(this._markdownHoverParticipant, this._markdownHoverParticipant.createLoadingMessage(this._range));\r\n\t\t\treturn this._result.slice(0).concat([loadingMessage]);\r\n\r\n\t\t}\r\n\t\treturn this._result.slice(0);\r\n\t}\r\n}\r\n\r\nexport class ModesContentHoverWidget extends Widget implements IContentWidget, IEditorHover {\r\n\r\n\tstatic readonly ID = 'editor.contrib.modesContentHoverWidget';\r\n\r\n\tprivate readonly _markerHoverParticipant: IEditorHoverParticipant;\r\n\tprivate readonly _markdownHoverParticipant: MarkdownHoverParticipant;\r\n\r\n\tprivate readonly _hover: HoverWidget;\r\n\tprivate readonly _id: string;\r\n\tprivate readonly _editor: ICodeEditor;\r\n\tprivate _isVisible: boolean;\r\n\tprivate _showAtPosition: Position | null;\r\n\tprivate _showAtRange: Range | null;\r\n\tprivate _stoleFocus: boolean;\r\n\r\n\t// IContentWidget.allowEditorOverflow\r\n\tpublic readonly allowEditorOverflow = true;\r\n\r\n\tprivate _messages: HoverPartInfo[];\r\n\tprivate _lastRange: Range | null;\r\n\tprivate readonly _computer: ModesContentComputer;\r\n\tprivate readonly _hoverOperation: HoverOperation;\r\n\tprivate _highlightDecorations: string[];\r\n\tprivate _isChangingDecorations: boolean;\r\n\tprivate _shouldFocus: boolean;\r\n\tprivate _colorPicker: ColorPickerWidget | null;\r\n\tprivate _renderDisposable: IDisposable | null;\r\n\r\n\tconstructor(\r\n\t\teditor: ICodeEditor,\r\n\t\tprivate readonly _hoverVisibleKey: IContextKey,\r\n\t\tinstantiationService: IInstantiationService,\r\n\t\tprivate readonly _themeService: IThemeService,\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\tthis._markerHoverParticipant = instantiationService.createInstance(MarkerHoverParticipant, editor, this);\r\n\t\tthis._markdownHoverParticipant = instantiationService.createInstance(MarkdownHoverParticipant, editor, this);\r\n\r\n\t\tthis._hover = this._register(new HoverWidget());\r\n\t\tthis._id = ModesContentHoverWidget.ID;\r\n\t\tthis._editor = editor;\r\n\t\tthis._isVisible = false;\r\n\t\tthis._stoleFocus = false;\r\n\t\tthis._renderDisposable = null;\r\n\r\n\t\tthis.onkeydown(this._hover.containerDomNode, (e: IKeyboardEvent) => {\r\n\t\t\tif (e.equals(KeyCode.Escape)) {\r\n\t\t\t\tthis.hide();\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tthis._register(this._editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => {\r\n\t\t\tif (e.hasChanged(EditorOption.fontInfo)) {\r\n\t\t\t\tthis._updateFont();\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tthis._editor.onDidLayoutChange(() => this.layout());\r\n\r\n\t\tthis.layout();\r\n\t\tthis._editor.addContentWidget(this);\r\n\t\tthis._showAtPosition = null;\r\n\t\tthis._showAtRange = null;\r\n\t\tthis._stoleFocus = false;\r\n\r\n\t\tthis._messages = [];\r\n\t\tthis._lastRange = null;\r\n\t\tthis._computer = new ModesContentComputer(this._editor, this._markerHoverParticipant, this._markdownHoverParticipant);\r\n\t\tthis._highlightDecorations = [];\r\n\t\tthis._isChangingDecorations = false;\r\n\t\tthis._shouldFocus = false;\r\n\t\tthis._colorPicker = null;\r\n\r\n\t\tthis._hoverOperation = new HoverOperation(\r\n\t\t\tthis._computer,\r\n\t\t\tresult => this._withResult(result, true),\r\n\t\t\tnull,\r\n\t\t\tresult => this._withResult(result, false),\r\n\t\t\tthis._editor.getOption(EditorOption.hover).delay\r\n\t\t);\r\n\r\n\t\tthis._register(dom.addStandardDisposableListener(this.getDomNode(), dom.EventType.FOCUS, () => {\r\n\t\t\tif (this._colorPicker) {\r\n\t\t\t\tthis.getDomNode().classList.add('colorpicker-hover');\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._register(dom.addStandardDisposableListener(this.getDomNode(), dom.EventType.BLUR, () => {\r\n\t\t\tthis.getDomNode().classList.remove('colorpicker-hover');\r\n\t\t}));\r\n\t\tthis._register(editor.onDidChangeConfiguration(() => {\r\n\t\t\tthis._hoverOperation.setHoverTime(this._editor.getOption(EditorOption.hover).delay);\r\n\t\t}));\r\n\t\tthis._register(TokenizationRegistry.onDidChange(() => {\r\n\t\t\tif (this._isVisible && this._lastRange && this._messages.length > 0) {\r\n\t\t\t\tthis._messages = this._messages.map(msg => {\r\n\t\t\t\t\t// If a color hover is visible, we need to update the message that\r\n\t\t\t\t\t// created it so that the color matches the last chosen color\r\n\t\t\t\t\tif (msg.data instanceof ColorHover && !!this._lastRange?.intersectRanges(msg.data.range) && this._colorPicker?.model.color) {\r\n\t\t\t\t\t\tconst color = this._colorPicker.model.color;\r\n\t\t\t\t\t\tconst newColor = {\r\n\t\t\t\t\t\t\tred: color.rgba.r / 255,\r\n\t\t\t\t\t\t\tgreen: color.rgba.g / 255,\r\n\t\t\t\t\t\t\tblue: color.rgba.b / 255,\r\n\t\t\t\t\t\t\talpha: color.rgba.a\r\n\t\t\t\t\t\t};\r\n\t\t\t\t\t\treturn new HoverPartInfo(msg.owner, new ColorHover(msg.data.range, newColor, msg.data.provider));\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\treturn msg;\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\r\n\t\t\t\tthis._hover.contentsDomNode.textContent = '';\r\n\t\t\t\tthis._renderMessages(this._lastRange, this._messages);\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._hoverOperation.cancel();\r\n\t\tthis._editor.removeContentWidget(this);\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tpublic getId(): string {\r\n\t\treturn this._id;\r\n\t}\r\n\r\n\tpublic getDomNode(): HTMLElement {\r\n\t\treturn this._hover.containerDomNode;\r\n\t}\r\n\r\n\tpublic showAt(position: Position, range: Range | null, focus: boolean): void {\r\n\t\t// Position has changed\r\n\t\tthis._showAtPosition = position;\r\n\t\tthis._showAtRange = range;\r\n\t\tthis._hoverVisibleKey.set(true);\r\n\t\tthis._isVisible = true;\r\n\t\tthis._hover.containerDomNode.classList.toggle('hidden', !this._isVisible);\r\n\r\n\t\tthis._editor.layoutContentWidget(this);\r\n\t\t// Simply force a synchronous render on the editor\r\n\t\t// such that the widget does not really render with left = '0px'\r\n\t\tthis._editor.render();\r\n\t\tthis._stoleFocus = focus;\r\n\t\tif (focus) {\r\n\t\t\tthis._hover.containerDomNode.focus();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getPosition(): IContentWidgetPosition | null {\r\n\t\tif (this._isVisible) {\r\n\t\t\treturn {\r\n\t\t\t\tposition: this._showAtPosition,\r\n\t\t\t\trange: this._showAtRange,\r\n\t\t\t\tpreference: [\r\n\t\t\t\t\tContentWidgetPositionPreference.ABOVE,\r\n\t\t\t\t\tContentWidgetPositionPreference.BELOW\r\n\t\t\t\t]\r\n\t\t\t};\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate _updateFont(): void {\r\n\t\tconst codeClasses: HTMLElement[] = Array.prototype.slice.call(this._hover.contentsDomNode.getElementsByClassName('code'));\r\n\t\tcodeClasses.forEach(node => this._editor.applyFontInfo(node));\r\n\t}\r\n\r\n\tprivate _updateContents(node: Node): void {\r\n\t\tthis._hover.contentsDomNode.textContent = '';\r\n\t\tthis._hover.contentsDomNode.appendChild(node);\r\n\t\tthis._updateFont();\r\n\r\n\t\tthis._editor.layoutContentWidget(this);\r\n\t\tthis._hover.onContentsChanged();\r\n\t}\r\n\r\n\tprivate layout(): void {\r\n\t\tconst height = Math.max(this._editor.getLayoutInfo().height / 4, 250);\r\n\t\tconst { fontSize, lineHeight } = this._editor.getOption(EditorOption.fontInfo);\r\n\r\n\t\tthis._hover.contentsDomNode.style.fontSize = `${fontSize}px`;\r\n\t\tthis._hover.contentsDomNode.style.lineHeight = `${lineHeight}px`;\r\n\t\tthis._hover.contentsDomNode.style.maxHeight = `${height}px`;\r\n\t\tthis._hover.contentsDomNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width * 0.66, 500)}px`;\r\n\t}\r\n\r\n\tpublic onModelDecorationsChanged(): void {\r\n\t\tif (this._isChangingDecorations) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (this._isVisible) {\r\n\t\t\t// The decorations have changed and the hover is visible,\r\n\t\t\t// we need to recompute the displayed text\r\n\t\t\tthis._hoverOperation.cancel();\r\n\t\t\tthis._computer.clearResult();\r\n\r\n\t\t\tif (!this._colorPicker) { // TODO@Michel ensure that displayed text for other decorations is computed even if color picker is in place\r\n\t\t\t\tthis._hoverOperation.start(HoverStartMode.Delayed);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic startShowingAt(range: Range, mode: HoverStartMode, focus: boolean): void {\r\n\t\tif (this._lastRange && this._lastRange.equalsRange(range)) {\r\n\t\t\t// We have to show the widget at the exact same range as before, so no work is needed\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis._hoverOperation.cancel();\r\n\r\n\t\tif (this._isVisible) {\r\n\t\t\t// The range might have changed, but the hover is visible\r\n\t\t\t// Instead of hiding it completely, filter out messages that are still in the new range and\r\n\t\t\t// kick off a new computation\r\n\t\t\tif (!this._showAtPosition || this._showAtPosition.lineNumber !== range.startLineNumber) {\r\n\t\t\t\tthis.hide();\r\n\t\t\t} else {\r\n\t\t\t\tlet filteredMessages: HoverPartInfo[] = [];\r\n\t\t\t\tfor (let i = 0, len = this._messages.length; i < len; i++) {\r\n\t\t\t\t\tconst msg = this._messages[i];\r\n\t\t\t\t\tconst rng = msg.data.range;\r\n\t\t\t\t\tif (rng && rng.startColumn <= range.startColumn && rng.endColumn >= range.endColumn) {\r\n\t\t\t\t\t\tfilteredMessages.push(msg);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tif (filteredMessages.length > 0) {\r\n\t\t\t\t\tif (hoverContentsEquals(filteredMessages, this._messages)) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tthis._renderMessages(range, filteredMessages);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis.hide();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._lastRange = range;\r\n\t\tthis._computer.setRange(range);\r\n\t\tthis._shouldFocus = focus;\r\n\t\tthis._hoverOperation.start(mode);\r\n\t}\r\n\r\n\tpublic hide(): void {\r\n\t\tthis._lastRange = null;\r\n\t\tthis._hoverOperation.cancel();\r\n\r\n\t\tif (this._isVisible) {\r\n\t\t\tsetTimeout(() => {\r\n\t\t\t\t// Give commands a chance to see the key\r\n\t\t\t\tif (!this._isVisible) {\r\n\t\t\t\t\tthis._hoverVisibleKey.set(false);\r\n\t\t\t\t}\r\n\t\t\t}, 0);\r\n\t\t\tthis._isVisible = false;\r\n\t\t\tthis._hover.containerDomNode.classList.toggle('hidden', !this._isVisible);\r\n\r\n\t\t\tthis._editor.layoutContentWidget(this);\r\n\t\t\tif (this._stoleFocus) {\r\n\t\t\t\tthis._editor.focus();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._isChangingDecorations = true;\r\n\t\tthis._highlightDecorations = this._editor.deltaDecorations(this._highlightDecorations, []);\r\n\t\tthis._isChangingDecorations = false;\r\n\t\tif (this._renderDisposable) {\r\n\t\t\tthis._renderDisposable.dispose();\r\n\t\t\tthis._renderDisposable = null;\r\n\t\t}\r\n\t\tthis._colorPicker = null;\r\n\t}\r\n\r\n\tpublic isColorPickerVisible(): boolean {\r\n\t\treturn !!this._colorPicker;\r\n\t}\r\n\r\n\tpublic onContentsChanged(): void {\r\n\t\tthis._hover.onContentsChanged();\r\n\t}\r\n\r\n\tprivate _withResult(result: HoverPartInfo[], complete: boolean): void {\r\n\t\tthis._messages = result;\r\n\r\n\t\tif (this._lastRange && this._messages.length > 0) {\r\n\t\t\tthis._renderMessages(this._lastRange, this._messages);\r\n\t\t} else if (complete) {\r\n\t\t\tthis.hide();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _renderMessages(renderRange: Range, messages: HoverPartInfo[]): void {\r\n\t\tif (this._renderDisposable) {\r\n\t\t\tthis._renderDisposable.dispose();\r\n\t\t\tthis._renderDisposable = null;\r\n\t\t}\r\n\t\tthis._colorPicker = null;\r\n\r\n\t\t// update column from which to show\r\n\t\tlet renderColumn = Constants.MAX_SAFE_SMALL_INTEGER;\r\n\t\tlet highlightRange: Range | null = messages[0].data.range ? Range.lift(messages[0].data.range) : null;\r\n\t\tlet fragment = document.createDocumentFragment();\r\n\r\n\t\tlet containColorPicker = false;\r\n\t\tconst disposables = new DisposableStore();\r\n\t\tconst markerMessages: MarkerHover[] = [];\r\n\t\tconst markdownParts: MarkdownHover[] = [];\r\n\t\tmessages.forEach((_msg) => {\r\n\t\t\tconst msg = _msg.data;\r\n\t\t\tif (!msg.range) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\trenderColumn = Math.min(renderColumn, msg.range.startColumn);\r\n\t\t\thighlightRange = highlightRange ? Range.plusRange(highlightRange, msg.range) : Range.lift(msg.range);\r\n\r\n\t\t\tif (msg instanceof ColorHover) {\r\n\t\t\t\tcontainColorPicker = true;\r\n\r\n\t\t\t\tconst { red, green, blue, alpha } = msg.color;\r\n\t\t\t\tconst rgba = new RGBA(Math.round(red * 255), Math.round(green * 255), Math.round(blue * 255), alpha);\r\n\t\t\t\tconst color = new Color(rgba);\r\n\r\n\t\t\t\tif (!this._editor.hasModel()) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst editorModel = this._editor.getModel();\r\n\t\t\t\tlet range = new Range(msg.range.startLineNumber, msg.range.startColumn, msg.range.endLineNumber, msg.range.endColumn);\r\n\t\t\t\tlet colorInfo = { range: msg.range, color: msg.color };\r\n\r\n\t\t\t\t// create blank olor picker model and widget first to ensure it's positioned correctly.\r\n\t\t\t\tconst model = new ColorPickerModel(color, [], 0);\r\n\t\t\t\tconst widget = new ColorPickerWidget(fragment, model, this._editor.getOption(EditorOption.pixelRatio), this._themeService);\r\n\r\n\t\t\t\tgetColorPresentations(editorModel, colorInfo, msg.provider, CancellationToken.None).then(colorPresentations => {\r\n\t\t\t\t\tmodel.colorPresentations = colorPresentations || [];\r\n\t\t\t\t\tif (!this._editor.hasModel()) {\r\n\t\t\t\t\t\t// gone...\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tconst originalText = this._editor.getModel().getValueInRange(msg.range);\r\n\t\t\t\t\tmodel.guessColorPresentation(color, originalText);\r\n\r\n\t\t\t\t\tconst updateEditorModel = () => {\r\n\t\t\t\t\t\tlet textEdits: IIdentifiedSingleEditOperation[];\r\n\t\t\t\t\t\tlet newRange: Range;\r\n\t\t\t\t\t\tif (model.presentation.textEdit) {\r\n\t\t\t\t\t\t\ttextEdits = [model.presentation.textEdit as IIdentifiedSingleEditOperation];\r\n\t\t\t\t\t\t\tnewRange = new Range(\r\n\t\t\t\t\t\t\t\tmodel.presentation.textEdit.range.startLineNumber,\r\n\t\t\t\t\t\t\t\tmodel.presentation.textEdit.range.startColumn,\r\n\t\t\t\t\t\t\t\tmodel.presentation.textEdit.range.endLineNumber,\r\n\t\t\t\t\t\t\t\tmodel.presentation.textEdit.range.endColumn\r\n\t\t\t\t\t\t\t);\r\n\t\t\t\t\t\t\tconst trackedRange = this._editor.getModel()!._setTrackedRange(null, newRange, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter);\r\n\t\t\t\t\t\t\tthis._editor.pushUndoStop();\r\n\t\t\t\t\t\t\tthis._editor.executeEdits('colorpicker', textEdits);\r\n\t\t\t\t\t\t\tnewRange = this._editor.getModel()!._getTrackedRange(trackedRange) || newRange;\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\ttextEdits = [{ identifier: null, range, text: model.presentation.label, forceMoveMarkers: false }];\r\n\t\t\t\t\t\t\tnewRange = range.setEndPosition(range.endLineNumber, range.startColumn + model.presentation.label.length);\r\n\t\t\t\t\t\t\tthis._editor.pushUndoStop();\r\n\t\t\t\t\t\t\tthis._editor.executeEdits('colorpicker', textEdits);\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif (model.presentation.additionalTextEdits) {\r\n\t\t\t\t\t\t\ttextEdits = [...model.presentation.additionalTextEdits as IIdentifiedSingleEditOperation[]];\r\n\t\t\t\t\t\t\tthis._editor.executeEdits('colorpicker', textEdits);\r\n\t\t\t\t\t\t\tthis.hide();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tthis._editor.pushUndoStop();\r\n\t\t\t\t\t\trange = newRange;\r\n\t\t\t\t\t};\r\n\r\n\t\t\t\t\tconst updateColorPresentations = (color: Color) => {\r\n\t\t\t\t\t\treturn getColorPresentations(editorModel, {\r\n\t\t\t\t\t\t\trange: range,\r\n\t\t\t\t\t\t\tcolor: {\r\n\t\t\t\t\t\t\t\tred: color.rgba.r / 255,\r\n\t\t\t\t\t\t\t\tgreen: color.rgba.g / 255,\r\n\t\t\t\t\t\t\t\tblue: color.rgba.b / 255,\r\n\t\t\t\t\t\t\t\talpha: color.rgba.a\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}, msg.provider, CancellationToken.None).then((colorPresentations) => {\r\n\t\t\t\t\t\t\tmodel.colorPresentations = colorPresentations || [];\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t};\r\n\r\n\t\t\t\t\tconst colorListener = model.onColorFlushed((color: Color) => {\r\n\t\t\t\t\t\tupdateColorPresentations(color).then(updateEditorModel);\r\n\t\t\t\t\t});\r\n\t\t\t\t\tconst colorChangeListener = model.onDidChangeColor(updateColorPresentations);\r\n\r\n\t\t\t\t\tthis._colorPicker = widget;\r\n\t\t\t\t\tthis.showAt(range.getStartPosition(), range, this._shouldFocus);\r\n\t\t\t\t\tthis._updateContents(fragment);\r\n\t\t\t\t\tthis._colorPicker.layout();\r\n\r\n\t\t\t\t\tthis._renderDisposable = combinedDisposable(colorListener, colorChangeListener, widget, disposables);\r\n\t\t\t\t});\r\n\t\t\t} else {\r\n\t\t\t\tif (msg instanceof MarkerHover) {\r\n\t\t\t\t\tmarkerMessages.push(msg);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tif (msg instanceof MarkdownHover) {\r\n\t\t\t\t\t\tmarkdownParts.push(msg);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tif (markdownParts.length > 0) {\r\n\t\t\tdisposables.add(this._markdownHoverParticipant.renderHoverParts(markdownParts, fragment));\r\n\t\t}\r\n\r\n\t\tif (markerMessages.length) {\r\n\t\t\tdisposables.add(this._markerHoverParticipant.renderHoverParts(markerMessages, fragment));\r\n\t\t}\r\n\r\n\t\tthis._renderDisposable = disposables;\r\n\r\n\t\t// show\r\n\r\n\t\tif (!containColorPicker && fragment.hasChildNodes()) {\r\n\t\t\tthis.showAt(new Position(renderRange.startLineNumber, renderColumn), highlightRange, this._shouldFocus);\r\n\t\t\tthis._updateContents(fragment);\r\n\t\t}\r\n\r\n\t\tthis._isChangingDecorations = true;\r\n\t\tthis._highlightDecorations = this._editor.deltaDecorations(this._highlightDecorations, highlightRange ? [{\r\n\t\t\trange: highlightRange,\r\n\t\t\toptions: ModesContentHoverWidget._DECORATION_OPTIONS\r\n\t\t}] : []);\r\n\t\tthis._isChangingDecorations = false;\r\n\t}\r\n\r\n\tprivate static readonly _DECORATION_OPTIONS = ModelDecorationOptions.register({\r\n\t\tclassName: 'hoverHighlight'\r\n\t});\r\n}\r\n\r\nfunction hoverContentsEquals(first: HoverPartInfo[], second: HoverPartInfo[]): boolean {\r\n\tif (first.length !== second.length) {\r\n\t\treturn false;\r\n\t}\r\n\tfor (let i = 0; i < first.length; i++) {\r\n\t\tif (!first[i].data.equals(second[i].data)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n\treturn true;\r\n}\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst linkFg = theme.getColor(textLinkForeground);\r\n\tif (linkFg) {\r\n\t\tcollector.addRule(`.monaco-hover .hover-contents a.code-link span:hover { color: ${linkFg}; }`);\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { RunOnceScheduler } from 'vs/base/common/async';\r\nimport { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { Disposable, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions';\r\nimport { CursorChangeReason, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';\r\nimport { CursorMoveCommands } from 'vs/editor/common/controller/cursorMoveCommands';\r\nimport { Range } from 'vs/editor/common/core/range';\r\nimport { Selection } from 'vs/editor/common/core/selection';\r\nimport { Constants } from 'vs/base/common/uint';\r\nimport { IEditorContribution, ScrollType } from 'vs/editor/common/editorCommon';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { FindMatch, ITextModel, OverviewRulerLane, TrackedRangeStickiness } from 'vs/editor/common/model';\r\nimport { ModelDecorationOptions } from 'vs/editor/common/model/textModel';\r\nimport { DocumentHighlightProviderRegistry } from 'vs/editor/common/modes';\r\nimport { CommonFindController } from 'vs/editor/contrib/find/findController';\r\nimport { FindOptionOverride, INewFindReplaceState } from 'vs/editor/contrib/find/findState';\r\nimport { MenuId } from 'vs/platform/actions/common/actions';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport { overviewRulerSelectionHighlightForeground } from 'vs/platform/theme/common/colorRegistry';\r\nimport { themeColorFromId } from 'vs/platform/theme/common/themeService';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';\r\n\r\nexport class InsertCursorAbove extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.insertCursorAbove',\r\n\t\t\tlabel: nls.localize('mutlicursor.insertAbove', \"Add Cursor Above\"),\r\n\t\t\talias: 'Add Cursor Above',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.UpArrow,\r\n\t\t\t\tlinux: {\r\n\t\t\t\t\tprimary: KeyMod.Shift | KeyMod.Alt | KeyCode.UpArrow,\r\n\t\t\t\t\tsecondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow]\r\n\t\t\t\t},\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tmenuOpts: {\r\n\t\t\t\tmenuId: MenuId.MenubarSelectionMenu,\r\n\t\t\t\tgroup: '3_multi',\r\n\t\t\t\ttitle: nls.localize({ key: 'miInsertCursorAbove', comment: ['&& denotes a mnemonic'] }, \"&&Add Cursor Above\"),\r\n\t\t\t\torder: 2\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst useLogicalLine = (args && args.logicalLine === true);\r\n\t\tconst viewModel = editor._getViewModel();\r\n\r\n\t\tif (viewModel.cursorConfig.readOnly) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tviewModel.pushStackElement();\r\n\t\tviewModel.setCursorStates(\r\n\t\t\targs.source,\r\n\t\t\tCursorChangeReason.Explicit,\r\n\t\t\tCursorMoveCommands.addCursorUp(viewModel, viewModel.getCursorStates(), useLogicalLine)\r\n\t\t);\r\n\t\tviewModel.revealTopMostCursor(args.source);\r\n\t}\r\n}\r\n\r\nexport class InsertCursorBelow extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.insertCursorBelow',\r\n\t\t\tlabel: nls.localize('mutlicursor.insertBelow', \"Add Cursor Below\"),\r\n\t\t\talias: 'Add Cursor Below',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.DownArrow,\r\n\t\t\t\tlinux: {\r\n\t\t\t\t\tprimary: KeyMod.Shift | KeyMod.Alt | KeyCode.DownArrow,\r\n\t\t\t\t\tsecondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow]\r\n\t\t\t\t},\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tmenuOpts: {\r\n\t\t\t\tmenuId: MenuId.MenubarSelectionMenu,\r\n\t\t\t\tgroup: '3_multi',\r\n\t\t\t\ttitle: nls.localize({ key: 'miInsertCursorBelow', comment: ['&& denotes a mnemonic'] }, \"A&&dd Cursor Below\"),\r\n\t\t\t\torder: 3\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst useLogicalLine = (args && args.logicalLine === true);\r\n\t\tconst viewModel = editor._getViewModel();\r\n\r\n\t\tif (viewModel.cursorConfig.readOnly) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tviewModel.pushStackElement();\r\n\t\tviewModel.setCursorStates(\r\n\t\t\targs.source,\r\n\t\t\tCursorChangeReason.Explicit,\r\n\t\t\tCursorMoveCommands.addCursorDown(viewModel, viewModel.getCursorStates(), useLogicalLine)\r\n\t\t);\r\n\t\tviewModel.revealBottomMostCursor(args.source);\r\n\t}\r\n}\r\n\r\nclass InsertCursorAtEndOfEachLineSelected extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.insertCursorAtEndOfEachLineSelected',\r\n\t\t\tlabel: nls.localize('mutlicursor.insertAtEndOfEachLineSelected', \"Add Cursors to Line Ends\"),\r\n\t\t\talias: 'Add Cursors to Line Ends',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_I,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tmenuOpts: {\r\n\t\t\t\tmenuId: MenuId.MenubarSelectionMenu,\r\n\t\t\t\tgroup: '3_multi',\r\n\t\t\t\ttitle: nls.localize({ key: 'miInsertCursorAtEndOfEachLineSelected', comment: ['&& denotes a mnemonic'] }, \"Add C&&ursors to Line Ends\"),\r\n\t\t\t\torder: 4\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprivate getCursorsForSelection(selection: Selection, model: ITextModel, result: Selection[]): void {\r\n\t\tif (selection.isEmpty()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tfor (let i = selection.startLineNumber; i < selection.endLineNumber; i++) {\r\n\t\t\tlet currentLineMaxColumn = model.getLineMaxColumn(i);\r\n\t\t\tresult.push(new Selection(i, currentLineMaxColumn, i, currentLineMaxColumn));\r\n\t\t}\r\n\t\tif (selection.endColumn > 1) {\r\n\t\t\tresult.push(new Selection(selection.endLineNumber, selection.endColumn, selection.endLineNumber, selection.endColumn));\r\n\t\t}\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst model = editor.getModel();\r\n\t\tconst selections = editor.getSelections();\r\n\t\tlet newSelections: Selection[] = [];\r\n\t\tselections.forEach((sel) => this.getCursorsForSelection(sel, model, newSelections));\r\n\r\n\t\tif (newSelections.length > 0) {\r\n\t\t\teditor.setSelections(newSelections);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass InsertCursorAtEndOfLineSelected extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.addCursorsToBottom',\r\n\t\t\tlabel: nls.localize('mutlicursor.addCursorsToBottom', \"Add Cursors To Bottom\"),\r\n\t\t\talias: 'Add Cursors To Bottom',\r\n\t\t\tprecondition: undefined\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst selections = editor.getSelections();\r\n\t\tconst lineCount = editor.getModel().getLineCount();\r\n\r\n\t\tlet newSelections: Selection[] = [];\r\n\t\tfor (let i = selections[0].startLineNumber; i <= lineCount; i++) {\r\n\t\t\tnewSelections.push(new Selection(i, selections[0].startColumn, i, selections[0].endColumn));\r\n\t\t}\r\n\r\n\t\tif (newSelections.length > 0) {\r\n\t\t\teditor.setSelections(newSelections);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass InsertCursorAtTopOfLineSelected extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.addCursorsToTop',\r\n\t\t\tlabel: nls.localize('mutlicursor.addCursorsToTop', \"Add Cursors To Top\"),\r\n\t\t\talias: 'Add Cursors To Top',\r\n\t\t\tprecondition: undefined\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst selections = editor.getSelections();\r\n\r\n\t\tlet newSelections: Selection[] = [];\r\n\t\tfor (let i = selections[0].startLineNumber; i >= 1; i--) {\r\n\t\t\tnewSelections.push(new Selection(i, selections[0].startColumn, i, selections[0].endColumn));\r\n\t\t}\r\n\r\n\t\tif (newSelections.length > 0) {\r\n\t\t\teditor.setSelections(newSelections);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class MultiCursorSessionResult {\r\n\tconstructor(\r\n\t\tpublic readonly selections: Selection[],\r\n\t\tpublic readonly revealRange: Range,\r\n\t\tpublic readonly revealScrollType: ScrollType\r\n\t) { }\r\n}\r\n\r\nexport class MultiCursorSession {\r\n\r\n\tpublic static create(editor: ICodeEditor, findController: CommonFindController): MultiCursorSession | null {\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tconst findState = findController.getState();\r\n\r\n\t\t// Find widget owns entirely what we search for if:\r\n\t\t// - focus is not in the editor (i.e. it is in the find widget)\r\n\t\t// - and the search widget is visible\r\n\t\t// - and the search string is non-empty\r\n\t\tif (!editor.hasTextFocus() && findState.isRevealed && findState.searchString.length > 0) {\r\n\t\t\t// Find widget owns what is searched for\r\n\t\t\treturn new MultiCursorSession(editor, findController, false, findState.searchString, findState.wholeWord, findState.matchCase, null);\r\n\t\t}\r\n\r\n\t\t// Otherwise, the selection gives the search text, and the find widget gives the search settings\r\n\t\t// The exception is the find state disassociation case: when beginning with a single, collapsed selection\r\n\t\tlet isDisconnectedFromFindController = false;\r\n\t\tlet wholeWord: boolean;\r\n\t\tlet matchCase: boolean;\r\n\t\tconst selections = editor.getSelections();\r\n\t\tif (selections.length === 1 && selections[0].isEmpty()) {\r\n\t\t\tisDisconnectedFromFindController = true;\r\n\t\t\twholeWord = true;\r\n\t\t\tmatchCase = true;\r\n\t\t} else {\r\n\t\t\twholeWord = findState.wholeWord;\r\n\t\t\tmatchCase = findState.matchCase;\r\n\t\t}\r\n\r\n\t\t// Selection owns what is searched for\r\n\t\tconst s = editor.getSelection();\r\n\r\n\t\tlet searchText: string;\r\n\t\tlet currentMatch: Selection | null = null;\r\n\r\n\t\tif (s.isEmpty()) {\r\n\t\t\t// selection is empty => expand to current word\r\n\t\t\tconst word = editor.getConfiguredWordAtPosition(s.getStartPosition());\r\n\t\t\tif (!word) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t\tsearchText = word.word;\r\n\t\t\tcurrentMatch = new Selection(s.startLineNumber, word.startColumn, s.startLineNumber, word.endColumn);\r\n\t\t} else {\r\n\t\t\tsearchText = editor.getModel().getValueInRange(s).replace(/\\r\\n/g, '\\n');\r\n\t\t}\r\n\r\n\t\treturn new MultiCursorSession(editor, findController, isDisconnectedFromFindController, searchText, wholeWord, matchCase, currentMatch);\r\n\t}\r\n\r\n\tconstructor(\r\n\t\tprivate readonly _editor: ICodeEditor,\r\n\t\tpublic readonly findController: CommonFindController,\r\n\t\tpublic readonly isDisconnectedFromFindController: boolean,\r\n\t\tpublic readonly searchText: string,\r\n\t\tpublic readonly wholeWord: boolean,\r\n\t\tpublic readonly matchCase: boolean,\r\n\t\tpublic currentMatch: Selection | null\r\n\t) { }\r\n\r\n\tpublic addSelectionToNextFindMatch(): MultiCursorSessionResult | null {\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst nextMatch = this._getNextMatch();\r\n\t\tif (!nextMatch) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst allSelections = this._editor.getSelections();\r\n\t\treturn new MultiCursorSessionResult(allSelections.concat(nextMatch), nextMatch, ScrollType.Smooth);\r\n\t}\r\n\r\n\tpublic moveSelectionToNextFindMatch(): MultiCursorSessionResult | null {\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst nextMatch = this._getNextMatch();\r\n\t\tif (!nextMatch) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst allSelections = this._editor.getSelections();\r\n\t\treturn new MultiCursorSessionResult(allSelections.slice(0, allSelections.length - 1).concat(nextMatch), nextMatch, ScrollType.Smooth);\r\n\t}\r\n\r\n\tprivate _getNextMatch(): Selection | null {\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (this.currentMatch) {\r\n\t\t\tconst result = this.currentMatch;\r\n\t\t\tthis.currentMatch = null;\r\n\t\t\treturn result;\r\n\t\t}\r\n\r\n\t\tthis.findController.highlightFindOptions();\r\n\r\n\t\tconst allSelections = this._editor.getSelections();\r\n\t\tconst lastAddedSelection = allSelections[allSelections.length - 1];\r\n\t\tconst nextMatch = this._editor.getModel().findNextMatch(this.searchText, lastAddedSelection.getEndPosition(), false, this.matchCase, this.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, false);\r\n\r\n\t\tif (!nextMatch) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn new Selection(nextMatch.range.startLineNumber, nextMatch.range.startColumn, nextMatch.range.endLineNumber, nextMatch.range.endColumn);\r\n\t}\r\n\r\n\tpublic addSelectionToPreviousFindMatch(): MultiCursorSessionResult | null {\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst previousMatch = this._getPreviousMatch();\r\n\t\tif (!previousMatch) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst allSelections = this._editor.getSelections();\r\n\t\treturn new MultiCursorSessionResult(allSelections.concat(previousMatch), previousMatch, ScrollType.Smooth);\r\n\t}\r\n\r\n\tpublic moveSelectionToPreviousFindMatch(): MultiCursorSessionResult | null {\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst previousMatch = this._getPreviousMatch();\r\n\t\tif (!previousMatch) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tconst allSelections = this._editor.getSelections();\r\n\t\treturn new MultiCursorSessionResult(allSelections.slice(0, allSelections.length - 1).concat(previousMatch), previousMatch, ScrollType.Smooth);\r\n\t}\r\n\r\n\tprivate _getPreviousMatch(): Selection | null {\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (this.currentMatch) {\r\n\t\t\tconst result = this.currentMatch;\r\n\t\t\tthis.currentMatch = null;\r\n\t\t\treturn result;\r\n\t\t}\r\n\r\n\t\tthis.findController.highlightFindOptions();\r\n\r\n\t\tconst allSelections = this._editor.getSelections();\r\n\t\tconst lastAddedSelection = allSelections[allSelections.length - 1];\r\n\t\tconst previousMatch = this._editor.getModel().findPreviousMatch(this.searchText, lastAddedSelection.getStartPosition(), false, this.matchCase, this.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, false);\r\n\r\n\t\tif (!previousMatch) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn new Selection(previousMatch.range.startLineNumber, previousMatch.range.startColumn, previousMatch.range.endLineNumber, previousMatch.range.endColumn);\r\n\t}\r\n\r\n\tpublic selectAll(): FindMatch[] {\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn [];\r\n\t\t}\r\n\r\n\t\tthis.findController.highlightFindOptions();\r\n\r\n\t\treturn this._editor.getModel().findMatches(this.searchText, true, false, this.matchCase, this.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, false, Constants.MAX_SAFE_SMALL_INTEGER);\r\n\t}\r\n}\r\n\r\nexport class MultiCursorSelectionController extends Disposable implements IEditorContribution {\r\n\r\n\tpublic static readonly ID = 'editor.contrib.multiCursorController';\r\n\r\n\tprivate readonly _editor: ICodeEditor;\r\n\tprivate _ignoreSelectionChange: boolean;\r\n\tprivate _session: MultiCursorSession | null;\r\n\tprivate readonly _sessionDispose = this._register(new DisposableStore());\r\n\r\n\tpublic static get(editor: ICodeEditor): MultiCursorSelectionController {\r\n\t\treturn editor.getContribution(MultiCursorSelectionController.ID);\r\n\t}\r\n\r\n\tconstructor(editor: ICodeEditor) {\r\n\t\tsuper();\r\n\t\tthis._editor = editor;\r\n\t\tthis._ignoreSelectionChange = false;\r\n\t\tthis._session = null;\r\n\t}\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._endSession();\r\n\t\tsuper.dispose();\r\n\t}\r\n\r\n\tprivate _beginSessionIfNeeded(findController: CommonFindController): void {\r\n\t\tif (!this._session) {\r\n\t\t\t// Create a new session\r\n\t\t\tconst session = MultiCursorSession.create(this._editor, findController);\r\n\t\t\tif (!session) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tthis._session = session;\r\n\r\n\t\t\tconst newState: INewFindReplaceState = { searchString: this._session.searchText };\r\n\t\t\tif (this._session.isDisconnectedFromFindController) {\r\n\t\t\t\tnewState.wholeWordOverride = FindOptionOverride.True;\r\n\t\t\t\tnewState.matchCaseOverride = FindOptionOverride.True;\r\n\t\t\t\tnewState.isRegexOverride = FindOptionOverride.False;\r\n\t\t\t}\r\n\t\t\tfindController.getState().change(newState, false);\r\n\r\n\t\t\tthis._sessionDispose.add(this._editor.onDidChangeCursorSelection((e) => {\r\n\t\t\t\tif (this._ignoreSelectionChange) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\tthis._endSession();\r\n\t\t\t}));\r\n\t\t\tthis._sessionDispose.add(this._editor.onDidBlurEditorText(() => {\r\n\t\t\t\tthis._endSession();\r\n\t\t\t}));\r\n\t\t\tthis._sessionDispose.add(findController.getState().onFindReplaceStateChange((e) => {\r\n\t\t\t\tif (e.matchCase || e.wholeWord) {\r\n\t\t\t\t\tthis._endSession();\r\n\t\t\t\t}\r\n\t\t\t}));\r\n\t\t}\r\n\t}\r\n\r\n\tprivate _endSession(): void {\r\n\t\tthis._sessionDispose.clear();\r\n\t\tif (this._session && this._session.isDisconnectedFromFindController) {\r\n\t\t\tconst newState: INewFindReplaceState = {\r\n\t\t\t\twholeWordOverride: FindOptionOverride.NotSet,\r\n\t\t\t\tmatchCaseOverride: FindOptionOverride.NotSet,\r\n\t\t\t\tisRegexOverride: FindOptionOverride.NotSet,\r\n\t\t\t};\r\n\t\t\tthis._session.findController.getState().change(newState, false);\r\n\t\t}\r\n\t\tthis._session = null;\r\n\t}\r\n\r\n\tprivate _setSelections(selections: Selection[]): void {\r\n\t\tthis._ignoreSelectionChange = true;\r\n\t\tthis._editor.setSelections(selections);\r\n\t\tthis._ignoreSelectionChange = false;\r\n\t}\r\n\r\n\tprivate _expandEmptyToWord(model: ITextModel, selection: Selection): Selection {\r\n\t\tif (!selection.isEmpty()) {\r\n\t\t\treturn selection;\r\n\t\t}\r\n\t\tconst word = this._editor.getConfiguredWordAtPosition(selection.getStartPosition());\r\n\t\tif (!word) {\r\n\t\t\treturn selection;\r\n\t\t}\r\n\t\treturn new Selection(selection.startLineNumber, word.startColumn, selection.startLineNumber, word.endColumn);\r\n\t}\r\n\r\n\tprivate _applySessionResult(result: MultiCursorSessionResult | null): void {\r\n\t\tif (!result) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._setSelections(result.selections);\r\n\t\tif (result.revealRange) {\r\n\t\t\tthis._editor.revealRangeInCenterIfOutsideViewport(result.revealRange, result.revealScrollType);\r\n\t\t}\r\n\t}\r\n\r\n\tpublic getSession(findController: CommonFindController): MultiCursorSession | null {\r\n\t\treturn this._session;\r\n\t}\r\n\r\n\tpublic addSelectionToNextFindMatch(findController: CommonFindController): void {\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (!this._session) {\r\n\t\t\t// If there are multiple cursors, handle the case where they do not all select the same text.\r\n\t\t\tconst allSelections = this._editor.getSelections();\r\n\t\t\tif (allSelections.length > 1) {\r\n\t\t\t\tconst findState = findController.getState();\r\n\t\t\t\tconst matchCase = findState.matchCase;\r\n\t\t\t\tconst selectionsContainSameText = modelRangesContainSameText(this._editor.getModel(), allSelections, matchCase);\r\n\t\t\t\tif (!selectionsContainSameText) {\r\n\t\t\t\t\tconst model = this._editor.getModel();\r\n\t\t\t\t\tlet resultingSelections: Selection[] = [];\r\n\t\t\t\t\tfor (let i = 0, len = allSelections.length; i < len; i++) {\r\n\t\t\t\t\t\tresultingSelections[i] = this._expandEmptyToWord(model, allSelections[i]);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tthis._editor.setSelections(resultingSelections);\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis._beginSessionIfNeeded(findController);\r\n\t\tif (this._session) {\r\n\t\t\tthis._applySessionResult(this._session.addSelectionToNextFindMatch());\r\n\t\t}\r\n\t}\r\n\r\n\tpublic addSelectionToPreviousFindMatch(findController: CommonFindController): void {\r\n\t\tthis._beginSessionIfNeeded(findController);\r\n\t\tif (this._session) {\r\n\t\t\tthis._applySessionResult(this._session.addSelectionToPreviousFindMatch());\r\n\t\t}\r\n\t}\r\n\r\n\tpublic moveSelectionToNextFindMatch(findController: CommonFindController): void {\r\n\t\tthis._beginSessionIfNeeded(findController);\r\n\t\tif (this._session) {\r\n\t\t\tthis._applySessionResult(this._session.moveSelectionToNextFindMatch());\r\n\t\t}\r\n\t}\r\n\r\n\tpublic moveSelectionToPreviousFindMatch(findController: CommonFindController): void {\r\n\t\tthis._beginSessionIfNeeded(findController);\r\n\t\tif (this._session) {\r\n\t\t\tthis._applySessionResult(this._session.moveSelectionToPreviousFindMatch());\r\n\t\t}\r\n\t}\r\n\r\n\tpublic selectAll(findController: CommonFindController): void {\r\n\t\tif (!this._editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet matches: FindMatch[] | null = null;\r\n\r\n\t\tconst findState = findController.getState();\r\n\r\n\t\t// Special case: find widget owns entirely what we search for if:\r\n\t\t// - focus is not in the editor (i.e. it is in the find widget)\r\n\t\t// - and the search widget is visible\r\n\t\t// - and the search string is non-empty\r\n\t\t// - and we're searching for a regex\r\n\t\tif (findState.isRevealed && findState.searchString.length > 0 && findState.isRegex) {\r\n\r\n\t\t\tmatches = this._editor.getModel().findMatches(findState.searchString, true, findState.isRegex, findState.matchCase, findState.wholeWord ? this._editor.getOption(EditorOption.wordSeparators) : null, false, Constants.MAX_SAFE_SMALL_INTEGER);\r\n\r\n\t\t} else {\r\n\r\n\t\t\tthis._beginSessionIfNeeded(findController);\r\n\t\t\tif (!this._session) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tmatches = this._session.selectAll();\r\n\t\t}\r\n\r\n\t\tif (findState.searchScope) {\r\n\t\t\tconst states = findState.searchScope;\r\n\t\t\tlet inSelection: FindMatch[] | null = [];\r\n\t\t\tmatches.forEach((match) => {\r\n\t\t\t\tstates.forEach((state) => {\r\n\t\t\t\t\tif (match.range.endLineNumber <= state.endLineNumber && match.range.startLineNumber >= state.startLineNumber) {\r\n\t\t\t\t\t\tinSelection!.push(match);\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t});\r\n\t\t\tmatches = inSelection;\r\n\t\t}\r\n\r\n\t\tif (matches.length > 0) {\r\n\t\t\tconst editorSelection = this._editor.getSelection();\r\n\t\t\t// Have the primary cursor remain the one where the action was invoked\r\n\t\t\tfor (let i = 0, len = matches.length; i < len; i++) {\r\n\t\t\t\tconst match = matches[i];\r\n\t\t\t\tconst intersection = match.range.intersectRanges(editorSelection);\r\n\t\t\t\tif (intersection) {\r\n\t\t\t\t\t// bingo!\r\n\t\t\t\t\tmatches[i] = matches[0];\r\n\t\t\t\t\tmatches[0] = match;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tthis._setSelections(matches.map(m => new Selection(m.range.startLineNumber, m.range.startColumn, m.range.endLineNumber, m.range.endColumn)));\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport abstract class MultiCursorSelectionControllerAction extends EditorAction {\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tconst multiCursorController = MultiCursorSelectionController.get(editor);\r\n\t\tif (!multiCursorController) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst findController = CommonFindController.get(editor);\r\n\t\tif (!findController) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._run(multiCursorController, findController);\r\n\t}\r\n\r\n\tprotected abstract _run(multiCursorController: MultiCursorSelectionController, findController: CommonFindController): void;\r\n}\r\n\r\nexport class AddSelectionToNextFindMatchAction extends MultiCursorSelectionControllerAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.addSelectionToNextFindMatch',\r\n\t\t\tlabel: nls.localize('addSelectionToNextFindMatch', \"Add Selection To Next Find Match\"),\r\n\t\t\talias: 'Add Selection To Next Find Match',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.focus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.KEY_D,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tmenuOpts: {\r\n\t\t\t\tmenuId: MenuId.MenubarSelectionMenu,\r\n\t\t\t\tgroup: '3_multi',\r\n\t\t\t\ttitle: nls.localize({ key: 'miAddSelectionToNextFindMatch', comment: ['&& denotes a mnemonic'] }, \"Add &&Next Occurrence\"),\r\n\t\t\t\torder: 5\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\tprotected _run(multiCursorController: MultiCursorSelectionController, findController: CommonFindController): void {\r\n\t\tmultiCursorController.addSelectionToNextFindMatch(findController);\r\n\t}\r\n}\r\n\r\nexport class AddSelectionToPreviousFindMatchAction extends MultiCursorSelectionControllerAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.addSelectionToPreviousFindMatch',\r\n\t\t\tlabel: nls.localize('addSelectionToPreviousFindMatch', \"Add Selection To Previous Find Match\"),\r\n\t\t\talias: 'Add Selection To Previous Find Match',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tmenuOpts: {\r\n\t\t\t\tmenuId: MenuId.MenubarSelectionMenu,\r\n\t\t\t\tgroup: '3_multi',\r\n\t\t\t\ttitle: nls.localize({ key: 'miAddSelectionToPreviousFindMatch', comment: ['&& denotes a mnemonic'] }, \"Add P&&revious Occurrence\"),\r\n\t\t\t\torder: 6\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\tprotected _run(multiCursorController: MultiCursorSelectionController, findController: CommonFindController): void {\r\n\t\tmultiCursorController.addSelectionToPreviousFindMatch(findController);\r\n\t}\r\n}\r\n\r\nexport class MoveSelectionToNextFindMatchAction extends MultiCursorSelectionControllerAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.moveSelectionToNextFindMatch',\r\n\t\t\tlabel: nls.localize('moveSelectionToNextFindMatch', \"Move Last Selection To Next Find Match\"),\r\n\t\t\talias: 'Move Last Selection To Next Find Match',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.focus,\r\n\t\t\t\tprimary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_D),\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\tprotected _run(multiCursorController: MultiCursorSelectionController, findController: CommonFindController): void {\r\n\t\tmultiCursorController.moveSelectionToNextFindMatch(findController);\r\n\t}\r\n}\r\n\r\nexport class MoveSelectionToPreviousFindMatchAction extends MultiCursorSelectionControllerAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.moveSelectionToPreviousFindMatch',\r\n\t\t\tlabel: nls.localize('moveSelectionToPreviousFindMatch', \"Move Last Selection To Previous Find Match\"),\r\n\t\t\talias: 'Move Last Selection To Previous Find Match',\r\n\t\t\tprecondition: undefined\r\n\t\t});\r\n\t}\r\n\tprotected _run(multiCursorController: MultiCursorSelectionController, findController: CommonFindController): void {\r\n\t\tmultiCursorController.moveSelectionToPreviousFindMatch(findController);\r\n\t}\r\n}\r\n\r\nexport class SelectHighlightsAction extends MultiCursorSelectionControllerAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.selectHighlights',\r\n\t\t\tlabel: nls.localize('selectAllOccurrencesOfFindMatch', \"Select All Occurrences of Find Match\"),\r\n\t\t\talias: 'Select All Occurrences of Find Match',\r\n\t\t\tprecondition: undefined,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.focus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_L,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tmenuOpts: {\r\n\t\t\t\tmenuId: MenuId.MenubarSelectionMenu,\r\n\t\t\t\tgroup: '3_multi',\r\n\t\t\t\ttitle: nls.localize({ key: 'miSelectHighlights', comment: ['&& denotes a mnemonic'] }, \"Select All &&Occurrences\"),\r\n\t\t\t\torder: 7\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\tprotected _run(multiCursorController: MultiCursorSelectionController, findController: CommonFindController): void {\r\n\t\tmultiCursorController.selectAll(findController);\r\n\t}\r\n}\r\n\r\nexport class CompatChangeAll extends MultiCursorSelectionControllerAction {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.changeAll',\r\n\t\t\tlabel: nls.localize('changeAll.label', \"Change All Occurrences\"),\r\n\t\t\talias: 'Change All Occurrences',\r\n\t\t\tprecondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.editorTextFocus),\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.F2,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t},\r\n\t\t\tcontextMenuOpts: {\r\n\t\t\t\tgroup: '1_modification',\r\n\t\t\t\torder: 1.2\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\tprotected _run(multiCursorController: MultiCursorSelectionController, findController: CommonFindController): void {\r\n\t\tmultiCursorController.selectAll(findController);\r\n\t}\r\n}\r\n\r\nclass SelectionHighlighterState {\r\n\tpublic readonly searchText: string;\r\n\tpublic readonly matchCase: boolean;\r\n\tpublic readonly wordSeparators: string | null;\r\n\tpublic readonly modelVersionId: number;\r\n\r\n\tconstructor(searchText: string, matchCase: boolean, wordSeparators: string | null, modelVersionId: number) {\r\n\t\tthis.searchText = searchText;\r\n\t\tthis.matchCase = matchCase;\r\n\t\tthis.wordSeparators = wordSeparators;\r\n\t\tthis.modelVersionId = modelVersionId;\r\n\t}\r\n\r\n\t/**\r\n\t * Everything equals except for `lastWordUnderCursor`\r\n\t */\r\n\tpublic static softEquals(a: SelectionHighlighterState | null, b: SelectionHighlighterState | null): boolean {\r\n\t\tif (!a && !b) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (!a || !b) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn (\r\n\t\t\ta.searchText === b.searchText\r\n\t\t\t&& a.matchCase === b.matchCase\r\n\t\t\t&& a.wordSeparators === b.wordSeparators\r\n\t\t\t&& a.modelVersionId === b.modelVersionId\r\n\t\t);\r\n\t}\r\n}\r\n\r\nexport class SelectionHighlighter extends Disposable implements IEditorContribution {\r\n\tpublic static readonly ID = 'editor.contrib.selectionHighlighter';\r\n\r\n\tprivate readonly editor: ICodeEditor;\r\n\tprivate _isEnabled: boolean;\r\n\tprivate decorations: string[];\r\n\tprivate readonly updateSoon: RunOnceScheduler;\r\n\tprivate state: SelectionHighlighterState | null;\r\n\r\n\tconstructor(editor: ICodeEditor) {\r\n\t\tsuper();\r\n\t\tthis.editor = editor;\r\n\t\tthis._isEnabled = editor.getOption(EditorOption.selectionHighlight);\r\n\t\tthis.decorations = [];\r\n\t\tthis.updateSoon = this._register(new RunOnceScheduler(() => this._update(), 300));\r\n\t\tthis.state = null;\r\n\r\n\t\tthis._register(editor.onDidChangeConfiguration((e) => {\r\n\t\t\tthis._isEnabled = editor.getOption(EditorOption.selectionHighlight);\r\n\t\t}));\r\n\t\tthis._register(editor.onDidChangeCursorSelection((e: ICursorSelectionChangedEvent) => {\r\n\r\n\t\t\tif (!this._isEnabled) {\r\n\t\t\t\t// Early exit if nothing needs to be done!\r\n\t\t\t\t// Leave some form of early exit check here if you wish to continue being a cursor position change listener ;)\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (e.selection.isEmpty()) {\r\n\t\t\t\tif (e.reason === CursorChangeReason.Explicit) {\r\n\t\t\t\t\tif (this.state) {\r\n\t\t\t\t\t\t// no longer valid\r\n\t\t\t\t\t\tthis._setState(null);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tthis.updateSoon.schedule();\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis._setState(null);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tthis._update();\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._register(editor.onDidChangeModel((e) => {\r\n\t\t\tthis._setState(null);\r\n\t\t}));\r\n\t\tthis._register(editor.onDidChangeModelContent((e) => {\r\n\t\t\tif (this._isEnabled) {\r\n\t\t\t\tthis.updateSoon.schedule();\r\n\t\t\t}\r\n\t\t}));\r\n\t\tthis._register(CommonFindController.get(editor).getState().onFindReplaceStateChange((e) => {\r\n\t\t\tthis._update();\r\n\t\t}));\r\n\t}\r\n\r\n\tprivate _update(): void {\r\n\t\tthis._setState(SelectionHighlighter._createState(this._isEnabled, this.editor));\r\n\t}\r\n\r\n\tprivate static _createState(isEnabled: boolean, editor: ICodeEditor): SelectionHighlighterState | null {\r\n\t\tif (!isEnabled) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tif (!editor.hasModel()) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tconst s = editor.getSelection();\r\n\t\tif (s.startLineNumber !== s.endLineNumber) {\r\n\t\t\t// multiline forbidden for perf reasons\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tconst multiCursorController = MultiCursorSelectionController.get(editor);\r\n\t\tif (!multiCursorController) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tconst findController = CommonFindController.get(editor);\r\n\t\tif (!findController) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tlet r = multiCursorController.getSession(findController);\r\n\t\tif (!r) {\r\n\t\t\tconst allSelections = editor.getSelections();\r\n\t\t\tif (allSelections.length > 1) {\r\n\t\t\t\tconst findState = findController.getState();\r\n\t\t\t\tconst matchCase = findState.matchCase;\r\n\t\t\t\tconst selectionsContainSameText = modelRangesContainSameText(editor.getModel(), allSelections, matchCase);\r\n\t\t\t\tif (!selectionsContainSameText) {\r\n\t\t\t\t\treturn null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tr = MultiCursorSession.create(editor, findController);\r\n\t\t}\r\n\t\tif (!r) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tif (r.currentMatch) {\r\n\t\t\t// This is an empty selection\r\n\t\t\t// Do not interfere with semantic word highlighting in the no selection case\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tif (/^[ \\t]+$/.test(r.searchText)) {\r\n\t\t\t// whitespace only selection\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tif (r.searchText.length > 200) {\r\n\t\t\t// very long selection\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\t// TODO: better handling of this case\r\n\t\tconst findState = findController.getState();\r\n\t\tconst caseSensitive = findState.matchCase;\r\n\r\n\t\t// Return early if the find widget shows the exact same matches\r\n\t\tif (findState.isRevealed) {\r\n\t\t\tlet findStateSearchString = findState.searchString;\r\n\t\t\tif (!caseSensitive) {\r\n\t\t\t\tfindStateSearchString = findStateSearchString.toLowerCase();\r\n\t\t\t}\r\n\r\n\t\t\tlet mySearchString = r.searchText;\r\n\t\t\tif (!caseSensitive) {\r\n\t\t\t\tmySearchString = mySearchString.toLowerCase();\r\n\t\t\t}\r\n\r\n\t\t\tif (findStateSearchString === mySearchString && r.matchCase === findState.matchCase && r.wholeWord === findState.wholeWord && !findState.isRegex) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn new SelectionHighlighterState(r.searchText, r.matchCase, r.wholeWord ? editor.getOption(EditorOption.wordSeparators) : null, editor.getModel().getVersionId());\r\n\t}\r\n\r\n\tprivate _setState(state: SelectionHighlighterState | null): void {\r\n\t\tif (SelectionHighlighterState.softEquals(this.state, state)) {\r\n\t\t\tthis.state = state;\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis.state = state;\r\n\r\n\t\tif (!this.state) {\r\n\t\t\tthis.decorations = this.editor.deltaDecorations(this.decorations, []);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!this.editor.hasModel()) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst model = this.editor.getModel();\r\n\t\tif (model.isTooLargeForTokenization()) {\r\n\t\t\t// the file is too large, so searching word under cursor in the whole document takes is blocking the UI.\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst hasFindOccurrences = DocumentHighlightProviderRegistry.has(model) && this.editor.getOption(EditorOption.occurrencesHighlight);\r\n\r\n\t\tlet allMatches = model.findMatches(this.state.searchText, true, false, this.state.matchCase, this.state.wordSeparators, false).map(m => m.range);\r\n\t\tallMatches.sort(Range.compareRangesUsingStarts);\r\n\r\n\t\tlet selections = this.editor.getSelections();\r\n\t\tselections.sort(Range.compareRangesUsingStarts);\r\n\r\n\t\t// do not overlap with selection (issue #64 and #512)\r\n\t\tlet matches: Range[] = [];\r\n\t\tfor (let i = 0, j = 0, len = allMatches.length, lenJ = selections.length; i < len;) {\r\n\t\t\tconst match = allMatches[i];\r\n\r\n\t\t\tif (j >= lenJ) {\r\n\t\t\t\t// finished all editor selections\r\n\t\t\t\tmatches.push(match);\r\n\t\t\t\ti++;\r\n\t\t\t} else {\r\n\t\t\t\tconst cmp = Range.compareRangesUsingStarts(match, selections[j]);\r\n\t\t\t\tif (cmp < 0) {\r\n\t\t\t\t\t// match is before sel\r\n\t\t\t\t\tif (selections[j].isEmpty() || !Range.areIntersecting(match, selections[j])) {\r\n\t\t\t\t\t\tmatches.push(match);\r\n\t\t\t\t\t}\r\n\t\t\t\t\ti++;\r\n\t\t\t\t} else if (cmp > 0) {\r\n\t\t\t\t\t// sel is before match\r\n\t\t\t\t\tj++;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// sel is equal to match\r\n\t\t\t\t\ti++;\r\n\t\t\t\t\tj++;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst decorations = matches.map(r => {\r\n\t\t\treturn {\r\n\t\t\t\trange: r,\r\n\t\t\t\t// Show in overviewRuler only if model has no semantic highlighting\r\n\t\t\t\toptions: (hasFindOccurrences ? SelectionHighlighter._SELECTION_HIGHLIGHT : SelectionHighlighter._SELECTION_HIGHLIGHT_OVERVIEW)\r\n\t\t\t};\r\n\t\t});\r\n\r\n\t\tthis.decorations = this.editor.deltaDecorations(this.decorations, decorations);\r\n\t}\r\n\r\n\tprivate static readonly _SELECTION_HIGHLIGHT_OVERVIEW = ModelDecorationOptions.register({\r\n\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,\r\n\t\tclassName: 'selectionHighlight',\r\n\t\toverviewRuler: {\r\n\t\t\tcolor: themeColorFromId(overviewRulerSelectionHighlightForeground),\r\n\t\t\tposition: OverviewRulerLane.Center\r\n\t\t}\r\n\t});\r\n\r\n\tprivate static readonly _SELECTION_HIGHLIGHT = ModelDecorationOptions.register({\r\n\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,\r\n\t\tclassName: 'selectionHighlight',\r\n\t});\r\n\r\n\tpublic dispose(): void {\r\n\t\tthis._setState(null);\r\n\t\tsuper.dispose();\r\n\t}\r\n}\r\n\r\nfunction modelRangesContainSameText(model: ITextModel, ranges: Range[], matchCase: boolean): boolean {\r\n\tconst selectedText = getValueInRange(model, ranges[0], !matchCase);\r\n\tfor (let i = 1, len = ranges.length; i < len; i++) {\r\n\t\tconst range = ranges[i];\r\n\t\tif (range.isEmpty()) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tconst thisSelectedText = getValueInRange(model, range, !matchCase);\r\n\t\tif (selectedText !== thisSelectedText) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n\treturn true;\r\n}\r\n\r\nfunction getValueInRange(model: ITextModel, range: Range, toLowerCase: boolean): string {\r\n\tconst text = model.getValueInRange(range);\r\n\treturn (toLowerCase ? text.toLowerCase() : text);\r\n}\r\n\r\nregisterEditorContribution(MultiCursorSelectionController.ID, MultiCursorSelectionController);\r\nregisterEditorContribution(SelectionHighlighter.ID, SelectionHighlighter);\r\n\r\nregisterEditorAction(InsertCursorAbove);\r\nregisterEditorAction(InsertCursorBelow);\r\nregisterEditorAction(InsertCursorAtEndOfEachLineSelected);\r\nregisterEditorAction(AddSelectionToNextFindMatchAction);\r\nregisterEditorAction(AddSelectionToPreviousFindMatchAction);\r\nregisterEditorAction(MoveSelectionToNextFindMatchAction);\r\nregisterEditorAction(MoveSelectionToPreviousFindMatchAction);\r\nregisterEditorAction(SelectHighlightsAction);\r\nregisterEditorAction(CompatChangeAll);\r\nregisterEditorAction(InsertCursorAtEndOfLineSelected);\r\nregisterEditorAction(InsertCursorAtTopOfLineSelected);\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as dom from 'vs/base/browser/dom';\r\nimport { domEvent, stop } from 'vs/base/browser/event';\r\nimport * as aria from 'vs/base/browser/ui/aria/aria';\r\nimport { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';\r\nimport { Event } from 'vs/base/common/event';\r\nimport { Disposable, DisposableStore } from 'vs/base/common/lifecycle';\r\nimport 'vs/css!./parameterHints';\r\nimport { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';\r\nimport { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport * as modes from 'vs/editor/common/modes';\r\nimport { IModeService } from 'vs/editor/common/services/modeService';\r\nimport { IMarkdownRenderResult, MarkdownRenderer } from 'vs/editor/browser/core/markdownRenderer';\r\nimport { Context } from 'vs/editor/contrib/parameterHints/provideSignatureHelp';\r\nimport * as nls from 'vs/nls';\r\nimport { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\r\nimport { IOpenerService } from 'vs/platform/opener/common/opener';\r\nimport { editorHoverBackground, editorHoverBorder, textCodeBlockBackground, textLinkForeground, editorHoverForeground } from 'vs/platform/theme/common/colorRegistry';\r\nimport { registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService';\r\nimport { ParameterHintsModel, TriggerContext } from 'vs/editor/contrib/parameterHints/parameterHintsModel';\r\nimport { escapeRegExpCharacters } from 'vs/base/common/strings';\r\nimport { Codicon } from 'vs/base/common/codicons';\r\nimport { assertIsDefined } from 'vs/base/common/types';\r\nimport { ColorScheme } from 'vs/platform/theme/common/theme';\r\nimport { registerIcon } from 'vs/platform/theme/common/iconRegistry';\r\nimport { IMarkdownString } from 'vs/base/common/htmlContent';\r\n\r\nconst $ = dom.$;\r\n\r\nconst parameterHintsNextIcon = registerIcon('parameter-hints-next', Codicon.chevronDown, nls.localize('parameterHintsNextIcon', 'Icon for show next parameter hint.'));\r\nconst parameterHintsPreviousIcon = registerIcon('parameter-hints-previous', Codicon.chevronUp, nls.localize('parameterHintsPreviousIcon', 'Icon for show previous parameter hint.'));\r\n\r\nexport class ParameterHintsWidget extends Disposable implements IContentWidget {\r\n\r\n\tprivate static readonly ID = 'editor.widget.parameterHintsWidget';\r\n\r\n\tprivate readonly markdownRenderer: MarkdownRenderer;\r\n\tprivate readonly renderDisposeables = this._register(new DisposableStore());\r\n\tprivate readonly model: ParameterHintsModel;\r\n\tprivate readonly keyVisible: IContextKey;\r\n\tprivate readonly keyMultipleSignatures: IContextKey;\r\n\r\n\tprivate domNodes?: {\r\n\t\treadonly element: HTMLElement;\r\n\t\treadonly signature: HTMLElement;\r\n\t\treadonly docs: HTMLElement;\r\n\t\treadonly overloads: HTMLElement;\r\n\t\treadonly scrollbar: DomScrollableElement;\r\n\t};\r\n\r\n\tprivate visible: boolean = false;\r\n\tprivate announcedLabel: string | null = null;\r\n\r\n\t// Editor.IContentWidget.allowEditorOverflow\r\n\tallowEditorOverflow = true;\r\n\r\n\tconstructor(\r\n\t\tprivate readonly editor: ICodeEditor,\r\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\r\n\t\t@IOpenerService openerService: IOpenerService,\r\n\t\t@IModeService modeService: IModeService,\r\n\t) {\r\n\t\tsuper();\r\n\t\tthis.markdownRenderer = this._register(new MarkdownRenderer({ editor }, modeService, openerService));\r\n\t\tthis.model = this._register(new ParameterHintsModel(editor));\r\n\t\tthis.keyVisible = Context.Visible.bindTo(contextKeyService);\r\n\t\tthis.keyMultipleSignatures = Context.MultipleSignatures.bindTo(contextKeyService);\r\n\r\n\t\tthis._register(this.model.onChangedHints(newParameterHints => {\r\n\t\t\tif (newParameterHints) {\r\n\t\t\t\tthis.show();\r\n\t\t\t\tthis.render(newParameterHints);\r\n\t\t\t} else {\r\n\t\t\t\tthis.hide();\r\n\t\t\t}\r\n\t\t}));\r\n\t}\r\n\r\n\tprivate createParamaterHintDOMNodes() {\r\n\t\tconst element = $('.editor-widget.parameter-hints-widget');\r\n\t\tconst wrapper = dom.append(element, $('.phwrapper'));\r\n\t\twrapper.tabIndex = -1;\r\n\r\n\t\tconst controls = dom.append(wrapper, $('.controls'));\r\n\t\tconst previous = dom.append(controls, $('.button' + ThemeIcon.asCSSSelector(parameterHintsPreviousIcon)));\r\n\t\tconst overloads = dom.append(controls, $('.overloads'));\r\n\t\tconst next = dom.append(controls, $('.button' + ThemeIcon.asCSSSelector(parameterHintsNextIcon)));\r\n\r\n\t\tconst onPreviousClick = stop(domEvent(previous, 'click'));\r\n\t\tthis._register(onPreviousClick(this.previous, this));\r\n\r\n\t\tconst onNextClick = stop(domEvent(next, 'click'));\r\n\t\tthis._register(onNextClick(this.next, this));\r\n\r\n\t\tconst body = $('.body');\r\n\t\tconst scrollbar = new DomScrollableElement(body, {});\r\n\t\tthis._register(scrollbar);\r\n\t\twrapper.appendChild(scrollbar.getDomNode());\r\n\r\n\t\tconst signature = dom.append(body, $('.signature'));\r\n\t\tconst docs = dom.append(body, $('.docs'));\r\n\r\n\t\telement.style.userSelect = 'text';\r\n\r\n\t\tthis.domNodes = {\r\n\t\t\telement,\r\n\t\t\tsignature,\r\n\t\t\toverloads,\r\n\t\t\tdocs,\r\n\t\t\tscrollbar,\r\n\t\t};\r\n\r\n\t\tthis.editor.addContentWidget(this);\r\n\t\tthis.hide();\r\n\r\n\t\tthis._register(this.editor.onDidChangeCursorSelection(e => {\r\n\t\t\tif (this.visible) {\r\n\t\t\t\tthis.editor.layoutContentWidget(this);\r\n\t\t\t}\r\n\t\t}));\r\n\r\n\t\tconst updateFont = () => {\r\n\t\t\tif (!this.domNodes) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tconst fontInfo = this.editor.getOption(EditorOption.fontInfo);\r\n\t\t\tthis.domNodes.element.style.fontSize = `${fontInfo.fontSize}px`;\r\n\t\t};\r\n\r\n\t\tupdateFont();\r\n\r\n\t\tthis._register(Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor))\r\n\t\t\t.filter(e => e.hasChanged(EditorOption.fontInfo))\r\n\t\t\t.on(updateFont, null));\r\n\r\n\t\tthis._register(this.editor.onDidLayoutChange(e => this.updateMaxHeight()));\r\n\t\tthis.updateMaxHeight();\r\n\t}\r\n\r\n\tprivate show(): void {\r\n\t\tif (this.visible) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!this.domNodes) {\r\n\t\t\tthis.createParamaterHintDOMNodes();\r\n\t\t}\r\n\r\n\t\tthis.keyVisible.set(true);\r\n\t\tthis.visible = true;\r\n\t\tsetTimeout(() => {\r\n\t\t\tif (this.domNodes) {\r\n\t\t\t\tthis.domNodes.element.classList.add('visible');\r\n\t\t\t}\r\n\t\t}, 100);\r\n\t\tthis.editor.layoutContentWidget(this);\r\n\t}\r\n\r\n\tprivate hide(): void {\r\n\t\tthis.renderDisposeables.clear();\r\n\r\n\t\tif (!this.visible) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.keyVisible.reset();\r\n\t\tthis.visible = false;\r\n\t\tthis.announcedLabel = null;\r\n\t\tif (this.domNodes) {\r\n\t\t\tthis.domNodes.element.classList.remove('visible');\r\n\t\t}\r\n\t\tthis.editor.layoutContentWidget(this);\r\n\t}\r\n\r\n\tgetPosition(): IContentWidgetPosition | null {\r\n\t\tif (this.visible) {\r\n\t\t\treturn {\r\n\t\t\t\tposition: this.editor.getPosition(),\r\n\t\t\t\tpreference: [ContentWidgetPositionPreference.ABOVE, ContentWidgetPositionPreference.BELOW]\r\n\t\t\t};\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate render(hints: modes.SignatureHelp): void {\r\n\t\tthis.renderDisposeables.clear();\r\n\r\n\t\tif (!this.domNodes) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst multiple = hints.signatures.length > 1;\r\n\t\tthis.domNodes.element.classList.toggle('multiple', multiple);\r\n\t\tthis.keyMultipleSignatures.set(multiple);\r\n\r\n\t\tthis.domNodes.signature.innerText = '';\r\n\t\tthis.domNodes.docs.innerText = '';\r\n\r\n\t\tconst signature = hints.signatures[hints.activeSignature];\r\n\t\tif (!signature) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst code = dom.append(this.domNodes.signature, $('.code'));\r\n\t\tconst fontInfo = this.editor.getOption(EditorOption.fontInfo);\r\n\t\tcode.style.fontSize = `${fontInfo.fontSize}px`;\r\n\t\tcode.style.fontFamily = fontInfo.fontFamily;\r\n\r\n\t\tconst hasParameters = signature.parameters.length > 0;\r\n\t\tconst activeParameterIndex = signature.activeParameter ?? hints.activeParameter;\r\n\r\n\t\tif (!hasParameters) {\r\n\t\t\tconst label = dom.append(code, $('span'));\r\n\t\t\tlabel.textContent = signature.label;\r\n\t\t} else {\r\n\t\t\tthis.renderParameters(code, signature, activeParameterIndex);\r\n\t\t}\r\n\r\n\t\tconst activeParameter: modes.ParameterInformation | undefined = signature.parameters[activeParameterIndex];\r\n\t\tif (activeParameter?.documentation) {\r\n\t\t\tconst documentation = $('span.documentation');\r\n\t\t\tif (typeof activeParameter.documentation === 'string') {\r\n\t\t\t\tdocumentation.textContent = activeParameter.documentation;\r\n\t\t\t} else {\r\n\t\t\t\tconst renderedContents = this.renderMarkdownDocs(activeParameter.documentation);\r\n\t\t\t\tdocumentation.appendChild(renderedContents.element);\r\n\t\t\t}\r\n\t\t\tdom.append(this.domNodes.docs, $('p', {}, documentation));\r\n\t\t}\r\n\r\n\t\tif (signature.documentation === undefined) {\r\n\t\t\t/** no op */\r\n\t\t} else if (typeof signature.documentation === 'string') {\r\n\t\t\tdom.append(this.domNodes.docs, $('p', {}, signature.documentation));\r\n\t\t} else {\r\n\t\t\tconst renderedContents = this.renderMarkdownDocs(signature.documentation);\r\n\t\t\tdom.append(this.domNodes.docs, renderedContents.element);\r\n\t\t}\r\n\r\n\t\tconst hasDocs = this.hasDocs(signature, activeParameter);\r\n\r\n\t\tthis.domNodes.signature.classList.toggle('has-docs', hasDocs);\r\n\t\tthis.domNodes.docs.classList.toggle('empty', !hasDocs);\r\n\r\n\t\tthis.domNodes.overloads.textContent =\r\n\t\t\tString(hints.activeSignature + 1).padStart(hints.signatures.length.toString().length, '0') + '/' + hints.signatures.length;\r\n\r\n\t\tif (activeParameter) {\r\n\t\t\tconst labelToAnnounce = this.getParameterLabel(signature, activeParameterIndex);\r\n\t\t\t// Select method gets called on every user type while parameter hints are visible.\r\n\t\t\t// We do not want to spam the user with same announcements, so we only announce if the current parameter changed.\r\n\r\n\t\t\tif (this.announcedLabel !== labelToAnnounce) {\r\n\t\t\t\taria.alert(nls.localize('hint', \"{0}, hint\", labelToAnnounce));\r\n\t\t\t\tthis.announcedLabel = labelToAnnounce;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis.editor.layoutContentWidget(this);\r\n\t\tthis.domNodes.scrollbar.scanDomNode();\r\n\t}\r\n\r\n\tprivate renderMarkdownDocs(markdown: IMarkdownString | undefined): IMarkdownRenderResult {\r\n\t\tconst renderedContents = this.renderDisposeables.add(this.markdownRenderer.render(markdown, {\r\n\t\t\tasyncRenderCallback: () => {\r\n\t\t\t\tthis.domNodes?.scrollbar.scanDomNode();\r\n\t\t\t}\r\n\t\t}));\r\n\t\trenderedContents.element.classList.add('markdown-docs');\r\n\t\treturn renderedContents;\r\n\t}\r\n\r\n\tprivate hasDocs(signature: modes.SignatureInformation, activeParameter: modes.ParameterInformation | undefined): boolean {\r\n\t\tif (activeParameter && typeof activeParameter.documentation === 'string' && assertIsDefined(activeParameter.documentation).length > 0) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (activeParameter && typeof activeParameter.documentation === 'object' && assertIsDefined(activeParameter.documentation).value.length > 0) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (signature.documentation && typeof signature.documentation === 'string' && assertIsDefined(signature.documentation).length > 0) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (signature.documentation && typeof signature.documentation === 'object' && assertIsDefined(signature.documentation.value).length > 0) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tprivate renderParameters(parent: HTMLElement, signature: modes.SignatureInformation, activeParameterIndex: number): void {\r\n\t\tconst [start, end] = this.getParameterLabelOffsets(signature, activeParameterIndex);\r\n\r\n\t\tconst beforeSpan = document.createElement('span');\r\n\t\tbeforeSpan.textContent = signature.label.substring(0, start);\r\n\r\n\t\tconst paramSpan = document.createElement('span');\r\n\t\tparamSpan.textContent = signature.label.substring(start, end);\r\n\t\tparamSpan.className = 'parameter active';\r\n\r\n\t\tconst afterSpan = document.createElement('span');\r\n\t\tafterSpan.textContent = signature.label.substring(end);\r\n\r\n\t\tdom.append(parent, beforeSpan, paramSpan, afterSpan);\r\n\t}\r\n\r\n\tprivate getParameterLabel(signature: modes.SignatureInformation, paramIdx: number): string {\r\n\t\tconst param = signature.parameters[paramIdx];\r\n\t\tif (Array.isArray(param.label)) {\r\n\t\t\treturn signature.label.substring(param.label[0], param.label[1]);\r\n\t\t} else {\r\n\t\t\treturn param.label;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate getParameterLabelOffsets(signature: modes.SignatureInformation, paramIdx: number): [number, number] {\r\n\t\tconst param = signature.parameters[paramIdx];\r\n\t\tif (!param) {\r\n\t\t\treturn [0, 0];\r\n\t\t} else if (Array.isArray(param.label)) {\r\n\t\t\treturn param.label;\r\n\t\t} else if (!param.label.length) {\r\n\t\t\treturn [0, 0];\r\n\t\t} else {\r\n\t\t\tconst regex = new RegExp(`(\\\\W|^)${escapeRegExpCharacters(param.label)}(?=\\\\W|$)`, 'g');\r\n\t\t\tregex.test(signature.label);\r\n\t\t\tconst idx = regex.lastIndex - param.label.length;\r\n\t\t\treturn idx >= 0\r\n\t\t\t\t? [idx, regex.lastIndex]\r\n\t\t\t\t: [0, 0];\r\n\t\t}\r\n\t}\r\n\r\n\tnext(): void {\r\n\t\tthis.editor.focus();\r\n\t\tthis.model.next();\r\n\t}\r\n\r\n\tprevious(): void {\r\n\t\tthis.editor.focus();\r\n\t\tthis.model.previous();\r\n\t}\r\n\r\n\tcancel(): void {\r\n\t\tthis.model.cancel();\r\n\t}\r\n\r\n\tgetDomNode(): HTMLElement {\r\n\t\tif (!this.domNodes) {\r\n\t\t\tthis.createParamaterHintDOMNodes();\r\n\t\t}\r\n\t\treturn this.domNodes!.element;\r\n\t}\r\n\r\n\tgetId(): string {\r\n\t\treturn ParameterHintsWidget.ID;\r\n\t}\r\n\r\n\ttrigger(context: TriggerContext): void {\r\n\t\tthis.model.trigger(context, 0);\r\n\t}\r\n\r\n\tprivate updateMaxHeight(): void {\r\n\t\tif (!this.domNodes) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst height = Math.max(this.editor.getLayoutInfo().height / 4, 250);\r\n\t\tconst maxHeight = `${height}px`;\r\n\t\tthis.domNodes.element.style.maxHeight = maxHeight;\r\n\t\tconst wrapper = this.domNodes.element.getElementsByClassName('phwrapper') as HTMLCollectionOf;\r\n\t\tif (wrapper.length) {\r\n\t\t\twrapper[0].style.maxHeight = maxHeight;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nregisterThemingParticipant((theme, collector) => {\r\n\tconst border = theme.getColor(editorHoverBorder);\r\n\tif (border) {\r\n\t\tconst borderWidth = theme.type === ColorScheme.HIGH_CONTRAST ? 2 : 1;\r\n\t\tcollector.addRule(`.monaco-editor .parameter-hints-widget { border: ${borderWidth}px solid ${border}; }`);\r\n\t\tcollector.addRule(`.monaco-editor .parameter-hints-widget.multiple .body { border-left: 1px solid ${border.transparent(0.5)}; }`);\r\n\t\tcollector.addRule(`.monaco-editor .parameter-hints-widget .signature.has-docs { border-bottom: 1px solid ${border.transparent(0.5)}; }`);\r\n\t}\r\n\tconst background = theme.getColor(editorHoverBackground);\r\n\tif (background) {\r\n\t\tcollector.addRule(`.monaco-editor .parameter-hints-widget { background-color: ${background}; }`);\r\n\t}\r\n\r\n\tconst link = theme.getColor(textLinkForeground);\r\n\tif (link) {\r\n\t\tcollector.addRule(`.monaco-editor .parameter-hints-widget a { color: ${link}; }`);\r\n\t}\r\n\r\n\tconst foreground = theme.getColor(editorHoverForeground);\r\n\tif (foreground) {\r\n\t\tcollector.addRule(`.monaco-editor .parameter-hints-widget { color: ${foreground}; }`);\r\n\t}\r\n\r\n\tconst codeBackground = theme.getColor(textCodeBlockBackground);\r\n\tif (codeBackground) {\r\n\t\tcollector.addRule(`.monaco-editor .parameter-hints-widget code { background-color: ${codeBackground}; }`);\r\n\t}\r\n});\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\r\nimport { Disposable } from 'vs/base/common/lifecycle';\r\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\r\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';\r\nimport { registerEditorAction, registerEditorContribution, ServicesAccessor, EditorAction, EditorCommand, registerEditorCommand } from 'vs/editor/browser/editorExtensions';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { ParameterHintsWidget } from './parameterHintsWidget';\r\nimport { Context } from 'vs/editor/contrib/parameterHints/provideSignatureHelp';\r\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\r\nimport * as modes from 'vs/editor/common/modes';\r\nimport { TriggerContext } from 'vs/editor/contrib/parameterHints/parameterHintsModel';\r\n\r\nclass ParameterHintsController extends Disposable implements IEditorContribution {\r\n\r\n\tpublic static readonly ID = 'editor.controller.parameterHints';\r\n\r\n\tpublic static get(editor: ICodeEditor): ParameterHintsController {\r\n\t\treturn editor.getContribution(ParameterHintsController.ID);\r\n\t}\r\n\r\n\tprivate readonly editor: ICodeEditor;\r\n\tprivate readonly widget: ParameterHintsWidget;\r\n\r\n\tconstructor(editor: ICodeEditor, @IInstantiationService instantiationService: IInstantiationService) {\r\n\t\tsuper();\r\n\t\tthis.editor = editor;\r\n\t\tthis.widget = this._register(instantiationService.createInstance(ParameterHintsWidget, this.editor));\r\n\t}\r\n\r\n\tcancel(): void {\r\n\t\tthis.widget.cancel();\r\n\t}\r\n\r\n\tprevious(): void {\r\n\t\tthis.widget.previous();\r\n\t}\r\n\r\n\tnext(): void {\r\n\t\tthis.widget.next();\r\n\t}\r\n\r\n\ttrigger(context: TriggerContext): void {\r\n\t\tthis.widget.trigger(context);\r\n\t}\r\n}\r\n\r\nexport class TriggerParameterHintsAction extends EditorAction {\r\n\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'editor.action.triggerParameterHints',\r\n\t\t\tlabel: nls.localize('parameterHints.trigger.label', \"Trigger Parameter Hints\"),\r\n\t\t\talias: 'Trigger Parameter Hints',\r\n\t\t\tprecondition: EditorContextKeys.hasSignatureHelpProvider,\r\n\t\t\tkbOpts: {\r\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\r\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Space,\r\n\t\t\t\tweight: KeybindingWeight.EditorContrib\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\r\n\t\tconst controller = ParameterHintsController.get(editor);\r\n\t\tif (controller) {\r\n\t\t\tcontroller.trigger({\r\n\t\t\t\ttriggerKind: modes.SignatureHelpTriggerKind.Invoke\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n}\r\n\r\nregisterEditorContribution(ParameterHintsController.ID, ParameterHintsController);\r\nregisterEditorAction(TriggerParameterHintsAction);\r\n\r\nconst weight = KeybindingWeight.EditorContrib + 75;\r\n\r\nconst ParameterHintsCommand = EditorCommand.bindToContribution(ParameterHintsController.get);\r\n\r\nregisterEditorCommand(new ParameterHintsCommand({\r\n\tid: 'closeParameterHints',\r\n\tprecondition: Context.Visible,\r\n\thandler: x => x.cancel(),\r\n\tkbOpts: {\r\n\t\tweight: weight,\r\n\t\tkbExpr: EditorContextKeys.focus,\r\n\t\tprimary: KeyCode.Escape,\r\n\t\tsecondary: [KeyMod.Shift | KeyCode.Escape]\r\n\t}\r\n}));\r\nregisterEditorCommand(new ParameterHintsCommand({\r\n\tid: 'showPrevParameterHint',\r\n\tprecondition: ContextKeyExpr.and(Context.Visible, Context.MultipleSignatures),\r\n\thandler: x => x.previous(),\r\n\tkbOpts: {\r\n\t\tweight: weight,\r\n\t\tkbExpr: EditorContextKeys.focus,\r\n\t\tprimary: KeyCode.UpArrow,\r\n\t\tsecondary: [KeyMod.Alt | KeyCode.UpArrow],\r\n\t\tmac: { primary: KeyCode.UpArrow, secondary: [KeyMod.Alt | KeyCode.UpArrow, KeyMod.WinCtrl | KeyCode.KEY_P] }\r\n\t}\r\n}));\r\nregisterEditorCommand(new ParameterHintsCommand({\r\n\tid: 'showNextParameterHint',\r\n\tprecondition: ContextKeyExpr.and(Context.Visible, Context.MultipleSignatures),\r\n\thandler: x => x.next(),\r\n\tkbOpts: {\r\n\t\tweight: weight,\r\n\t\tkbExpr: EditorContextKeys.focus,\r\n\t\tprimary: KeyCode.DownArrow,\r\n\t\tsecondary: [KeyMod.Alt | KeyCode.DownArrow],\r\n\t\tmac: { primary: KeyCode.DownArrow, secondary: [KeyMod.Alt | KeyCode.DownArrow, KeyMod.WinCtrl | KeyCode.KEY_N] }\r\n\t}\r\n}));\r\n","/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Microsoft Corporation. All rights reserved.\r\n * Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport * as nls from 'vs/nls';\r\nimport { createMatches } from 'vs/base/common/filters';\r\nimport { DisposableStore } from 'vs/base/common/lifecycle';\r\nimport { append, $, hide, show } from 'vs/base/browser/dom';\r\nimport { IListRenderer } from 'vs/base/browser/ui/list/list';\r\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { CompletionItem } from './suggest';\r\nimport { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService';\r\nimport { IModeService } from 'vs/editor/common/services/modeService';\r\nimport { CompletionItemKind, completionKindToCssClass, CompletionItemTag } from 'vs/editor/common/modes';\r\nimport { IconLabel, IIconLabelValueOptions } from 'vs/base/browser/ui/iconLabel/iconLabel';\r\nimport { getIconClasses } from 'vs/editor/common/services/getIconClasses';\r\nimport { IModelService } from 'vs/editor/common/services/modelService';\r\nimport { URI } from 'vs/base/common/uri';\r\nimport { FileKind } from 'vs/platform/files/common/files';\r\nimport { flatten } from 'vs/base/common/arrays';\r\nimport { canExpandCompletionItem } from './suggestWidgetDetails';\r\nimport { Codicon } from 'vs/base/common/codicons';\r\nimport { Emitter, Event } from 'vs/base/common/event';\r\nimport { registerIcon } from 'vs/platform/theme/common/iconRegistry';\r\n\r\nexport function getAriaId(index: number): string {\r\n\treturn `suggest-aria-id:${index}`;\r\n}\r\n\r\nexport const suggestMoreInfoIcon = registerIcon('suggest-more-info', Codicon.chevronRight, nls.localize('suggestMoreInfoIcon', 'Icon for more information in the suggest widget.'));\r\n\r\nconst _completionItemColor = new class ColorExtractor {\r\n\r\n\tprivate static _regexRelaxed = /(#([\\da-fA-F]{3}){1,2}|(rgb|hsl)a\\(\\s*(\\d{1,3}%?\\s*,\\s*){3}(1|0?\\.\\d+)\\)|(rgb|hsl)\\(\\s*\\d{1,3}%?(\\s*,\\s*\\d{1,3}%?){2}\\s*\\))/;\r\n\tprivate static _regexStrict = new RegExp(`^${ColorExtractor._regexRelaxed.source}$`, 'i');\r\n\r\n\textract(item: CompletionItem, out: string[]): boolean {\r\n\t\tif (item.textLabel.match(ColorExtractor._regexStrict)) {\r\n\t\t\tout[0] = item.textLabel;\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (item.completion.detail && item.completion.detail.match(ColorExtractor._regexStrict)) {\r\n\t\t\tout[0] = item.completion.detail;\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif (typeof item.completion.documentation === 'string') {\r\n\t\t\tconst match = ColorExtractor._regexRelaxed.exec(item.completion.documentation);\r\n\t\t\tif (match && (match.index === 0 || match.index + match[0].length === item.completion.documentation.length)) {\r\n\t\t\t\tout[0] = match[0];\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n};\r\n\r\n\r\nexport interface ISuggestionTemplateData {\r\n\troot: HTMLElement;\r\n\r\n\t/**\r\n\t * Flexbox\r\n\t * < ------------- left ------------ > < --- right -- >\r\n\t *